Helios-Debugger.st 9.6 KB

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