1
0

IDE.st 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347
  1. Widget subclass: #TabManager
  2. instanceVariableNames: 'selectedTab tabs opened'
  3. category: 'IDE'!
  4. !TabManager methodsFor: 'accessing'!
  5. tabs
  6. ^tabs ifNil: [tabs := Array new]
  7. ! !
  8. !TabManager methodsFor: 'actions'!
  9. updateBodyMargin
  10. self setBodyMargin: '#jtalk' asJQuery height + 27
  11. !
  12. updatePosition
  13. <jQuery('#jtalk').css('top', '').css('bottom', '27px')>
  14. !
  15. removeBodyMargin
  16. self setBodyMargin: 0
  17. !
  18. setBodyMargin: anInteger
  19. '.jtalkBody' asJQuery cssAt: 'margin-bottom' put: anInteger asString, 'px'
  20. !
  21. onResize: aBlock
  22. <jQuery('#jtalk').resizable({
  23. handles: 'n',
  24. resize: aBlock,
  25. minHeight: 230
  26. })>
  27. !
  28. onWindowResize: aBlock
  29. <jQuery(window).resize(aBlock)>
  30. !
  31. open
  32. opened ifFalse: [
  33. self root asJQuery show.
  34. 'body' asJQuery addClass: 'jtalkBody'.
  35. '#jtalk' asJQuery show.
  36. self updateBodyMargin.
  37. selectedTab root asJQuery show.
  38. opened := true]
  39. !
  40. close
  41. opened ifTrue: [
  42. self root asJQuery hide.
  43. '#jtalk' asJQuery hide.
  44. self removeBodyMargin.
  45. 'body' asJQuery removeClass: 'jtalkBody'.
  46. opened := false]
  47. !
  48. newBrowserTab
  49. Browser open
  50. !
  51. selectTab: aWidget
  52. self open.
  53. selectedTab := aWidget.
  54. self tabs do: [:each |
  55. each root asJQuery hide].
  56. aWidget root asJQuery show.
  57. self update
  58. !
  59. closeTab: aWidget
  60. self removeTab: aWidget.
  61. self selectTab: self tabs last.
  62. aWidget root asJQuery remove.
  63. self update
  64. ! !
  65. !TabManager methodsFor: 'adding/Removing'!
  66. addTab: aWidget
  67. self tabs add: aWidget.
  68. '#jtalk' asJQuery append: aWidget.
  69. aWidget root asJQuery hide
  70. !
  71. removeTab: aWidget
  72. self tabs remove: aWidget.
  73. self update
  74. ! !
  75. !TabManager methodsFor: 'initialization'!
  76. initialize
  77. super initialize.
  78. opened := true.
  79. 'body' asJQuery
  80. append: self;
  81. append: [:html | html div id: 'jtalk'];
  82. addClass: 'jtalkBody'.
  83. self
  84. addTab: Transcript current;
  85. addTab: Workspace new.
  86. self selectTab: self tabs last.
  87. self
  88. onResize: [self updateBodyMargin; updatePosition];
  89. onWindowResize: [self updatePosition]
  90. ! !
  91. !TabManager methodsFor: 'rendering'!
  92. renderOn: html
  93. html ul
  94. id: 'jtalkTabs';
  95. with: [
  96. html li
  97. class: 'closeAll';
  98. with: 'x';
  99. onClick: [self close].
  100. self tabs do: [:each |
  101. self renderTabFor: each on: html].
  102. html li
  103. class: 'newtab';
  104. with: ' + ';
  105. onClick: [self newBrowserTab]]
  106. !
  107. renderTabFor: aWidget on: html
  108. | li |
  109. li := html li.
  110. selectedTab = aWidget ifTrue: [
  111. li class: 'selected'].
  112. li with: [
  113. html span
  114. with: aWidget label;
  115. onClick: [self selectTab: aWidget].
  116. aWidget canBeClosed ifTrue: [
  117. html span
  118. class: 'close';
  119. with: 'x';
  120. onClick: [self closeTab: aWidget]]]
  121. ! !
  122. TabManager class instanceVariableNames: 'current'!
  123. !TabManager class methodsFor: 'instance creation'!
  124. current
  125. ^current ifNil: [current := super new]
  126. !
  127. new
  128. self shouldNotImplement
  129. ! !
  130. Widget subclass: #TabWidget
  131. instanceVariableNames: ''
  132. category: 'IDE'!
  133. !TabWidget methodsFor: 'accessing'!
  134. label
  135. self subclassResponsibility
  136. ! !
  137. !TabWidget methodsFor: 'actions'!
  138. open
  139. TabManager current
  140. addTab: self;
  141. selectTab: self
  142. ! !
  143. !TabWidget methodsFor: 'rendering'!
  144. renderOn: html
  145. html root
  146. class: 'jtalkTool';
  147. with: [
  148. html div
  149. class: 'jt_box';
  150. with: [self renderBoxOn: html].
  151. html div
  152. class: 'jt_buttons';
  153. with: [self renderButtonsOn: html]]
  154. !
  155. renderBoxOn: html
  156. !
  157. renderButtonsOn: html
  158. ! !
  159. !TabWidget methodsFor: 'testing'!
  160. canBeClosed
  161. ^false
  162. ! !
  163. !TabWidget class methodsFor: 'instance creation'!
  164. open
  165. ^self new open
  166. ! !
  167. TabWidget subclass: #Workspace
  168. instanceVariableNames: 'textarea'
  169. category: 'IDE'!
  170. !Workspace methodsFor: 'accessing'!
  171. label
  172. ^'[Workspace]'
  173. !
  174. selection
  175. <return document.selection>
  176. !
  177. selectionStart
  178. <return jQuery('.jt_workspace')[0].selectionStart>
  179. !
  180. selectionEnd
  181. <return jQuery('.jt_workspace')[0].selectionEnd>
  182. !
  183. selectionStart: anInteger
  184. <jQuery('.jt_workspace')[0].selectionStart = anInteger>
  185. !
  186. selectionEnd: anInteger
  187. <jQuery('.jt_workspace')[0].selectionEnd = anInteger>
  188. !
  189. currentLine
  190. | lines startLine endLine|
  191. lines := textarea asJQuery val tokenize: String lf.
  192. startLine := endLine := 0.
  193. lines do: [:each |
  194. endLine := startLine + each size.
  195. startLine := endLine + 1.
  196. endLine >= self selectionStart ifTrue: [
  197. self selectionEnd: endLine.
  198. ^each]]
  199. ! !
  200. !Workspace methodsFor: 'actions'!
  201. handleKeyDown: anEvent
  202. <if(anEvent.ctrlKey) {
  203. if(anEvent.keyCode === 80) { //ctrl+p
  204. self._printIt();
  205. anEvent.preventDefault();
  206. return false;
  207. }
  208. if(anEvent.keyCode === 68) { //ctrl+d
  209. self._doIt();
  210. anEvent.preventDefault();
  211. return false;
  212. }
  213. if(anEvent.keyCode === 73) { //ctrl+i
  214. self._inspectIt();
  215. anEvent.preventDefault();
  216. return false;
  217. }
  218. }>
  219. !
  220. clearWorkspace
  221. textarea asJQuery val: ''
  222. !
  223. doIt
  224. | selection |
  225. textarea asJQuery focus.
  226. self selectionStart = self selectionEnd
  227. ifTrue: [selection := self currentLine]
  228. ifFalse: [
  229. selection := textarea asJQuery val copyFrom: self selectionStart + 1 to: self selectionEnd + 1].
  230. ^self eval: selection
  231. !
  232. printIt
  233. self print: self doIt printString
  234. !
  235. print: aString
  236. | start |
  237. start := self selectionEnd.
  238. textarea asJQuery val: (
  239. (textarea asJQuery val copyFrom: 1 to: start),
  240. ' ', aString, ' ',
  241. (textarea asJQuery val copyFrom: start + 1 to: textarea asJQuery val size)).
  242. self selectionStart: start.
  243. self selectionEnd: start + aString size + 2
  244. !
  245. eval: aString
  246. | compiler node |
  247. compiler := Compiler new.
  248. node := compiler parseExpression: aString.
  249. node isParseFailure ifTrue: [
  250. ^self alert: node reason, ', position: ', node position].
  251. ^compiler loadExpression: aString
  252. !
  253. inspectIt
  254. self doIt inspect
  255. ! !
  256. !Workspace methodsFor: 'rendering'!
  257. renderBoxOn: html
  258. textarea := html textarea.
  259. textarea asJQuery call: 'tabby'.
  260. textarea onKeyDown: [:e | self handleKeyDown: e].
  261. textarea
  262. class: 'jt_workspace';
  263. at: 'spellcheck' put: 'false'
  264. !
  265. renderButtonsOn: html
  266. html button
  267. with: 'DoIt';
  268. title: 'ctrl+d';
  269. onClick: [self doIt].
  270. html button
  271. with: 'PrintIt';
  272. title: 'ctrl+p';
  273. onClick: [self printIt].
  274. html button
  275. with: 'InspectIt';
  276. title: 'ctrl+i';
  277. onClick: [self inspectIt].
  278. html button
  279. with: 'Clear workspace';
  280. onClick: [self clearWorkspace]
  281. ! !
  282. TabWidget subclass: #Transcript
  283. instanceVariableNames: 'textarea'
  284. category: 'IDE'!
  285. !Transcript methodsFor: 'accessing'!
  286. label
  287. ^'[Transcript]'
  288. ! !
  289. !Transcript methodsFor: 'actions'!
  290. show: anObject
  291. textarea asJQuery val: textarea asJQuery val, anObject asString.
  292. !
  293. cr
  294. textarea asJQuery val: textarea asJQuery val, String cr.
  295. !
  296. clear
  297. textarea asJQuery val: ''
  298. ! !
  299. !Transcript methodsFor: 'rendering'!
  300. renderBoxOn: html
  301. textarea := html textarea.
  302. textarea asJQuery call: 'tabby'.
  303. textarea
  304. class: 'jt_transcript';
  305. at: 'spellcheck' put: 'false'
  306. !
  307. renderButtonsOn: html
  308. html button
  309. with: 'Clear transcript';
  310. onClick: [self clear]
  311. ! !
  312. Transcript class instanceVariableNames: 'current'!
  313. !Transcript class methodsFor: 'instance creation'!
  314. open
  315. self current open
  316. !
  317. new
  318. self shouldNotImplement
  319. !
  320. current
  321. ^current ifNil: [current := super new]
  322. ! !
  323. !Transcript class methodsFor: 'printing'!
  324. show: anObject
  325. self current show: anObject
  326. !
  327. cr
  328. self current show: String cr
  329. !
  330. clear
  331. self current clear
  332. ! !
  333. TabWidget subclass: #Browser
  334. instanceVariableNames: 'selectedCategory selectedClass selectedProtocol selectedMethod commitButton categoriesList classesList protocolsList methodsList sourceTextarea tabsList selectedTab saveButton classButtons methodButtons unsavedChanges'
  335. category: 'IDE'!
  336. !Browser methodsFor: 'accessing'!
  337. label
  338. ^selectedClass
  339. ifNil: ['Browser (nil)']
  340. ifNotNil: [selectedClass name]
  341. !
  342. categories
  343. | categories |
  344. categories := Array new.
  345. Smalltalk current classes do: [:each |
  346. (categories includes: each category) ifFalse: [
  347. categories add: each category]].
  348. ^categories sort
  349. !
  350. classes
  351. ^(Smalltalk current classes
  352. select: [:each | each category = selectedCategory])
  353. sort: [:a :b | a name > b name]
  354. !
  355. protocols
  356. | klass |
  357. selectedClass ifNotNil: [
  358. selectedTab = #comment ifTrue: [^#()].
  359. klass := selectedTab = #instance
  360. ifTrue: [selectedClass]
  361. ifFalse: [selectedClass class].
  362. klass methodDictionary isEmpty ifTrue: [
  363. ^Array with: 'not yet classified'].
  364. ^klass protocols].
  365. ^Array new
  366. !
  367. methods
  368. | klass |
  369. selectedTab = #comment ifTrue: [^#()].
  370. selectedClass ifNotNil: [
  371. klass := selectedTab = #instance
  372. ifTrue: [selectedClass]
  373. ifFalse: [selectedClass class]].
  374. ^(selectedProtocol
  375. ifNil: [
  376. klass
  377. ifNil: [#()]
  378. ifNotNil: [klass methodDictionary values]]
  379. ifNotNil: [
  380. klass methodDictionary values select: [:each |
  381. each category = selectedProtocol]]) sort: [:a :b | a selector > b selector]
  382. !
  383. source
  384. selectedTab = #comment ifFalse: [
  385. ^(selectedProtocol notNil or: [selectedMethod notNil])
  386. ifFalse: [self declarationSource]
  387. ifTrue: [self methodSource]].
  388. ^selectedClass
  389. ifNil: ['']
  390. ifNotNil: [self classCommentSource]
  391. !
  392. methodSource
  393. ^selectedMethod
  394. ifNil: [self dummyMethodSource]
  395. ifNotNil: [selectedMethod source]
  396. !
  397. dummyMethodSource
  398. ^'messageSelectorAndArgumentNames
  399. "comment stating purpose of message"
  400. | temporary variable names |
  401. statements'
  402. !
  403. declarationSource
  404. ^selectedTab = #instance
  405. ifTrue: [self classDeclarationSource]
  406. ifFalse: [self metaclassDeclarationSource]
  407. !
  408. classDeclarationSource
  409. | stream |
  410. stream := '' writeStream.
  411. selectedClass ifNotNil: [
  412. stream
  413. nextPutAll: selectedClass superclass asString;
  414. nextPutAll: ' subclass: #';
  415. nextPutAll: selectedClass name;
  416. nextPutAll: String lf, String tab;
  417. nextPutAll: 'instanceVariableNames: '''.
  418. selectedClass instanceVariableNames
  419. do: [:each | stream nextPutAll: each]
  420. separatedBy: [stream nextPutAll: ' '].
  421. stream
  422. nextPutAll: '''', String lf, String tab;
  423. nextPutAll: 'category: ''';
  424. nextPutAll: selectedClass category;
  425. nextPutAll: ''''].
  426. ^stream contents
  427. !
  428. metaclassDeclarationSource
  429. | stream |
  430. stream := '' writeStream.
  431. selectedClass ifNotNil: [
  432. stream
  433. nextPutAll: selectedClass asString;
  434. nextPutAll: ' class ';
  435. nextPutAll: 'instanceVariableNames: '''.
  436. selectedClass class instanceVariableNames
  437. do: [:each | stream nextPutAll: each]
  438. separatedBy: [stream nextPutAll: ' '].
  439. stream nextPutAll: ''''].
  440. ^stream contents
  441. !
  442. classCommentSource
  443. ^selectedClass comment
  444. ! !
  445. !Browser methodsFor: 'actions'!
  446. enableSaveButton
  447. saveButton removeAt: 'disabled'.
  448. unsavedChanges := true
  449. !
  450. disableSaveButton
  451. saveButton ifNotNil: [
  452. saveButton at: 'disabled' put: true].
  453. unsavedChanges := false
  454. !
  455. hideClassButtons
  456. classButtons asJQuery hide
  457. !
  458. showClassButtons
  459. classButtons asJQuery show
  460. !
  461. hideMethodButtons
  462. methodButtons asJQuery hide
  463. !
  464. showMethodButtons
  465. methodButtons asJQuery show
  466. !
  467. compile
  468. self disableSaveButton.
  469. selectedTab = #comment ifTrue: [
  470. selectedClass ifNotNil: [
  471. self compileClassComment]].
  472. (selectedProtocol notNil or: [selectedMethod notNil])
  473. ifFalse: [self compileDefinition]
  474. ifTrue: [self compileMethodDefinition]
  475. !
  476. compileClassComment
  477. selectedClass comment: sourceTextarea asJQuery val
  478. !
  479. compileMethodDefinition
  480. selectedTab = #instance
  481. ifTrue: [self compileMethodDefinitionFor: selectedClass]
  482. ifFalse: [self compileMethodDefinitionFor: selectedClass class]
  483. !
  484. compileMethodDefinitionFor: aClass
  485. | compiler method source node |
  486. source := sourceTextarea asJQuery val.
  487. selectedProtocol ifNil: [selectedProtocol := selectedMethod category].
  488. compiler := Compiler new.
  489. node := compiler parse: source.
  490. node isParseFailure ifTrue: [
  491. ^self alert: 'PARSE ERROR: ', node reason, ', position: ', node position asString].
  492. compiler currentClass: selectedClass.
  493. method := compiler eval: (compiler compileNode: node).
  494. method category: selectedProtocol.
  495. compiler unknownVariables do: [:each |
  496. (self confirm: 'Declare ''', each, ''' as instance variable?') ifTrue: [
  497. self addInstanceVariableNamed: each toClass: aClass.
  498. ^self compileMethodDefinitionFor: aClass]].
  499. aClass addCompiledMethod: method.
  500. self updateMethodsList.
  501. self selectMethod: method
  502. !
  503. compileDefinition
  504. | newClass |
  505. newClass := Compiler new loadExpression: sourceTextarea asJQuery val.
  506. self
  507. updateCategoriesList;
  508. updateClassesList
  509. !
  510. commitCategory
  511. selectedCategory ifNotNil: [
  512. (Ajax url: self class commitPathJs, '/', selectedCategory, '.js')
  513. at: 'type' put: 'PUT';
  514. at: 'data' put: (Exporter new exportCategory: selectedCategory);
  515. at: 'error' put: [self alert: 'Commit failed!!'];
  516. send.
  517. (Ajax url: self class commitPathSt, '/', selectedCategory, '.st')
  518. at: 'type' put: 'PUT';
  519. at: 'data' put: (ChunkExporter new exportCategory: selectedCategory);
  520. at: 'error' put: [self alert: 'Commit failed!!'];
  521. send]
  522. !
  523. cancelChanges
  524. ^unsavedChanges
  525. ifTrue: [self confirm: 'Cancel changes?']
  526. ifFalse: [true]
  527. !
  528. removeClass
  529. (self confirm: 'Do you really want to remove ', selectedClass name, '?')
  530. ifTrue: [
  531. Smalltalk current basicDelete: selectedClass name.
  532. self selectClass: nil]
  533. !
  534. removeMethod
  535. self cancelChanges ifTrue: [
  536. (self confirm: 'Do you really want to remove #', selectedMethod selector, '?')
  537. ifTrue: [
  538. selectedTab = #instance
  539. ifTrue: [selectedClass removeCompiledMethod: selectedMethod]
  540. ifFalse: [selectedClass class removeCompiledMethod: selectedMethod].
  541. self selectMethod: nil]]
  542. !
  543. setMethodProtocol: aString
  544. self cancelChanges ifTrue: [
  545. (self protocols includes: aString)
  546. ifFalse: [self addNewProtocol]
  547. ifTrue: [
  548. selectedMethod category: aString.
  549. selectedProtocol := aString.
  550. selectedMethod := selectedMethod.
  551. self
  552. updateProtocolsList;
  553. updateMethodsList;
  554. updateSourceAndButtons]]
  555. !
  556. addNewProtocol
  557. | newProtocol |
  558. newProtocol := self prompt: 'New method protocol'.
  559. newProtocol notEmpty ifTrue: [
  560. selectedMethod category: newProtocol.
  561. self setMethodProtocol: newProtocol]
  562. !
  563. selectCategory: aCategory
  564. self cancelChanges ifTrue: [
  565. selectedCategory := aCategory.
  566. selectedClass := selectedProtocol := selectedMethod := nil.
  567. self
  568. updateCategoriesList;
  569. updateClassesList;
  570. updateProtocolsList;
  571. updateMethodsList;
  572. updateSourceAndButtons]
  573. !
  574. selectClass: aClass
  575. self cancelChanges ifTrue: [
  576. selectedClass := aClass.
  577. selectedProtocol := selectedMethod := nil.
  578. self
  579. updateClassesList;
  580. updateProtocolsList;
  581. updateMethodsList;
  582. updateSourceAndButtons]
  583. !
  584. selectProtocol: aString
  585. self cancelChanges ifTrue: [
  586. selectedProtocol := aString.
  587. selectedMethod := nil.
  588. self
  589. updateProtocolsList;
  590. updateMethodsList;
  591. updateSourceAndButtons]
  592. !
  593. selectMethod: aMethod
  594. self cancelChanges ifTrue: [
  595. selectedMethod := aMethod.
  596. self
  597. updateProtocolsList;
  598. updateMethodsList;
  599. updateSourceAndButtons]
  600. !
  601. selectTab: aString
  602. self cancelChanges ifTrue: [
  603. selectedTab := aString.
  604. self selectProtocol: nil.
  605. self updateTabsList]
  606. !
  607. renameClass
  608. | newName |
  609. newName := self prompt: 'Rename class ', selectedClass name.
  610. newName notEmpty ifTrue: [
  611. selectedClass rename: newName.
  612. self
  613. updateClassesList;
  614. updateSourceAndButtons]
  615. !
  616. addInstanceVariableNamed: aString toClass: aClass
  617. ClassBuilder new
  618. addSubclassOf: aClass superclass named: aClass name instanceVariableNames: (aClass instanceVariableNames copy add: aString; yourself)
  619. !
  620. searchReferencesOf: aString
  621. ReferencesBrowser search: aString
  622. !
  623. searchClassReferences
  624. ReferencesBrowser search: selectedClass name
  625. ! !
  626. !Browser methodsFor: 'initialization'!
  627. initialize
  628. super initialize.
  629. selectedTab := #instance.
  630. unsavedChanges := false
  631. ! !
  632. !Browser methodsFor: 'rendering'!
  633. renderBoxOn: html
  634. self
  635. renderTopPanelOn: html;
  636. renderTabsOn: html;
  637. renderBottomPanelOn: html
  638. !
  639. renderTopPanelOn: html
  640. html div
  641. class: 'top';
  642. with: [
  643. categoriesList := html ul class: 'jt_column categories'.
  644. commitButton := html button
  645. class: 'jt_commit';
  646. title: 'Commit classes in this category to disk';
  647. onClick: [self commitCategory];
  648. with: 'Commit category'.
  649. classesList := html ul class: 'jt_column classes'.
  650. protocolsList := html ul class: 'jt_column protocols'.
  651. methodsList := html ul class: 'jt_column methods'.
  652. self
  653. updateCategoriesList;
  654. updateClassesList;
  655. updateProtocolsList;
  656. updateMethodsList.
  657. html div class: 'jt_clear']
  658. !
  659. renderTabsOn: html
  660. tabsList := html ul class: 'jt_tabs'.
  661. self updateTabsList.
  662. !
  663. renderBottomPanelOn: html
  664. html div
  665. class: 'jt_sourceCode';
  666. with: [
  667. sourceTextarea := html textarea
  668. onKeyPress: [self enableSaveButton];
  669. class: 'source';
  670. at: 'spellcheck' put: 'false'.
  671. sourceTextarea asJQuery call: 'tabby']
  672. !
  673. renderButtonsOn: html
  674. saveButton := html button.
  675. saveButton
  676. with: 'Save';
  677. onClick: [self compile].
  678. methodButtons := html span.
  679. classButtons := html span.
  680. self updateSourceAndButtons
  681. ! !
  682. !Browser methodsFor: 'testing'!
  683. canBeClosed
  684. ^true
  685. ! !
  686. !Browser methodsFor: 'updating'!
  687. updateCategoriesList
  688. categoriesList contents: [:html |
  689. self categories do: [:each || li label |
  690. each isEmpty
  691. ifTrue: [label := 'Unclassified']
  692. ifFalse: [label := each].
  693. li := html li.
  694. selectedCategory = each ifTrue: [
  695. li class: 'selected'].
  696. li
  697. with: label;
  698. onClick: [self selectCategory: each]]]
  699. !
  700. updateClassesList
  701. TabManager current update.
  702. classesList contents: [:html |
  703. self classes do: [:each || li |
  704. li := html li.
  705. selectedClass = each ifTrue: [
  706. li class: 'selected'].
  707. li
  708. with: each name;
  709. onClick: [self selectClass: each]]]
  710. !
  711. updateProtocolsList
  712. protocolsList contents: [:html |
  713. self protocols do: [:each || li |
  714. li := html li.
  715. selectedProtocol = each ifTrue: [
  716. li class: 'selected'].
  717. li
  718. with: each;
  719. onClick: [self selectProtocol: each]]]
  720. !
  721. updateMethodsList
  722. methodsList contents: [:html |
  723. self methods do: [:each || li |
  724. li := html li.
  725. selectedMethod = each ifTrue: [
  726. li class: 'selected'].
  727. li
  728. with: each selector;
  729. onClick: [self selectMethod: each]]]
  730. !
  731. updateTabsList
  732. tabsList contents: [:html || li |
  733. li := html li.
  734. selectedTab = #instance ifTrue: [li class: 'selected'].
  735. li
  736. with: 'Instance';
  737. onClick: [self selectTab: #instance].
  738. li := html li.
  739. selectedTab = #class ifTrue: [li class: 'selected'].
  740. li
  741. with: 'Class';
  742. onClick: [self selectTab: #class].
  743. li := html li.
  744. selectedTab = #comment ifTrue: [li class: 'selected'].
  745. li
  746. with: 'Comment';
  747. onClick: [self selectTab: #comment]]
  748. !
  749. updateSourceAndButtons
  750. self disableSaveButton.
  751. classButtons contents: [:html |
  752. html button
  753. with: 'Rename class';
  754. onClick: [self renameClass].
  755. html button
  756. with: 'Remove class';
  757. onClick: [self removeClass].
  758. html button
  759. with: 'References';
  760. onClick: [self searchClassReferences]].
  761. methodButtons contents: [:html |
  762. html button
  763. with: 'Remove method';
  764. onClick: [self removeMethod].
  765. html select
  766. onChange: [:e :select | self setMethodProtocol: select val];
  767. with: [
  768. html option
  769. with: 'Method protocol';
  770. at: 'disabled' put: 'disabled'.
  771. html option
  772. class: 'important';
  773. with: 'New...'.
  774. self protocols do: [:each |
  775. html option with: each]].
  776. selectedMethod isNil ifFalse: [
  777. html select
  778. onChange: [:e :select | self searchReferencesOf: select val];
  779. with: [
  780. html option
  781. with: 'References';
  782. at: 'disabled' put: 'disabled'.
  783. html option
  784. class: 'important';
  785. with: selectedMethod selector.
  786. selectedMethod messageSends sorted do: [:each |
  787. html option with: each]]]].
  788. selectedMethod isNil
  789. ifTrue: [
  790. self hideMethodButtons.
  791. (selectedClass isNil or: [selectedProtocol notNil])
  792. ifTrue: [self hideClassButtons]
  793. ifFalse: [self showClassButtons]]
  794. ifFalse: [
  795. self hideClassButtons.
  796. self showMethodButtons].
  797. sourceTextarea asJQuery val: self source
  798. ! !
  799. !Browser class methodsFor: 'accessing'!
  800. commitPathJs
  801. ^'js'
  802. !
  803. commitPathSt
  804. ^'st'
  805. ! !
  806. !Browser class methodsFor: 'convenience'!
  807. openOn: aClass
  808. ^self new
  809. open;
  810. selectCategory: aClass category;
  811. selectClass: aClass
  812. !
  813. open
  814. self new open
  815. ! !
  816. TabWidget subclass: #Inspector
  817. instanceVariableNames: 'label variables object selectedVariable variablesList valueTextarea workspaceTextarea diveButton'
  818. category: 'IDE'!
  819. !Inspector methodsFor: 'accessing'!
  820. label
  821. ^label ifNil: ['Inspector (nil)']
  822. !
  823. variables
  824. ^variables
  825. !
  826. setVariables: aCollection
  827. variables := aCollection
  828. !
  829. setLabel: aString
  830. label := aString
  831. !
  832. selectedVariable
  833. ^selectedVariable
  834. !
  835. selectedVariable: aString
  836. selectedVariable := aString
  837. ! !
  838. !Inspector methodsFor: 'actions'!
  839. inspect: anObject
  840. object := anObject.
  841. variables := #().
  842. object inspectOn: self
  843. !
  844. dive
  845. (self variables at: self selectedVariable) inspect
  846. !
  847. refresh
  848. self
  849. inspect: object;
  850. updateVariablesList;
  851. updateValueTextarea
  852. ! !
  853. !Inspector methodsFor: 'rendering'!
  854. renderBoxOn: html
  855. self
  856. renderTopPanelOn: html;
  857. renderBottomPanelOn: html
  858. !
  859. renderTopPanelOn: html
  860. html div
  861. class: 'top';
  862. with: [
  863. variablesList := html ul class: 'jt_column variables'.
  864. valueTextarea := html textarea class: 'jt_column value'; at: 'readonly' put: 'readonly'.
  865. self
  866. updateVariablesList;
  867. updateValueTextarea.
  868. html div class: 'jt_clear']
  869. !
  870. renderBottomPanelOn: html
  871. html div
  872. class: 'jt_sourceCode';
  873. with: [
  874. workspaceTextarea := html textarea
  875. class: 'source';
  876. at: 'spellcheck' put: 'false'.
  877. workspaceTextarea asJQuery call: 'tabby']
  878. !
  879. renderButtonsOn: html
  880. html button
  881. with: 'Refresh';
  882. onClick: [self refresh].
  883. diveButton := html button
  884. with: 'Dive';
  885. onClick: [self dive].
  886. self updateButtons
  887. ! !
  888. !Inspector methodsFor: 'testing'!
  889. canBeClosed
  890. ^true
  891. ! !
  892. !Inspector methodsFor: 'updating'!
  893. updateVariablesList
  894. variablesList contents: [:html |
  895. self variables keys do: [:each || li |
  896. li := html li.
  897. li
  898. with: each;
  899. onClick: [self selectVariable: each].
  900. self selectedVariable = each ifTrue: [
  901. li class: 'selected']]]
  902. !
  903. selectVariable: aString
  904. self selectedVariable: aString.
  905. self
  906. updateVariablesList;
  907. updateValueTextarea;
  908. updateButtons
  909. !
  910. updateValueTextarea
  911. valueTextarea asJQuery val: (self selectedVariable isNil
  912. ifTrue: ['']
  913. ifFalse: [(self variables at: self selectedVariable) printString])
  914. !
  915. updateButtons
  916. (self selectedVariable notNil and: [(self variables at: self selectedVariable) notNil])
  917. ifFalse: [diveButton at: 'disabled' put: true]
  918. ifTrue: [diveButton removeAt: 'disabled']
  919. ! !
  920. !Inspector class methodsFor: 'instance creation'!
  921. on: anObject
  922. ^self new
  923. inspect: anObject;
  924. yourself
  925. ! !
  926. TabWidget subclass: #ReferencesBrowser
  927. instanceVariableNames: 'implementors senders implementorsList input timer selector sendersList referencedClasses referencedClassesList'
  928. category: 'IDE'!
  929. !ReferencesBrowser methodsFor: 'accessing'!
  930. implementors
  931. ^implementors ifNil: [implementors := Array new]
  932. !
  933. label
  934. ^'[ReferencesBrowser]'
  935. !
  936. selector
  937. ^selector
  938. !
  939. senders
  940. ^senders ifNil: [senders := Array new]
  941. !
  942. classesAndMetaclasses
  943. ^Smalltalk current classes, (Smalltalk current classes collect: [:each | each class])
  944. !
  945. referencedClasses
  946. ^referencedClasses ifNil: [referencedClasses := Array new]
  947. ! !
  948. !ReferencesBrowser methodsFor: 'actions'!
  949. openBrowserOn: aMethod
  950. | browser |
  951. browser := Browser openOn: (aMethod class isMetaclass
  952. ifTrue: [aMethod methodClass instanceClass] ifFalse: [aMethod methodClass]).
  953. aMethod methodClass isMetaclass ifTrue: [browser selectTab: #class].
  954. browser
  955. selectProtocol: aMethod category;
  956. selectMethod: aMethod
  957. !
  958. searchReferencesFor: aString
  959. selector := aString.
  960. implementors := Array new.
  961. senders := Array new.
  962. referencedClasses := Array new.
  963. (selector match: '^[A-Z]')
  964. ifFalse: [self searchSelectorReferencesFor: selector]
  965. ifTrue: [self searchReferencedClassesFor: selector]
  966. !
  967. search: aString
  968. self
  969. searchReferencesFor: aString;
  970. updateImplementorsList;
  971. updateSendersList;
  972. updateReferencedClassesList
  973. !
  974. searchReferencedClassesFor: aString
  975. self classesAndMetaclasses do: [:each |
  976. each methodDictionary values do: [:value |
  977. (((value referencedClasses select: [:each | each notNil])collect: [:each | each name]) includes: selector) ifTrue: [
  978. self referencedClasses add: value]]]
  979. !
  980. searchSelectorReferencesFor: aString
  981. self classesAndMetaclasses do: [:each |
  982. each methodDictionary keysAndValuesDo: [:key :value |
  983. key = selector ifTrue: [self implementors add: value]].
  984. each methodDictionary keysAndValuesDo: [:key :value |
  985. (value messageSends includes: selector) ifTrue: [
  986. self senders add: value]]]
  987. ! !
  988. !ReferencesBrowser methodsFor: 'initialization'!
  989. initialize
  990. super initialize.
  991. selector := ''
  992. ! !
  993. !ReferencesBrowser methodsFor: 'private'!
  994. setInputEvents
  995. input
  996. onKeyUp: [timer := [self search: input asJQuery val] valueWithTimeout: 100];
  997. onKeyDown: [timer ifNotNil: [timer clearTimeout]]
  998. ! !
  999. !ReferencesBrowser methodsFor: 'rendering'!
  1000. renderBoxOn: html
  1001. self
  1002. renderInputOn: html;
  1003. renderImplementorsOn: html;
  1004. renderSendersOn: html;
  1005. renderReferencedClassesOn: html
  1006. !
  1007. renderInputOn: html
  1008. input := html input
  1009. class: 'implementors';
  1010. yourself.
  1011. input asJQuery val: selector.
  1012. self setInputEvents
  1013. !
  1014. renderImplementorsOn: html
  1015. implementorsList := html ul class: 'jt_column implementors'.
  1016. self updateImplementorsList
  1017. !
  1018. renderSendersOn: html
  1019. sendersList := html ul class: 'jt_column senders'.
  1020. self updateSendersList
  1021. !
  1022. renderReferencedClassesOn: html
  1023. referencedClassesList := html ul class: 'jt_column referenced_classes'.
  1024. self updateReferencedClassesList
  1025. ! !
  1026. !ReferencesBrowser methodsFor: 'testing'!
  1027. canBeClosed
  1028. ^true
  1029. ! !
  1030. !ReferencesBrowser methodsFor: 'updating'!
  1031. updateImplementorsList
  1032. implementorsList contents: [:html |
  1033. html li
  1034. class: 'column_label';
  1035. with: 'Implementors';
  1036. style: 'font-weight: bold'.
  1037. self implementors do: [:each || li |
  1038. li := html li.
  1039. li
  1040. with: (each methodClass asString, ' >> ', self selector);
  1041. onClick: [self openBrowserOn: each]]]
  1042. !
  1043. updateSendersList
  1044. sendersList contents: [:html |
  1045. html li
  1046. class: 'column_label';
  1047. with: 'Senders';
  1048. style: 'font-weight: bold'.
  1049. self senders do: [:each |
  1050. html li
  1051. with: (each methodClass asString, ' >> ', each selector);
  1052. onClick: [self openBrowserOn: each]]]
  1053. !
  1054. updateReferencedClassesList
  1055. referencedClassesList contents: [:html |
  1056. html li
  1057. class: 'column_label';
  1058. with: 'Class references';
  1059. style: 'font-weight: bold'.
  1060. self referencedClasses do: [:each |
  1061. html li
  1062. with: (each methodClass asString, ' >> ', each selector);
  1063. onClick: [self openBrowserOn: each]]]
  1064. ! !
  1065. !ReferencesBrowser class methodsFor: 'instance creation'!
  1066. search: aString
  1067. ^self new
  1068. searchReferencesFor: aString;
  1069. open
  1070. ! !
  1071. !Object methodsFor: '*IDE'!
  1072. inspect
  1073. Inspector new
  1074. inspect: self;
  1075. open
  1076. !
  1077. inspectOn: anInspector
  1078. | variables |
  1079. variables := Dictionary new.
  1080. variables at: '#self' put: self.
  1081. self class instanceVariableNames do: [:each |
  1082. variables at: each put: (self instVarAt: each)].
  1083. anInspector
  1084. setLabel: self printString;
  1085. setVariables: variables
  1086. ! !
  1087. !Date methodsFor: '*IDE'!
  1088. inspectOn: anInspector
  1089. | variables |
  1090. variables := Dictionary new.
  1091. variables at: '#self' put: self.
  1092. variables at: '#year' put: self year.
  1093. variables at: '#month' put: self month.
  1094. variables at: '#day' put: self day.
  1095. variables at: '#hours' put: self hours.
  1096. variables at: '#minutes' put: self minutes.
  1097. variables at: '#seconds' put: self seconds.
  1098. variables at: '#milliseconds' put: self milliseconds.
  1099. anInspector
  1100. setLabel: self printString;
  1101. setVariables: variables
  1102. ! !
  1103. !Collection methodsFor: '*IDE'!
  1104. inspectOn: anInspector
  1105. | variables |
  1106. variables := Dictionary new.
  1107. variables at: '#self' put: self.
  1108. self withIndexDo: [:each :i |
  1109. variables at: i put: each].
  1110. anInspector
  1111. setLabel: self printString;
  1112. setVariables: variables
  1113. ! !
  1114. !String methodsFor: '*IDE'!
  1115. inspectOn: anInspector
  1116. | label |
  1117. super inspectOn: anInspector.
  1118. self printString size > 30
  1119. ifTrue: [label := (self printString copyFrom: 1 to: 30), '...''']
  1120. ifFalse: [label := self printString].
  1121. anInspector setLabel: label
  1122. ! !
  1123. !Dictionary methodsFor: '*IDE'!
  1124. inspectOn: anInspector
  1125. | variables |
  1126. variables := Dictionary new.
  1127. variables at: '#self' put: self.
  1128. variables at: '#keys' put: self keys.
  1129. self keysAndValuesDo: [:key :value |
  1130. variables at: key put: value].
  1131. anInspector
  1132. setLabel: self printString;
  1133. setVariables: variables
  1134. ! !