Helios-Debugger.st 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540
  1. Smalltalk createPackage: 'Helios-Debugger'!
  2. Object subclass: #HLContextInspectorDecorator
  3. instanceVariableNames: 'context'
  4. package: 'Helios-Debugger'!
  5. !HLContextInspectorDecorator methodsFor: 'accessing'!
  6. context
  7. ^ context
  8. ! !
  9. !HLContextInspectorDecorator methodsFor: 'evaluating'!
  10. evaluate: aString on: anEvaluator
  11. ^ self context evaluate: aString on: anEvaluator
  12. ! !
  13. !HLContextInspectorDecorator methodsFor: 'initialization'!
  14. initializeFromContext: aContext
  15. context := aContext
  16. ! !
  17. !HLContextInspectorDecorator methodsFor: 'inspecting'!
  18. inspectOn: anInspector
  19. | variables inspectedContext |
  20. variables := Dictionary new.
  21. inspectedContext := self context.
  22. variables addAll: inspectedContext locals.
  23. [ inspectedContext notNil and: [ inspectedContext isBlockContext ] ] whileTrue: [
  24. inspectedContext := inspectedContext outerContext.
  25. inspectedContext ifNotNil: [
  26. variables addAll: inspectedContext locals ] ].
  27. anInspector
  28. setLabel: 'Context';
  29. setVariables: variables
  30. ! !
  31. !HLContextInspectorDecorator class methodsFor: 'instance creation'!
  32. on: aContext
  33. ^ self new
  34. initializeFromContext: aContext;
  35. yourself
  36. ! !
  37. HLFocusableWidget subclass: #HLDebugger
  38. instanceVariableNames: 'model stackListWidget codeWidget inspectorWidget'
  39. package: 'Helios-Debugger'!
  40. !HLDebugger commentStamp!
  41. I am the main widget for the Helios debugger.!
  42. !HLDebugger methodsFor: 'accessing'!
  43. cssClass
  44. ^ super cssClass, ' hl_debugger'
  45. !
  46. model
  47. ^ model ifNil: [ model := HLDebuggerModel new ]
  48. ! !
  49. !HLDebugger methodsFor: 'actions'!
  50. focus
  51. self stackListWidget focus
  52. !
  53. observeModel
  54. self model announcer
  55. on: HLDebuggerContextSelected
  56. send: #onContextSelected:
  57. to: self;
  58. on: HLDebuggerStepped
  59. send: #onDebuggerStepped:
  60. to: self;
  61. on: HLDebuggerProceeded
  62. send: #onDebuggerProceeded
  63. to: self
  64. !
  65. unregister
  66. super unregister.
  67. self inspectorWidget unregister
  68. ! !
  69. !HLDebugger methodsFor: 'initialization'!
  70. initializeFromError: anError
  71. model := HLDebuggerModel on: anError.
  72. self observeModel
  73. ! !
  74. !HLDebugger methodsFor: 'keybindings'!
  75. registerBindingsOn: aBindingGroup
  76. HLToolCommand
  77. registerConcreteClassesOn: aBindingGroup
  78. for: self model
  79. ! !
  80. !HLDebugger methodsFor: 'reactions'!
  81. onContextSelected: anAnnouncement
  82. self inspectorWidget inspect: (HLContextInspectorDecorator on: anAnnouncement context)
  83. !
  84. onDebuggerProceeded
  85. self removeTab
  86. !
  87. onDebuggerStepped: anAnnouncement
  88. self model atEnd ifTrue: [ self removeTab ].
  89. self inspectorWidget inspect: (HLContextInspectorDecorator on: anAnnouncement context).
  90. self stackListWidget refresh
  91. ! !
  92. !HLDebugger methodsFor: 'rendering'!
  93. renderContentOn: html
  94. self renderHeadOn: html.
  95. html with: (HLContainer with: (HLVerticalSplitter
  96. with: self codeWidget
  97. with: (HLVerticalSplitter
  98. with: self stackListWidget
  99. with: self inspectorWidget)))
  100. !
  101. renderHeadOn: html
  102. html div
  103. class: 'head';
  104. with: [ html h2 with: self model error messageText ]
  105. ! !
  106. !HLDebugger methodsFor: 'widgets'!
  107. codeWidget
  108. ^ codeWidget ifNil: [ codeWidget := HLDebuggerCodeWidget new
  109. model: (HLDebuggerCodeModel new
  110. debuggerModel: self model;
  111. yourself);
  112. browserModel: self model;
  113. yourself ]
  114. !
  115. inspectorWidget
  116. ^ inspectorWidget ifNil: [
  117. inspectorWidget := HLInspectorWidget new ]
  118. !
  119. stackListWidget
  120. ^ stackListWidget ifNil: [
  121. stackListWidget := (HLStackListWidget on: self model)
  122. next: self codeWidget;
  123. yourself ]
  124. ! !
  125. !HLDebugger class methodsFor: 'accessing'!
  126. tabClass
  127. ^ 'debugger'
  128. !
  129. tabLabel
  130. ^ 'Debugger'
  131. ! !
  132. !HLDebugger class methodsFor: 'instance creation'!
  133. on: anError
  134. ^ self new
  135. initializeFromError: anError;
  136. yourself
  137. ! !
  138. HLCodeModel subclass: #HLDebuggerCodeModel
  139. instanceVariableNames: 'debuggerModel'
  140. package: 'Helios-Debugger'!
  141. !HLDebuggerCodeModel methodsFor: 'accessing'!
  142. debuggerModel
  143. ^ debuggerModel
  144. !
  145. debuggerModel: anObject
  146. debuggerModel := anObject
  147. ! !
  148. !HLDebuggerCodeModel methodsFor: 'actions'!
  149. doIt: aString
  150. ^ [ self debuggerModel evaluate: aString ]
  151. tryCatch: [ :e |
  152. ErrorHandler handleError: e.
  153. nil ]
  154. ! !
  155. HLBrowserCodeWidget subclass: #HLDebuggerCodeWidget
  156. instanceVariableNames: ''
  157. package: 'Helios-Debugger'!
  158. !HLDebuggerCodeWidget methodsFor: 'accessing'!
  159. contents: aString
  160. self clearHighlight.
  161. super contents: aString
  162. !
  163. editorOptions
  164. ^ super editorOptions
  165. at: 'gutters' put: #('CodeMirror-linenumbers' 'stops');
  166. yourself
  167. ! !
  168. !HLDebuggerCodeWidget methodsFor: 'actions'!
  169. addStopAt: anInteger
  170. editor
  171. setGutterMarker: anInteger
  172. gutter: 'stops'
  173. value: '<div class="stop"></stop>' asJQuery toArray first
  174. !
  175. clearHighlight
  176. self editor clearGutter: 'stops'
  177. !
  178. highlight
  179. self browserModel nextNode ifNotNil: [ :node |
  180. self highlightNode: node ]
  181. !
  182. highlightNode: aNode
  183. | token |
  184. aNode ifNotNil: [
  185. self
  186. clearHighlight;
  187. addStopAt: aNode positionStart x - 1.
  188. self editor
  189. setSelection: #{ 'line' -> (aNode positionStart x - 1). 'ch' -> (aNode positionStart y - 1) }
  190. to: #{ 'line' -> (aNode positionEnd x - 1). 'ch' -> (aNode positionEnd y) } ]
  191. !
  192. observeBrowserModel
  193. super observeBrowserModel.
  194. self browserModel announcer
  195. on: HLDebuggerContextSelected
  196. send: #onContextSelected
  197. to: self.
  198. self browserModel announcer
  199. on: HLDebuggerStepped
  200. send: #onContextSelected
  201. to: self.
  202. self browserModel announcer
  203. on: HLDebuggerWhere
  204. send: #onContextSelected
  205. to: self
  206. ! !
  207. !HLDebuggerCodeWidget methodsFor: 'reactions'!
  208. onContextSelected
  209. self highlight
  210. ! !
  211. !HLDebuggerCodeWidget methodsFor: 'rendering'!
  212. renderOn: html
  213. super renderOn: html.
  214. self contents: self browserModel selectedMethod source
  215. ! !
  216. HLToolModel subclass: #HLDebuggerModel
  217. instanceVariableNames: 'rootContext debugger error'
  218. package: 'Helios-Debugger'!
  219. !HLDebuggerModel commentStamp!
  220. I am a model for debugging Amber code in Helios.
  221. My instances hold a reference to an `ASTDebugger` instance, itself referencing the current `context`. The context should be the root of the context stack.!
  222. !HLDebuggerModel methodsFor: 'accessing'!
  223. contexts
  224. | contexts context |
  225. contexts := OrderedCollection new.
  226. context := self rootContext.
  227. [ context notNil ] whileTrue: [
  228. contexts add: context.
  229. context := context outerContext ].
  230. ^ contexts
  231. !
  232. currentContext
  233. ^ self debugger context
  234. !
  235. currentContext: aContext
  236. self withChangesDo: [
  237. self selectedMethod: aContext method.
  238. self debugger context: aContext.
  239. self announcer announce: (HLDebuggerContextSelected new
  240. context: aContext;
  241. yourself) ]
  242. !
  243. debugger
  244. ^ debugger ifNil: [ debugger := ASTDebugger new ]
  245. !
  246. error
  247. ^ error
  248. !
  249. nextNode
  250. ^ self debugger node
  251. !
  252. rootContext
  253. ^ rootContext
  254. ! !
  255. !HLDebuggerModel methodsFor: 'actions'!
  256. proceed
  257. self debugger proceed.
  258. self announcer announce: HLDebuggerProceeded new
  259. !
  260. restart
  261. self debugger restart.
  262. self onStep.
  263. self announcer announce: (HLDebuggerStepped new
  264. context: self currentContext;
  265. yourself)
  266. !
  267. stepOver
  268. self debugger stepOver.
  269. self onStep.
  270. self announcer announce: (HLDebuggerStepped new
  271. context: self currentContext;
  272. yourself)
  273. !
  274. where
  275. self announcer announce: HLDebuggerWhere new
  276. ! !
  277. !HLDebuggerModel methodsFor: 'evaluating'!
  278. evaluate: aString
  279. ^ self environment
  280. evaluate: aString
  281. for: self currentContext
  282. ! !
  283. !HLDebuggerModel methodsFor: 'initialization'!
  284. initializeFromError: anError
  285. error := anError.
  286. rootContext := (AIContext fromMethodContext: error context).
  287. self currentContext: rootContext
  288. ! !
  289. !HLDebuggerModel methodsFor: 'private'!
  290. flushInnerContexts
  291. "When stepping, the inner contexts are not relevent anymore,
  292. and can be flushed"
  293. self currentContext innerContext: nil.
  294. rootContext := self currentContext.
  295. self initializeContexts
  296. ! !
  297. !HLDebuggerModel methodsFor: 'reactions'!
  298. onStep
  299. rootContext := self currentContext.
  300. "Force a refresh of the context list and code widget"
  301. self selectedMethod: self currentContext method.
  302. self announcer announce: (HLDebuggerContextSelected new
  303. context: self currentContext;
  304. yourself)
  305. ! !
  306. !HLDebuggerModel methodsFor: 'testing'!
  307. atEnd
  308. ^ self debugger atEnd
  309. ! !
  310. !HLDebuggerModel class methodsFor: 'instance creation'!
  311. on: anError
  312. ^ self new
  313. initializeFromError: anError;
  314. yourself
  315. ! !
  316. Object subclass: #HLErrorHandler
  317. instanceVariableNames: ''
  318. package: 'Helios-Debugger'!
  319. !HLErrorHandler methodsFor: 'error handling'!
  320. confirmDebugError: anError
  321. HLConfirmationWidget new
  322. confirmationString: anError messageText;
  323. actionBlock: [ self debugError: anError ];
  324. cancelButtonLabel: 'Abandon';
  325. confirmButtonLabel: 'Debug';
  326. show
  327. !
  328. debugError: anError
  329. [
  330. (HLDebugger on: anError) openAsTab
  331. ]
  332. on: Error
  333. do: [ :error | ConsoleErrorHandler new handleError: error ]
  334. !
  335. handleError: anError
  336. self confirmDebugError: anError
  337. !
  338. onErrorHandled
  339. "when an error is handled, we need to make sure that
  340. any progress bar widget gets removed. Because HLProgressBarWidget is asynchronous,
  341. it has to be done here."
  342. HLProgressWidget default
  343. flush;
  344. remove
  345. ! !
  346. HLToolListWidget subclass: #HLStackListWidget
  347. instanceVariableNames: ''
  348. package: 'Helios-Debugger'!
  349. !HLStackListWidget methodsFor: 'accessing'!
  350. items
  351. ^ self model contexts
  352. !
  353. label
  354. ^ 'Call stack'
  355. ! !
  356. !HLStackListWidget methodsFor: 'actions'!
  357. observeModel
  358. super observeModel.
  359. self model announcer
  360. on: HLDebuggerStepped
  361. send: #onDebuggerStepped:
  362. to: self
  363. !
  364. proceed
  365. self model proceed
  366. !
  367. restart
  368. self model restart
  369. !
  370. selectItem: aContext
  371. self model currentContext: aContext.
  372. super selectItem: aContext
  373. !
  374. selectedItem
  375. ^ self model currentContext
  376. !
  377. stepOver
  378. self model stepOver
  379. !
  380. where
  381. self model where
  382. ! !
  383. !HLStackListWidget methodsFor: 'reactions'!
  384. onDebuggerStepped: anAnnouncement
  385. items := nil.
  386. self refresh
  387. ! !
  388. !HLStackListWidget methodsFor: 'rendering'!
  389. renderButtonsOn: html
  390. html div
  391. class: 'debugger_bar';
  392. with: [
  393. html button
  394. class: 'btn restart';
  395. with: 'Restart';
  396. onClick: [ self restart ].
  397. html button
  398. class: 'btn where';
  399. with: 'Where';
  400. onClick: [ self where ].
  401. html button
  402. class: 'btn stepOver';
  403. with: 'Step over';
  404. onClick: [ self stepOver ].
  405. html button
  406. class: 'btn proceed';
  407. with: 'Proceed';
  408. onClick: [ self proceed ] ]
  409. ! !