Helios-Debugger.st 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543
  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: (HLHorizontalSplitter
  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. | errorContext |
  286. error := anError.
  287. errorContext := (AIContext fromMethodContext: error context).
  288. rootContext := error signalerContextFrom: errorContext.
  289. self selectedMethod: rootContext method
  290. ! !
  291. !HLDebuggerModel methodsFor: 'private'!
  292. flushInnerContexts
  293. "When stepping, the inner contexts are not relevent anymore,
  294. and can be flushed"
  295. self currentContext innerContext: nil.
  296. rootContext := self currentContext.
  297. self initializeContexts
  298. ! !
  299. !HLDebuggerModel methodsFor: 'reactions'!
  300. onStep
  301. rootContext := self currentContext.
  302. "Force a refresh of the context list and code widget"
  303. self selectedMethod: self currentContext method.
  304. self announcer announce: (HLDebuggerContextSelected new
  305. context: self currentContext;
  306. yourself)
  307. ! !
  308. !HLDebuggerModel methodsFor: 'testing'!
  309. atEnd
  310. ^ self debugger atEnd
  311. ! !
  312. !HLDebuggerModel class methodsFor: 'instance creation'!
  313. on: anError
  314. ^ self new
  315. initializeFromError: anError;
  316. yourself
  317. ! !
  318. Object subclass: #HLErrorHandler
  319. instanceVariableNames: ''
  320. package: 'Helios-Debugger'!
  321. !HLErrorHandler methodsFor: 'error handling'!
  322. confirmDebugError: anError
  323. HLConfirmationWidget new
  324. confirmationString: anError messageText;
  325. actionBlock: [ self debugError: anError ];
  326. cancelButtonLabel: 'Abandon';
  327. confirmButtonLabel: 'Debug';
  328. show
  329. !
  330. debugError: anError
  331. [
  332. (HLDebugger on: anError) openAsTab
  333. ]
  334. on: Error
  335. do: [ :error | ConsoleErrorHandler new handleError: error ]
  336. !
  337. handleError: anError
  338. self confirmDebugError: anError
  339. !
  340. onErrorHandled
  341. "when an error is handled, we need to make sure that
  342. any progress bar widget gets removed. Because HLProgressBarWidget is asynchronous,
  343. it has to be done here."
  344. HLProgressWidget default
  345. flush;
  346. remove
  347. ! !
  348. HLToolListWidget subclass: #HLStackListWidget
  349. instanceVariableNames: ''
  350. package: 'Helios-Debugger'!
  351. !HLStackListWidget methodsFor: 'accessing'!
  352. items
  353. ^ self model contexts
  354. !
  355. label
  356. ^ 'Call stack'
  357. ! !
  358. !HLStackListWidget methodsFor: 'actions'!
  359. observeModel
  360. super observeModel.
  361. self model announcer
  362. on: HLDebuggerStepped
  363. send: #onDebuggerStepped:
  364. to: self
  365. !
  366. proceed
  367. self model proceed
  368. !
  369. restart
  370. self model restart
  371. !
  372. selectItem: aContext
  373. self model currentContext: aContext.
  374. super selectItem: aContext
  375. !
  376. selectedItem
  377. ^ self model currentContext
  378. !
  379. stepOver
  380. self model stepOver
  381. !
  382. where
  383. self model where
  384. ! !
  385. !HLStackListWidget methodsFor: 'reactions'!
  386. onDebuggerStepped: anAnnouncement
  387. items := nil.
  388. self refresh
  389. ! !
  390. !HLStackListWidget methodsFor: 'rendering'!
  391. renderButtonsOn: html
  392. html div
  393. class: 'debugger_bar';
  394. with: [
  395. html button
  396. class: 'btn btn-default restart';
  397. with: 'Restart';
  398. onClick: [ self restart ].
  399. html button
  400. class: 'btn btn-default where';
  401. with: 'Where';
  402. onClick: [ self where ].
  403. html button
  404. class: 'btn btn-default stepOver';
  405. with: 'Step over';
  406. onClick: [ self stepOver ].
  407. html button
  408. class: 'btn btn-default proceed';
  409. with: 'Proceed';
  410. onClick: [ self proceed ] ]
  411. ! !