much love
[mu.git] / shell / trace.mu
blobe4c9ec5e45d32a09783ff1735429e1a81f0f0078
1 # A trace records the evolution of a computation.
2 # Traces are useful for:
3 #   error-handling
4 #   testing
5 #   auditing
6 #   debugging
7 #   learning
9 # An integral part of the Mu computer is facilities for browsing traces.
11 type trace {
12   max-depth: int
13   curr-depth: int  # depth that will be assigned to next line appended
14   data: (handle array trace-line)
15   first-free: int
16   first-full: int  # used only by check-trace-scan
18   # steady-state life cycle of a trace:
19   #   reload loop:
20   #     there are already some visible lines
21   #     append a bunch of new trace lines to the trace
22   #     recreate trace caches
23   #     render loop:
24   #       rendering displays trace lines that match visible lines
25   #         (caching in each line)
26   #         (caching top-line)
27   #       rendering computes cursor-line based on the cursor-y coordinate
28   #       edit-trace updates cursor-y coordinate
29   #       edit-trace might add/remove lines to visible
30   #       edit-trace might update top-line
31   visible: (handle array trace-line)
32   recreate-caches?: boolean
33   cursor-line-index: int  # index into data
34   cursor-y: int  # row index on screen
35   unclip-cursor-line?: boolean  # extremely short-lived; reset any time cursor moves
36   top-line-index: int  # start rendering trace past this index into data (updated on re-evaluation)
37   top-line-y: int  # trace starts rendering at this row index on screen (updated on re-evaluation)
38   screen-height: int  # initialized during render-trace
41 type trace-line {
42   depth: int
43   label: (handle array byte)
44   data: (handle array byte)
45   visible?: boolean
48 # when we recreate the trace this data structure will help stabilize our view into it
49 # we can shallowly copy handles because lines are not reused across reruns
50 type trace-index-stash {
51   cursor-line-depth: int
52   cursor-line-label: (handle array byte)
53   cursor-line-data: (handle array byte)
54   top-line-depth: int
55   top-line-label: (handle array byte)
56   top-line-data: (handle array byte)
59 ## generating traces
61 fn initialize-trace _self: (addr trace), max-depth: int, capacity: int, visible-capacity: int {
62   var self/esi: (addr trace) <- copy _self
63   compare self, 0
64   {
65     break-if-!=
66     abort "null trace"
67   }
68   var src/ecx: int <- copy max-depth
69   var dest/eax: (addr int) <- get self, max-depth
70   copy-to *dest, src
71   dest <- get self, curr-depth
72   copy-to *dest, 1  # 0 is the error depth
73   var trace-ah/eax: (addr handle array trace-line) <- get self, data
74   populate trace-ah, capacity
75   var visible-ah/eax: (addr handle array trace-line) <- get self, visible
76   populate visible-ah, visible-capacity
77   mark-lines-dirty self
80 fn clear-trace _self: (addr trace) {
81   var self/eax: (addr trace) <- copy _self
82   compare self, 0
83   {
84     break-if-!=
85     abort "null trace"
86   }
87   var curr-depth-addr/ecx: (addr int) <- get self, curr-depth
88   copy-to *curr-depth-addr, 1
89   var len/edx: (addr int) <- get self, first-free
90   copy-to *len, 0
91   # leak: nested handles within trace-lines
94 fn has-errors? _self: (addr trace) -> _/eax: boolean {
95   var self/eax: (addr trace) <- copy _self
96   compare self, 0
97   {
98     break-if-!=
99     abort "null trace"
100   }
101   var max/edx: (addr int) <- get self, first-free
102   var trace-ah/eax: (addr handle array trace-line) <- get self, data
103   var _trace/eax: (addr array trace-line) <- lookup *trace-ah
104   var trace/esi: (addr array trace-line) <- copy _trace
105   var i/ecx: int <- copy 0
106   {
107     compare i, *max
108     break-if->=
109     var offset/eax: (offset trace-line) <- compute-offset trace, i
110     var curr/eax: (addr trace-line) <- index trace, offset
111     var curr-depth-a/eax: (addr int) <- get curr, depth
112     compare *curr-depth-a, 0/error
113     {
114       break-if-!=
115       return 1/true
116     }
117     i <- increment
118     loop
119   }
120   return 0/false
123 fn should-trace? _self: (addr trace) -> _/eax: boolean {
124   var self/esi: (addr trace) <- copy _self
125   compare self, 0
126   {
127     break-if-!=
128     abort "null trace"
129   }
130   var depth-a/ecx: (addr int) <- get self, curr-depth
131   var depth/ecx: int <- copy *depth-a
132   var max-depth-a/eax: (addr int) <- get self, max-depth
133   compare depth, *max-depth-a
134   {
135     break-if->=
136     return 1/true
137   }
138   return 0/false
141 fn trace _self: (addr trace), label: (addr array byte), message: (addr stream byte) {
142   var self/esi: (addr trace) <- copy _self
143   compare self, 0
144   {
145     break-if-!=
146     abort "null trace"
147   }
148   var should-trace?/eax: boolean <- should-trace? self
149   compare should-trace?, 0/false
150   {
151     break-if-!=
152     return
153   }
154   var data-ah/eax: (addr handle array trace-line) <- get self, data
155   var data/eax: (addr array trace-line) <- lookup *data-ah
156   var index-addr/edi: (addr int) <- get self, first-free
157   {
158     compare *index-addr, 0x8000/lines
159     break-if-<
160     return
161   }
162   var index/ecx: int <- copy *index-addr
163   var offset/ecx: (offset trace-line) <- compute-offset data, index
164   var dest/eax: (addr trace-line) <- index data, offset
165   var depth/ecx: (addr int) <- get self, curr-depth
166   rewind-stream message
167   {
168     compare *index-addr, 0x7fff/lines
169     break-if-<
170     clear-stream message
171     write message, "No space left in trace\n"
172     write message, "Please either:\n"
173     write message, "  - find a smaller sub-computation to test,\n"
174     write message, "  - allocate more space to the trace in initialize-sandbox\n"
175     write message, "    (shell/sandbox.mu), or\n"
176     write message, "  - move the computation to 'main' and run it using ctrl-r"
177     initialize-trace-line 0/depth, "error", message, dest
178     increment *index-addr
179     return
180   }
181   initialize-trace-line *depth, label, message, dest
182   increment *index-addr
185 fn trace-text self: (addr trace), label: (addr array byte), s: (addr array byte) {
186   compare self, 0
187   {
188     break-if-!=
189     abort "null trace"
190   }
191   var data-storage: (stream byte 0x100)
192   var data/eax: (addr stream byte) <- address data-storage
193   write data, s
194   trace self, label, data
197 fn error _self: (addr trace), message: (addr array byte) {
198   var self/esi: (addr trace) <- copy _self
199   compare self, 0
200   {
201     break-if-!=
202     abort "null trace"
203   }
204   var curr-depth-a/eax: (addr int) <- get self, curr-depth
205   var save-depth/ecx: int <- copy *curr-depth-a
206   copy-to *curr-depth-a, 0/error
207   trace-text self, "error", message
208   copy-to *curr-depth-a, save-depth
211 fn error-stream _self: (addr trace), message: (addr stream byte) {
212   var self/esi: (addr trace) <- copy _self
213   compare self, 0
214   {
215     break-if-!=
216     abort "null trace"
217   }
218   var curr-depth-a/eax: (addr int) <- get self, curr-depth
219   var save-depth/ecx: int <- copy *curr-depth-a
220   copy-to *curr-depth-a, 0/error
221   trace self, "error", message
222   copy-to *curr-depth-a, save-depth
225 fn initialize-trace-line depth: int, label: (addr array byte), data: (addr stream byte), _out: (addr trace-line) {
226   var out/edi: (addr trace-line) <- copy _out
227   # depth
228   var src/eax: int <- copy depth
229   var dest/ecx: (addr int) <- get out, depth
230   copy-to *dest, src
231   # label
232   var dest/eax: (addr handle array byte) <- get out, label
233   copy-array-object label, dest
234   # data
235   var dest/eax: (addr handle array byte) <- get out, data
236   stream-to-array data, dest
239 fn trace-lower _self: (addr trace) {
240   var self/esi: (addr trace) <- copy _self
241   compare self, 0
242   {
243     break-if-!=
244     abort "null trace"
245   }
246   var depth/eax: (addr int) <- get self, curr-depth
247   increment *depth
250 fn trace-higher _self: (addr trace) {
251   var self/esi: (addr trace) <- copy _self
252   compare self, 0
253   {
254     break-if-!=
255     abort "null trace"
256   }
257   var depth/eax: (addr int) <- get self, curr-depth
258   decrement *depth
261 ## checking traces
263 fn check-trace-scans-to self: (addr trace), label: (addr array byte), data: (addr array byte), message: (addr array byte) {
264   var tmp/eax: boolean <- trace-scans-to? self, label, data
265   check tmp, message
268 fn trace-scans-to? _self: (addr trace), label: (addr array byte), data: (addr array byte) -> _/eax: boolean {
269   var self/esi: (addr trace) <- copy _self
270   var start/eax: (addr int) <- get self, first-full
271   var result/eax: boolean <- trace-contains? self, label, data, *start
272   return result
275 fn test-trace-scans-to {
276   var t-storage: trace
277   var t/esi: (addr trace) <- address t-storage
278   initialize-trace t, 0x100/max-depth, 0x10/capacity, 0/visible  # we don't use trace UI
279   #
280   trace-text t, "label", "line 1"
281   trace-text t, "label", "line 2"
282   check-trace-scans-to t, "label", "line 1", "F - test-trace-scans-to/0"
283   check-trace-scans-to t, "label", "line 2", "F - test-trace-scans-to/1"
284   var tmp/eax: boolean <- trace-scans-to? t, "label", "line 1"
285   check-not tmp, "F - test-trace-scans-to: fail on previously encountered lines"
286   var tmp/eax: boolean <- trace-scans-to? t, "label", "line 3"
287   check-not tmp, "F - test-trace-scans-to: fail on missing"
290 # scan trace from start
291 # resets previous scans
292 fn check-trace-contains self: (addr trace), label: (addr array byte), data: (addr array byte), message: (addr array byte) {
293   var tmp/eax: boolean <- trace-contains? self, label, data, 0
294   check tmp, message
297 fn test-trace-contains {
298   var t-storage: trace
299   var t/esi: (addr trace) <- address t-storage
300   initialize-trace t, 0x100/max-depth, 0x10/capacity, 0/visible  # we don't use trace UI
301   #
302   trace-text t, "label", "line 1"
303   trace-text t, "label", "line 2"
304   check-trace-contains t, "label", "line 1", "F - test-trace-contains/0"
305   check-trace-contains t, "label", "line 2", "F - test-trace-contains/1"
306   check-trace-contains t, "label", "line 1", "F - test-trace-contains: find previously encountered lines"
307   var tmp/eax: boolean <- trace-contains? t, "label", "line 3", 0/start
308   check-not tmp, "F - test-trace-contains: fail on missing"
311 # this is super-inefficient, string comparing every trace line
312 fn trace-contains? _self: (addr trace), label: (addr array byte), data: (addr array byte), start: int -> _/eax: boolean {
313   var self/esi: (addr trace) <- copy _self
314   var candidates-ah/eax: (addr handle array trace-line) <- get self, data
315   var candidates/eax: (addr array trace-line) <- lookup *candidates-ah
316   var i/ecx: int <- copy start
317   var max/edx: (addr int) <- get self, first-free
318   {
319     compare i, *max
320     break-if->=
321     {
322       var read-until-index/eax: (addr int) <- get self, first-full
323       copy-to *read-until-index, i
324     }
325     {
326       var curr-offset/ecx: (offset trace-line) <- compute-offset candidates, i
327       var curr/ecx: (addr trace-line) <- index candidates, curr-offset
328       # if curr->label does not match, return false
329       var curr-label-ah/eax: (addr handle array byte) <- get curr, label
330       var curr-label/eax: (addr array byte) <- lookup *curr-label-ah
331       var match?/eax: boolean <- string-equal? curr-label, label
332       compare match?, 0/false
333       break-if-=
334       # if curr->data does not match, return false
335       var curr-data-ah/eax: (addr handle array byte) <- get curr, data
336       var curr-data/eax: (addr array byte) <- lookup *curr-data-ah
337       var match?/eax: boolean <- string-equal? curr-data, data
338       compare match?, 0/false
339       break-if-=
340       return 1/true
341     }
342     i <- increment
343     loop
344   }
345   return 0/false
348 fn trace-lines-equal? _a: (addr trace-line), _b: (addr trace-line) -> _/eax: boolean {
349   var a/esi: (addr trace-line) <- copy _a
350   var b/edi: (addr trace-line) <- copy _b
351   var a-depth/ecx: (addr int) <- get a, depth
352   var b-depth/edx: (addr int) <- get b, depth
353   var benchmark/eax: int <- copy *b-depth
354   compare *a-depth, benchmark
355   {
356     break-if-=
357     return 0/false
358   }
359   var a-label-ah/eax: (addr handle array byte) <- get a, label
360   var _a-label/eax: (addr array byte) <- lookup *a-label-ah
361   var a-label/ecx: (addr array byte) <- copy _a-label
362   var b-label-ah/ebx: (addr handle array byte) <- get b, label
363   var b-label/eax: (addr array byte) <- lookup *b-label-ah
364   var label-match?/eax: boolean <- string-equal? a-label, b-label
365   {
366     compare label-match?, 0/false
367     break-if-!=
368     return 0/false
369   }
370   var a-data-ah/eax: (addr handle array byte) <- get a, data
371   var _a-data/eax: (addr array byte) <- lookup *a-data-ah
372   var a-data/ecx: (addr array byte) <- copy _a-data
373   var b-data-ah/ebx: (addr handle array byte) <- get b, data
374   var b-data/eax: (addr array byte) <- lookup *b-data-ah
375   var data-match?/eax: boolean <- string-equal? a-data, b-data
376   return data-match?
379 fn dump-trace _self: (addr trace) {
380   var y/ecx: int <- copy 0
381   var self/esi: (addr trace) <- copy _self
382   compare self, 0
383   {
384     break-if-!=
385     abort "null trace"
386   }
387   var trace-ah/eax: (addr handle array trace-line) <- get self, data
388   var _trace/eax: (addr array trace-line) <- lookup *trace-ah
389   var trace/edi: (addr array trace-line) <- copy _trace
390   var i/edx: int <- copy 0
391   var max-addr/ebx: (addr int) <- get self, first-free
392   var max/ebx: int <- copy *max-addr
393   $dump-trace:loop: {
394     compare i, max
395     break-if->=
396     $dump-trace:iter: {
397       var offset/ebx: (offset trace-line) <- compute-offset trace, i
398       var curr/ebx: (addr trace-line) <- index trace, offset
399       y <- render-trace-line 0/screen, curr, 0, y, 0x80/width, 0x30/height, 7/fg, 0/bg, 0/clip
400     }
401     i <- increment
402     loop
403   }
406 fn dump-trace-with-label _self: (addr trace), label: (addr array byte) {
407   var y/ecx: int <- copy 0
408   var self/esi: (addr trace) <- copy _self
409   compare self, 0
410   {
411     break-if-!=
412     abort "null trace"
413   }
414   var trace-ah/eax: (addr handle array trace-line) <- get self, data
415   var _trace/eax: (addr array trace-line) <- lookup *trace-ah
416   var trace/edi: (addr array trace-line) <- copy _trace
417   var i/edx: int <- copy 0
418   var max-addr/ebx: (addr int) <- get self, first-free
419   var max/ebx: int <- copy *max-addr
420   $dump-trace-with-label:loop: {
421     compare i, max
422     break-if->=
423     $dump-trace-with-label:iter: {
424       var offset/ebx: (offset trace-line) <- compute-offset trace, i
425       var curr/ebx: (addr trace-line) <- index trace, offset
426       var curr-label-ah/eax: (addr handle array byte) <- get curr, label
427       var curr-label/eax: (addr array byte) <- lookup *curr-label-ah
428       var show?/eax: boolean <- string-equal? curr-label, label
429       compare show?, 0/false
430       break-if-=
431       y <- render-trace-line 0/screen, curr, 0, y, 0x80/width, 0x30/height, 7/fg, 0/bg, 0/clip
432     }
433     i <- increment
434     loop
435   }
438 ## UI stuff
440 fn mark-lines-dirty _self: (addr trace) {
441   var self/eax: (addr trace) <- copy _self
442   var dest/edx: (addr boolean) <- get self, recreate-caches?
443   copy-to *dest, 1/true
446 fn mark-lines-clean _self: (addr trace) {
447   var self/eax: (addr trace) <- copy _self
448   var dest/edx: (addr boolean) <- get self, recreate-caches?
449   copy-to *dest, 0/false
452 fn render-trace screen: (addr screen), _self: (addr trace), xmin: int, ymin: int, xmax: int, ymax: int, show-cursor?: boolean -> _/ecx: int {
453   var already-hiding-lines?: boolean
454   var self/esi: (addr trace) <- copy _self
455   compare self, 0
456   {
457     break-if-!=
458     abort "null trace"
459   }
460   var y/ecx: int <- copy ymin
461   # recreate caches if necessary
462   var recreate-caches?/eax: (addr boolean) <- get self, recreate-caches?
463   compare *recreate-caches?, 0/false
464   {
465     break-if-=
466     # cache ymin
467     var dest/eax: (addr int) <- get self, top-line-y
468     copy-to *dest, y
469     # cache ymax
470     var ymax/ecx: int <- copy ymax
471     dest <- get self, screen-height
472     copy-to *dest, ymax
473     #
474     recompute-all-visible-lines self
475     mark-lines-clean self
476   }
477   clamp-cursor-to-top self, y
478   var trace-ah/eax: (addr handle array trace-line) <- get self, data
479   var _trace/eax: (addr array trace-line) <- lookup *trace-ah
480   var trace/edi: (addr array trace-line) <- copy _trace
481   var max-addr/ebx: (addr int) <- get self, first-free
482   var max/ebx: int <- copy *max-addr
483   # display trace depth (not in tests)
484   $render-trace:render-depth: {
485     compare max, 0
486     break-if-<=
487     var max-depth/edx: (addr int) <- get self, max-depth
488     {
489       var width/eax: int <- copy 0
490       var height/ecx: int <- copy 0
491       width, height <- screen-size screen
492       compare width, 0x80
493       break-if-< $render-trace:render-depth
494     }
495     set-cursor-position screen, 0x70/x, y
496     draw-text-rightward-from-cursor-over-full-screen screen, "trace depth: ", 0x17/fg, 0xc5/bg=blue-bg
497     draw-int32-decimal-wrapping-right-then-down-from-cursor-over-full-screen screen, *max-depth, 0x7/fg, 0xc5/bg=blue-bg
498   }
499   var top-line-addr/edx: (addr int) <- get self, top-line-index
500   var i/edx: int <- copy *top-line-addr
501   $render-trace:loop: {
502     compare i, max
503     break-if->=
504     compare y, ymax
505     break-if->=
506     $render-trace:iter: {
507       var offset/ebx: (offset trace-line) <- compute-offset trace, i
508       var curr/ebx: (addr trace-line) <- index trace, offset
509       var curr-label-ah/eax: (addr handle array byte) <- get curr, label
510       var curr-label/eax: (addr array byte) <- lookup *curr-label-ah
511       var bg: int
512       copy-to bg, 0xc5/bg=blue-bg
513       var fg: int
514       copy-to fg, 0x38/fg=trace
515       compare show-cursor?, 0/false
516       {
517         break-if-=
518         var cursor-y/eax: (addr int) <- get self, cursor-y
519         compare *cursor-y, y
520         break-if-!=
521         copy-to bg, 7/trace-cursor-line-bg
522         copy-to fg, 0x68/cursor-line-fg=sober-blue
523         var cursor-line-index/eax: (addr int) <- get self, cursor-line-index
524         copy-to *cursor-line-index, i
525       }
526       # always display errors
527       {
528         var curr-depth/eax: (addr int) <- get curr, depth
529         compare *curr-depth, 0/error
530         break-if-!=
531         y <- render-trace-line screen, curr, xmin, y, xmax, ymax, 0xc/fg=trace-error, bg, 0/clip
532         copy-to already-hiding-lines?, 0/false
533         break $render-trace:iter
534       }
535       # display expanded lines
536       var display?/eax: boolean <- should-render? curr
537       {
538         compare display?, 0/false
539         break-if-=
540         var unclip-cursor-line?/eax: boolean <- unclip-cursor-line? self, i
541         y <- render-trace-line screen, curr, xmin, y, xmax, ymax, fg, bg, unclip-cursor-line?
542         copy-to already-hiding-lines?, 0/false
543         break $render-trace:iter
544       }
545       # ignore the rest
546       compare already-hiding-lines?, 0/false
547       {
548         break-if-!=
549         var x/eax: int <- copy xmin
550         x, y <- draw-text-wrapping-right-then-down screen, "...", xmin, ymin, xmax, ymax, x, y, fg, bg
551         y <- increment
552         copy-to already-hiding-lines?, 1/true
553       }
554     }
555     i <- increment
556     loop
557   }
558   # prevent cursor from going too far down
559   clamp-cursor-to-bottom self, y, screen, xmin, ymin, xmax, ymax
560   return y
563 fn unclip-cursor-line? _self: (addr trace), _i: int -> _/eax: boolean {
564   # if unclip? and i == *cursor-line-index, render unclipped
565   var self/esi: (addr trace) <- copy _self
566   var unclip-cursor-line?/eax: (addr boolean) <- get self, unclip-cursor-line?
567   compare *unclip-cursor-line?, 0/false
568   {
569     break-if-!=
570     return 0/false
571   }
572   var cursor-line-index/eax: (addr int) <- get self, cursor-line-index
573   var i/ecx: int <- copy _i
574   compare i, *cursor-line-index
575   {
576     break-if-=
577     return 0/false
578   }
579   return 1/true
582 fn render-trace-line screen: (addr screen), _self: (addr trace-line), xmin: int, ymin: int, xmax: int, ymax: int, fg: int, bg: int, unclip?: boolean -> _/ecx: int {
583   var self/esi: (addr trace-line) <- copy _self
584   var xsave/edx: int <- copy xmin
585   var y/ecx: int <- copy ymin
586   # show depth for non-errors
587   var depth-a/ebx: (addr int) <- get self, depth
588   compare *depth-a, 0/error
589   {
590     break-if-=
591     var x/eax: int <- copy xsave
592     {
593       x, y <- draw-int32-decimal-wrapping-right-then-down screen, *depth-a, xmin, ymin, xmax, ymax, x, y, fg, bg
594       x, y <- draw-text-wrapping-right-then-down screen, " ", xmin, ymin, xmax, ymax, x, y, fg, bg
595       # don't show label in UI; it's just for tests
596     }
597     xsave <- copy x
598   }
599   var data-ah/eax: (addr handle array byte) <- get self, data
600   var _data/eax: (addr array byte) <- lookup *data-ah
601   var data/ebx: (addr array byte) <- copy _data
602   var x/eax: int <- copy xsave
603   compare unclip?, 0/false
604   {
605     break-if-=
606     x, y <- draw-text-wrapping-right-then-down screen, data, xmin, ymin, xmax, ymax, x, y, fg, bg
607   }
608   compare unclip?, 0/false
609   {
610     break-if-!=
611     x <- draw-text-rightward screen, data, x, xmax, y, fg, bg
612   }
613   y <- increment
614   return y
617 fn should-render? _line: (addr trace-line) -> _/eax: boolean {
618   var line/eax: (addr trace-line) <- copy _line
619   var result/eax: (addr boolean) <- get line, visible?
620   return *result
623 # This is super-inefficient, string-comparing every trace line
624 # against every visible line.
625 fn recompute-all-visible-lines _self: (addr trace) {
626   var self/esi: (addr trace) <- copy _self
627   var max-addr/edx: (addr int) <- get self, first-free
628   var trace-ah/eax: (addr handle array trace-line) <- get self, data
629   var _trace/eax: (addr array trace-line) <- lookup *trace-ah
630   var trace/esi: (addr array trace-line) <- copy _trace
631   var i/ecx: int <- copy 0
632   {
633     compare i, *max-addr
634     break-if->=
635     var offset/ebx: (offset trace-line) <- compute-offset trace, i
636     var curr/ebx: (addr trace-line) <- index trace, offset
637     recompute-visibility _self, curr
638     i <- increment
639     loop
640   }
643 fn recompute-visibility _self: (addr trace), _line: (addr trace-line) {
644   var self/esi: (addr trace) <- copy _self
645   # recompute
646   var candidates-ah/eax: (addr handle array trace-line) <- get self, visible
647   var candidates/eax: (addr array trace-line) <- lookup *candidates-ah
648   var i/ecx: int <- copy 0
649   var len/edx: int <- length candidates
650   {
651     compare i, len
652     break-if->=
653     {
654       var curr-offset/ecx: (offset trace-line) <- compute-offset candidates, i
655       var curr/ecx: (addr trace-line) <- index candidates, curr-offset
656       var match?/eax: boolean <- trace-lines-equal? curr, _line
657       compare match?, 0/false
658       break-if-=
659       var line/eax: (addr trace-line) <- copy _line
660       var dest/eax: (addr boolean) <- get line, visible?
661       copy-to *dest, 1/true
662       return
663     }
664     i <- increment
665     loop
666   }
667   var line/eax: (addr trace-line) <- copy _line
668   var dest/eax: (addr boolean) <- get line, visible?
669   copy-to *dest, 0/false
672 fn clamp-cursor-to-top _self: (addr trace), _y: int {
673   var y/ecx: int <- copy _y
674   var self/esi: (addr trace) <- copy _self
675   var cursor-y/eax: (addr int) <- get self, cursor-y
676   compare *cursor-y, y
677   break-if->=
678   copy-to *cursor-y, y
681 # extremely hacky; consider deleting test-render-trace-empty-3 when you clean this up
682 # TODO: duplicates logic for rendering a line
683 fn clamp-cursor-to-bottom _self: (addr trace), _y: int, screen: (addr screen), xmin: int, ymin: int, xmax: int, ymax: int {
684   var y/ebx: int <- copy _y
685   compare y, ymin
686   {
687     break-if->
688     return
689   }
690   y <- decrement
691   var self/esi: (addr trace) <- copy _self
692   var cursor-y/eax: (addr int) <- get self, cursor-y
693   compare *cursor-y, y
694   break-if-<=
695   copy-to *cursor-y, y
696   # redraw cursor-line
697   var trace-ah/eax: (addr handle array trace-line) <- get self, data
698   var trace/eax: (addr array trace-line) <- lookup *trace-ah
699   var cursor-line-index-addr/ecx: (addr int) <- get self, cursor-line-index
700   var cursor-line-index/ecx: int <- copy *cursor-line-index-addr
701   var first-free/edx: (addr int) <- get self, first-free
702   compare cursor-line-index, *first-free
703   {
704     break-if-<
705     return
706   }
707   var cursor-offset/ecx: (offset trace-line) <- compute-offset trace, cursor-line-index
708   var cursor-line/ecx: (addr trace-line) <- index trace, cursor-offset
709   var display?/eax: boolean <- should-render? cursor-line
710   {
711     compare display?, 0/false
712     break-if-=
713     var dummy/ecx: int <- render-trace-line screen, cursor-line, xmin, y, xmax, ymax, 0x38/fg=trace, 7/cursor-line-bg, 0/clip
714     return
715   }
716   var dummy1/eax: int <- copy 0
717   var dummy2/ecx: int <- copy 0
718   dummy1, dummy2 <- draw-text-wrapping-right-then-down screen, "...", xmin, ymin, xmax, ymax, xmin, y, 9/fg=trace, 7/cursor-line-bg
721 fn test-render-trace-empty {
722   var t-storage: trace
723   var t/esi: (addr trace) <- address t-storage
724   initialize-trace t, 0x100/max-depth, 0x10, 0x10
725   # setup: screen
726   var screen-on-stack: screen
727   var screen/edi: (addr screen) <- address screen-on-stack
728   initialize-screen screen, 5/width, 4/height, 0/no-pixel-graphics
729   #
730   var y/ecx: int <- render-trace screen, t, 0/xmin, 0/ymin, 5/xmax, 4/ymax, 0/no-cursor
731   #
732   check-ints-equal y, 0, "F - test-render-trace-empty/cursor"
733   check-screen-row screen,                                  0/y, "    ", "F - test-render-trace-empty"
734   check-background-color-in-screen-row screen, 7/bg=cursor, 0/y, "    ", "F - test-render-trace-empty/bg"
737 fn test-render-trace-empty-2 {
738   var t-storage: trace
739   var t/esi: (addr trace) <- address t-storage
740   initialize-trace t, 0x100/max-depth, 0x10, 0x10
741   # setup: screen
742   var screen-on-stack: screen
743   var screen/edi: (addr screen) <- address screen-on-stack
744   initialize-screen screen, 5/width, 4/height, 0/no-pixel-graphics
745   #
746   var y/ecx: int <- render-trace screen, t, 0/xmin, 2/ymin, 5/xmax, 4/ymax, 0/no-cursor  # cursor below top row
747   #
748   check-ints-equal y, 2, "F - test-render-trace-empty-2/cursor"
749   check-screen-row screen,                                  2/y, "    ", "F - test-render-trace-empty-2"
750   check-background-color-in-screen-row screen, 7/bg=cursor, 2/y, "    ", "F - test-render-trace-empty-2/bg"
753 fn test-render-trace-empty-3 {
754   var t-storage: trace
755   var t/esi: (addr trace) <- address t-storage
756   initialize-trace t, 0x100/max-depth, 0x10, 0x10
757   # setup: screen
758   var screen-on-stack: screen
759   var screen/edi: (addr screen) <- address screen-on-stack
760   initialize-screen screen, 5/width, 4/height, 0/no-pixel-graphics
761   #
762   var y/ecx: int <- render-trace screen, t, 0/xmin, 2/ymin, 5/xmax, 4/ymax, 1/show-cursor  # try show cursor
763   # still no cursor to show
764   check-ints-equal y, 2, "F - test-render-trace-empty-3/cursor"
765   check-screen-row screen,                                  1/y, "    ", "F - test-render-trace-empty-3/line-above-cursor"
766   check-background-color-in-screen-row screen, 7/bg=cursor, 1/y, "    ", "F - test-render-trace-empty-3/bg-for-line-above-cursor"
767   check-screen-row screen,                                  2/y, "    ", "F - test-render-trace-empty-3"
768   check-background-color-in-screen-row screen, 7/bg=cursor, 2/y, "    ", "F - test-render-trace-empty-3/bg"
771 fn test-render-trace-collapsed-by-default {
772   var t-storage: trace
773   var t/esi: (addr trace) <- address t-storage
774   initialize-trace t, 0x100/max-depth, 0x10, 0x10
775   trace-text t, "l", "data"
776   # setup: screen
777   var screen-on-stack: screen
778   var screen/edi: (addr screen) <- address screen-on-stack
779   initialize-screen screen, 5/width, 4/height, 0/no-pixel-graphics
780   #
781   var y/ecx: int <- render-trace screen, t, 0/xmin, 0/ymin, 5/xmax, 4/ymax, 0/no-cursor
782   #
783   check-ints-equal y, 1, "F - test-render-trace-collapsed-by-default/cursor"
784   check-screen-row screen, 0/y, "... ", "F - test-render-trace-collapsed-by-default"
787 fn test-render-trace-error {
788   var t-storage: trace
789   var t/esi: (addr trace) <- address t-storage
790   initialize-trace t, 0x100/max-depth, 0x10, 0x10
791   error t, "error"
792   # setup: screen
793   var screen-on-stack: screen
794   var screen/edi: (addr screen) <- address screen-on-stack
795   initialize-screen screen, 0xa/width, 4/height, 0/no-pixel-graphics
796   #
797   var y/ecx: int <- render-trace screen, t, 0/xmin, 0/ymin, 0xa/xmax, 4/ymax, 0/no-cursor
798   #
799   check-ints-equal y, 1, "F - test-render-trace-error/cursor"
800   check-screen-row screen, 0/y, "error", "F - test-render-trace-error"
803 fn test-render-trace-error-at-start {
804   var t-storage: trace
805   var t/esi: (addr trace) <- address t-storage
806   initialize-trace t, 0x100/max-depth, 0x10, 0x10
807   #
808   error t, "error"
809   trace-text t, "l", "data"
810   # setup: screen
811   var screen-on-stack: screen
812   var screen/edi: (addr screen) <- address screen-on-stack
813   initialize-screen screen, 0xa/width, 4/height, 0/no-pixel-graphics
814   #
815   var y/ecx: int <- render-trace screen, t, 0/xmin, 0/ymin, 0xa/xmax, 4/ymax, 0/no-cursor
816   #
817   check-ints-equal y, 2, "F - test-render-trace-error-at-start/cursor"
818   check-screen-row screen, 0/y, "error", "F - test-render-trace-error-at-start/0"
819   check-screen-row screen, 1/y, "...  ", "F - test-render-trace-error-at-start/1"
822 fn test-render-trace-error-at-end {
823   var t-storage: trace
824   var t/esi: (addr trace) <- address t-storage
825   initialize-trace t, 0x100/max-depth, 0x10, 0x10
826   #
827   trace-text t, "l", "data"
828   error t, "error"
829   # setup: screen
830   var screen-on-stack: screen
831   var screen/edi: (addr screen) <- address screen-on-stack
832   initialize-screen screen, 0xa/width, 4/height, 0/no-pixel-graphics
833   #
834   var y/ecx: int <- render-trace screen, t, 0/xmin, 0/ymin, 0xa/xmax, 4/ymax, 0/no-cursor
835   #
836   check-ints-equal y, 2, "F - test-render-trace-error-at-end/cursor"
837   check-screen-row screen, 0/y, "...  ", "F - test-render-trace-error-at-end/0"
838   check-screen-row screen, 1/y, "error", "F - test-render-trace-error-at-end/1"
841 fn test-render-trace-error-in-the-middle {
842   var t-storage: trace
843   var t/esi: (addr trace) <- address t-storage
844   initialize-trace t, 0x100/max-depth, 0x10, 0x10
845   #
846   trace-text t, "l", "line 1"
847   error t, "error"
848   trace-text t, "l", "line 3"
849   # setup: screen
850   var screen-on-stack: screen
851   var screen/edi: (addr screen) <- address screen-on-stack
852   initialize-screen screen, 0xa/width, 4/height, 0/no-pixel-graphics
853   #
854   var y/ecx: int <- render-trace screen, t, 0/xmin, 0/ymin, 0xa/xmax, 4/ymax, 0/no-cursor
855   #
856   check-ints-equal y, 3, "F - test-render-trace-error-in-the-middle/cursor"
857   check-screen-row screen, 0/y, "...  ", "F - test-render-trace-error-in-the-middle/0"
858   check-screen-row screen, 1/y, "error", "F - test-render-trace-error-in-the-middle/1"
859   check-screen-row screen, 2/y, "...  ", "F - test-render-trace-error-in-the-middle/2"
862 fn test-render-trace-cursor-in-single-line {
863   var t-storage: trace
864   var t/esi: (addr trace) <- address t-storage
865   initialize-trace t, 0x100/max-depth, 0x10, 0x10
866   #
867   trace-text t, "l", "line 1"
868   error t, "error"
869   trace-text t, "l", "line 3"
870   # setup: screen
871   var screen-on-stack: screen
872   var screen/edi: (addr screen) <- address screen-on-stack
873   initialize-screen screen, 0xa/width, 4/height, 0/no-pixel-graphics
874   #
875   var y/ecx: int <- render-trace screen, t, 0/xmin, 0/ymin, 0xa/xmax, 4/ymax, 1/show-cursor
876   #
877   check-screen-row screen,                                  0/y, "...   ", "F - test-render-trace-cursor-in-single-line/0"
878   check-background-color-in-screen-row screen, 7/bg=cursor, 0/y, "|||   ", "F - test-render-trace-cursor-in-single-line/0/cursor"
879   check-screen-row screen,                                  1/y, "error ", "F - test-render-trace-cursor-in-single-line/1"
880   check-background-color-in-screen-row screen, 7/bg=cursor, 1/y, "      ", "F - test-render-trace-cursor-in-single-line/1/cursor"
881   check-screen-row screen,                                  2/y, "...   ", "F - test-render-trace-cursor-in-single-line/2"
882   check-background-color-in-screen-row screen, 7/bg=cursor, 2/y, "      ", "F - test-render-trace-cursor-in-single-line/2/cursor"
885 fn render-trace-menu screen: (addr screen) {
886   var width/eax: int <- copy 0
887   var height/ecx: int <- copy 0
888   width, height <- screen-size screen
889   var y/ecx: int <- copy height
890   y <- decrement
891   var height/edx: int <- copy y
892   height <- increment
893   clear-rect screen, 0/x, y, width, height, 0xc5/bg=blue-bg
894   set-cursor-position screen, 0/x, y
895   draw-text-rightward-from-cursor screen, " ^r ", width, 0/fg, 0x5c/bg=menu-highlight
896   draw-text-rightward-from-cursor screen, " run main  ", width, 7/fg, 0xc5/bg=blue-bg
897   draw-text-rightward-from-cursor screen, " ^g ", width, 0/fg, 0x5c/bg=menu-highlight
898   draw-text-rightward-from-cursor screen, " go to  ", width, 7/fg, 0xc5/bg=blue-bg
899   draw-text-rightward-from-cursor screen, " ^m ", width, 0/fg, 3/bg=keyboard
900   draw-text-rightward-from-cursor screen, " to keyboard  ", width, 7/fg, 0xc5/bg=blue-bg
901   draw-text-rightward-from-cursor screen, " enter/bksp ", width, 0/fg, 0x5c/bg=menu-highlight
902   draw-text-rightward-from-cursor screen, " expand/collapse  ", width, 7/fg, 0xc5/bg=blue-bg
903   draw-text-rightward-from-cursor screen, " ^s ", width, 0/fg, 0x5c/bg=menu-highlight
904   draw-text-rightward-from-cursor screen, " show whole line  ", width, 7/fg, 0xc5/bg=blue-bg
907 fn edit-trace _self: (addr trace), key: code-point-utf8 {
908   var self/esi: (addr trace) <- copy _self
909   # cursor down
910   {
911     compare key, 0x6a/j
912     break-if-!=
913     var cursor-y/eax: (addr int) <- get self, cursor-y
914     increment *cursor-y
915     var unclip-cursor-line?/eax: (addr boolean) <- get self, unclip-cursor-line?
916     copy-to *unclip-cursor-line?, 0/false
917     return
918   }
919   {
920     compare key, 0x81/down-arrow
921     break-if-!=
922     var cursor-y/eax: (addr int) <- get self, cursor-y
923     increment *cursor-y
924     var unclip-cursor-line?/eax: (addr boolean) <- get self, unclip-cursor-line?
925     copy-to *unclip-cursor-line?, 0/false
926     return
927   }
928   # cursor up
929   {
930     compare key, 0x6b/k
931     break-if-!=
932     var cursor-y/eax: (addr int) <- get self, cursor-y
933     decrement *cursor-y
934     var unclip-cursor-line?/eax: (addr boolean) <- get self, unclip-cursor-line?
935     copy-to *unclip-cursor-line?, 0/false
936     return
937   }
938   {
939     compare key, 0x82/up-arrow
940     break-if-!=
941     var cursor-y/eax: (addr int) <- get self, cursor-y
942     decrement *cursor-y
943     var unclip-cursor-line?/eax: (addr boolean) <- get self, unclip-cursor-line?
944     copy-to *unclip-cursor-line?, 0/false
945     return
946   }
947   # enter = expand
948   {
949     compare key, 0xa/newline
950     break-if-!=
951     expand self
952     return
953   }
954   # backspace = collapse
955   {
956     compare key, 8/backspace
957     break-if-!=
958     collapse self
959     return
960   }
961   # ctrl-s: temporarily unclip current line
962   {
963     compare key, 0x13/ctrl-s
964     break-if-!=
965     var unclip-cursor-line?/eax: (addr boolean) <- get self, unclip-cursor-line?
966     copy-to *unclip-cursor-line?, 1/true
967     return
968   }
969   # ctrl-f: scroll down
970   {
971     compare key, 6/ctrl-f
972     break-if-!=
973     scroll-down self
974     return
975   }
976   # ctrl-b: scroll up
977   {
978     compare key, 2/ctrl-b
979     break-if-!=
980     scroll-up self
981     return
982   }
985 fn expand _self: (addr trace) {
986   var self/esi: (addr trace) <- copy _self
987   var trace-ah/eax: (addr handle array trace-line) <- get self, data
988   var _trace/eax: (addr array trace-line) <- lookup *trace-ah
989   var trace/edi: (addr array trace-line) <- copy _trace
990   var cursor-line-index-addr/ecx: (addr int) <- get self, cursor-line-index
991   var cursor-line-index/ecx: int <- copy *cursor-line-index-addr
992   var cursor-line-offset/eax: (offset trace-line) <- compute-offset trace, cursor-line-index
993   var cursor-line/edx: (addr trace-line) <- index trace, cursor-line-offset
994   var cursor-line-visible?/eax: (addr boolean) <- get cursor-line, visible?
995   var cursor-line-depth/ebx: (addr int) <- get cursor-line, depth
996   var target-depth/ebx: int <- copy *cursor-line-depth
997   # if cursor-line is already visible, do nothing
998   compare *cursor-line-visible?, 0/false
999   {
1000     break-if-=
1001 #?     draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, "visible", 7/fg 0/bg
1002     return
1003   }
1004   # reveal the run of lines starting at cursor-line-index with depth target-depth
1005   var i/ecx: int <- copy cursor-line-index
1006   var max/edx: (addr int) <- get self, first-free
1007   {
1008     compare i, *max
1009     break-if->=
1010     var curr-line-offset/eax: (offset trace-line) <- compute-offset trace, i
1011     var curr-line/edx: (addr trace-line) <- index trace, curr-line-offset
1012     var curr-line-depth/eax: (addr int) <- get curr-line, depth
1013     compare *curr-line-depth, target-depth
1014     break-if-<
1015     {
1016       break-if-!=
1017       var curr-line-visible?/eax: (addr boolean) <- get curr-line, visible?
1018       copy-to *curr-line-visible?, 1/true
1019       reveal-trace-line self, curr-line
1020     }
1021     i <- increment
1022     loop
1023   }
1026 fn collapse _self: (addr trace) {
1027   var self/esi: (addr trace) <- copy _self
1028   var trace-ah/eax: (addr handle array trace-line) <- get self, data
1029   var _trace/eax: (addr array trace-line) <- lookup *trace-ah
1030   var trace/edi: (addr array trace-line) <- copy _trace
1031   var cursor-line-index-addr/ecx: (addr int) <- get self, cursor-line-index
1032   var cursor-line-index/ecx: int <- copy *cursor-line-index-addr
1033   var cursor-line-offset/eax: (offset trace-line) <- compute-offset trace, cursor-line-index
1034   var cursor-line/edx: (addr trace-line) <- index trace, cursor-line-offset
1035   var cursor-line-visible?/eax: (addr boolean) <- get cursor-line, visible?
1036   # if cursor-line is not visible, do nothing
1037   compare *cursor-line-visible?, 0/false
1038   {
1039     break-if-!=
1040     return
1041   }
1042   # hide all lines between previous and next line with a lower depth
1043   var cursor-line-depth/ebx: (addr int) <- get cursor-line, depth
1044   var cursor-y/edx: (addr int) <- get self, cursor-y
1045   var target-depth/ebx: int <- copy *cursor-line-depth
1046   var i/ecx: int <- copy cursor-line-index
1047   $collapse:loop1: {
1048     compare i, 0
1049     break-if-<
1050     var curr-line-offset/eax: (offset trace-line) <- compute-offset trace, i
1051     var curr-line/eax: (addr trace-line) <- index trace, curr-line-offset
1052     {
1053       var curr-line-depth/eax: (addr int) <- get curr-line, depth
1054       compare *curr-line-depth, target-depth
1055       break-if-< $collapse:loop1
1056     }
1057     # if cursor-line is visible, decrement cursor-y
1058     {
1059       var curr-line-visible?/eax: (addr boolean) <- get curr-line, visible?
1060       compare *curr-line-visible?, 0/false
1061       break-if-=
1062       decrement *cursor-y
1063     }
1064     i <- decrement
1065     loop
1066   }
1067   i <- increment
1068   var max/edx: (addr int) <- get self, first-free
1069   $collapse:loop2: {
1070     compare i, *max
1071     break-if->=
1072     var curr-line-offset/eax: (offset trace-line) <- compute-offset trace, i
1073     var curr-line/edx: (addr trace-line) <- index trace, curr-line-offset
1074     var curr-line-depth/eax: (addr int) <- get curr-line, depth
1075     compare *curr-line-depth, target-depth
1076     break-if-<
1077     {
1078       hide-trace-line self, curr-line
1079       var curr-line-visible?/eax: (addr boolean) <- get curr-line, visible?
1080       copy-to *curr-line-visible?, 0/false
1081     }
1082     i <- increment
1083     loop
1084   }
1087 # the 'visible' array is not required to be in order
1088 # elements can also be deleted out of order
1089 # so it can have holes
1090 # however, lines in it always have visible? set
1091 # we'll use visible? being unset as a sign of emptiness
1092 fn reveal-trace-line _self: (addr trace), line: (addr trace-line) {
1093   var self/esi: (addr trace) <- copy _self
1094   var visible-ah/eax: (addr handle array trace-line) <- get self, visible
1095   var visible/eax: (addr array trace-line) <- lookup *visible-ah
1096   var i/ecx: int <- copy 0
1097   var len/edx: int <- length visible
1098   {
1099     compare i, len
1100     break-if->=
1101     var curr-offset/edx: (offset trace-line) <- compute-offset visible, i
1102     var curr/edx: (addr trace-line) <- index visible, curr-offset
1103     var curr-visible?/eax: (addr boolean) <- get curr, visible?
1104     compare *curr-visible?, 0/false
1105     {
1106       break-if-!=
1107       # empty slot found
1108       copy-object line, curr
1109       return
1110     }
1111     i <- increment
1112     loop
1113   }
1114   abort "too many visible lines; increase size of array trace.visible"
1117 fn hide-trace-line _self: (addr trace), line: (addr trace-line) {
1118   var self/esi: (addr trace) <- copy _self
1119   var visible-ah/eax: (addr handle array trace-line) <- get self, visible
1120   var visible/eax: (addr array trace-line) <- lookup *visible-ah
1121   var i/ecx: int <- copy 0
1122   var len/edx: int <- length visible
1123   {
1124     compare i, len
1125     break-if->=
1126     var curr-offset/edx: (offset trace-line) <- compute-offset visible, i
1127     var curr/edx: (addr trace-line) <- index visible, curr-offset
1128     var found?/eax: boolean <- trace-lines-equal? curr, line
1129     compare found?, 0/false
1130     {
1131       break-if-=
1132       clear-object curr
1133     }
1134     i <- increment
1135     loop
1136   }
1139 fn cursor-too-deep? _self: (addr trace) -> _/eax: boolean {
1140   var self/esi: (addr trace) <- copy _self
1141   var trace-ah/eax: (addr handle array trace-line) <- get self, data
1142   var _trace/eax: (addr array trace-line) <- lookup *trace-ah
1143   var trace/edi: (addr array trace-line) <- copy _trace
1144   var cursor-line-index-addr/ecx: (addr int) <- get self, cursor-line-index
1145   var cursor-line-index/ecx: int <- copy *cursor-line-index-addr
1146   var cursor-line-offset/eax: (offset trace-line) <- compute-offset trace, cursor-line-index
1147   var cursor-line/edx: (addr trace-line) <- index trace, cursor-line-offset
1148   var cursor-line-visible?/eax: (addr boolean) <- get cursor-line, visible?
1149   var cursor-line-depth/ebx: (addr int) <- get cursor-line, depth
1150   var target-depth/ebx: int <- copy *cursor-line-depth
1151   # if cursor-line is visible, return false
1152   compare *cursor-line-visible?, 0/false
1153   {
1154     break-if-=
1155     return 0/false
1156   }
1157   # return cursor-line-depth >= max-depth-1
1158   target-depth <- increment
1159   var max-depth-addr/eax: (addr int) <- get self, max-depth
1160   compare target-depth, *max-depth-addr
1161   {
1162     break-if-<
1163     return 1/true
1164   }
1165   return 0/false
1168 fn test-cursor-down-and-up-within-trace {
1169   var t-storage: trace
1170   var t/esi: (addr trace) <- address t-storage
1171   initialize-trace t, 0x100/max-depth, 0x10, 0x10
1172   #
1173   trace-text t, "l", "line 1"
1174   error t, "error"
1175   trace-text t, "l", "line 3"
1176   # setup: screen
1177   var screen-on-stack: screen
1178   var screen/edi: (addr screen) <- address screen-on-stack
1179   initialize-screen screen, 0xa/width, 4/height, 0/no-pixel-graphics
1180   #
1181   var y/ecx: int <- render-trace screen, t, 0/xmin, 0/ymin, 0xa/xmax, 4/ymax, 1/show-cursor
1182   #
1183   check-screen-row screen,                                  0/y, "...   ", "F - test-cursor-down-and-up-within-trace/pre-0"
1184   check-background-color-in-screen-row screen, 7/bg=cursor, 0/y, "|||   ", "F - test-cursor-down-and-up-within-trace/pre-0/cursor"
1185   check-screen-row screen,                                  1/y, "error ", "F - test-cursor-down-and-up-within-trace/pre-1"
1186   check-background-color-in-screen-row screen, 7/bg=cursor, 1/y, "      ", "F - test-cursor-down-and-up-within-trace/pre-1/cursor"
1187   check-screen-row screen,                                  2/y, "...   ", "F - test-cursor-down-and-up-within-trace/pre-2"
1188   check-background-color-in-screen-row screen, 7/bg=cursor, 2/y, "      ", "F - test-cursor-down-and-up-within-trace/pre-2/cursor"
1189   # cursor down
1190   edit-trace t, 0x6a/j
1191   var y/ecx: int <- render-trace screen, t, 0/xmin, 0/ymin, 0xa/xmax, 4/ymax, 1/show-cursor
1192   #
1193   check-screen-row screen,                                  0/y, "...   ", "F - test-cursor-down-and-up-within-trace/down-0"
1194   check-background-color-in-screen-row screen, 7/bg=cursor, 0/y, "      ", "F - test-cursor-down-and-up-within-trace/down-0/cursor"
1195   check-screen-row screen,                                  1/y, "error ", "F - test-cursor-down-and-up-within-trace/down-1"
1196   check-background-color-in-screen-row screen, 7/bg=cursor, 1/y, "||||| ", "F - test-cursor-down-and-up-within-trace/down-1/cursor"
1197   check-screen-row screen,                                  2/y, "...   ", "F - test-cursor-down-and-up-within-trace/down-2"
1198   check-background-color-in-screen-row screen, 7/bg=cursor, 2/y, "      ", "F - test-cursor-down-and-up-within-trace/down-2/cursor"
1199   # cursor up
1200   edit-trace t, 0x6b/k
1201   var y/ecx: int <- render-trace screen, t, 0/xmin, 0/ymin, 0xa/xmax, 4/ymax, 1/show-cursor
1202   #
1203   check-screen-row screen,                                  0/y, "...   ", "F - test-cursor-down-and-up-within-trace/up-0"
1204   check-background-color-in-screen-row screen, 7/bg=cursor, 0/y, "|||   ", "F - test-cursor-down-and-up-within-trace/up-0/cursor"
1205   check-screen-row screen,                                  1/y, "error ", "F - test-cursor-down-and-up-within-trace/up-1"
1206   check-background-color-in-screen-row screen, 7/bg=cursor, 1/y, "      ", "F - test-cursor-down-and-up-within-trace/up-1/cursor"
1207   check-screen-row screen,                                  2/y, "...   ", "F - test-cursor-down-and-up-within-trace/up-2"
1208   check-background-color-in-screen-row screen, 7/bg=cursor, 2/y, "      ", "F - test-cursor-down-and-up-within-trace/up-2/cursor"
1211 fn test-cursor-down-past-bottom-of-trace {
1212   var t-storage: trace
1213   var t/esi: (addr trace) <- address t-storage
1214   initialize-trace t, 0x100/max-depth, 0x10, 0x10
1215   #
1216   trace-text t, "l", "line 1"
1217   error t, "error"
1218   trace-text t, "l", "line 3"
1219   # setup: screen
1220   var screen-on-stack: screen
1221   var screen/edi: (addr screen) <- address screen-on-stack
1222   initialize-screen screen, 0xa/width, 4/height, 0/no-pixel-graphics
1223   #
1224   var y/ecx: int <- render-trace screen, t, 0/xmin, 0/ymin, 0xa/xmax, 4/ymax, 1/show-cursor
1225   #
1226   check-screen-row screen,                                  0/y, "...   ", "F - test-cursor-down-past-bottom-of-trace/pre-0"
1227   check-background-color-in-screen-row screen, 7/bg=cursor, 0/y, "|||   ", "F - test-cursor-down-past-bottom-of-trace/pre-0/cursor"
1228   check-screen-row screen,                                  1/y, "error ", "F - test-cursor-down-past-bottom-of-trace/pre-1"
1229   check-background-color-in-screen-row screen, 7/bg=cursor, 1/y, "      ", "F - test-cursor-down-past-bottom-of-trace/pre-1/cursor"
1230   check-screen-row screen,                                  2/y, "...   ", "F - test-cursor-down-past-bottom-of-trace/pre-2"
1231   check-background-color-in-screen-row screen, 7/bg=cursor, 2/y, "      ", "F - test-cursor-down-past-bottom-of-trace/pre-2/cursor"
1232   # cursor down several times
1233   edit-trace t, 0x6a/j
1234   edit-trace t, 0x6a/j
1235   edit-trace t, 0x6a/j
1236   edit-trace t, 0x6a/j
1237   edit-trace t, 0x6a/j
1238   # hack: we do need to render to make this test pass; we're mixing state management with rendering
1239   var y/ecx: int <- render-trace screen, t, 0/xmin, 0/ymin, 0xa/xmax, 4/ymax, 1/show-cursor
1240   # cursor clamps at bottom
1241   check-screen-row screen,                                  0/y, "...   ", "F - test-cursor-down-past-bottom-of-trace/down-0"
1242   check-background-color-in-screen-row screen, 7/bg=cursor, 0/y, "      ", "F - test-cursor-down-past-bottom-of-trace/down-0/cursor"
1243   check-screen-row screen,                                  1/y, "error ", "F - test-cursor-down-past-bottom-of-trace/down-1"
1244   check-background-color-in-screen-row screen, 7/bg=cursor, 1/y, "      ", "F - test-cursor-down-past-bottom-of-trace/down-1/cursor"
1245   check-screen-row screen,                                  2/y, "...   ", "F - test-cursor-down-past-bottom-of-trace/down-2"
1246   check-background-color-in-screen-row screen, 7/bg=cursor, 2/y, "|||   ", "F - test-cursor-down-past-bottom-of-trace/down-2/cursor"
1249 fn test-expand-within-trace {
1250   var t-storage: trace
1251   var t/esi: (addr trace) <- address t-storage
1252   initialize-trace t, 0x100/max-depth, 0x10, 0x10
1253   #
1254   trace-text t, "l", "line 1"
1255   trace-text t, "l", "line 2"
1256   # setup: screen
1257   var screen-on-stack: screen
1258   var screen/edi: (addr screen) <- address screen-on-stack
1259   initialize-screen screen, 0x10/width, 4/height, 0/no-pixel-graphics
1260   #
1261   var y/ecx: int <- render-trace screen, t, 0/xmin, 0/ymin, 0x10/xmax, 4/ymax, 1/show-cursor
1262   #
1263   check-screen-row screen,                                  0/y, "...      ", "F - test-expand-within-trace/pre-0"
1264   check-background-color-in-screen-row screen, 7/bg=cursor, 0/y, "|||      ", "F - test-expand-within-trace/pre-0/cursor"
1265   check-screen-row screen,                                  1/y, "         ", "F - test-expand-within-trace/pre-1"
1266   check-background-color-in-screen-row screen, 7/bg=cursor, 1/y, "         ", "F - test-expand-within-trace/pre-1/cursor"
1267   # expand
1268   edit-trace t, 0xa/enter
1269   var y/ecx: int <- render-trace screen, t, 0/xmin, 0/ymin, 0x10/xmax, 4/ymax, 1/show-cursor
1270   #
1271   check-screen-row screen,                                  0/y, "1 line 1 ", "F - test-expand-within-trace/expand-0"
1272   check-background-color-in-screen-row screen, 7/bg=cursor, 0/y, "|||||||| ", "F - test-expand-within-trace/expand-0/cursor"
1273   check-screen-row screen,                                  1/y, "1 line 2 ", "F - test-expand-within-trace/expand-1"
1274   check-background-color-in-screen-row screen, 7/bg=cursor, 1/y, "         ", "F - test-expand-within-trace/expand-1/cursor"
1275   check-screen-row screen,                                  2/y, "         ", "F - test-expand-within-trace/expand-2"
1276   check-background-color-in-screen-row screen, 7/bg=cursor, 2/y, "         ", "F - test-expand-within-trace/expand-2/cursor"
1279 fn test-trace-expand-skips-lower-depth {
1280   var t-storage: trace
1281   var t/esi: (addr trace) <- address t-storage
1282   initialize-trace t, 0x100/max-depth, 0x10, 0x10
1283   #
1284   trace-text t, "l", "line 1"
1285   trace-lower t
1286   trace-text t, "l", "line 2"
1287   # setup: screen
1288   var screen-on-stack: screen
1289   var screen/edi: (addr screen) <- address screen-on-stack
1290   initialize-screen screen, 0x10/width, 4/height, 0/no-pixel-graphics
1291   #
1292   var y/ecx: int <- render-trace screen, t, 0/xmin, 0/ymin, 0x10/xmax, 4/ymax, 1/show-cursor
1293   #
1294   check-screen-row screen,                                  0/y, "...      ", "F - test-trace-expand-skips-lower-depth/pre-0"
1295   check-background-color-in-screen-row screen, 7/bg=cursor, 0/y, "|||      ", "F - test-trace-expand-skips-lower-depth/pre-0/cursor"
1296   check-screen-row screen,                                  1/y, "         ", "F - test-trace-expand-skips-lower-depth/pre-1"
1297   check-background-color-in-screen-row screen, 7/bg=cursor, 1/y, "         ", "F - test-trace-expand-skips-lower-depth/pre-1/cursor"
1298   # expand
1299   edit-trace t, 0xa/enter
1300   var y/ecx: int <- render-trace screen, t, 0/xmin, 0/ymin, 0x10/xmax, 4/ymax, 1/show-cursor
1301   #
1302   check-screen-row screen,                                  0/y, "1 line 1 ", "F - test-trace-expand-skips-lower-depth/expand-0"
1303   check-background-color-in-screen-row screen, 7/bg=cursor, 0/y, "|||||||| ", "F - test-trace-expand-skips-lower-depth/expand-0/cursor"
1304   check-screen-row screen,                                  1/y, "...      ", "F - test-trace-expand-skips-lower-depth/expand-1"
1305   check-background-color-in-screen-row screen, 7/bg=cursor, 1/y, "         ", "F - test-trace-expand-skips-lower-depth/expand-1/cursor"
1306   check-screen-row screen,                                  2/y, "         ", "F - test-trace-expand-skips-lower-depth/expand-2"
1307   check-background-color-in-screen-row screen, 7/bg=cursor, 2/y, "         ", "F - test-trace-expand-skips-lower-depth/expand-2/cursor"
1310 fn test-trace-expand-continues-past-lower-depth {
1311   var t-storage: trace
1312   var t/esi: (addr trace) <- address t-storage
1313   initialize-trace t, 0x100/max-depth, 0x10, 0x10
1314   #
1315   trace-text t, "l", "line 1"
1316   trace-lower t
1317   trace-text t, "l", "line 1.1"
1318   trace-higher t
1319   trace-text t, "l", "line 2"
1320   # setup: screen
1321   var screen-on-stack: screen
1322   var screen/edi: (addr screen) <- address screen-on-stack
1323   initialize-screen screen, 0x10/width, 4/height, 0/no-pixel-graphics
1324   #
1325   var y/ecx: int <- render-trace screen, t, 0/xmin, 0/ymin, 0x10/xmax, 4/ymax, 1/show-cursor
1326   #
1327   check-screen-row screen,                                  0/y, "...      ", "F - test-trace-expand-continues-past-lower-depth/pre-0"
1328   check-background-color-in-screen-row screen, 7/bg=cursor, 0/y, "|||      ", "F - test-trace-expand-continues-past-lower-depth/pre-0/cursor"
1329   check-screen-row screen,                                  1/y, "         ", "F - test-trace-expand-continues-past-lower-depth/pre-1"
1330   check-background-color-in-screen-row screen, 7/bg=cursor, 1/y, "         ", "F - test-trace-expand-continues-past-lower-depth/pre-1/cursor"
1331   # expand
1332   edit-trace t, 0xa/enter
1333   var y/ecx: int <- render-trace screen, t, 0/xmin, 0/ymin, 0x10/xmax, 4/ymax, 1/show-cursor
1334   #
1335   check-screen-row screen,                                  0/y, "1 line 1 ", "F - test-trace-expand-continues-past-lower-depth/expand-0"
1336   check-background-color-in-screen-row screen, 7/bg=cursor, 0/y, "|||||||| ", "F - test-trace-expand-continues-past-lower-depth/expand-0/cursor"
1337   # TODO: might be too wasteful to show every place where lines are hidden
1338   check-screen-row screen,                                  1/y, "...      ", "F - test-trace-expand-continues-past-lower-depth/expand-1"
1339   check-background-color-in-screen-row screen, 7/bg=cursor, 1/y, "         ", "F - test-trace-expand-continues-past-lower-depth/expand-1/cursor"
1340   check-screen-row screen,                                  2/y, "1 line 2 ", "F - test-trace-expand-continues-past-lower-depth/expand-2"
1341   check-background-color-in-screen-row screen, 7/bg=cursor, 2/y, "         ", "F - test-trace-expand-continues-past-lower-depth/expand-2/cursor"
1344 fn test-trace-expand-stops-at-higher-depth {
1345   var t-storage: trace
1346   var t/esi: (addr trace) <- address t-storage
1347   initialize-trace t, 0x100/max-depth, 0x10, 0x10
1348   #
1349   trace-lower t
1350   trace-text t, "l", "line 1.1"
1351   trace-lower t
1352   trace-text t, "l", "line 1.1.1"
1353   trace-higher t
1354   trace-text t, "l", "line 1.2"
1355   trace-higher t
1356   trace-text t, "l", "line 2"
1357   trace-lower t
1358   trace-text t, "l", "line 2.1"
1359   # setup: screen
1360   var screen-on-stack: screen
1361   var screen/edi: (addr screen) <- address screen-on-stack
1362   initialize-screen screen, 0x10/width, 8/height, 0/no-pixel-graphics
1363   #
1364   var y/ecx: int <- render-trace screen, t, 0/xmin, 0/ymin, 0x10/xmax, 8/ymax, 1/show-cursor
1365   #
1366   check-screen-row screen,                                  0/y, "...        ", "F - test-trace-expand-stops-at-higher-depth/pre-0"
1367   check-background-color-in-screen-row screen, 7/bg=cursor, 0/y, "|||        ", "F - test-trace-expand-stops-at-higher-depth/pre-0/cursor"
1368   check-screen-row screen,                                  1/y, "           ", "F - test-trace-expand-stops-at-higher-depth/pre-1"
1369   check-background-color-in-screen-row screen, 7/bg=cursor, 1/y, "           ", "F - test-trace-expand-stops-at-higher-depth/pre-1/cursor"
1370   # expand
1371   edit-trace t, 0xa/enter
1372   var y/ecx: int <- render-trace screen, t, 0/xmin, 0/ymin, 0x10/xmax, 8/ymax, 1/show-cursor
1373   #
1374   check-screen-row screen,                                  0/y, "2 line 1.1 ", "F - test-trace-expand-stops-at-higher-depth/expand-0"
1375   check-background-color-in-screen-row screen, 7/bg=cursor, 0/y, "|||||||||| ", "F - test-trace-expand-stops-at-higher-depth/expand-0/cursor"
1376   check-screen-row screen,                                  1/y, "...        ", "F - test-trace-expand-stops-at-higher-depth/expand-1"
1377   check-background-color-in-screen-row screen, 7/bg=cursor, 1/y, "           ", "F - test-trace-expand-stops-at-higher-depth/expand-1/cursor"
1378   check-screen-row screen,                                  2/y, "2 line 1.2 ", "F - test-trace-expand-stops-at-higher-depth/expand-2"
1379   check-background-color-in-screen-row screen, 7/bg=cursor, 2/y, "           ", "F - test-trace-expand-stops-at-higher-depth/expand-2/cursor"
1380   check-screen-row screen,                                  3/y, "...        ", "F - test-trace-expand-stops-at-higher-depth/expand-3"
1381   check-background-color-in-screen-row screen, 7/bg=cursor, 3/y, "           ", "F - test-trace-expand-stops-at-higher-depth/expand-3/cursor"
1382   check-screen-row screen,                                  4/y, "           ", "F - test-trace-expand-stops-at-higher-depth/expand-4"
1383   check-background-color-in-screen-row screen, 7/bg=cursor, 4/y, "           ", "F - test-trace-expand-stops-at-higher-depth/expand-4/cursor"
1386 fn test-trace-expand-twice {
1387   var t-storage: trace
1388   var t/esi: (addr trace) <- address t-storage
1389   initialize-trace t, 0x100/max-depth, 0x10, 0x10
1390   #
1391   trace-text t, "l", "line 1"
1392   trace-lower t
1393   trace-text t, "l", "line 1.1"
1394   trace-higher t
1395   trace-text t, "l", "line 2"
1396   # setup: screen
1397   var screen-on-stack: screen
1398   var screen/edi: (addr screen) <- address screen-on-stack
1399   initialize-screen screen, 0x10/width, 4/height, 0/no-pixel-graphics
1400   #
1401   var y/ecx: int <- render-trace screen, t, 0/xmin, 0/ymin, 0x10/xmax, 4/ymax, 1/show-cursor
1402   #
1403   check-screen-row screen,                                  0/y, "...        ", "F - test-trace-expand-twice/pre-0"
1404   check-background-color-in-screen-row screen, 7/bg=cursor, 0/y, "|||        ", "F - test-trace-expand-twice/pre-0/cursor"
1405   check-screen-row screen,                                  1/y, "           ", "F - test-trace-expand-twice/pre-1"
1406   check-background-color-in-screen-row screen, 7/bg=cursor, 1/y, "           ", "F - test-trace-expand-twice/pre-1/cursor"
1407   # expand
1408   edit-trace t, 0xa/enter
1409   var y/ecx: int <- render-trace screen, t, 0/xmin, 0/ymin, 0x10/xmax, 4/ymax, 1/show-cursor
1410   #
1411   check-screen-row screen,                                  0/y, "1 line 1   ", "F - test-trace-expand-twice/expand-0"
1412   check-background-color-in-screen-row screen, 7/bg=cursor, 0/y, "||||||||   ", "F - test-trace-expand-twice/expand-0/cursor"
1413   check-screen-row screen,                                  1/y, "...        ", "F - test-trace-expand-twice/expand-1"
1414   check-background-color-in-screen-row screen, 7/bg=cursor, 1/y, "           ", "F - test-trace-expand-twice/expand-1/cursor"
1415   check-screen-row screen,                                  2/y, "1 line 2   ", "F - test-trace-expand-twice/expand-2"
1416   check-background-color-in-screen-row screen, 7/bg=cursor, 2/y, "           ", "F - test-trace-expand-twice/expand-2/cursor"
1417   # cursor down
1418   edit-trace t, 0x6a/j
1419   # hack: we need to render here to make this test pass; we're mixing state management with rendering
1420   var y/ecx: int <- render-trace screen, t, 0/xmin, 0/ymin, 0x10/xmax, 4/ymax, 1/show-cursor
1421   #
1422   check-screen-row screen,                                  0/y, "1 line 1   ", "F - test-trace-expand-twice/down-0"
1423   check-background-color-in-screen-row screen, 7/bg=cursor, 0/y, "           ", "F - test-trace-expand-twice/down-0/cursor"
1424   check-screen-row screen,                                  1/y, "...        ", "F - test-trace-expand-twice/down-1"
1425   check-background-color-in-screen-row screen, 7/bg=cursor, 1/y, "|||        ", "F - test-trace-expand-twice/down-1/cursor"
1426   check-screen-row screen,                                  2/y, "1 line 2   ", "F - test-trace-expand-twice/down-2"
1427   check-background-color-in-screen-row screen, 7/bg=cursor, 2/y, "           ", "F - test-trace-expand-twice/down-2/cursor"
1428   # expand again
1429   edit-trace t, 0xa/enter
1430   var y/ecx: int <- render-trace screen, t, 0/xmin, 0/ymin, 0x10/xmax, 4/ymax, 1/show-cursor
1431   #
1432   check-screen-row screen,                                  0/y, "1 line 1   ", "F - test-trace-expand-twice/expand2-0"
1433   check-background-color-in-screen-row screen, 7/bg=cursor, 0/y, "           ", "F - test-trace-expand-twice/expand2-0/cursor"
1434   check-screen-row screen,                                  1/y, "2 line 1.1 ", "F - test-trace-expand-twice/expand2-1"
1435   check-background-color-in-screen-row screen, 7/bg=cursor, 1/y, "|||||||||| ", "F - test-trace-expand-twice/expand2-1/cursor"
1436   check-screen-row screen,                                  2/y, "1 line 2   ", "F - test-trace-expand-twice/expand2-2"
1437   check-background-color-in-screen-row screen, 7/bg=cursor, 2/y, "           ", "F - test-trace-expand-twice/expand2-2/cursor"
1440 fn test-trace-refresh-cursor {
1441   var t-storage: trace
1442   var t/esi: (addr trace) <- address t-storage
1443   initialize-trace t, 0x100/max-depth, 0x10, 0x10
1444   #
1445   trace-text t, "l", "line 1"
1446   trace-text t, "l", "line 2"
1447   trace-text t, "l", "line 3"
1448   # setup: screen
1449   var screen-on-stack: screen
1450   var screen/edi: (addr screen) <- address screen-on-stack
1451   initialize-screen screen, 0x10/width, 4/height, 0/no-pixel-graphics
1452   #
1453   var y/ecx: int <- render-trace screen, t, 0/xmin, 0/ymin, 0x10/xmax, 4/ymax, 1/show-cursor
1454   #
1455   check-screen-row screen,                                  0/y, "...        ", "F - test-trace-refresh-cursor/pre-0"
1456   check-background-color-in-screen-row screen, 7/bg=cursor, 0/y, "|||        ", "F - test-trace-refresh-cursor/pre-0/cursor"
1457   check-screen-row screen,                                  1/y, "           ", "F - test-trace-refresh-cursor/pre-1"
1458   check-background-color-in-screen-row screen, 7/bg=cursor, 1/y, "           ", "F - test-trace-refresh-cursor/pre-1/cursor"
1459   # expand
1460   edit-trace t, 0xa/enter
1461   var y/ecx: int <- render-trace screen, t, 0/xmin, 0/ymin, 0x10/xmax, 4/ymax, 1/show-cursor
1462   #
1463   check-screen-row screen,                                  0/y, "1 line 1   ", "F - test-trace-refresh-cursor/expand-0"
1464   check-background-color-in-screen-row screen, 7/bg=cursor, 0/y, "||||||||   ", "F - test-trace-refresh-cursor/expand-0/cursor"
1465   check-screen-row screen,                                  1/y, "1 line 2   ", "F - test-trace-refresh-cursor/expand-1"
1466   check-background-color-in-screen-row screen, 7/bg=cursor, 1/y, "           ", "F - test-trace-refresh-cursor/expand-1/cursor"
1467   check-screen-row screen,                                  2/y, "1 line 3   ", "F - test-trace-refresh-cursor/expand-2"
1468   check-background-color-in-screen-row screen, 7/bg=cursor, 2/y, "           ", "F - test-trace-refresh-cursor/expand-2/cursor"
1469   # cursor down
1470   edit-trace t, 0x6a/j
1471   edit-trace t, 0x6a/j
1472   var y/ecx: int <- render-trace screen, t, 0/xmin, 0/ymin, 0x10/xmax, 4/ymax, 1/show-cursor
1473   #
1474   check-screen-row screen,                                  0/y, "1 line 1   ", "F - test-trace-refresh-cursor/down-0"
1475   check-background-color-in-screen-row screen, 7/bg=cursor, 0/y, "           ", "F - test-trace-refresh-cursor/down-0/cursor"
1476   check-screen-row screen,                                  1/y, "1 line 2   ", "F - test-trace-refresh-cursor/down-1"
1477   check-background-color-in-screen-row screen, 7/bg=cursor, 1/y, "           ", "F - test-trace-refresh-cursor/down-1/cursor"
1478   check-screen-row screen,                                  2/y, "1 line 3   ", "F - test-trace-refresh-cursor/down-2"
1479   check-background-color-in-screen-row screen, 7/bg=cursor, 2/y, "||||||||   ", "F - test-trace-refresh-cursor/down-2/cursor"
1480   # recreate trace
1481   clear-trace t
1482   trace-text t, "l", "line 1"
1483   trace-text t, "l", "line 2"
1484   trace-text t, "l", "line 3"
1485   var y/ecx: int <- render-trace screen, t, 0/xmin, 0/ymin, 0x10/xmax, 4/ymax, 1/show-cursor
1486   # cursor remains unchanged
1487   check-screen-row screen,                                  0/y, "1 line 1   ", "F - test-trace-refresh-cursor/refresh-0"
1488   check-background-color-in-screen-row screen, 7/bg=cursor, 0/y, "           ", "F - test-trace-refresh-cursor/refresh-0/cursor"
1489   check-screen-row screen,                                  1/y, "1 line 2   ", "F - test-trace-refresh-cursor/refresh-1"
1490   check-background-color-in-screen-row screen, 7/bg=cursor, 1/y, "           ", "F - test-trace-refresh-cursor/refresh-1/cursor"
1491   check-screen-row screen,                                  2/y, "1 line 3   ", "F - test-trace-refresh-cursor/refresh-2"
1492   check-background-color-in-screen-row screen, 7/bg=cursor, 2/y, "||||||||   ", "F - test-trace-refresh-cursor/refresh-2/cursor"
1495 fn test-trace-preserve-cursor-on-refresh {
1496   var t-storage: trace
1497   var t/esi: (addr trace) <- address t-storage
1498   initialize-trace t, 0x100/max-depth, 0x10, 0x10
1499   #
1500   trace-text t, "l", "line 1"
1501   trace-text t, "l", "line 2"
1502   trace-text t, "l", "line 3"
1503   # setup: screen
1504   var screen-on-stack: screen
1505   var screen/edi: (addr screen) <- address screen-on-stack
1506   initialize-screen screen, 0x10/width, 4/height, 0/no-pixel-graphics
1507   #
1508   var y/ecx: int <- render-trace screen, t, 0/xmin, 0/ymin, 0x10/xmax, 4/ymax, 1/show-cursor
1509   #
1510   check-screen-row screen,                                  0/y, "...        ", "F - test-trace-preserve-cursor-on-refresh/pre-0"
1511   check-background-color-in-screen-row screen, 7/bg=cursor, 0/y, "|||        ", "F - test-trace-preserve-cursor-on-refresh/pre-0/cursor"
1512   check-screen-row screen,                                  1/y, "           ", "F - test-trace-preserve-cursor-on-refresh/pre-1"
1513   check-background-color-in-screen-row screen, 7/bg=cursor, 1/y, "           ", "F - test-trace-preserve-cursor-on-refresh/pre-1/cursor"
1514   # expand
1515   edit-trace t, 0xa/enter
1516   var y/ecx: int <- render-trace screen, t, 0/xmin, 0/ymin, 0x10/xmax, 4/ymax, 1/show-cursor
1517   #
1518   check-screen-row screen,                                  0/y, "1 line 1   ", "F - test-trace-preserve-cursor-on-refresh/expand-0"
1519   check-background-color-in-screen-row screen, 7/bg=cursor, 0/y, "||||||||   ", "F - test-trace-preserve-cursor-on-refresh/expand-0/cursor"
1520   check-screen-row screen,                                  1/y, "1 line 2   ", "F - test-trace-preserve-cursor-on-refresh/expand-1"
1521   check-background-color-in-screen-row screen, 7/bg=cursor, 1/y, "           ", "F - test-trace-preserve-cursor-on-refresh/expand-1/cursor"
1522   check-screen-row screen,                                  2/y, "1 line 3   ", "F - test-trace-preserve-cursor-on-refresh/expand-2"
1523   check-background-color-in-screen-row screen, 7/bg=cursor, 2/y, "              ", "F - test-trace-preserve-cursor-on-refresh/expand-2/cursor"
1524   # cursor down
1525   edit-trace t, 0x6a/j
1526   edit-trace t, 0x6a/j
1527   var y/ecx: int <- render-trace screen, t, 0/xmin, 0/ymin, 0x10/xmax, 4/ymax, 1/show-cursor
1528   #
1529   check-screen-row screen,                                  0/y, "1 line 1   ", "F - test-trace-preserve-cursor-on-refresh/down-0"
1530   check-background-color-in-screen-row screen, 7/bg=cursor, 0/y, "           ", "F - test-trace-preserve-cursor-on-refresh/down-0/cursor"
1531   check-screen-row screen,                                  1/y, "1 line 2   ", "F - test-trace-preserve-cursor-on-refresh/down-1"
1532   check-background-color-in-screen-row screen, 7/bg=cursor, 1/y, "           ", "F - test-trace-preserve-cursor-on-refresh/down-1/cursor"
1533   check-screen-row screen,                                  2/y, "1 line 3   ", "F - test-trace-preserve-cursor-on-refresh/down-2"
1534   check-background-color-in-screen-row screen, 7/bg=cursor, 2/y, "||||||||   ", "F - test-trace-preserve-cursor-on-refresh/down-2/cursor"
1535   # recreate trace with slightly different lines
1536   clear-trace t
1537   trace-text t, "l", "line 4"
1538   trace-text t, "l", "line 5"
1539   trace-text t, "l", "line 3"  # cursor line is unchanged
1540   var y/ecx: int <- render-trace screen, t, 0/xmin, 0/ymin, 0x10/xmax, 4/ymax, 1/show-cursor
1541   # cursor remains unchanged
1542   check-screen-row screen,                                  0/y, "1 line 4   ", "F - test-trace-preserve-cursor-on-refresh/refresh-0"
1543   check-background-color-in-screen-row screen, 7/bg=cursor, 0/y, "           ", "F - test-trace-preserve-cursor-on-refresh/refresh-0/cursor"
1544   check-screen-row screen,                                  1/y, "1 line 5   ", "F - test-trace-preserve-cursor-on-refresh/refresh-1"
1545   check-background-color-in-screen-row screen, 7/bg=cursor, 1/y, "           ", "F - test-trace-preserve-cursor-on-refresh/refresh-1/cursor"
1546   check-screen-row screen,                                  2/y, "1 line 3   ", "F - test-trace-preserve-cursor-on-refresh/refresh-2"
1547   check-background-color-in-screen-row screen, 7/bg=cursor, 2/y, "||||||||   ", "F - test-trace-preserve-cursor-on-refresh/refresh-2/cursor"
1550 fn test-trace-keep-cursor-visible-on-refresh {
1551   var t-storage: trace
1552   var t/esi: (addr trace) <- address t-storage
1553   initialize-trace t, 0x100/max-depth, 0x10, 0x10
1554   #
1555   trace-text t, "l", "line 1"
1556   trace-text t, "l", "line 2"
1557   trace-text t, "l", "line 3"
1558   # setup: screen
1559   var screen-on-stack: screen
1560   var screen/edi: (addr screen) <- address screen-on-stack
1561   initialize-screen screen, 0x10/width, 4/height, 0/no-pixel-graphics
1562   #
1563   var y/ecx: int <- render-trace screen, t, 0/xmin, 0/ymin, 0x10/xmax, 4/ymax, 1/show-cursor
1564   #
1565   check-screen-row screen,                                  0/y, "...        ", "F - test-trace-keep-cursor-visible-on-refresh/pre-0"
1566   check-background-color-in-screen-row screen, 7/bg=cursor, 0/y, "|||        ", "F - test-trace-keep-cursor-visible-on-refresh/pre-0/cursor"
1567   check-screen-row screen,                                  1/y, "           ", "F - test-trace-keep-cursor-visible-on-refresh/pre-1"
1568   check-background-color-in-screen-row screen, 7/bg=cursor, 1/y, "           ", "F - test-trace-keep-cursor-visible-on-refresh/pre-1/cursor"
1569   # expand
1570   edit-trace t, 0xa/enter
1571   var y/ecx: int <- render-trace screen, t, 0/xmin, 0/ymin, 0x10/xmax, 4/ymax, 1/show-cursor
1572   #
1573   check-screen-row screen,                                  0/y, "1 line 1   ", "F - test-trace-keep-cursor-visible-on-refresh/expand-0"
1574   check-background-color-in-screen-row screen, 7/bg=cursor, 0/y, "||||||||   ", "F - test-trace-keep-cursor-visible-on-refresh/expand-0/cursor"
1575   check-screen-row screen,                                  1/y, "1 line 2   ", "F - test-trace-keep-cursor-visible-on-refresh/expand-1"
1576   check-background-color-in-screen-row screen, 7/bg=cursor, 1/y, "           ", "F - test-trace-keep-cursor-visible-on-refresh/expand-1/cursor"
1577   check-screen-row screen,                                  2/y, "1 line 3   ", "F - test-trace-keep-cursor-visible-on-refresh/expand-2"
1578   check-background-color-in-screen-row screen, 7/bg=cursor, 2/y, "              ", "F - test-trace-keep-cursor-visible-on-refresh/expand-2/cursor"
1579   # cursor down
1580   edit-trace t, 0x6a/j
1581   edit-trace t, 0x6a/j
1582   var y/ecx: int <- render-trace screen, t, 0/xmin, 0/ymin, 0x10/xmax, 4/ymax, 1/show-cursor
1583   #
1584   check-screen-row screen,                                  0/y, "1 line 1   ", "F - test-trace-keep-cursor-visible-on-refresh/down-0"
1585   check-background-color-in-screen-row screen, 7/bg=cursor, 0/y, "           ", "F - test-trace-keep-cursor-visible-on-refresh/down-0/cursor"
1586   check-screen-row screen,                                  1/y, "1 line 2   ", "F - test-trace-keep-cursor-visible-on-refresh/down-1"
1587   check-background-color-in-screen-row screen, 7/bg=cursor, 1/y, "           ", "F - test-trace-keep-cursor-visible-on-refresh/down-1/cursor"
1588   check-screen-row screen,                                  2/y, "1 line 3   ", "F - test-trace-keep-cursor-visible-on-refresh/down-2"
1589   check-background-color-in-screen-row screen, 7/bg=cursor, 2/y, "||||||||   ", "F - test-trace-keep-cursor-visible-on-refresh/down-2/cursor"
1590   # recreate trace with entirely different lines
1591   clear-trace t
1592   trace-text t, "l", "line 4"
1593   trace-text t, "l", "line 5"
1594   trace-text t, "l", "line 6"
1595   mark-lines-dirty t
1596   clear-screen screen
1597   var y/ecx: int <- render-trace screen, t, 0/xmin, 0/ymin, 0x10/xmax, 4/ymax, 1/show-cursor
1598   # trace collapses, and cursor bumps up
1599   check-screen-row screen,                                  0/y, "...        ", "F - test-trace-keep-cursor-visible-on-refresh/refresh-0"
1600   check-background-color-in-screen-row screen, 7/bg=cursor, 0/y, "|||        ", "F - test-trace-keep-cursor-visible-on-refresh/refresh-0/cursor"
1601   check-screen-row screen,                                  1/y, "           ", "F - test-trace-keep-cursor-visible-on-refresh/refresh-1"
1602   check-background-color-in-screen-row screen, 7/bg=cursor, 1/y, "           ", "F - test-trace-keep-cursor-visible-on-refresh/refresh-1/cursor"
1603   check-screen-row screen,                                  2/y, "           ", "F - test-trace-keep-cursor-visible-on-refresh/refresh-2"
1604   check-background-color-in-screen-row screen, 7/bg=cursor, 2/y, "           ", "F - test-trace-keep-cursor-visible-on-refresh/refresh-2/cursor"
1607 fn test-trace-collapse-at-top {
1608   var t-storage: trace
1609   var t/esi: (addr trace) <- address t-storage
1610   initialize-trace t, 0x100/max-depth, 0x10, 0x10
1611   #
1612   trace-text t, "l", "line 1"
1613   trace-lower t
1614   trace-text t, "l", "line 1.1"
1615   trace-higher t
1616   trace-text t, "l", "line 2"
1617   # setup: screen
1618   var screen-on-stack: screen
1619   var screen/edi: (addr screen) <- address screen-on-stack
1620   initialize-screen screen, 0x10/width, 4/height, 0/no-pixel-graphics
1621   #
1622   var y/ecx: int <- render-trace screen, t, 0/xmin, 0/ymin, 0x10/xmax, 4/ymax, 1/show-cursor
1623   #
1624   check-screen-row screen,                                  0/y, "...        ", "F - test-trace-collapse-at-top/pre-0"
1625   check-background-color-in-screen-row screen, 7/bg=cursor, 0/y, "|||        ", "F - test-trace-collapse-at-top/pre-0/cursor"
1626   check-screen-row screen,                                  1/y, "           ", "F - test-trace-collapse-at-top/pre-1"
1627   check-background-color-in-screen-row screen, 7/bg=cursor, 1/y, "           ", "F - test-trace-collapse-at-top/pre-1/cursor"
1628   # expand
1629   edit-trace t, 0xa/enter
1630   var y/ecx: int <- render-trace screen, t, 0/xmin, 0/ymin, 0x10/xmax, 4/ymax, 1/show-cursor
1631   #
1632   check-screen-row screen,                                  0/y, "1 line 1   ", "F - test-trace-collapse-at-top/expand-0"
1633   check-background-color-in-screen-row screen, 7/bg=cursor, 0/y, "||||||||   ", "F - test-trace-collapse-at-top/expand-0/cursor"
1634   check-screen-row screen,                                  1/y, "...        ", "F - test-trace-collapse-at-top/expand-1"
1635   check-background-color-in-screen-row screen, 7/bg=cursor, 1/y, "           ", "F - test-trace-collapse-at-top/expand-1/cursor"
1636   check-screen-row screen,                                  2/y, "1 line 2   ", "F - test-trace-collapse-at-top/expand-2"
1637   check-background-color-in-screen-row screen, 7/bg=cursor, 2/y, "           ", "F - test-trace-collapse-at-top/expand-2/cursor"
1638   # collapse
1639   edit-trace t, 8/backspace
1640   # hack: we need to render here to make this test pass; we're mixing state management with rendering
1641   clear-screen screen
1642   var y/ecx: int <- render-trace screen, t, 0/xmin, 0/ymin, 0x10/xmax, 4/ymax, 1/show-cursor
1643   #
1644   check-ints-equal y, 1, "F - test-trace-collapse-at-top/post-0/y"
1645   check-screen-row screen,                                  0/y, "...        ", "F - test-trace-collapse-at-top/post-0"
1646   check-background-color-in-screen-row screen, 7/bg=cursor, 0/y, "|||        ", "F - test-trace-collapse-at-top/post-0/cursor"
1647   check-screen-row screen,                                  1/y, "           ", "F - test-trace-collapse-at-top/post-1"
1648   check-background-color-in-screen-row screen, 7/bg=cursor, 1/y, "           ", "F - test-trace-collapse-at-top/post-1/cursor"
1651 fn test-trace-collapse {
1652   var t-storage: trace
1653   var t/esi: (addr trace) <- address t-storage
1654   initialize-trace t, 0x100/max-depth, 0x10, 0x10
1655   #
1656   trace-text t, "l", "line 1"
1657   trace-text t, "l", "line 2"
1658   # setup: screen
1659   var screen-on-stack: screen
1660   var screen/edi: (addr screen) <- address screen-on-stack
1661   initialize-screen screen, 0x10/width, 4/height, 0/no-pixel-graphics
1662   #
1663   var y/ecx: int <- render-trace screen, t, 0/xmin, 0/ymin, 0x10/xmax, 4/ymax, 1/show-cursor
1664   #
1665   check-screen-row screen,                                  0/y, "...        ", "F - test-trace-collapse/pre-0"
1666   check-background-color-in-screen-row screen, 7/bg=cursor, 0/y, "|||        ", "F - test-trace-collapse/pre-0/cursor"
1667   check-screen-row screen,                                  1/y, "           ", "F - test-trace-collapse/pre-1"
1668   check-background-color-in-screen-row screen, 7/bg=cursor, 1/y, "           ", "F - test-trace-collapse/pre-1/cursor"
1669   # expand
1670   edit-trace t, 0xa/enter
1671   var y/ecx: int <- render-trace screen, t, 0/xmin, 0/ymin, 0x10/xmax, 4/ymax, 1/show-cursor
1672   #
1673   check-screen-row screen,                                  0/y, "1 line 1   ", "F - test-trace-collapse/expand-0"
1674   check-background-color-in-screen-row screen, 7/bg=cursor, 0/y, "||||||||   ", "F - test-trace-collapse/expand-0/cursor"
1675   check-screen-row screen,                                  1/y, "1 line 2   ", "F - test-trace-collapse/expand-1"
1676   check-background-color-in-screen-row screen, 7/bg=cursor, 1/y, "           ", "F - test-trace-collapse/expand-1/cursor"
1677   # cursor down
1678   edit-trace t, 0x6a/j
1679   var y/ecx: int <- render-trace screen, t, 0/xmin, 0/ymin, 0x10/xmax, 4/ymax, 1/show-cursor
1680   # collapse
1681   edit-trace t, 8/backspace
1682   clear-screen screen
1683   var y/ecx: int <- render-trace screen, t, 0/xmin, 0/ymin, 0x10/xmax, 4/ymax, 1/show-cursor
1684   #
1685   check-ints-equal y, 1, "F - test-trace-collapse/post-0/y"
1686   check-screen-row screen,                                  0/y, "...        ", "F - test-trace-collapse/post-0"
1687   check-background-color-in-screen-row screen, 7/bg=cursor, 0/y, "|||        ", "F - test-trace-collapse/post-0/cursor"
1688   check-screen-row screen,                                  1/y, "           ", "F - test-trace-collapse/post-1"
1689   check-background-color-in-screen-row screen, 7/bg=cursor, 1/y, "           ", "F - test-trace-collapse/post-1/cursor"
1692 fn test-trace-collapse-skips-invisible-lines {
1693   var t-storage: trace
1694   var t/esi: (addr trace) <- address t-storage
1695   initialize-trace t, 0x100/max-depth, 0x10, 0x10
1696   #
1697   trace-text t, "l", "line 1"
1698   trace-lower t
1699   trace-text t, "l", "line 1.1"
1700   trace-higher t
1701   trace-text t, "l", "line 2"
1702   # setup: screen
1703   var screen-on-stack: screen
1704   var screen/edi: (addr screen) <- address screen-on-stack
1705   initialize-screen screen, 0x10/width, 4/height, 0/no-pixel-graphics
1706   #
1707   var y/ecx: int <- render-trace screen, t, 0/xmin, 0/ymin, 0x10/xmax, 4/ymax, 1/show-cursor
1708   #
1709   check-screen-row screen,                                  0/y, "...        ", "F - test-trace-collapse-skips-invisible-lines/pre-0"
1710   check-background-color-in-screen-row screen, 7/bg=cursor, 0/y, "|||        ", "F - test-trace-collapse-skips-invisible-lines/pre-0/cursor"
1711   check-screen-row screen,                                  1/y, "           ", "F - test-trace-collapse-skips-invisible-lines/pre-1"
1712   check-background-color-in-screen-row screen, 7/bg=cursor, 1/y, "           ", "F - test-trace-collapse-skips-invisible-lines/pre-1/cursor"
1713   # expand
1714   edit-trace t, 0xa/enter
1715   var y/ecx: int <- render-trace screen, t, 0/xmin, 0/ymin, 0x10/xmax, 4/ymax, 1/show-cursor
1716   # two visible lines with an invisible line in between
1717   check-screen-row screen,                                  0/y, "1 line 1   ", "F - test-trace-collapse-skips-invisible-lines/expand-0"
1718   check-background-color-in-screen-row screen, 7/bg=cursor, 0/y, "||||||||   ", "F - test-trace-collapse-skips-invisible-lines/expand-0/cursor"
1719   check-screen-row screen,                                  1/y, "...        ", "F - test-trace-collapse-skips-invisible-lines/expand-1"
1720   check-background-color-in-screen-row screen, 7/bg=cursor, 1/y, "           ", "F - test-trace-collapse-skips-invisible-lines/expand-1/cursor"
1721   check-screen-row screen,                                  2/y, "1 line 2   ", "F - test-trace-collapse-skips-invisible-lines/expand-2"
1722   check-background-color-in-screen-row screen, 7/bg=cursor, 2/y, "           ", "F - test-trace-collapse-skips-invisible-lines/expand-2/cursor"
1723   # cursor down to second visible line
1724   edit-trace t, 0x6a/j
1725   var y/ecx: int <- render-trace screen, t, 0/xmin, 0/ymin, 0x10/xmax, 4/ymax, 1/show-cursor
1726   edit-trace t, 0x6a/j
1727   var y/ecx: int <- render-trace screen, t, 0/xmin, 0/ymin, 0x10/xmax, 4/ymax, 1/show-cursor
1728   # collapse
1729   edit-trace t, 8/backspace
1730   clear-screen screen
1731   var y/ecx: int <- render-trace screen, t, 0/xmin, 0/ymin, 0x10/xmax, 4/ymax, 1/show-cursor
1732   #
1733   check-ints-equal y, 1, "F - test-trace-collapse-skips-invisible-lines/post-0/y"
1734   var cursor-y/eax: (addr int) <- get t, cursor-y
1735   check-ints-equal *cursor-y, 0, "F - test-trace-collapse-skips-invisible-lines/post-0/cursor-y"
1736   check-screen-row screen,                                  0/y, "...        ", "F - test-trace-collapse-skips-invisible-lines/post-0"
1737   check-background-color-in-screen-row screen, 7/bg=cursor, 0/y, "|||        ", "F - test-trace-collapse-skips-invisible-lines/post-0/cursor"
1738   check-screen-row screen,                                  1/y, "           ", "F - test-trace-collapse-skips-invisible-lines/post-1"
1739   check-background-color-in-screen-row screen, 7/bg=cursor, 1/y, "           ", "F - test-trace-collapse-skips-invisible-lines/post-1/cursor"
1742 fn test-trace-collapse-two-levels {
1743   var t-storage: trace
1744   var t/esi: (addr trace) <- address t-storage
1745   initialize-trace t, 0x100/max-depth, 0x10, 0x10
1746   #
1747   trace-text t, "l", "line 1"
1748   trace-lower t
1749   trace-text t, "l", "line 1.1"
1750   trace-higher t
1751   trace-text t, "l", "line 2"
1752   # setup: screen
1753   var screen-on-stack: screen
1754   var screen/edi: (addr screen) <- address screen-on-stack
1755   initialize-screen screen, 0x10/width, 4/height, 0/no-pixel-graphics
1756   #
1757   var y/ecx: int <- render-trace screen, t, 0/xmin, 0/ymin, 0x10/xmax, 4/ymax, 1/show-cursor
1758   #
1759   check-screen-row screen,                                  0/y, "...        ", "F - test-trace-collapse-two-levels/pre-0"
1760   check-background-color-in-screen-row screen, 7/bg=cursor, 0/y, "|||        ", "F - test-trace-collapse-two-levels/pre-0/cursor"
1761   check-screen-row screen,                                  1/y, "           ", "F - test-trace-collapse-two-levels/pre-1"
1762   check-background-color-in-screen-row screen, 7/bg=cursor, 1/y, "           ", "F - test-trace-collapse-two-levels/pre-1/cursor"
1763   # expand
1764   edit-trace t, 0xa/enter
1765   var y/ecx: int <- render-trace screen, t, 0/xmin, 0/ymin, 0x10/xmax, 4/ymax, 1/show-cursor
1766   # two visible lines with an invisible line in between
1767   check-screen-row screen,                                  0/y, "1 line 1   ", "F - test-trace-collapse-two-levels/expand-0"
1768   check-background-color-in-screen-row screen, 7/bg=cursor, 0/y, "||||||||   ", "F - test-trace-collapse-two-levels/expand-0/cursor"
1769   check-screen-row screen,                                  1/y, "...        ", "F - test-trace-collapse-two-levels/expand-1"
1770   check-background-color-in-screen-row screen, 7/bg=cursor, 1/y, "           ", "F - test-trace-collapse-two-levels/expand-1/cursor"
1771   check-screen-row screen,                                  2/y, "1 line 2   ", "F - test-trace-collapse-two-levels/expand-2"
1772   check-background-color-in-screen-row screen, 7/bg=cursor, 2/y, "           ", "F - test-trace-collapse-two-levels/expand-2/cursor"
1773   # cursor down to ellipses
1774   edit-trace t, 0x6a/j
1775   var y/ecx: int <- render-trace screen, t, 0/xmin, 0/ymin, 0x10/xmax, 4/ymax, 1/show-cursor
1776   # expand
1777   edit-trace t, 0xa/enter
1778   var y/ecx: int <- render-trace screen, t, 0/xmin, 0/ymin, 0x10/xmax, 4/ymax, 1/show-cursor
1779   # two visible lines with an invisible line in between
1780   check-screen-row screen,                                  0/y, "1 line 1   ", "F - test-trace-collapse-two-levels/expand2-0"
1781   check-background-color-in-screen-row screen, 7/bg=cursor, 0/y, "           ", "F - test-trace-collapse-two-levels/expand2-0/cursor"
1782   check-screen-row screen,                                  1/y, "2 line 1.1 ", "F - test-trace-collapse-two-levels/expand2-1"
1783   check-background-color-in-screen-row screen, 7/bg=cursor, 1/y, "|||||||||| ", "F - test-trace-collapse-two-levels/expand2-1/cursor"
1784   check-screen-row screen,                                  2/y, "1 line 2   ", "F - test-trace-collapse-two-levels/expand2-2"
1785   check-background-color-in-screen-row screen, 7/bg=cursor, 2/y, "           ", "F - test-trace-collapse-two-levels/expand2-2/cursor"
1786   # cursor down to second visible line
1787   edit-trace t, 0x6a/j
1788   var y/ecx: int <- render-trace screen, t, 0/xmin, 0/ymin, 0x10/xmax, 4/ymax, 1/show-cursor
1789   # collapse
1790   edit-trace t, 8/backspace
1791   clear-screen screen
1792   var y/ecx: int <- render-trace screen, t, 0/xmin, 0/ymin, 0x10/xmax, 4/ymax, 1/show-cursor
1793   #
1794   check-ints-equal y, 1, "F - test-trace-collapse-two-levels/post-0/y"
1795   var cursor-y/eax: (addr int) <- get t, cursor-y
1796   check-ints-equal *cursor-y, 0, "F - test-trace-collapse-two-levels/post-0/cursor-y"
1797   check-screen-row screen,                                  0/y, "...        ", "F - test-trace-collapse-two-levels/post-0"
1798   check-background-color-in-screen-row screen, 7/bg=cursor, 0/y, "|||        ", "F - test-trace-collapse-two-levels/post-0/cursor"
1799   check-screen-row screen,                                  1/y, "           ", "F - test-trace-collapse-two-levels/post-1"
1800   check-background-color-in-screen-row screen, 7/bg=cursor, 1/y, "           ", "F - test-trace-collapse-two-levels/post-1/cursor"
1803 fn test-trace-collapse-nested-level {
1804   var t-storage: trace
1805   var t/esi: (addr trace) <- address t-storage
1806   initialize-trace t, 0x100/max-depth, 0x10, 0x10
1807   #
1808   trace-text t, "l", "line 1"
1809   trace-lower t
1810   trace-text t, "l", "line 1.1"
1811   trace-higher t
1812   trace-text t, "l", "line 2"
1813   trace-lower t
1814   trace-text t, "l", "line 2.1"
1815   trace-text t, "l", "line 2.2"
1816   trace-higher t
1817   # setup: screen
1818   var screen-on-stack: screen
1819   var screen/edi: (addr screen) <- address screen-on-stack
1820   initialize-screen screen, 0x10/width, 8/height, 0/no-pixel-graphics
1821   #
1822   var y/ecx: int <- render-trace screen, t, 0/xmin, 0/ymin, 0x10/xmax, 8/ymax, 1/show-cursor
1823   #
1824   check-screen-row screen,                                  0/y, "...        ", "F - test-trace-collapse-nested-level/pre-0"
1825   check-background-color-in-screen-row screen, 7/bg=cursor, 0/y, "|||        ", "F - test-trace-collapse-nested-level/pre-0/cursor"
1826   check-screen-row screen,                                  1/y, "           ", "F - test-trace-collapse-nested-level/pre-1"
1827   check-background-color-in-screen-row screen, 7/bg=cursor, 1/y, "           ", "F - test-trace-collapse-nested-level/pre-1/cursor"
1828   # expand
1829   edit-trace t, 0xa/enter
1830   var y/ecx: int <- render-trace screen, t, 0/xmin, 0/ymin, 0x10/xmax, 8/ymax, 1/show-cursor
1831   # two visible lines with an invisible line in between
1832   check-screen-row screen,                                  0/y, "1 line 1   ", "F - test-trace-collapse-nested-level/expand-0"
1833   check-background-color-in-screen-row screen, 7/bg=cursor, 0/y, "||||||||   ", "F - test-trace-collapse-nested-level/expand-0/cursor"
1834   check-screen-row screen,                                  1/y, "...        ", "F - test-trace-collapse-nested-level/expand-1"
1835   check-background-color-in-screen-row screen, 7/bg=cursor, 1/y, "           ", "F - test-trace-collapse-nested-level/expand-1/cursor"
1836   check-screen-row screen,                                  2/y, "1 line 2   ", "F - test-trace-collapse-nested-level/expand-2"
1837   check-background-color-in-screen-row screen, 7/bg=cursor, 2/y, "           ", "F - test-trace-collapse-nested-level/expand-2/cursor"
1838   check-screen-row screen,                                  3/y, "...        ", "F - test-trace-collapse-nested-level/expand-3"
1839   check-background-color-in-screen-row screen, 7/bg=cursor, 3/y, "           ", "F - test-trace-collapse-nested-level/expand-3/cursor"
1840   # cursor down to bottom
1841   edit-trace t, 0x6a/j
1842   var y/ecx: int <- render-trace screen, t, 0/xmin, 0/ymin, 0x10/xmax, 8/ymax, 1/show-cursor
1843   edit-trace t, 0x6a/j
1844   var y/ecx: int <- render-trace screen, t, 0/xmin, 0/ymin, 0x10/xmax, 8/ymax, 1/show-cursor
1845   edit-trace t, 0x6a/j
1846   var y/ecx: int <- render-trace screen, t, 0/xmin, 0/ymin, 0x10/xmax, 8/ymax, 1/show-cursor
1847   # expand
1848   edit-trace t, 0xa/enter
1849   var y/ecx: int <- render-trace screen, t, 0/xmin, 0/ymin, 0x10/xmax, 8/ymax, 1/show-cursor
1850   # two visible lines with an invisible line in between
1851   check-screen-row screen,                                  0/y, "1 line 1   ", "F - test-trace-collapse-nested-level/expand2-0"
1852   check-background-color-in-screen-row screen, 7/bg=cursor, 0/y, "           ", "F - test-trace-collapse-nested-level/expand2-0/cursor"
1853   check-screen-row screen,                                  1/y, "...        ", "F - test-trace-collapse-nested-level/expand2-1"
1854   check-background-color-in-screen-row screen, 7/bg=cursor, 1/y, "           ", "F - test-trace-collapse-nested-level/expand2-1/cursor"
1855   check-screen-row screen,                                  2/y, "1 line 2   ", "F - test-trace-collapse-nested-level/expand2-2"
1856   check-background-color-in-screen-row screen, 7/bg=cursor, 2/y, "           ", "F - test-trace-collapse-nested-level/expand2-2/cursor"
1857   check-screen-row screen,                                  3/y, "2 line 2.1 ", "F - test-trace-collapse-nested-level/expand2-3"
1858   check-background-color-in-screen-row screen, 7/bg=cursor, 3/y, "|||||||||| ", "F - test-trace-collapse-nested-level/expand2-3/cursor"
1859   check-screen-row screen,                                  4/y, "2 line 2.2 ", "F - test-trace-collapse-nested-level/expand2-4"
1860   check-background-color-in-screen-row screen, 7/bg=cursor, 4/y, "           ", "F - test-trace-collapse-nested-level/expand2-4/cursor"
1861   # collapse
1862   edit-trace t, 8/backspace
1863   clear-screen screen
1864   var y/ecx: int <- render-trace screen, t, 0/xmin, 0/ymin, 0x10/xmax, 8/ymax, 1/show-cursor
1865   #
1866   check-ints-equal y, 4, "F - test-trace-collapse-nested-level/post-0/y"
1867   var cursor-y/eax: (addr int) <- get t, cursor-y
1868   check-ints-equal *cursor-y, 2, "F - test-trace-collapse-nested-level/post-0/cursor-y"
1869   check-screen-row screen,                                  0/y, "1 line 1   ", "F - test-trace-collapse-nested-level/post-0"
1870   check-background-color-in-screen-row screen, 7/bg=cursor, 0/y, "           ", "F - test-trace-collapse-nested-level/post-0/cursor"
1871   check-screen-row screen,                                  1/y, "...        ", "F - test-trace-collapse-nested-level/post-1"
1872   check-background-color-in-screen-row screen, 7/bg=cursor, 1/y, "           ", "F - test-trace-collapse-nested-level/post-1/cursor"
1873   check-screen-row screen,                                  2/y, "1 line 2   ", "F - test-trace-collapse-nested-level/post-2"
1874   check-background-color-in-screen-row screen, 7/bg=cursor, 2/y, "||||||||   ", "F - test-trace-collapse-nested-level/post-2/cursor"
1875   check-screen-row screen,                                  3/y, "...        ", "F - test-trace-collapse-nested-level/post-3"
1876   check-background-color-in-screen-row screen, 7/bg=cursor, 3/y, "           ", "F - test-trace-collapse-nested-level/post-3/cursor"
1879 fn scroll-down _self: (addr trace) {
1880   var self/esi: (addr trace) <- copy _self
1881   var screen-height-addr/ebx: (addr int) <- get self, screen-height  # only available after first render
1882   var lines-to-skip/ebx: int <- copy *screen-height-addr
1883   var top-line-y-addr/eax: (addr int) <- get self, top-line-y
1884   lines-to-skip <- subtract *top-line-y-addr
1885   var already-hiding-lines-storage: boolean
1886   var already-hiding-lines/edx: (addr boolean) <- address already-hiding-lines-storage
1887   var top-line-addr/edi: (addr int) <- get self, top-line-index
1888   var i/eax: int <- copy *top-line-addr
1889   var max-addr/ecx: (addr int) <- get self, first-free
1890   {
1891     # if we run out of trace, return without changing anything
1892     compare i, *max-addr
1893     {
1894       break-if-<
1895       return
1896     }
1897     # if we've skipped enough, break
1898     compare lines-to-skip, 0
1899     break-if-<=
1900     #
1901     {
1902       var display?/eax: boolean <- count-line? self, i, already-hiding-lines
1903       compare display?, 0/false
1904       break-if-=
1905       lines-to-skip <- decrement
1906     }
1907     i <- increment
1908     loop
1909   }
1910   # update top-line
1911   copy-to *top-line-addr, i
1914 fn scroll-up _self: (addr trace) {
1915   var self/esi: (addr trace) <- copy _self
1916   var screen-height-addr/ebx: (addr int) <- get self, screen-height  # only available after first render
1917   var lines-to-skip/ebx: int <- copy *screen-height-addr
1918   var top-line-y-addr/eax: (addr int) <- get self, top-line-y
1919   lines-to-skip <- subtract *top-line-y-addr
1920   var already-hiding-lines-storage: boolean
1921   var already-hiding-lines/edx: (addr boolean) <- address already-hiding-lines-storage
1922   var top-line-addr/ecx: (addr int) <- get self, top-line-index
1923   $scroll-up:loop: {
1924     # if we run out of trace, break
1925     compare *top-line-addr, 0
1926     break-if-<=
1927     # if we've skipped enough, break
1928     compare lines-to-skip, 0
1929     break-if-<=
1930     #
1931     var display?/eax: boolean <- count-line? self, *top-line-addr, already-hiding-lines
1932     compare display?, 0/false
1933     {
1934       break-if-=
1935       lines-to-skip <- decrement
1936     }
1937     decrement *top-line-addr
1938     loop
1939   }
1942 # TODO: duplicates logic for counting lines rendered
1943 fn count-line? _self: (addr trace), index: int, _already-hiding-lines?: (addr boolean) -> _/eax: boolean {
1944   var self/esi: (addr trace) <- copy _self
1945   var trace-ah/eax: (addr handle array trace-line) <- get self, data
1946   var trace/eax: (addr array trace-line) <- lookup *trace-ah
1947   var offset/ecx: (offset trace-line) <- compute-offset trace, index
1948   var curr/eax: (addr trace-line) <- index trace, offset
1949   var already-hiding-lines?/ecx: (addr boolean) <- copy _already-hiding-lines?
1950   # count errors
1951   {
1952     var curr-depth/eax: (addr int) <- get curr, depth
1953     compare *curr-depth, 0/error
1954     break-if-!=
1955     copy-to *already-hiding-lines?, 0/false
1956     return 1/true
1957   }
1958   # count visible lines
1959   {
1960     var display?/eax: boolean <- should-render? curr
1961     compare display?, 0/false
1962     break-if-=
1963     copy-to *already-hiding-lines?, 0/false
1964     return 1/true
1965   }
1966   # count first undisplayed line after line to display
1967   compare *already-hiding-lines?, 0/false
1968   {
1969     break-if-!=
1970     copy-to *already-hiding-lines?, 1/true
1971     return 1/true
1972   }
1973   return 0/false
1976 fn test-trace-scroll {
1977   var t-storage: trace
1978   var t/esi: (addr trace) <- address t-storage
1979   initialize-trace t, 0x100/max-depth, 0x10, 0x10
1980   #
1981   trace-text t, "l", "line 0"
1982   trace-text t, "l", "line 1"
1983   trace-text t, "l", "line 2"
1984   trace-text t, "l", "line 3"
1985   trace-text t, "l", "line 4"
1986   trace-text t, "l", "line 5"
1987   trace-text t, "l", "line 6"
1988   trace-text t, "l", "line 7"
1989   trace-text t, "l", "line 8"
1990   trace-text t, "l", "line 9"
1991   # setup: screen
1992   var screen-on-stack: screen
1993   var screen/edi: (addr screen) <- address screen-on-stack
1994   initialize-screen screen, 0x10/width, 4/height, 0/no-pixel-graphics
1995   # pre-render
1996   var y/ecx: int <- render-trace screen, t, 0/xmin, 0/ymin, 0x10/xmax, 4/ymax, 1/show-cursor
1997   #
1998   check-screen-row screen,                                  0/y, "...        ", "F - test-trace-scroll/pre-0"
1999   check-background-color-in-screen-row screen, 7/bg=cursor, 0/y, "|||        ", "F - test-trace-scroll/pre-0/cursor"
2000   check-screen-row screen,                                  1/y, "           ", "F - test-trace-scroll/pre-1"
2001   check-background-color-in-screen-row screen, 7/bg=cursor, 1/y, "           ", "F - test-trace-scroll/pre-1/cursor"
2002   check-screen-row screen,                                  2/y, "           ", "F - test-trace-scroll/pre-2"
2003   check-background-color-in-screen-row screen, 7/bg=cursor, 2/y, "           ", "F - test-trace-scroll/pre-2/cursor"
2004   check-screen-row screen,                                  3/y, "           ", "F - test-trace-scroll/pre-3"
2005   check-background-color-in-screen-row screen, 7/bg=cursor, 3/y, "           ", "F - test-trace-scroll/pre-3/cursor"
2006   # expand
2007   edit-trace t, 0xa/enter
2008   clear-screen screen
2009   var y/ecx: int <- render-trace screen, t, 0/xmin, 0/ymin, 0x10/xmax, 4/ymax, 1/show-cursor
2010   #
2011   check-screen-row screen,                                  0/y, "1 line 0   ", "F - test-trace-scroll/expand-0"
2012   check-background-color-in-screen-row screen, 7/bg=cursor, 0/y, "||||||||   ", "F - test-trace-scroll/expand-0/cursor"
2013   check-screen-row screen,                                  1/y, "1 line 1   ", "F - test-trace-scroll/expand-1"
2014   check-background-color-in-screen-row screen, 7/bg=cursor, 1/y, "           ", "F - test-trace-scroll/expand-1/cursor"
2015   check-screen-row screen,                                  2/y, "1 line 2   ", "F - test-trace-scroll/expand-2"
2016   check-background-color-in-screen-row screen, 7/bg=cursor, 2/y, "           ", "F - test-trace-scroll/expand-2/cursor"
2017   check-screen-row screen,                                  3/y, "1 line 3   ", "F - test-trace-scroll/expand-3"
2018   check-background-color-in-screen-row screen, 7/bg=cursor, 3/y, "           ", "F - test-trace-scroll/expand-3/cursor"
2019   # scroll up
2020   # hack: we must have rendered before this point; we're mixing state management with rendering
2021   edit-trace t, 2/ctrl-b
2022   clear-screen screen
2023   var y/ecx: int <- render-trace screen, t, 0/xmin, 0/ymin, 0x10/xmax, 4/ymax, 1/show-cursor
2024   # no change since we're already at the top
2025   check-screen-row screen,                                  0/y, "1 line 0   ", "F - test-trace-scroll/up0-0"
2026   check-background-color-in-screen-row screen, 7/bg=cursor, 0/y, "||||||||   ", "F - test-trace-scroll/up0-0/cursor"
2027   check-screen-row screen,                                  1/y, "1 line 1   ", "F - test-trace-scroll/up0-1"
2028   check-background-color-in-screen-row screen, 7/bg=cursor, 1/y, "           ", "F - test-trace-scroll/up0-1/cursor"
2029   check-screen-row screen,                                  2/y, "1 line 2   ", "F - test-trace-scroll/up0-2"
2030   check-background-color-in-screen-row screen, 7/bg=cursor, 2/y, "           ", "F - test-trace-scroll/up0-2/cursor"
2031   check-screen-row screen,                                  3/y, "1 line 3   ", "F - test-trace-scroll/up0-3"
2032   check-background-color-in-screen-row screen, 7/bg=cursor, 3/y, "           ", "F - test-trace-scroll/up0-3/cursor"
2033   # scroll down
2034   edit-trace t, 6/ctrl-f
2035   clear-screen screen
2036   var y/ecx: int <- render-trace screen, t, 0/xmin, 0/ymin, 0x10/xmax, 4/ymax, 1/show-cursor
2037   check-screen-row screen,                                  0/y, "1 line 4   ", "F - test-trace-scroll/down1-0"
2038   check-background-color-in-screen-row screen, 7/bg=cursor, 0/y, "||||||||   ", "F - test-trace-scroll/down1-0/cursor"
2039   check-screen-row screen,                                  1/y, "1 line 5   ", "F - test-trace-scroll/down1-1"
2040   check-background-color-in-screen-row screen, 7/bg=cursor, 1/y, "           ", "F - test-trace-scroll/down1-1/cursor"
2041   check-screen-row screen,                                  2/y, "1 line 6   ", "F - test-trace-scroll/down1-2"
2042   check-background-color-in-screen-row screen, 7/bg=cursor, 2/y, "           ", "F - test-trace-scroll/down1-2/cursor"
2043   check-screen-row screen,                                  3/y, "1 line 7   ", "F - test-trace-scroll/down1-3"
2044   check-background-color-in-screen-row screen, 7/bg=cursor, 3/y, "           ", "F - test-trace-scroll/down1-3/cursor"
2045   # scroll down
2046   edit-trace t, 6/ctrl-f
2047   clear-screen screen
2048   var y/ecx: int <- render-trace screen, t, 0/xmin, 0/ymin, 0x10/xmax, 4/ymax, 1/show-cursor
2049   check-screen-row screen,                                  0/y, "1 line 8   ", "F - test-trace-scroll/down2-0"
2050   check-background-color-in-screen-row screen, 7/bg=cursor, 0/y, "||||||||   ", "F - test-trace-scroll/down2-0/cursor"
2051   check-screen-row screen,                                  1/y, "1 line 9   ", "F - test-trace-scroll/down2-1"
2052   check-background-color-in-screen-row screen, 7/bg=cursor, 1/y, "           ", "F - test-trace-scroll/down2-1/cursor"
2053   check-screen-row screen,                                  2/y, "           ", "F - test-trace-scroll/down2-2"
2054   check-background-color-in-screen-row screen, 7/bg=cursor, 2/y, "           ", "F - test-trace-scroll/down2-2/cursor"
2055   check-screen-row screen,                                  3/y, "           ", "F - test-trace-scroll/down2-3"
2056   check-background-color-in-screen-row screen, 7/bg=cursor, 3/y, "           ", "F - test-trace-scroll/down2-3/cursor"
2057   # scroll down
2058   edit-trace t, 6/ctrl-f
2059   clear-screen screen
2060   var y/ecx: int <- render-trace screen, t, 0/xmin, 0/ymin, 0x10/xmax, 4/ymax, 1/show-cursor
2061   # no change since we're already at the bottom
2062   check-screen-row screen,                                  0/y, "1 line 8   ", "F - test-trace-scroll/down3-0"
2063   check-background-color-in-screen-row screen, 7/bg=cursor, 0/y, "||||||||   ", "F - test-trace-scroll/down3-0/cursor"
2064   check-screen-row screen,                                  1/y, "1 line 9   ", "F - test-trace-scroll/down3-1"
2065   check-background-color-in-screen-row screen, 7/bg=cursor, 1/y, "           ", "F - test-trace-scroll/down3-1/cursor"
2066   check-screen-row screen,                                  2/y, "           ", "F - test-trace-scroll/down3-2"
2067   check-background-color-in-screen-row screen, 7/bg=cursor, 2/y, "           ", "F - test-trace-scroll/down3-2/cursor"
2068   check-screen-row screen,                                  3/y, "           ", "F - test-trace-scroll/down3-3"
2069   check-background-color-in-screen-row screen, 7/bg=cursor, 3/y, "           ", "F - test-trace-scroll/down3-3/cursor"
2070   # scroll up
2071   edit-trace t, 2/ctrl-b
2072   clear-screen screen
2073   var y/ecx: int <- render-trace screen, t, 0/xmin, 0/ymin, 0x10/xmax, 4/ymax, 1/show-cursor
2074   check-screen-row screen,                                  0/y, "1 line 4   ", "F - test-trace-scroll/up1-0"
2075   check-background-color-in-screen-row screen, 7/bg=cursor, 0/y, "||||||||   ", "F - test-trace-scroll/up1-0/cursor"
2076   check-screen-row screen,                                  1/y, "1 line 5   ", "F - test-trace-scroll/up1-1"
2077   check-background-color-in-screen-row screen, 7/bg=cursor, 1/y, "           ", "F - test-trace-scroll/up1-1/cursor"
2078   check-screen-row screen,                                  2/y, "1 line 6   ", "F - test-trace-scroll/up1-2"
2079   check-background-color-in-screen-row screen, 7/bg=cursor, 2/y, "           ", "F - test-trace-scroll/up1-2/cursor"
2080   check-screen-row screen,                                  3/y, "1 line 7   ", "F - test-trace-scroll/up1-3"
2081   check-background-color-in-screen-row screen, 7/bg=cursor, 3/y, "           ", "F - test-trace-scroll/up1-3/cursor"
2082   # scroll up
2083   edit-trace t, 2/ctrl-b
2084   clear-screen screen
2085   var y/ecx: int <- render-trace screen, t, 0/xmin, 0/ymin, 0x10/xmax, 4/ymax, 1/show-cursor
2086   check-screen-row screen,                                  0/y, "1 line 0   ", "F - test-trace-scroll/up2-0"
2087   check-background-color-in-screen-row screen, 7/bg=cursor, 0/y, "||||||||   ", "F - test-trace-scroll/up2-0/cursor"
2088   check-screen-row screen,                                  1/y, "1 line 1   ", "F - test-trace-scroll/up2-1"
2089   check-background-color-in-screen-row screen, 7/bg=cursor, 1/y, "           ", "F - test-trace-scroll/up2-1/cursor"
2090   check-screen-row screen,                                  2/y, "1 line 2   ", "F - test-trace-scroll/up2-2"
2091   check-background-color-in-screen-row screen, 7/bg=cursor, 2/y, "           ", "F - test-trace-scroll/up2-2/cursor"
2092   check-screen-row screen,                                  3/y, "1 line 3   ", "F - test-trace-scroll/up2-3"
2093   check-background-color-in-screen-row screen, 7/bg=cursor, 3/y, "           ", "F - test-trace-scroll/up2-3/cursor"
2096 # saving and restoring trace indices
2098 fn save-indices _self: (addr trace), _out: (addr trace-index-stash) {
2099   var self/esi: (addr trace) <- copy _self
2100   var out/edi: (addr trace-index-stash) <- copy _out
2101   var data-ah/eax: (addr handle array trace-line) <- get self, data
2102   var _data/eax: (addr array trace-line) <- lookup *data-ah
2103   var data/ebx: (addr array trace-line) <- copy _data
2104   # cursor
2105   var cursor-line-index-addr/eax: (addr int) <- get self, cursor-line-index
2106   var cursor-line-index/eax: int <- copy *cursor-line-index-addr
2107 #?   draw-int32-decimal-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, cursor-line-index, 2/fg 0/bg
2108   var offset/eax: (offset trace-line) <- compute-offset data, cursor-line-index
2109   var cursor-line/ecx: (addr trace-line) <- index data, offset
2110   var src/eax: (addr int) <- get cursor-line, depth
2111   var dest/edx: (addr int) <- get out, cursor-line-depth
2112   copy-object src, dest
2113   var src/eax: (addr handle array byte) <- get cursor-line, label
2114   var dest/edx: (addr handle array byte) <- get out, cursor-line-label
2115   copy-object src, dest
2116   src <- get cursor-line, data
2117 #?   {
2118 #?     var foo/eax: (addr array byte) <- lookup *src
2119 #?     draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, foo, 7/fg 0/bg
2120 #?     var cursor-line-visible-addr/eax: (addr boolean) <- get cursor-line, visible?
2121 #?     var cursor-line-visible?/eax: boolean <- copy *cursor-line-visible-addr
2122 #?     var foo/eax: int <- copy cursor-line-visible?
2123 #?     draw-int32-decimal-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, foo, 5/fg 0/bg
2124 #?   }
2125   dest <- get out, cursor-line-data
2126   copy-object src, dest
2127   # top of screen
2128   var top-line-index-addr/eax: (addr int) <- get self, top-line-index
2129   var top-line-index/eax: int <- copy *top-line-index-addr
2130 #?   draw-int32-decimal-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, top-line-index, 2/fg 0/bg
2131   var offset/eax: (offset trace-line) <- compute-offset data, top-line-index
2132   var top-line/ecx: (addr trace-line) <- index data, offset
2133   var src/eax: (addr int) <- get top-line, depth
2134   var dest/edx: (addr int) <- get out, top-line-depth
2135   copy-object src, dest
2136   var src/eax: (addr handle array byte) <- get top-line, label
2137   var dest/edx: (addr handle array byte) <- get out, top-line-label
2138   copy-object src, dest
2139   src <- get top-line, data
2140   dest <- get out, top-line-data
2141   copy-object src, dest
2144 fn restore-indices _self: (addr trace), _in: (addr trace-index-stash) {
2145   var self/edi: (addr trace) <- copy _self
2146   var in/esi: (addr trace-index-stash) <- copy _in
2147   var data-ah/eax: (addr handle array trace-line) <- get self, data
2148   var _data/eax: (addr array trace-line) <- lookup *data-ah
2149   var data/ebx: (addr array trace-line) <- copy _data
2150   # cursor
2151   var cursor-depth/edx: (addr int) <- get in, cursor-line-depth
2152   var cursor-line-label-ah/eax: (addr handle array byte) <- get in, cursor-line-label
2153   var _cursor-line-label/eax: (addr array byte) <- lookup *cursor-line-label-ah
2154   var cursor-line-label/ecx: (addr array byte) <- copy _cursor-line-label
2155   var cursor-line-data-ah/eax: (addr handle array byte) <- get in, cursor-line-data
2156   var cursor-line-data/eax: (addr array byte) <- lookup *cursor-line-data-ah
2157   var new-cursor-line-index/eax: int <- find-in-trace self, *cursor-depth, cursor-line-label, cursor-line-data
2158   var dest/edx: (addr int) <- get self, cursor-line-index
2159   copy-to *dest, new-cursor-line-index
2160   # top of screen
2161   var top-depth/edx: (addr int) <- get in, top-line-depth
2162   var top-line-label-ah/eax: (addr handle array byte) <- get in, top-line-label
2163   var _top-line-label/eax: (addr array byte) <- lookup *top-line-label-ah
2164   var top-line-label/ecx: (addr array byte) <- copy _top-line-label
2165   var top-line-data-ah/eax: (addr handle array byte) <- get in, top-line-data
2166   var top-line-data/eax: (addr array byte) <- lookup *top-line-data-ah
2167   var new-top-line-index/eax: int <- find-in-trace self, *top-depth, top-line-label, top-line-data
2168   var dest/edx: (addr int) <- get self, top-line-index
2169   copy-to *dest, new-top-line-index
2172 # like trace-contains? but stateless
2173 # this is super-inefficient, string comparing every trace line
2174 fn find-in-trace _self: (addr trace), depth: int, label: (addr array byte), data: (addr array byte) -> _/eax: int {
2175   var self/esi: (addr trace) <- copy _self
2176   var candidates-ah/eax: (addr handle array trace-line) <- get self, data
2177   var candidates/eax: (addr array trace-line) <- lookup *candidates-ah
2178   var i/ecx: int <- copy 0
2179   var max/edx: (addr int) <- get self, first-free
2180   {
2181     compare i, *max
2182     break-if->=
2183     {
2184       var curr-offset/edx: (offset trace-line) <- compute-offset candidates, i
2185       var curr/edx: (addr trace-line) <- index candidates, curr-offset
2186       # if curr->depth does not match, continue
2187       var curr-depth-addr/eax: (addr int) <- get curr, depth
2188       var curr-depth/eax: int <- copy *curr-depth-addr
2189       compare curr-depth, depth
2190       break-if-!=
2191       # if curr->label does not match, continue
2192       var curr-label-ah/eax: (addr handle array byte) <- get curr, label
2193       var curr-label/eax: (addr array byte) <- lookup *curr-label-ah
2194       var match?/eax: boolean <- string-equal? curr-label, label
2195       compare match?, 0/false
2196       break-if-=
2197       # if curr->data does not match, continue
2198       var curr-data-ah/eax: (addr handle array byte) <- get curr, data
2199       var curr-data/eax: (addr array byte) <- lookup *curr-data-ah
2200       {
2201         var match?/eax: boolean <- string-equal? curr-data, data
2202         compare match?, 0/false
2203       }
2204       break-if-=
2205 #?       draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, " => ", 7/fg 0/bg
2206 #? #?       draw-int32-decimal-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, i, 4/fg 0/bg
2207 #?       draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, curr-data, 7/fg 0/bg
2208 #?       var curr-visible-addr/eax: (addr boolean) <- get curr, visible?
2209 #?       var curr-visible?/eax: boolean <- copy *curr-visible-addr
2210 #?       var foo/eax: int <- copy curr-visible?
2211 #?       draw-int32-decimal-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, foo, 2/fg 0/bg
2212       return i
2213     }
2214     i <- increment
2215     loop
2216   }
2217   abort "not in trace"
2218   return -1