ide.st 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762
  1. Widget subclass: #TabManager
  2. instanceVariableNames: 'selectedTab tabs opened'
  3. category: 'IDE'!
  4. TabManager class instanceVariableNames: 'current'!
  5. !TabManager class methodsFor: 'instance creation'!
  6. current
  7. ^current ifNil: [current := super new]
  8. !
  9. new
  10. self shouldNotImplement
  11. ! !
  12. !TabManager methodsFor: 'initialization'!
  13. initialize
  14. super initialize.
  15. opened := true.
  16. 'body' asJQuery
  17. append: self;
  18. addClass: 'jtalk'.
  19. self
  20. addTab: Transcript current;
  21. addTab: Workspace new.
  22. self selectTab: self tabs last.
  23. ! !
  24. !TabManager methodsFor: 'accessing'!
  25. tabs
  26. ^tabs ifNil: [tabs := Array new]
  27. ! !
  28. !TabManager methodsFor: 'adding/Removing'!
  29. addTab: aWidget
  30. self tabs add: aWidget.
  31. 'body' asJQuery append: aWidget.
  32. aWidget root asJQuery hide
  33. !
  34. removeTab: aWidget
  35. self tabs remove: aWidget.
  36. self update
  37. ! !
  38. !TabManager methodsFor: 'actions'!
  39. open
  40. opened ifFalse: [
  41. self root asJQuery show.
  42. 'body' asJQuery addClass: 'jtalk'.
  43. selectedTab root asJQuery show.
  44. opened := true]
  45. !
  46. close
  47. opened ifTrue: [
  48. self tabs do: [:each |
  49. each root asJQuery hide].
  50. self root asJQuery hide.
  51. 'body' asJQuery removeClass: 'jtalk'.
  52. opened := false]
  53. !
  54. newBrowserTab
  55. Browser open
  56. !
  57. selectTab: aWidget
  58. self open.
  59. selectedTab := aWidget.
  60. self tabs do: [:each |
  61. each root asJQuery hide].
  62. aWidget root asJQuery show.
  63. self update
  64. !
  65. closeTab: aWidget
  66. self removeTab: aWidget.
  67. self selectTab: self tabs last.
  68. aWidget root asJQuery remove.
  69. self update
  70. ! !
  71. !TabManager methodsFor: 'rendering'!
  72. renderOn: html
  73. html ul
  74. id: 'jtalkTabs';
  75. with: [
  76. html li
  77. class: 'closeAll';
  78. with: 'x';
  79. onClick: [self close].
  80. self tabs do: [:each |
  81. self renderTabFor: each on: html].
  82. html li
  83. class: 'newtab';
  84. with: ' + ';
  85. onClick: [self newBrowserTab]]
  86. !
  87. renderTabFor: aWidget on: html
  88. | li |
  89. li := html li.
  90. selectedTab = aWidget ifTrue: [
  91. li class: 'selected'].
  92. li with: [
  93. html span
  94. with: aWidget label;
  95. onClick: [self selectTab: aWidget].
  96. aWidget canBeClosed ifTrue: [
  97. html span
  98. class: 'close';
  99. with: 'x';
  100. onClick: [self closeTab: aWidget]]]
  101. ! !
  102. Widget subclass: #TabWidget
  103. instanceVariableNames: ''
  104. category: 'IDE'!
  105. !TabWidget class methodsFor: 'instance creation'!
  106. open
  107. ^self new open
  108. ! !
  109. !TabWidget methodsFor: 'accessing'!
  110. label
  111. self subclassResponsibility
  112. ! !
  113. !TabWidget methodsFor: 'actions'!
  114. open
  115. TabManager current
  116. addTab: self;
  117. selectTab: self
  118. ! !
  119. !TabWidget methodsFor: 'testing'!
  120. canBeClosed
  121. ^false
  122. ! !
  123. !TabWidget methodsFor: 'rendering'!
  124. renderOn: html
  125. html div
  126. class: 'jtalkTool';
  127. with: [
  128. html div
  129. class: 'box';
  130. with: [self renderBoxOn: html].
  131. html div
  132. class: 'buttons';
  133. with: [self renderButtonsOn: html]]
  134. !
  135. renderBoxOn: html
  136. !
  137. renderButtonsOn: html
  138. ! !
  139. TabWidget subclass: #Workspace
  140. instanceVariableNames: 'textarea'
  141. category: 'IDE'!
  142. !Workspace methodsFor: 'accessing'!
  143. label
  144. ^'[Workspace]'
  145. !
  146. selection
  147. ^{'return document.selection'}
  148. !
  149. selectionStart
  150. ^{'return jQuery(''.workspace'')[0].selectionStart'}
  151. !
  152. selectionEnd
  153. ^{'return jQuery(''.workspace'')[0].selectionEnd'}
  154. !
  155. selectionStart: anInteger
  156. {'jQuery(''.workspace'')[0].selectionStart = anInteger'}
  157. !
  158. selectionEnd: anInteger
  159. {'jQuery(''.workspace'')[0].selectionEnd = anInteger'}
  160. !
  161. currentLine
  162. | lines startLine endLine|
  163. lines := textarea asJQuery val tokenize: String cr.
  164. startLine := endLine := 0.
  165. lines do: [:each |
  166. endLine := startLine + each size.
  167. startLine := endLine + 1.
  168. endLine >= self selectionStart ifTrue: [
  169. self selectionEnd: endLine.
  170. ^each]]
  171. ! !
  172. !Workspace methodsFor: 'actions'!
  173. handleKeyDown: anEvent
  174. ^{'if(anEvent.ctrlKey) {
  175. if(anEvent.keyCode === 68) { //ctrl+p
  176. self._printIt();
  177. return false;
  178. }
  179. if(anEvent.keyCode === 80) { //ctrl+d
  180. self._doIt();
  181. return false;
  182. }
  183. }'}
  184. !
  185. clearWorkspace
  186. textarea asJQuery val: ''
  187. !
  188. doIt
  189. self printIt
  190. !
  191. printIt
  192. | selection |
  193. textarea asJQuery focus.
  194. self selectionStart = self selectionEnd
  195. ifTrue: [selection := self currentLine]
  196. ifFalse: [
  197. selection := textarea asJQuery val copyFrom: self selectionStart + 1 to: self selectionEnd + 1].
  198. self print: (self eval: selection) printString
  199. !
  200. print: aString
  201. | start |
  202. start := self selectionEnd.
  203. textarea asJQuery val: (
  204. (textarea asJQuery val copyFrom: 1 to: start),
  205. ' ', aString, ' ',
  206. (textarea asJQuery val copyFrom: start + 1 to: textarea asJQuery val size)).
  207. self selectionStart: start.
  208. self selectionEnd: start + aString size + 2
  209. !
  210. eval: aString
  211. ^Compiler new loadExpression: aString
  212. ! !
  213. !Workspace methodsFor: 'rendering'!
  214. renderBoxOn: html
  215. textarea := html textarea.
  216. textarea onKeyDown: [:e | self handleKeyDown: e].
  217. textarea
  218. class: 'workspace';
  219. at: 'spellcheck' put: 'false'
  220. !
  221. renderButtonsOn: html
  222. html button
  223. with: 'DoIt';
  224. title: 'ctrl+d';
  225. onClick: [self doIt].
  226. html button
  227. with: 'PrintIt';
  228. title: 'ctrl+p';
  229. onClick: [self printIt].
  230. html button
  231. with: 'Clear workspace';
  232. onClick: [self clearWorkspace]
  233. ! !
  234. TabWidget subclass: #Transcript
  235. instanceVariableNames: 'textarea'
  236. category: 'IDE'!
  237. Transcript class instanceVariableNames: 'current'!
  238. !Transcript class methodsFor: 'instance creation'!
  239. open
  240. self current open
  241. !
  242. new
  243. self shouldNotImplement
  244. !
  245. current
  246. ^current ifNil: [current := super new]
  247. ! !
  248. !Transcript class methodsFor: 'printing'!
  249. show: anObject
  250. self current show: anObject
  251. !
  252. cr
  253. self current show: String cr
  254. !
  255. clear
  256. self current clear
  257. ! !
  258. !Transcript methodsFor: 'accessing'!
  259. label
  260. ^'[Transcript]'
  261. ! !
  262. !Transcript methodsFor: 'actions'!
  263. show: anObject
  264. textarea asJQuery val: textarea asJQuery val, anObject asString.
  265. !
  266. cr
  267. textarea asJQuery val: textarea asJQuery val, String cr.
  268. !
  269. clear
  270. textarea asJQuery val: ''
  271. ! !
  272. !Transcript methodsFor: 'rendering'!
  273. renderBoxOn: html
  274. textarea := html textarea.
  275. textarea
  276. class: 'transcript';
  277. at: 'spellcheck' put: 'false'
  278. !
  279. renderButtonsOn: html
  280. html button
  281. with: 'Clear transcript';
  282. onClick: [self clear]
  283. ! !
  284. TabWidget subclass: #Browser
  285. instanceVariableNames: 'selectedCategory selectedClass selectedProtocol selectedMethod categoriesList classesList protocolsList methodsList sourceTextarea tabsList selectedTab saveButton classButtons methodButtons'
  286. category: 'IDE'!
  287. !Browser class methodsFor: 'convenience'!
  288. open
  289. self new open
  290. ! !
  291. !Browser methodsFor: 'initialization'!
  292. initialize
  293. super initialize.
  294. selectedTab := #instance
  295. ! !
  296. !Browser methodsFor: 'accessing'!
  297. label
  298. ^selectedClass
  299. ifNil: ['Browser (nil)']
  300. ifNotNil: [selectedClass name]
  301. !
  302. categories
  303. | categories |
  304. categories := Array new.
  305. Smalltalk current classes do: [:each |
  306. (categories includes: each category) ifFalse: [
  307. categories add: each category]].
  308. ^categories sort
  309. !
  310. classes
  311. ^(Smalltalk current classes
  312. select: [:each | each category = selectedCategory])
  313. sort: [:a :b | a name > b name]
  314. !
  315. protocols
  316. | class protocols |
  317. protocols := Array new.
  318. selectedClass ifNotNil: [
  319. selectedTab = #comment ifTrue: [^#()].
  320. class := selectedTab = #instance
  321. ifTrue: [selectedClass]
  322. ifFalse: [selectedClass class].
  323. class methodDictionary isEmpty ifTrue: [
  324. protocols add: 'not yet classified'].
  325. class methodDictionary do: [:each |
  326. (protocols includes: each category) ifFalse: [
  327. protocols add: each category]]].
  328. ^protocols sort
  329. !
  330. methods
  331. | class |
  332. selectedTab = #comment ifTrue: [^#()].
  333. selectedClass ifNotNil: [
  334. class := selectedTab = #instance
  335. ifTrue: [selectedClass]
  336. ifFalse: [selectedClass class]].
  337. ^(selectedProtocol
  338. ifNil: [
  339. class
  340. ifNil: [#()]
  341. ifNotNil: [class methodDictionary values]]
  342. ifNotNil: [
  343. class methodDictionary values select: [:each |
  344. each category = selectedProtocol]]) sort: [:a :b | a selector > b selector]
  345. !
  346. source
  347. selectedTab = #comment ifFalse: [
  348. ^(selectedProtocol notNil or: [selectedMethod notNil])
  349. ifFalse: [self declarationSource]
  350. ifTrue: [self methodSource]].
  351. ^selectedClass
  352. ifNil: ['']
  353. ifNotNil: [self classCommentSource]
  354. !
  355. methodSource
  356. ^selectedMethod
  357. ifNil: [self dummyMethodSource]
  358. ifNotNil: [selectedMethod source]
  359. !
  360. dummyMethodSource
  361. ^'messageSelectorAndArgumentNames
  362. "comment stating purpose of message"
  363. | temporary variable names |
  364. statements'
  365. !
  366. declarationSource
  367. ^selectedTab = #instance
  368. ifTrue: [self classDeclarationSource]
  369. ifFalse: [self metaclassDeclarationSource]
  370. !
  371. classDeclarationSource
  372. | stream |
  373. stream := '' writeStream.
  374. selectedClass ifNotNil: [
  375. stream
  376. nextPutAll: selectedClass superclass asString;
  377. nextPutAll: ' subclass: #';
  378. nextPutAll: selectedClass name;
  379. nextPutAll: String cr, String tab;
  380. nextPutAll: 'instanceVariableNames: '''.
  381. selectedClass instanceVariableNames
  382. do: [:each | stream nextPutAll: each]
  383. separatedBy: [stream nextPutAll: ' '].
  384. stream
  385. nextPutAll: '''', String cr, String tab;
  386. nextPutAll: 'category: ''';
  387. nextPutAll: selectedClass category;
  388. nextPutAll: ''''].
  389. ^stream contents
  390. !
  391. metaclassDeclarationSource
  392. | stream |
  393. stream := '' writeStream.
  394. selectedClass ifNotNil: [
  395. stream
  396. nextPutAll: selectedClass asString;
  397. nextPutAll: ' class ';
  398. nextPutAll: 'instanceVariableNames: '''.
  399. selectedClass class instanceVariableNames
  400. do: [:each | stream nextPutAll: each]
  401. separatedBy: [stream nextPutAll: ' '].
  402. stream nextPutAll: ''''].
  403. ^stream contents
  404. !
  405. classCommentSource
  406. ^selectedClass comment
  407. ! !
  408. !Browser methodsFor: 'actions'!
  409. enableSaveButton
  410. saveButton removeAt: 'disabled'
  411. !
  412. disableSaveButton
  413. saveButton ifNotNil: [
  414. saveButton at: 'disabled' put: true]
  415. !
  416. hideClassButtons
  417. classButtons asJQuery hide
  418. !
  419. showClassButtons
  420. classButtons asJQuery show
  421. !
  422. hideMethodButtons
  423. methodButtons asJQuery hide
  424. !
  425. showMethodButtons
  426. methodButtons asJQuery show
  427. !
  428. compile
  429. selectedTab = #comment ifTrue: [
  430. selectedClass ifNotNil: [
  431. self compileClassComment]].
  432. (selectedProtocol notNil or: [selectedMethod notNil])
  433. ifFalse: [self compileDefinition]
  434. ifTrue: [self compileMethodDefinition].
  435. self disableSaveButton
  436. !
  437. compileClassComment
  438. selectedClass comment: sourceTextarea asJQuery val
  439. !
  440. compileMethodDefinition
  441. selectedTab = #instance
  442. ifTrue: [self compileMethodDefinitionFor: selectedClass]
  443. ifFalse: [self compileMethodDefinitionFor: selectedClass class]
  444. !
  445. compileMethodDefinitionFor: aClass
  446. | method |
  447. method := Compiler new load: sourceTextarea asJQuery val forClass: selectedClass.
  448. method category: selectedProtocol.
  449. aClass addCompiledMethod: method.
  450. self updateMethodsList.
  451. self selectMethod: method
  452. !
  453. compileDefinition
  454. | newClass |
  455. newClass := Compiler new loadExpression: sourceTextarea asJQuery val.
  456. self
  457. updateCategoriesList;
  458. updateClassesList
  459. !
  460. selectCategory: aCategory
  461. selectedCategory := aCategory.
  462. selectedClass := selectedProtocol := selectedMethod := nil.
  463. self
  464. updateCategoriesList;
  465. updateClassesList;
  466. updateProtocolsList;
  467. updateMethodsList;
  468. updateSourceAndButtons
  469. !
  470. selectClass: aClass
  471. selectedClass := aClass.
  472. selectedProtocol := selectedMethod := nil.
  473. self
  474. updateClassesList;
  475. updateProtocolsList;
  476. updateMethodsList;
  477. updateSourceAndButtons
  478. !
  479. selectProtocol: aString
  480. selectedProtocol := aString.
  481. selectedMethod := nil.
  482. self
  483. updateProtocolsList;
  484. updateMethodsList;
  485. updateSourceAndButtons
  486. !
  487. selectMethod: aMethod
  488. selectedMethod := aMethod.
  489. self
  490. updateProtocolsList;
  491. updateMethodsList;
  492. updateSourceAndButtons
  493. !
  494. selectTab: aString
  495. selectedTab := aString.
  496. self selectProtocol: nil.
  497. self updateTabsList.
  498. ! !
  499. !Browser methodsFor: 'rendering'!
  500. renderBoxOn: html
  501. self
  502. renderTopPanelOn: html;
  503. renderTabsOn: html;
  504. renderBottomPanelOn: html
  505. !
  506. renderTopPanelOn: html
  507. html div
  508. class: 'top';
  509. with: [
  510. categoriesList := html ul class: 'column categories'.
  511. classesList := html ul class: 'column classes'.
  512. protocolsList := html ul class: 'column protocols'.
  513. methodsList := html ul class: 'column methods'.
  514. self
  515. updateCategoriesList;
  516. updateClassesList;
  517. updateProtocolsList;
  518. updateMethodsList.
  519. html div class: 'clear']
  520. !
  521. renderTabsOn: html
  522. tabsList := html ul class: 'tabs'.
  523. self updateTabsList.
  524. !
  525. renderBottomPanelOn: html
  526. html div
  527. class: 'sourceCode';
  528. with: [
  529. sourceTextarea := html textarea
  530. onKeyPress: [self enableSaveButton];
  531. class: 'source';
  532. at: 'spellcheck' put: 'false']
  533. !
  534. renderButtonsOn: html
  535. saveButton := html button.
  536. saveButton
  537. with: 'Save';
  538. onClick: [self compile].
  539. methodButtons := html span with: [
  540. html button
  541. with: 'Remove method';
  542. onClick: [self removeMethod]].
  543. classButtons := html span with: [
  544. html button
  545. with: 'Remove class';
  546. onClick: [self removeClass]].
  547. self updateSourceAndButtons
  548. ! !
  549. !Browser methodsFor: 'updating'!
  550. updateCategoriesList
  551. categoriesList contents: [:html |
  552. self categories do: [:each || li |
  553. li := html li.
  554. selectedCategory = each ifTrue: [
  555. li class: 'selected'].
  556. li
  557. with: each;
  558. onClick: [self selectCategory: each]]]
  559. !
  560. updateClassesList
  561. TabManager current update.
  562. classesList contents: [:html |
  563. self classes do: [:each || li |
  564. li := html li.
  565. selectedClass = each ifTrue: [
  566. li class: 'selected'].
  567. li
  568. with: each name;
  569. onClick: [self selectClass: each]]]
  570. !
  571. updateProtocolsList
  572. protocolsList contents: [:html |
  573. self protocols do: [:each || li |
  574. li := html li.
  575. selectedProtocol = each ifTrue: [
  576. li class: 'selected'].
  577. li
  578. with: each;
  579. onClick: [self selectProtocol: each]]]
  580. !
  581. updateMethodsList
  582. methodsList contents: [:html |
  583. self methods do: [:each || li |
  584. li := html li.
  585. selectedMethod = each ifTrue: [
  586. li class: 'selected'].
  587. li
  588. with: each selector;
  589. onClick: [self selectMethod: each]]]
  590. !
  591. updateTabsList
  592. tabsList contents: [:html || li |
  593. li := html li.
  594. selectedTab = #instance ifTrue: [li class: 'selected'].
  595. li
  596. with: 'Instance';
  597. onClick: [self selectTab: #instance].
  598. li := html li.
  599. selectedTab = #class ifTrue: [li class: 'selected'].
  600. li
  601. with: 'Class';
  602. onClick: [self selectTab: #class].
  603. li := html li.
  604. selectedTab = #comment ifTrue: [li class: 'selected'].
  605. li
  606. with: 'Comment';
  607. onClick: [self selectTab: #comment]]
  608. !
  609. updateSourceAndButtons
  610. self disableSaveButton.
  611. selectedMethod
  612. ifNil: [
  613. self hideMethodButtons.
  614. selectedClass
  615. ifNil: [self hideClassButtons]
  616. ifNotNil: [self showClassButtons]]
  617. ifNotNil: [
  618. self hideClassButtons
  619. self showMethodButtons].
  620. sourceTextarea asJQuery val: self source
  621. ! !
  622. !Browser methodsFor: 'testing'!
  623. canBeClosed
  624. ^true
  625. ! !