https://github.com/akkartik/mu/blob/main/shell/trace.mu

       1 # A trace records the evolution of a computation.
       2 # An integral part of the Mu Shell is facilities for browsing traces.
       3
       4 type trace {
       5   curr-depth: int  # depth that will be assigned to next line appended
       6   data: (handle array trace-line)
       7   first-free: int
       8   first-full: int  # used only by check-trace-scan
       9
      10   # steady-state life cycle of a trace:
      11   #   reload loop:
      12   #     there are already some visible lines
      13   #     append a bunch of new trace lines to the trace
      14   #     render loop:
      15   #       rendering displays trace lines that match visible lines
      16   #       rendering computes cursor-line based on the cursor-y coordinate
      17   #       edit-trace updates cursor-y coordinate
      18   #       edit-trace might add/remove lines to visible
      19   visible: (handle array trace-line)
      20   recompute-visible?: boolean
      21   top-line-index: int  # index into data
      22   cursor-y: int  # row index on screen
      23   cursor-line-index: int  # index into data
      24 }
      25
      26 type trace-line {
      27   depth: int
      28   label: (handle array byte)
      29   data: (handle array byte)
      30   visible?: boolean
      31 }
      32
      33 ## generating traces
      34
      35 fn initialize-trace _self: (addr trace), capacity: int, visible-capacity: int {
      36   var self/esi: (addr trace) <- copy _self
      37   compare self, 0
      38   break-if-=
      39   var trace-ah/eax: (addr handle array trace-line) <- get self, data
      40   populate trace-ah, capacity
      41   var visible-ah/eax: (addr handle array trace-line) <- get self, visible
      42   populate visible-ah, visible-capacity
      43 }
      44
      45 fn clear-trace _self: (addr trace) {
      46   var self/eax: (addr trace) <- copy _self
      47   compare self, 0
      48   break-if-=
      49   var len/edx: (addr int) <- get self, first-free
      50   copy-to *len, 0
      51   # might leak memory; existing elements won't be used anymore
      52 }
      53
      54 fn has-errors? _self: (addr trace) -> _/eax: boolean {
      55   var self/eax: (addr trace) <- copy _self
      56   {
      57     compare self, 0
      58     break-if-!=
      59     return 0/false
      60   }
      61   var max/edx: (addr int) <- get self, first-free
      62   var trace-ah/eax: (addr handle array trace-line) <- get self, data
      63   var _trace/eax: (addr array trace-line) <- lookup *trace-ah
      64   var trace/esi: (addr array trace-line) <- copy _trace
      65   var i/ecx: int <- copy 0
      66   {
      67     compare i, *max
      68     break-if->=
      69     var offset/eax: (offset trace-line) <- compute-offset trace, i
      70     var curr/eax: (addr trace-line) <- index trace, offset
      71     var curr-label-ah/eax: (addr handle array byte) <- get curr, label
      72     var curr-label/eax: (addr array byte) <- lookup *curr-label-ah
      73     var error?/eax: boolean <- string-equal? curr-label, "error"
      74     compare error?, 0/false
      75     {
      76       break-if-=
      77       return 1/true
      78     }
      79     i <- increment
      80     loop
      81   }
      82   return 0/false
      83 }
      84
      85 fn trace _self: (addr trace), label: (addr array byte), message: (addr stream byte) {
      86   var self/esi: (addr trace) <- copy _self
      87   compare self, 0
      88   break-if-=
      89   var data-ah/eax: (addr handle array trace-line) <- get self, data
      90   var data/eax: (addr array trace-line) <- lookup *data-ah
      91   var index-addr/edi: (addr int) <- get self, first-free
      92   {
      93     compare *index-addr, 0x8000/lines
      94     break-if-<
      95     return
      96   }
      97   var index/ecx: int <- copy *index-addr
      98   var offset/ecx: (offset trace-line) <- compute-offset data, index
      99   var dest/eax: (addr trace-line) <- index data, offset
     100   var depth/ecx: (addr int) <- get self, curr-depth
     101   rewind-stream message
     102   {
     103     compare *index-addr, 0x7fff/lines
     104     break-if-<
     105     clear-stream message
     106     write message, "No space left in trace\n"
     107     write message, "Please either:\n"
     108     write message, "  - find a smaller sub-computation to test,\n"
     109     write message, "  - allocate more space to the trace in initialize-sandbox\n"
     110     write message, "    (shell/sandbox.mu), or\n"
     111     write message, "  - move the computation to 'main' and run it using ctrl-s"
     112     initialize-trace-line 0/depth, "error", message, dest
     113     increment *index-addr
     114     return
     115   }
     116   initialize-trace-line *depth, label, message, dest
     117   increment *index-addr
     118 }
     119
     120 fn trace-text self: (addr trace), label: (addr array byte), s: (addr array byte) {
     121   compare self, 0
     122   break-if-=
     123   var data-storage: (stream byte 0x100)
     124   var data/eax: (addr stream byte) <- address data-storage
     125   write data, s
     126   trace self, label, data
     127 }
     128
     129 fn error self: (addr trace), message: (addr array byte) {
     130   trace-text self, "error", message
     131 }
     132
     133 fn initialize-trace-line depth: int, label: (addr array byte), data: (addr stream byte), _out: (addr trace-line) {
     134   var out/edi: (addr trace-line) <- copy _out
     135   # depth
     136   var src/eax: int <- copy depth
     137   var dest/ecx: (addr int) <- get out, depth
     138   copy-to *dest, src
     139   # label
     140   var dest/eax: (addr handle array byte) <- get out, label
     141   copy-array-object label, dest
     142   # data
     143   var dest/eax: (addr handle array byte) <- get out, data
     144   stream-to-array data, dest
     145 }
     146
     147 fn trace-lower _self: (addr trace) {
     148   var self/esi: (addr trace) <- copy _self
     149   compare self, 0
     150   break-if-=
     151   var depth/eax: (addr int) <- get self, curr-depth
     152   increment *depth
     153 }
     154
     155 fn trace-higher _self: (addr trace) {
     156   var self/esi: (addr trace) <- copy _self
     157   compare self, 0
     158   break-if-=
     159   var depth/eax: (addr int) <- get self, curr-depth
     160   decrement *depth
     161 }
     162
     163 ## checking traces
     164
     165 fn check-trace-scans-to self: (addr trace), label: (addr array byte), data: (addr array byte), message: (addr array byte) {
     166   var tmp/eax: boolean <- trace-scans-to? self, label, data
     167   check tmp, message
     168 }
     169
     170 fn trace-scans-to? _self: (addr trace), label: (addr array byte), data: (addr array byte) -> _/eax: boolean {
     171   var self/esi: (addr trace) <- copy _self
     172   var start/eax: (addr int) <- get self, first-full
     173   var result/eax: boolean <- trace-contains? self, label, data, *start
     174   return result
     175 }
     176
     177 fn test-trace-scans-to {
     178   var t-storage: trace
     179   var t/esi: (addr trace) <- address t-storage
     180   initialize-trace t, 0x10, 0/visible  # we don't use trace UI
     181   #
     182   trace-text t, "label", "line 1"
     183   trace-text t, "label", "line 2"
     184   check-trace-scans-to t, "label", "line 1", "F - test-trace-scans-to/0"
     185   check-trace-scans-to t, "label", "line 2", "F - test-trace-scans-to/1"
     186   var tmp/eax: boolean <- trace-scans-to? t, "label", "line 1"
     187   check-not tmp, "F - test-trace-scans-to: fail on previously encountered lines"
     188   var tmp/eax: boolean <- trace-scans-to? t, "label", "line 3"
     189   check-not tmp, "F - test-trace-scans-to: fail on missing"
     190 }
     191
     192 # scan trace from start
     193 # resets previous scans
     194 fn check-trace-contains self: (addr trace), label: (addr array byte), data: (addr array byte), message: (addr array byte) {
     195   var tmp/eax: boolean <- trace-contains? self, label, data, 0
     196   check tmp, message
     197 }
     198
     199 fn test-trace-contains {
     200   var t-storage: trace
     201   var t/esi: (addr trace) <- address t-storage
     202   initialize-trace t, 0x10, 0/visible  # we don't use trace UI
     203   #
     204   trace-text t, "label", "line 1"
     205   trace-text t, "label", "line 2"
     206   check-trace-contains t, "label", "line 1", "F - test-trace-contains/0"
     207   check-trace-contains t, "label", "line 2", "F - test-trace-contains/1"
     208   check-trace-contains t, "label", "line 1", "F - test-trace-contains: find previously encountered lines"
     209   var tmp/eax: boolean <- trace-contains? t, "label", "line 3", 0/start
     210   check-not tmp, "F - test-trace-contains: fail on missing"
     211 }
     212
     213 # this is super-inefficient, string comparing every trace line
     214 # against every visible line on every render
     215 fn trace-contains? _self: (addr trace), label: (addr array byte), data: (addr array byte), start: int -> _/eax: boolean {
     216   var self/esi: (addr trace) <- copy _self
     217   var candidates-ah/eax: (addr handle array trace-line) <- get self, data
     218   var candidates/eax: (addr array trace-line) <- lookup *candidates-ah
     219   var i/ecx: int <- copy start
     220   var max/edx: (addr int) <- get self, first-free
     221   {
     222     compare i, *max
     223     break-if->=
     224     {
     225       var read-until-index/eax: (addr int) <- get self, first-full
     226       copy-to *read-until-index, i
     227     }
     228     {
     229       var curr-offset/ecx: (offset trace-line) <- compute-offset candidates, i
     230       var curr/ecx: (addr trace-line) <- index candidates, curr-offset
     231       # if curr->label does not match, return false
     232       var curr-label-ah/eax: (addr handle array byte) <- get curr, label
     233       var curr-label/eax: (addr array byte) <- lookup *curr-label-ah
     234       var match?/eax: boolean <- string-equal? curr-label, label
     235       compare match?, 0/false
     236       break-if-=
     237       # if curr->data does not match, return false
     238       var curr-data-ah/eax: (addr handle array byte) <- get curr, data
     239       var curr-data/eax: (addr array byte) <- lookup *curr-data-ah
     240       var match?/eax: boolean <- string-equal? curr-data, data
     241       compare match?, 0/false
     242       break-if-=
     243       return 1/true
     244     }
     245     i <- increment
     246     loop
     247   }
     248   return 0/false
     249 }
     250
     251 fn trace-lines-equal? _a: (addr trace-line), _b: (addr trace-line) -> _/eax: boolean {
     252   var a/esi: (addr trace-line) <- copy _a
     253   var b/edi: (addr trace-line) <- copy _b
     254   var a-depth/ecx: (addr int) <- get a, depth
     255   var b-depth/edx: (addr int) <- get b, depth
     256   var benchmark/eax: int <- copy *b-depth
     257   compare *a-depth, benchmark
     258   {
     259     break-if-=
     260     return 0/false
     261   }
     262   var a-label-ah/eax: (addr handle array byte) <- get a, label
     263   var _a-label/eax: (addr array byte) <- lookup *a-label-ah
     264   var a-label/ecx: (addr array byte) <- copy _a-label
     265   var b-label-ah/ebx: (addr handle array byte) <- get b, label
     266   var b-label/eax: (addr array byte) <- lookup *b-label-ah
     267   var label-match?/eax: boolean <- string-equal? a-label, b-label
     268   {
     269     compare label-match?, 0/false
     270     break-if-!=
     271     return 0/false
     272   }
     273   var a-data-ah/eax: (addr handle array byte) <- get a, data
     274   var _a-data/eax: (addr array byte) <- lookup *a-data-ah
     275   var a-data/ecx: (addr array byte) <- copy _a-data
     276   var b-data-ah/ebx: (addr handle array byte) <- get b, data
     277   var b-data/eax: (addr array byte) <- lookup *b-data-ah
     278   var data-match?/eax: boolean <- string-equal? a-data, b-data
     279   return data-match?
     280 }
     281
     282 fn dump-trace _self: (addr trace) {
     283   var already-hiding-lines?: boolean
     284   var y/ecx: int <- copy 0
     285   var self/esi: (addr trace) <- copy _self
     286   compare self, 0
     287   {
     288     break-if-!=
     289     return
     290   }
     291   var trace-ah/eax: (addr handle array trace-line) <- get self, data
     292   var _trace/eax: (addr array trace-line) <- lookup *trace-ah
     293   var trace/edi: (addr array trace-line) <- copy _trace
     294   var i/edx: int <- copy 0
     295   var max-addr/ebx: (addr int) <- get self, first-free
     296   var max/ebx: int <- copy *max-addr
     297   $dump-trace:loop: {
     298     compare i, max
     299     break-if->=
     300     $dump-trace:iter: {
     301       var offset/ebx: (offset trace-line) <- compute-offset trace, i
     302       var curr/ebx: (addr trace-line) <- index trace, offset
     303       var curr-label-ah/eax: (addr handle array byte) <- get curr, label
     304       var curr-label/eax: (addr array byte) <- lookup *curr-label-ah
     305       y <- render-trace-line 0/screen, curr, 0, y, 0x80/width, 0x30/height, 7/fg, 0xc5/bg=blue-bg
     306     }
     307     i <- increment
     308     loop
     309   }
     310 }
     311
     312 ## UI stuff
     313
     314 fn mark-lines-dirty _self: (addr trace) {
     315   var self/eax: (addr trace) <- copy _self
     316   var dest/edx: (addr boolean) <- get self, recompute-visible?
     317   copy-to *dest, 1/true
     318 }
     319
     320 fn mark-lines-clean _self: (addr trace) {
     321   var self/eax: (addr trace) <- copy _self
     322   var dest/edx: (addr boolean) <- get self, recompute-visible?
     323   copy-to *dest, 0/false
     324 }
     325
     326 fn render-trace screen: (addr screen), _self: (addr trace), xmin: int, ymin: int, xmax: int, ymax: int, show-cursor?: boolean -> _/ecx: int {
     327   var already-hiding-lines?: boolean
     328   var y/ecx: int <- copy ymin
     329   var self/esi: (addr trace) <- copy _self
     330   compare self, 0
     331   {
     332     break-if-!=
     333     return ymin
     334   }
     335   clamp-cursor-to-top self, y
     336   var trace-ah/eax: (addr handle array trace-line) <- get self, data
     337   var _trace/eax: (addr array trace-line) <- lookup *trace-ah
     338   var trace/edi: (addr array trace-line) <- copy _trace
     339   var i/edx: int <- copy 0
     340   var max-addr/ebx: (addr int) <- get self, first-free
     341   var max/ebx: int <- copy *max-addr
     342   $render-trace:loop: {
     343     compare i, max
     344     break-if->=
     345     $render-trace:iter: {
     346       var offset/ebx: (offset trace-line) <- compute-offset trace, i
     347       var curr/ebx: (addr trace-line) <- index trace, offset
     348       var curr-label-ah/eax: (addr handle array byte) <- get curr, label
     349       var curr-label/eax: (addr array byte) <- lookup *curr-label-ah
     350       var bg/edi: int <- copy 0xc5/bg=blue-bg
     351       compare show-cursor?, 0/false
     352       {
     353         break-if-=
     354         var cursor-y/eax: (addr int) <- get self, cursor-y
     355         compare *cursor-y, y
     356         break-if-!=
     357         bg <- copy 7/cursor-line-bg
     358         var cursor-line-index/eax: (addr int) <- get self, cursor-line-index
     359         copy-to *cursor-line-index, i
     360       }
     361       # always display errors
     362       var error?/eax: boolean <- string-equal? curr-label, "error"
     363       {
     364         compare error?, 0/false
     365         break-if-=
     366         y <- render-trace-line screen, curr, xmin, y, xmax, ymax, 0xc/fg=trace-error, bg
     367         copy-to already-hiding-lines?, 0/false
     368         break $render-trace:iter
     369       }
     370       # display expanded lines
     371       var display?/eax: boolean <- should-render? self, curr
     372       {
     373         compare display?, 0/false
     374         break-if-=
     375         y <- render-trace-line screen, curr, xmin, y, xmax, ymax, 0x38/fg=trace, bg
     376         copy-to already-hiding-lines?, 0/false
     377         break $render-trace:iter
     378       }
     379       # ignore the rest
     380       compare already-hiding-lines?, 0/false
     381       {
     382         break-if-!=
     383         var x/eax: int <- copy xmin
     384         x, y <- draw-text-wrapping-right-then-down screen, "...", xmin, ymin, xmax, ymax, x, y, 9/fg=trace, bg
     385         y <- increment
     386         copy-to already-hiding-lines?, 1/true
     387       }
     388     }
     389     i <- increment
     390     loop
     391   }
     392   # prevent cursor from going too far down
     393   clamp-cursor-to-bottom self, y, screen, xmin, ymin, xmax, ymax
     394   mark-lines-clean self
     395   return y
     396 }
     397
     398 fn render-trace-line screen: (addr screen), _self: (addr trace-line), xmin: int, ymin: int, xmax: int, ymax: int, fg: int, bg: int -> _/ecx: int {
     399   var self/esi: (addr trace-line) <- copy _self
     400   var xsave/edx: int <- copy xmin
     401   var y/ecx: int <- copy ymin
     402   var label-ah/eax: (addr handle array byte) <- get self, label
     403   var _label/eax: (addr array byte) <- lookup *label-ah
     404   var label/ebx: (addr array byte) <- copy _label
     405   var error?/eax: boolean <- string-equal? label, "error"
     406   compare error?, 0/false
     407   {
     408     break-if-!=
     409     var x/eax: int <- copy xsave
     410     {
     411       var depth/edx: (addr int) <- get self, depth
     412       x, y <- draw-int32-decimal-wrapping-right-then-down screen, *depth, xmin, ymin, xmax, ymax, x, y, fg, bg
     413       x, y <- draw-text-wrapping-right-then-down screen, " ", xmin, ymin, xmax, ymax, x, y, fg, bg
     414       # don't show label in UI; it's just for tests
     415     }
     416     xsave <- copy x
     417   }
     418   var data-ah/eax: (addr handle array byte) <- get self, data
     419   var _data/eax: (addr array byte) <- lookup *data-ah
     420   var data/ebx: (addr array byte) <- copy _data
     421   var x/eax: int <- copy xsave
     422   x, y <- draw-text-wrapping-right-then-down screen, data, xmin, ymin, xmax, ymax, x, y, fg, bg
     423   y <- increment
     424   return y
     425 }
     426
     427 # this is super-inefficient, string comparing every trace line
     428 # against every visible line on every render
     429 fn should-render? _self: (addr trace), _line: (addr trace-line) -> _/eax: boolean {
     430   var self/esi: (addr trace) <- copy _self
     431   # if visible? is already cached, just return it
     432   var dest/edx: (addr boolean) <- get self, recompute-visible?
     433   compare *dest, 0/false
     434   {
     435     break-if-!=
     436     var line/eax: (addr trace-line) <- copy _line
     437     var result/eax: (addr boolean) <- get line, visible?
     438     return *result
     439   }
     440   # recompute
     441   var candidates-ah/eax: (addr handle array trace-line) <- get self, visible
     442   var candidates/eax: (addr array trace-line) <- lookup *candidates-ah
     443   var i/ecx: int <- copy 0
     444   var len/edx: int <- length candidates
     445   {
     446     compare i, len
     447     break-if->=
     448     {
     449       var curr-offset/ecx: (offset trace-line) <- compute-offset candidates, i
     450       var curr/ecx: (addr trace-line) <- index candidates, curr-offset
     451       var match?/eax: boolean <- trace-lines-equal? curr, _line
     452       compare match?, 0/false
     453       break-if-=
     454       var line/eax: (addr trace-line) <- copy _line
     455       var dest/eax: (addr boolean) <- get line, visible?
     456       copy-to *dest, 1/true
     457       return 1/true
     458     }
     459     i <- increment
     460     loop
     461   }
     462   var line/eax: (addr trace-line) <- copy _line
     463   var dest/eax: (addr boolean) <- get line, visible?
     464   copy-to *dest, 0/false
     465   return 0/false
     466 }
     467
     468 fn clamp-cursor-to-top _self: (addr trace), _y: int {
     469   var y/ecx: int <- copy _y
     470   var self/esi: (addr trace) <- copy _self
     471   var cursor-y/eax: (addr int) <- get self, cursor-y
     472   compare *cursor-y, y
     473   break-if->=
     474   copy-to *cursor-y, y
     475 }
     476
     477 # extremely hacky; consider deleting test-render-trace-empty-3 when you clean this up
     478 fn clamp-cursor-to-bottom _self: (addr trace), _y: int, screen: (addr screen), xmin: int, ymin: int, xmax: int, ymax: int {
     479   var y/ebx: int <- copy _y
     480   compare y, ymin
     481   {
     482     break-if->
     483     return
     484   }
     485   y <- decrement
     486   var self/esi: (addr trace) <- copy _self
     487   var cursor-y/eax: (addr int) <- get self, cursor-y
     488   compare *cursor-y, y
     489   break-if-<=
     490   copy-to *cursor-y, y
     491   # redraw cursor-line
     492   # TODO: ugly duplication
     493   var trace-ah/eax: (addr handle array trace-line) <- get self, data
     494   var trace/eax: (addr array trace-line) <- lookup *trace-ah
     495   var cursor-line-index-addr/ecx: (addr int) <- get self, cursor-line-index
     496   var cursor-line-index/ecx: int <- copy *cursor-line-index-addr
     497   var first-free/edx: (addr int) <- get self, first-free
     498   compare cursor-line-index, *first-free
     499   {
     500     break-if-<
     501     return
     502   }
     503   var cursor-offset/ecx: (offset trace-line) <- compute-offset trace, cursor-line-index
     504   var cursor-line/ecx: (addr trace-line) <- index trace, cursor-offset
     505   var display?/eax: boolean <- should-render? self, cursor-line
     506   {
     507     compare display?, 0/false
     508     break-if-=
     509     var dummy/ecx: int <- render-trace-line screen, cursor-line, xmin, y, xmax, ymax, 0x38/fg=trace, 7/cursor-line-bg
     510     return
     511   }
     512   var dummy1/eax: int <- copy 0
     513   var dummy2/ecx: int <- copy 0
     514   dummy1, dummy2 <- draw-text-wrapping-right-then-down screen, "...", xmin, ymin, xmax, ymax, xmin, y, 9/fg=trace, 7/cursor-line-bg
     515 }
     516
     517 fn test-render-trace-empty {
     518   var t-storage: trace
     519   var t/esi: (addr trace) <- address t-storage
     520   initialize-trace t, 0x10, 0x10
     521   # setup: screen
     522   var screen-on-stack: screen
     523   var screen/edi: (addr screen) <- address screen-on-stack
     524   initialize-screen screen, 5/width, 4/height, 0/no-pixel-graphics
     525   #
     526   var y/ecx: int <- render-trace screen, t, 0/xmin, 0/ymin, 5/xmax, 4/ymax, 0/no-cursor
     527   #
     528   check-ints-equal y, 0, "F - test-render-trace-empty/cursor"
     529   check-screen-row screen,                                  0/y, "    ", "F - test-render-trace-empty"
     530   check-background-color-in-screen-row screen, 7/bg=cursor, 0/y, "    ", "F - test-render-trace-empty/bg"
     531 }
     532
     533 fn test-render-trace-empty-2 {
     534   var t-storage: trace
     535   var t/esi: (addr trace) <- address t-storage
     536   initialize-trace t, 0x10, 0x10
     537   # setup: screen
     538   var screen-on-stack: screen
     539   var screen/edi: (addr screen) <- address screen-on-stack
     540   initialize-screen screen, 5/width, 4/height, 0/no-pixel-graphics
     541   #
     542   var y/ecx: int <- render-trace screen, t, 0/xmin, 2/ymin, 5/xmax, 4/ymax, 0/no-cursor  # cursor below top row
     543   #
     544   check-ints-equal y, 2, "F - test-render-trace-empty-2/cursor"
     545   check-screen-row screen,                                  2/y, "    ", "F - test-render-trace-empty-2"
     546   check-background-color-in-screen-row screen, 7/bg=cursor, 2/y, "    ", "F - test-render-trace-empty-2/bg"
     547 }
     548
     549 fn test-render-trace-empty-3 {
     550   var t-storage: trace
     551   var t/esi: (addr trace) <- address t-storage
     552   initialize-trace t, 0x10, 0x10
     553   # setup: screen
     554   var screen-on-stack: screen
     555   var screen/edi: (addr screen) <- address screen-on-stack
     556   initialize-screen screen, 5/width, 4/height, 0/no-pixel-graphics
     557   #
     558   var y/ecx: int <- render-trace screen, t, 0/xmin, 2/ymin, 5/xmax, 4/ymax, 1/show-cursor  # try show cursor
     559   # still no cursor to show
     560   check-ints-equal y, 2, "F - test-render-trace-empty-3/cursor"
     561   check-screen-row screen,                                  1/y, "    ", "F - test-render-trace-empty-3/line-above-cursor"
     562   check-background-color-in-screen-row screen, 7/bg=cursor, 1/y, "    ", "F - test-render-trace-empty-3/bg-for-line-above-cursor"
     563   check-screen-row screen,                                  2/y, "    ", "F - test-render-trace-empty-3"
     564   check-background-color-in-screen-row screen, 7/bg=cursor, 2/y, "    ", "F - test-render-trace-empty-3/bg"
     565 }
     566
     567 fn test-render-trace-collapsed-by-default {
     568   var t-storage: trace
     569   var t/esi: (addr trace) <- address t-storage
     570   initialize-trace t, 0x10, 0x10
     571   trace-text t, "l", "data"
     572   # setup: screen
     573   var screen-on-stack: screen
     574   var screen/edi: (addr screen) <- address screen-on-stack
     575   initialize-screen screen, 5/width, 4/height, 0/no-pixel-graphics
     576   #
     577   var y/ecx: int <- render-trace screen, t, 0/xmin, 0/ymin, 5/xmax, 4/ymax, 0/no-cursor
     578   #
     579   check-ints-equal y, 1, "F - test-render-trace-collapsed-by-default/cursor"
     580   check-screen-row screen, 0/y, "... ", "F - test-render-trace-collapsed-by-default"
     581 }
     582
     583 fn test-render-trace-error {
     584   var t-storage: trace
     585   var t/esi: (addr trace) <- address t-storage
     586   initialize-trace t, 0x10, 0x10
     587   error t, "error"
     588   # setup: screen
     589   var screen-on-stack: screen
     590   var screen/edi: (addr screen) <- address screen-on-stack
     591   initialize-screen screen, 0xa/width, 4/height, 0/no-pixel-graphics
     592   #
     593   var y/ecx: int <- render-trace screen, t, 0/xmin, 0/ymin, 0xa/xmax, 4/ymax, 0/no-cursor
     594   #
     595   check-ints-equal y, 1, "F - test-render-trace-error/cursor"
     596   check-screen-row screen, 0/y, "error", "F - test-render-trace-error"
     597 }
     598
     599 fn test-render-trace-error-at-start {
     600   var t-storage: trace
     601   var t/esi: (addr trace) <- address t-storage
     602   initialize-trace t, 0x10, 0x10
     603   #
     604   error t, "error"
     605   trace-text t, "l", "data"
     606   # setup: screen
     607   var screen-on-stack: screen
     608   var screen/edi: (addr screen) <- address screen-on-stack
     609   initialize-screen screen, 0xa/width, 4/height, 0/no-pixel-graphics
     610   #
     611   var y/ecx: int <- render-trace screen, t, 0/xmin, 0/ymin, 0xa/xmax, 4/ymax, 0/no-cursor
     612   #
     613   check-ints-equal y, 2, "F - test-render-trace-error-at-start/cursor"
     614   check-screen-row screen, 0/y, "error", "F - test-render-trace-error-at-start/0"
     615   check-screen-row screen, 1/y, "...  ", "F - test-render-trace-error-at-start/1"
     616 }
     617
     618 fn test-render-trace-error-at-end {
     619   var t-storage: trace
     620   var t/esi: (addr trace) <- address t-storage
     621   initialize-trace t, 0x10, 0x10
     622   #
     623   trace-text t, "l", "data"
     624   error t, "error"
     625   # setup: screen
     626   var screen-on-stack: screen
     627   var screen/edi: (addr screen) <- address screen-on-stack
     628   initialize-screen screen, 0xa/width, 4/height, 0/no-pixel-graphics
     629   #
     630   var y/ecx: int <- render-trace screen, t, 0/xmin, 0/ymin, 0xa/xmax, 4/ymax, 0/no-cursor
     631   #
     632   check-ints-equal y, 2, "F - test-render-trace-error-at-end/cursor"
     633   check-screen-row screen, 0/y, "...  ", "F - test-render-trace-error-at-end/0"
     634   check-screen-row screen, 1/y, "error", "F - test-render-trace-error-at-end/1"
     635 }
     636
     637 fn test-render-trace-error-in-the-middle {
     638   var t-storage: trace
     639   var t/esi: (addr trace) <- address t-storage
     640   initialize-trace t, 0x10, 0x10
     641   #
     642   trace-text t, "l", "line 1"
     643   error t, "error"
     644   trace-text t, "l", "line 3"
     645   # setup: screen
     646   var screen-on-stack: screen
     647   var screen/edi: (addr screen) <- address screen-on-stack
     648   initialize-screen screen, 0xa/width, 4/height, 0/no-pixel-graphics
     649   #
     650   var y/ecx: int <- render-trace screen, t, 0/xmin, 0/ymin, 0xa/xmax, 4/ymax, 0/no-cursor
     651   #
     652   check-ints-equal y, 3, "F - test-render-trace-error-in-the-middle/cursor"
     653   check-screen-row screen, 0/y, "...  ", "F - test-render-trace-error-in-the-middle/0"
     654   check-screen-row screen, 1/y, "error", "F - test-render-trace-error-in-the-middle/1"
     655   check-screen-row screen, 2/y, "...  ", "F - test-render-trace-error-in-the-middle/2"
     656 }
     657
     658 fn test-render-trace-cursor-in-single-line {
     659   var t-storage: trace
     660   var t/esi: (addr trace) <- address t-storage
     661   initialize-trace t, 0x10, 0x10
     662   #
     663   trace-text t, "l", "line 1"
     664   error t, "error"
     665   trace-text t, "l", "line 3"
     666   # setup: screen
     667   var screen-on-stack: screen
     668   var screen/edi: (addr screen) <- address screen-on-stack
     669   initialize-screen screen, 0xa/width, 4/height, 0/no-pixel-graphics
     670   #
     671   var y/ecx: int <- render-trace screen, t, 0/xmin, 0/ymin, 0xa/xmax, 4/ymax, 1/show-cursor
     672   #
     673   check-screen-row screen,                                  0/y, "...   ", "F - test-render-trace-cursor-in-single-line/0"
     674   check-background-color-in-screen-row screen, 7/bg=cursor, 0/y, "|||   ", "F - test-render-trace-cursor-in-single-line/0/cursor"
     675   check-screen-row screen,                                  1/y, "error ", "F - test-render-trace-cursor-in-single-line/1"
     676   check-background-color-in-screen-row screen, 7/bg=cursor, 1/y, "      ", "F - test-render-trace-cursor-in-single-line/1/cursor"
     677   check-screen-row screen,                                  2/y, "...   ", "F - test-render-trace-cursor-in-single-line/2"
     678   check-background-color-in-screen-row screen, 7/bg=cursor, 2/y, "      ", "F - test-render-trace-cursor-in-single-line/2/cursor"
     679 }
     680
     681 fn render-trace-menu screen: (addr screen) {
     682   var width/eax: int <- copy 0
     683   var height/ecx: int <- copy 0
     684   width, height <- screen-size screen
     685   var y/ecx: int <- copy height
     686   y <- decrement
     687   set-cursor-position screen, 0/x, y
     688   draw-text-rightward-from-cursor screen, " ctrl-r ", width, 0/fg, 0x5c/bg=black
     689   draw-text-rightward-from-cursor screen, " run main  ", width, 7/fg, 0xc5/bg=blue-bg
     690   draw-text-rightward-from-cursor screen, " ctrl-s ", width, 0/fg, 0x5c/bg=black
     691   draw-text-rightward-from-cursor screen, " run sandbox  ", width, 7/fg, 0xc5/bg=blue-bg
     692   draw-text-rightward-from-cursor screen, " ctrl-m ", width, 0/fg, 3/bg=keyboard
     693   draw-text-rightward-from-cursor screen, " to keyboard  ", width, 7/fg, 0xc5/bg=blue-bg
     694   draw-text-rightward-from-cursor screen, " j ", width, 0/fg, 0x5c/bg=black
     695   draw-text-rightward-from-cursor screen, " down  ", width, 7/fg, 0xc5/bg=blue-bg
     696   draw-text-rightward-from-cursor screen, " k ", width, 0/fg, 0x5c/bg=black
     697   draw-text-rightward-from-cursor screen, " up  ", width, 7/fg, 0xc5/bg=blue-bg
     698   draw-text-rightward-from-cursor screen, " enter ", width, 0/fg, 0x5c/bg=black
     699   draw-text-rightward-from-cursor screen, " expand  ", width, 7/fg, 0xc5/bg=blue-bg
     700   draw-text-rightward-from-cursor screen, " backspace ", width, 0/fg, 0x5c/bg=black
     701   draw-text-rightward-from-cursor screen, " collapse  ", width, 7/fg, 0xc5/bg=blue-bg
     702 }
     703
     704 fn edit-trace _self: (addr trace), key: grapheme {
     705   var self/esi: (addr trace) <- copy _self
     706   # cursor down
     707   {
     708     compare key, 0x6a/j
     709     break-if-!=
     710     var cursor-y/eax: (addr int) <- get self, cursor-y
     711     increment *cursor-y
     712     return
     713   }
     714   {
     715     compare key, 0x81/down-arrow
     716     break-if-!=
     717     var cursor-y/eax: (addr int) <- get self, cursor-y
     718     increment *cursor-y
     719     return
     720   }
     721   # cursor up
     722   {
     723     compare key, 0x6b/k
     724     break-if-!=
     725     var cursor-y/eax: (addr int) <- get self, cursor-y
     726     decrement *cursor-y
     727     return
     728   }
     729   {
     730     compare key, 0x82/up-arrow
     731     break-if-!=
     732     var cursor-y/eax: (addr int) <- get self, cursor-y
     733     decrement *cursor-y
     734     return
     735   }
     736   # enter = expand
     737   {
     738     compare key, 0xa/newline
     739     break-if-!=
     740     expand self
     741     return
     742   }
     743   # backspace = collapse
     744   {
     745     compare key, 8/backspace
     746     break-if-!=
     747     collapse self
     748     return
     749   }
     750 }
     751
     752 fn expand _self: (addr trace) {
     753   var self/esi: (addr trace) <- copy _self
     754   var trace-ah/eax: (addr handle array trace-line) <- get self, data
     755   var _trace/eax: (addr array trace-line) <- lookup *trace-ah
     756   var trace/edi: (addr array trace-line) <- copy _trace
     757   var cursor-line-index-addr/ecx: (addr int) <- get self, cursor-line-index
     758   var cursor-line-index/ecx: int <- copy *cursor-line-index-addr
     759   var cursor-line-offset/eax: (offset trace-line) <- compute-offset trace, cursor-line-index
     760   var cursor-line/edx: (addr trace-line) <- index trace, cursor-line-offset
     761   var cursor-line-visible?/eax: (addr boolean) <- get cursor-line, visible?
     762   var cursor-line-depth/ebx: (addr int) <- get cursor-line, depth
     763   var target-depth/ebx: int <- copy *cursor-line-depth
     764   # if cursor-line is already visible, increment target-depth
     765   compare *cursor-line-visible?, 0/false
     766   {
     767     break-if-=
     768     target-depth <- increment
     769   }
     770   # reveal the run of lines starting at cursor-line-index with depth target-depth
     771   var i/ecx: int <- copy cursor-line-index
     772   var max/edx: (addr int) <- get self, first-free
     773   {
     774     compare i, *max
     775     break-if->=
     776     var curr-line-offset/eax: (offset trace-line) <- compute-offset trace, i
     777     var curr-line/edx: (addr trace-line) <- index trace, curr-line-offset
     778     var curr-line-depth/eax: (addr int) <- get curr-line, depth
     779     compare *curr-line-depth, target-depth
     780     break-if-<
     781     {
     782       break-if-!=
     783       var curr-line-visible?/eax: (addr boolean) <- get curr-line, visible?
     784       copy-to *curr-line-visible?, 1/true
     785       reveal-trace-line self, curr-line
     786     }
     787     i <- increment
     788     loop
     789   }
     790 }
     791
     792 fn collapse _self: (addr trace) {
     793   var self/esi: (addr trace) <- copy _self
     794   var trace-ah/eax: (addr handle array trace-line) <- get self, data
     795   var _trace/eax: (addr array trace-line) <- lookup *trace-ah
     796   var trace/edi: (addr array trace-line) <- copy _trace
     797   var cursor-line-index-addr/ecx: (addr int) <- get self, cursor-line-index
     798   var cursor-line-index/ecx: int <- copy *cursor-line-index-addr
     799   var cursor-line-offset/eax: (offset trace-line) <- compute-offset trace, cursor-line-index
     800   var cursor-line/edx: (addr trace-line) <- index trace, cursor-line-offset
     801   var cursor-line-visible?/eax: (addr boolean) <- get cursor-line, visible?
     802   # if cursor-line is not visible, do nothing
     803   compare *cursor-line-visible?, 0/false
     804   {
     805     break-if-!=
     806     return
     807   }
     808   # hide all lines between previous and next line with a lower depth
     809   var cursor-line-depth/ebx: (addr int) <- get cursor-line, depth
     810   var cursor-y/edx: (addr int) <- get self, cursor-y
     811   var target-depth/ebx: int <- copy *cursor-line-depth
     812   var i/ecx: int <- copy cursor-line-index
     813   $collapse:loop1: {
     814     compare i, 0
     815     break-if-<
     816     var curr-line-offset/eax: (offset trace-line) <- compute-offset trace, i
     817     var curr-line/eax: (addr trace-line) <- index trace, curr-line-offset
     818     {
     819       var curr-line-depth/eax: (addr int) <- get curr-line, depth
     820       compare *curr-line-depth, target-depth
     821       break-if-< $collapse:loop1
     822     }
     823     # if cursor-line is visible, decrement cursor-y
     824     {
     825       var curr-line-visible?/eax: (addr boolean) <- get curr-line, visible?
     826       compare *curr-line-visible?, 0/false
     827       break-if-=
     828       decrement *cursor-y
     829     }
     830     i <- decrement
     831     loop
     832   }
     833   i <- increment
     834   var max/edx: (addr int) <- get self, first-free
     835   $collapse:loop2: {
     836     compare i, *max
     837     break-if->=
     838     var curr-line-offset/eax: (offset trace-line) <- compute-offset trace, i
     839     var curr-line/edx: (addr trace-line) <- index trace, curr-line-offset
     840     var curr-line-depth/eax: (addr int) <- get curr-line, depth
     841     compare *curr-line-depth, target-depth
     842     break-if-<
     843     {
     844       hide-trace-line self, curr-line
     845       var curr-line-visible?/eax: (addr boolean) <- get curr-line, visible?
     846       copy-to *curr-line-visible?, 0/false
     847     }
     848     i <- increment
     849     loop
     850   }
     851 }
     852
     853 # the 'visible' array is not required to be in order
     854 # elements can also be deleted out of order
     855 # so it can have holes
     856 # however, lines in it always have visible? set
     857 # we'll use visible? being unset as a sign of emptiness
     858 fn reveal-trace-line _self: (addr trace), line: (addr trace-line) {
     859   var self/esi: (addr trace) <- copy _self
     860   var visible-ah/eax: (addr handle array trace-line) <- get self, visible
     861   var visible/eax: (addr array trace-line) <- lookup *visible-ah
     862   var i/ecx: int <- copy 0
     863   var len/edx: int <- length visible
     864   {
     865     compare i, len
     866     break-if->=
     867     var curr-offset/edx: (offset trace-line) <- compute-offset visible, i
     868     var curr/edx: (addr trace-line) <- index visible, curr-offset
     869     var curr-visible?/eax: (addr boolean) <- get curr, visible?
     870     compare *curr-visible?, 0/false
     871     {
     872       break-if-!=
     873       # empty slot found
     874       copy-object line, curr
     875       return
     876     }
     877     i <- increment
     878     loop
     879   }
     880   abort "too many visible lines; increase size of array trace.visible"
     881 }
     882
     883 fn hide-trace-line _self: (addr trace), line: (addr trace-line) {
     884   var self/esi: (addr trace) <- copy _self
     885   var visible-ah/eax: (addr handle array trace-line) <- get self, visible
     886   var visible/eax: (addr array trace-line) <- lookup *visible-ah
     887   var i/ecx: int <- copy 0
     888   var len/edx: int <- length visible
     889   {
     890     compare i, len
     891     break-if->=
     892     var curr-offset/edx: (offset trace-line) <- compute-offset visible, i
     893     var curr/edx: (addr trace-line) <- index visible, curr-offset
     894     var found?/eax: boolean <- trace-lines-equal? curr, line
     895     compare found?, 0/false
     896     {
     897       break-if-=
     898       clear-object curr
     899     }
     900     i <- increment
     901     loop
     902   }
     903 }
     904
     905 fn test-cursor-down-and-up-within-trace {
     906   var t-storage: trace
     907   var t/esi: (addr trace) <- address t-storage
     908   initialize-trace t, 0x10, 0x10
     909   #
     910   trace-text t, "l", "line 1"
     911   error t, "error"
     912   trace-text t, "l", "line 3"
     913   # setup: screen
     914   var screen-on-stack: screen
     915   var screen/edi: (addr screen) <- address screen-on-stack
     916   initialize-screen screen, 0xa/width, 4/height, 0/no-pixel-graphics
     917   #
     918   var y/ecx: int <- render-trace screen, t, 0/xmin, 0/ymin, 0xa/xmax, 4/ymax, 1/show-cursor
     919   #
     920   check-screen-row screen,                                  0/y, "...   ", "F - test-cursor-down-and-up-within-trace/pre-0"
     921   check-background-color-in-screen-row screen, 7/bg=cursor, 0/y, "|||   ", "F - test-cursor-down-and-up-within-trace/pre-0/cursor"
     922   check-screen-row screen,                                  1/y, "error ", "F - test-cursor-down-and-up-within-trace/pre-1"
     923   check-background-color-in-screen-row screen, 7/bg=cursor, 1/y, "      ", "F - test-cursor-down-and-up-within-trace/pre-1/cursor"
     924   check-screen-row screen,                                  2/y, "...   ", "F - test-cursor-down-and-up-within-trace/pre-2"
     925   check-background-color-in-screen-row screen, 7/bg=cursor, 2/y, "      ", "F - test-cursor-down-and-up-within-trace/pre-2/cursor"
     926   # cursor down
     927   edit-trace t, 0x6a/j
     928   var y/ecx: int <- render-trace screen, t, 0/xmin, 0/ymin, 0xa/xmax, 4/ymax, 1/show-cursor
     929   #
     930   check-screen-row screen,                                  0/y, "...   ", "F - test-cursor-down-and-up-within-trace/down-0"
     931   check-background-color-in-screen-row screen, 7/bg=cursor, 0/y, "      ", "F - test-cursor-down-and-up-within-trace/down-0/cursor"
     932   check-screen-row screen,                                  1/y, "error ", "F - test-cursor-down-and-up-within-trace/down-1"
     933   check-background-color-in-screen-row screen, 7/bg=cursor, 1/y, "||||| ", "F - test-cursor-down-and-up-within-trace/down-1/cursor"
     934   check-screen-row screen,                                  2/y, "...   ", "F - test-cursor-down-and-up-within-trace/down-2"
     935   check-background-color-in-screen-row screen, 7/bg=cursor, 2/y, "      ", "F - test-cursor-down-and-up-within-trace/down-2/cursor"
     936   # cursor up
     937   edit-trace t, 0x6b/k
     938   var y/ecx: int <- render-trace screen, t, 0/xmin, 0/ymin, 0xa/xmax, 4/ymax, 1/show-cursor
     939   #
     940   check-screen-row screen,                                  0/y, "...   ", "F - test-cursor-down-and-up-within-trace/up-0"
     941   check-background-color-in-screen-row screen, 7/bg=cursor, 0/y, "|||   ", "F - test-cursor-down-and-up-within-trace/up-0/cursor"
     942   check-screen-row screen,                                  1/y, "error ", "F - test-cursor-down-and-up-within-trace/up-1"
     943   check-background-color-in-screen-row screen, 7/bg=cursor, 1/y, "      ", "F - test-cursor-down-and-up-within-trace/up-1/cursor"
     944   check-screen-row screen,                                  2/y, "...   ", "F - test-cursor-down-and-up-within-trace/up-2"
     945   check-background-color-in-screen-row screen, 7/bg=cursor, 2/y, "      ", "F - test-cursor-down-and-up-within-trace/up-2/cursor"
     946 }
     947
     948 fn test-cursor-down-past-bottom-of-trace {
     949   var t-storage: trace
     950   var t/esi: (addr trace) <- address t-storage
     951   initialize-trace t, 0x10, 0x10
     952   #
     953   trace-text t, "l", "line 1"
     954   error t, "error"
     955   trace-text t, "l", "line 3"
     956   # setup: screen
     957   var screen-on-stack: screen
     958   var screen/edi: (addr screen) <- address screen-on-stack
     959   initialize-screen screen, 0xa/width, 4/height, 0/no-pixel-graphics
     960   #
     961   var y/ecx: int <- render-trace screen, t, 0/xmin, 0/ymin, 0xa/xmax, 4/ymax, 1/show-cursor
     962   #
     963   check-screen-row screen,                                  0/y, "...   ", "F - test-cursor-down-past-bottom-of-trace/pre-0"
     964   check-background-color-in-screen-row screen, 7/bg=cursor, 0/y, "|||   ", "F - test-cursor-down-past-bottom-of-trace/pre-0/cursor"
     965   check-screen-row screen,                                  1/y, "error ", "F - test-cursor-down-past-bottom-of-trace/pre-1"
     966   check-background-color-in-screen-row screen, 7/bg=cursor, 1/y, "      ", "F - test-cursor-down-past-bottom-of-trace/pre-1/cursor"
     967   check-screen-row screen,                                  2/y, "...   ", "F - test-cursor-down-past-bottom-of-trace/pre-2"
     968   check-background-color-in-screen-row screen, 7/bg=cursor, 2/y, "      ", "F - test-cursor-down-past-bottom-of-trace/pre-2/cursor"
     969   # cursor down several times
     970   edit-trace t, 0x6a/j
     971   edit-trace t, 0x6a/j
     972   edit-trace t, 0x6a/j
     973   edit-trace t, 0x6a/j
     974   edit-trace t, 0x6a/j
     975   # hack: we do need to render to make this test pass; we're mixing state management with rendering
     976   var y/ecx: int <- render-trace screen, t, 0/xmin, 0/ymin, 0xa/xmax, 4/ymax, 1/show-cursor
     977   # cursor clamps at bottom
     978   check-screen-row screen,                                  0/y, "...   ", "F - test-cursor-down-past-bottom-of-trace/down-0"
     979   check-background-color-in-screen-row screen, 7/bg=cursor, 0/y, "      ", "F - test-cursor-down-past-bottom-of-trace/down-0/cursor"
     980   check-screen-row screen,                                  1/y, "error ", "F - test-cursor-down-past-bottom-of-trace/down-1"
     981   check-background-color-in-screen-row screen, 7/bg=cursor, 1/y, "      ", "F - test-cursor-down-past-bottom-of-trace/down-1/cursor"
     982   check-screen-row screen,                                  2/y, "...   ", "F - test-cursor-down-past-bottom-of-trace/down-2"
     983   check-background-color-in-screen-row screen, 7/bg=cursor, 2/y, "|||   ", "F - test-cursor-down-past-bottom-of-trace/down-2/cursor"
     984 }
     985
     986 fn test-expand-within-trace {
     987   var t-storage: trace
     988   var t/esi: (addr trace) <- address t-storage
     989   initialize-trace t, 0x10, 0x10
     990   #
     991   trace-text t, "l", "line 1"
     992   trace-text t, "l", "line 2"
     993   # setup: screen
     994   var screen-on-stack: screen
     995   var screen/edi: (addr screen) <- address screen-on-stack
     996   initialize-screen screen, 0x10/width, 4/height, 0/no-pixel-graphics
     997   #
     998   var y/ecx: int <- render-trace screen, t, 0/xmin, 0/ymin, 0x10/xmax, 4/ymax, 1/show-cursor
     999   #
    1000   check-screen-row screen,                                  0/y, "...      ", "F - test-expand-within-trace/pre-0"
    1001   check-background-color-in-screen-row screen, 7/bg=cursor, 0/y, "|||      ", "F - test-expand-within-trace/pre-0/cursor"
    1002   check-screen-row screen,                                  1/y, "         ", "F - test-expand-within-trace/pre-1"
    1003   check-background-color-in-screen-row screen, 7/bg=cursor, 1/y, "         ", "F - test-expand-within-trace/pre-1/cursor"
    1004   # expand
    1005   edit-trace t, 0xa/enter
    1006   var y/ecx: int <- render-trace screen, t, 0/xmin, 0/ymin, 0x10/xmax, 4/ymax, 1/show-cursor
    1007   #
    1008   check-screen-row screen,                                  0/y, "0 line 1 ", "F - test-expand-within-trace/expand-0"
    1009   check-background-color-in-screen-row screen, 7/bg=cursor, 0/y, "|||||||| ", "F - test-expand-within-trace/expand-0/cursor"
    1010   check-screen-row screen,                                  1/y, "0 line 2 ", "F - test-expand-within-trace/expand-1"
    1011   check-background-color-in-screen-row screen, 7/bg=cursor, 1/y, "         ", "F - test-expand-within-trace/expand-1/cursor"
    1012   check-screen-row screen,                                  2/y, "         ", "F - test-expand-within-trace/expand-2"
    1013   check-background-color-in-screen-row screen, 7/bg=cursor, 2/y, "         ", "F - test-expand-within-trace/expand-2/cursor"
    1014 }
    1015
    1016 fn test-trace-expand-skips-lower-depth {
    1017   var t-storage: trace
    1018   var t/esi: (addr trace) <- address t-storage
    1019   initialize-trace t, 0x10, 0x10
    1020   #
    1021   trace-text t, "l", "line 1"
    1022   trace-lower t
    1023   trace-text t, "l", "line 2"
    1024   # setup: screen
    1025   var screen-on-stack: screen
    1026   var screen/edi: (addr screen) <- address screen-on-stack
    1027   initialize-screen screen, 0x10/width, 4/height, 0/no-pixel-graphics
    1028   #
    1029   var y/ecx: int <- render-trace screen, t, 0/xmin, 0/ymin, 0x10/xmax, 4/ymax, 1/show-cursor
    1030   #
    1031   check-screen-row screen,                                  0/y, "...      ", "F - test-trace-expand-skips-lower-depth/pre-0"
    1032   check-background-color-in-screen-row screen, 7/bg=cursor, 0/y, "|||      ", "F - test-trace-expand-skips-lower-depth/pre-0/cursor"
    1033   check-screen-row screen,                                  1/y, "         ", "F - test-trace-expand-skips-lower-depth/pre-1"
    1034   check-background-color-in-screen-row screen, 7/bg=cursor, 1/y, "         ", "F - test-trace-expand-skips-lower-depth/pre-1/cursor"
    1035   # expand
    1036   edit-trace t, 0xa/enter
    1037   var y/ecx: int <- render-trace screen, t, 0/xmin, 0/ymin, 0x10/xmax, 4/ymax, 1/show-cursor
    1038   #
    1039   check-screen-row screen,                                  0/y, "0 line 1 ", "F - test-trace-expand-skips-lower-depth/expand-0"
    1040   check-background-color-in-screen-row screen, 7/bg=cursor, 0/y, "|||||||| ", "F - test-trace-expand-skips-lower-depth/expand-0/cursor"
    1041   check-screen-row screen,                                  1/y, "...      ", "F - test-trace-expand-skips-lower-depth/expand-1"
    1042   check-background-color-in-screen-row screen, 7/bg=cursor, 1/y, "         ", "F - test-trace-expand-skips-lower-depth/expand-1/cursor"
    1043   check-screen-row screen,                                  2/y, "         ", "F - test-trace-expand-skips-lower-depth/expand-2"
    1044   check-background-color-in-screen-row screen, 7/bg=cursor, 2/y, "         ", "F - test-trace-expand-skips-lower-depth/expand-2/cursor"
    1045 }
    1046
    1047 fn test-trace-expand-continues-past-lower-depth {
    1048   var t-storage: trace
    1049   var t/esi: (addr trace) <- address t-storage
    1050   initialize-trace t, 0x10, 0x10
    1051   #
    1052   trace-text t, "l", "line 1"
    1053   trace-lower t
    1054   trace-text t, "l", "line 1.1"
    1055   trace-higher t
    1056   trace-text t, "l", "line 2"
    1057   # setup: screen
    1058   var screen-on-stack: screen
    1059   var screen/edi: (addr screen) <- address screen-on-stack
    1060   initialize-screen screen, 0x10/width, 4/height, 0/no-pixel-graphics
    1061   #
    1062   var y/ecx: int <- render-trace screen, t, 0/xmin, 0/ymin, 0x10/xmax, 4/ymax, 1/show-cursor
    1063   #
    1064   check-screen-row screen,                                  0/y, "...      ", "F - test-trace-expand-continues-past-lower-depth/pre-0"
    1065   check-background-color-in-screen-row screen, 7/bg=cursor, 0/y, "|||      ", "F - test-trace-expand-continues-past-lower-depth/pre-0/cursor"
    1066   check-screen-row screen,                                  1/y, "         ", "F - test-trace-expand-continues-past-lower-depth/pre-1"
    1067   check-background-color-in-screen-row screen, 7/bg=cursor, 1/y, "         ", "F - test-trace-expand-continues-past-lower-depth/pre-1/cursor"
    1068   # expand
    1069   edit-trace t, 0xa/enter
    1070   var y/ecx: int <- render-trace screen, t, 0/xmin, 0/ymin, 0x10/xmax, 4/ymax, 1/show-cursor
    1071   #
    1072   check-screen-row screen,                                  0/y, "0 line 1 ", "F - test-trace-expand-continues-past-lower-depth/expand-0"
    1073   check-background-color-in-screen-row screen, 7/bg=cursor, 0/y, "|||||||| ", "F - test-trace-expand-continues-past-lower-depth/expand-0/cursor"
    1074   # TODO: might be too wasteful to show every place where lines are hidden
    1075   check-screen-row screen,                                  1/y, "...      ", "F - test-trace-expand-continues-past-lower-depth/expand-1"
    1076   check-background-color-in-screen-row screen, 7/bg=cursor, 1/y, "         ", "F - test-trace-expand-continues-past-lower-depth/expand-1/cursor"
    1077   check-screen-row screen,                                  2/y, "0 line 2 ", "F - test-trace-expand-continues-past-lower-depth/expand-2"
    1078   check-background-color-in-screen-row screen, 7/bg=cursor, 2/y, "         ", "F - test-trace-expand-continues-past-lower-depth/expand-2/cursor"
    1079 }
    1080
    1081 fn test-trace-expand-stops-at-higher-depth {
    1082   var t-storage: trace
    1083   var t/esi: (addr trace) <- address t-storage
    1084   initialize-trace t, 0x10, 0x10
    1085   #
    1086   trace-text t, "l", "line 1.1"
    1087   trace-lower t
    1088   trace-text t, "l", "line 1.1.1"
    1089   trace-higher t
    1090   trace-text t, "l", "line 1.2"
    1091   trace-higher t
    1092   trace-text t, "l", "line 2"
    1093   trace-lower t
    1094   trace-text t, "l", "line 2.1"
    1095   # setup: screen
    1096   var screen-on-stack: screen
    1097   var screen/edi: (addr screen) <- address screen-on-stack
    1098   initialize-screen screen, 0x10/width, 8/height, 0/no-pixel-graphics
    1099   #
    1100   var y/ecx: int <- render-trace screen, t, 0/xmin, 0/ymin, 0x10/xmax, 8/ymax, 1/show-cursor
    1101   #
    1102   check-screen-row screen,                                  0/y, "...        ", "F - test-trace-expand-stops-at-higher-depth/pre-0"
    1103   check-background-color-in-screen-row screen, 7/bg=cursor, 0/y, "|||        ", "F - test-trace-expand-stops-at-higher-depth/pre-0/cursor"
    1104   check-screen-row screen,                                  1/y, "           ", "F - test-trace-expand-stops-at-higher-depth/pre-1"
    1105   check-background-color-in-screen-row screen, 7/bg=cursor, 1/y, "           ", "F - test-trace-expand-stops-at-higher-depth/pre-1/cursor"
    1106   # expand
    1107   edit-trace t, 0xa/enter
    1108   var y/ecx: int <- render-trace screen, t, 0/xmin, 0/ymin, 0x10/xmax, 8/ymax, 1/show-cursor
    1109   #
    1110   check-screen-row screen,                                  0/y, "0 line 1.1 ", "F - test-trace-expand-stops-at-higher-depth/expand-0"
    1111   check-background-color-in-screen-row screen, 7/bg=cursor, 0/y, "|||||||||| ", "F - test-trace-expand-stops-at-higher-depth/expand-0/cursor"
    1112   check-screen-row screen,                                  1/y, "...        ", "F - test-trace-expand-stops-at-higher-depth/expand-1"
    1113   check-background-color-in-screen-row screen, 7/bg=cursor, 1/y, "           ", "F - test-trace-expand-stops-at-higher-depth/expand-1/cursor"
    1114   check-screen-row screen,                                  2/y, "0 line 1.2 ", "F - test-trace-expand-stops-at-higher-depth/expand-2"
    1115   check-background-color-in-screen-row screen, 7/bg=cursor, 2/y, "           ", "F - test-trace-expand-stops-at-higher-depth/expand-2/cursor"
    1116   check-screen-row screen,                                  3/y, "...        ", "F - test-trace-expand-stops-at-higher-depth/expand-3"
    1117   check-background-color-in-screen-row screen, 7/bg=cursor, 3/y, "           ", "F - test-trace-expand-stops-at-higher-depth/expand-3/cursor"
    1118   check-screen-row screen,                                  4/y, "           ", "F - test-trace-expand-stops-at-higher-depth/expand-4"
    1119   check-background-color-in-screen-row screen, 7/bg=cursor, 4/y, "           ", "F - test-trace-expand-stops-at-higher-depth/expand-4/cursor"
    1120 }
    1121
    1122 fn test-trace-expand-twice {
    1123   var t-storage: trace
    1124   var t/esi: (addr trace) <- address t-storage
    1125   initialize-trace t, 0x10, 0x10
    1126   #
    1127   trace-text t, "l", "line 1"
    1128   trace-lower t
    1129   trace-text t, "l", "line 1.1"
    1130   trace-higher t
    1131   trace-text t, "l", "line 2"
    1132   # setup: screen
    1133   var screen-on-stack: screen
    1134   var screen/edi: (addr screen) <- address screen-on-stack
    1135   initialize-screen screen, 0x10/width, 4/height, 0/no-pixel-graphics
    1136   #
    1137   var y/ecx: int <- render-trace screen, t, 0/xmin, 0/ymin, 0x10/xmax, 4/ymax, 1/show-cursor
    1138   #
    1139   check-screen-row screen,                                  0/y, "...        ", "F - test-trace-expand-twice/pre-0"
    1140   check-background-color-in-screen-row screen, 7/bg=cursor, 0/y, "|||        ", "F - test-trace-expand-twice/pre-0/cursor"
    1141   check-screen-row screen,                                  1/y, "           ", "F - test-trace-expand-twice/pre-1"
    1142   check-background-color-in-screen-row screen, 7/bg=cursor, 1/y, "           ", "F - test-trace-expand-twice/pre-1/cursor"
    1143   # expand
    1144   edit-trace t, 0xa/enter
    1145   var y/ecx: int <- render-trace screen, t, 0/xmin, 0/ymin, 0x10/xmax, 4/ymax, 1/show-cursor
    1146   #
    1147   check-screen-row screen,                                  0/y, "0 line 1   ", "F - test-trace-expand-twice/expand-0"
    1148   check-background-color-in-screen-row screen, 7/bg=cursor, 0/y, "||||||||   ", "F - test-trace-expand-twice/expand-0/cursor"
    1149   check-screen-row screen,                                  1/y, "...        ", "F - test-trace-expand-twice/expand-1"
    1150   check-background-color-in-screen-row screen, 7/bg=cursor, 1/y, "           ", "F - test-trace-expand-twice/expand-1/cursor"
    1151   check-screen-row screen,                                  2/y, "0 line 2   ", "F - test-trace-expand-twice/expand-2"
    1152   check-background-color-in-screen-row screen, 7/bg=cursor, 2/y, "           ", "F - test-trace-expand-twice/expand-2/cursor"
    1153   # cursor down
    1154   edit-trace t, 0x6a/j
    1155   # hack: we need to render here to make this test pass; we're mixing state management with rendering
    1156   var y/ecx: int <- render-trace screen, t, 0/xmin, 0/ymin, 0x10/xmax, 4/ymax, 1/show-cursor
    1157   #
    1158   check-screen-row screen,                                  0/y, "0 line 1   ", "F - test-trace-expand-twice/down-0"
    1159   check-background-color-in-screen-row screen, 7/bg=cursor, 0/y, "           ", "F - test-trace-expand-twice/down-0/cursor"
    1160   check-screen-row screen,                                  1/y, "...        ", "F - test-trace-expand-twice/down-1"
    1161   check-background-color-in-screen-row screen, 7/bg=cursor, 1/y, "|||        ", "F - test-trace-expand-twice/down-1/cursor"
    1162   check-screen-row screen,                                  2/y, "0 line 2   ", "F - test-trace-expand-twice/down-2"
    1163   check-background-color-in-screen-row screen, 7/bg=cursor, 2/y, "           ", "F - test-trace-expand-twice/down-2/cursor"
    1164   # expand again
    1165   edit-trace t, 0xa/enter
    1166   var y/ecx: int <- render-trace screen, t, 0/xmin, 0/ymin, 0x10/xmax, 4/ymax, 1/show-cursor
    1167   #
    1168   check-screen-row screen,                                  0/y, "0 line 1   ", "F - test-trace-expand-twice/expand2-0"
    1169   check-background-color-in-screen-row screen, 7/bg=cursor, 0/y, "           ", "F - test-trace-expand-twice/expand2-0/cursor"
    1170   check-screen-row screen,                                  1/y, "1 line 1.1 ", "F - test-trace-expand-twice/expand2-1"
    1171   check-background-color-in-screen-row screen, 7/bg=cursor, 1/y, "|||||||||| ", "F - test-trace-expand-twice/expand2-1/cursor"
    1172   check-screen-row screen,                                  2/y, "0 line 2   ", "F - test-trace-expand-twice/expand2-2"
    1173   check-background-color-in-screen-row screen, 7/bg=cursor, 2/y, "           ", "F - test-trace-expand-twice/expand2-2/cursor"
    1174 }
    1175
    1176 fn test-trace-refresh-cursor {
    1177   var t-storage: trace
    1178   var t/esi: (addr trace) <- address t-storage
    1179   initialize-trace t, 0x10, 0x10
    1180   #
    1181   trace-text t, "l", "line 1"
    1182   trace-text t, "l", "line 2"
    1183   trace-text t, "l", "line 3"
    1184   # setup: screen
    1185   var screen-on-stack: screen
    1186   var screen/edi: (addr screen) <- address screen-on-stack
    1187   initialize-screen screen, 0x10/width, 4/height, 0/no-pixel-graphics
    1188   #
    1189   var y/ecx: int <- render-trace screen, t, 0/xmin, 0/ymin, 0x10/xmax, 4/ymax, 1/show-cursor
    1190   #
    1191   check-screen-row screen,                                  0/y, "...        ", "F - test-trace-refresh-cursor/pre-0"
    1192   check-background-color-in-screen-row screen, 7/bg=cursor, 0/y, "|||        ", "F - test-trace-refresh-cursor/pre-0/cursor"
    1193   check-screen-row screen,                                  1/y, "           ", "F - test-trace-refresh-cursor/pre-1"
    1194   check-background-color-in-screen-row screen, 7/bg=cursor, 1/y, "           ", "F - test-trace-refresh-cursor/pre-1/cursor"
    1195   # expand
    1196   edit-trace t, 0xa/enter
    1197   var y/ecx: int <- render-trace screen, t, 0/xmin, 0/ymin, 0x10/xmax, 4/ymax, 1/show-cursor
    1198   #
    1199   check-screen-row screen,                                  0/y, "0 line 1   ", "F - test-trace-refresh-cursor/expand-0"
    1200   check-background-color-in-screen-row screen, 7/bg=cursor, 0/y, "||||||||   ", "F - test-trace-refresh-cursor/expand-0/cursor"
    1201   check-screen-row screen,                                  1/y, "0 line 2   ", "F - test-trace-refresh-cursor/expand-1"
    1202   check-background-color-in-screen-row screen, 7/bg=cursor, 1/y, "           ", "F - test-trace-refresh-cursor/expand-1/cursor"
    1203   check-screen-row screen,                                  2/y, "0 line 3   ", "F - test-trace-refresh-cursor/expand-2"
    1204   check-background-color-in-screen-row screen, 7/bg=cursor, 2/y, "           ", "F - test-trace-refresh-cursor/expand-2/cursor"
    1205   # cursor down
    1206   edit-trace t, 0x6a/j
    1207   edit-trace t, 0x6a/j
    1208   var y/ecx: int <- render-trace screen, t, 0/xmin, 0/ymin, 0x10/xmax, 4/ymax, 1/show-cursor
    1209   #
    1210   check-screen-row screen,                                  0/y, "0 line 1   ", "F - test-trace-refresh-cursor/down-0"
    1211   check-background-color-in-screen-row screen, 7/bg=cursor, 0/y, "           ", "F - test-trace-refresh-cursor/down-0/cursor"
    1212   check-screen-row screen,                                  1/y, "0 line 2   ", "F - test-trace-refresh-cursor/down-1"
    1213   check-background-color-in-screen-row screen, 7/bg=cursor, 1/y, "           ", "F - test-trace-refresh-cursor/down-1/cursor"
    1214   check-screen-row screen,                                  2/y, "0 line 3   ", "F - test-trace-refresh-cursor/down-2"
    1215   check-background-color-in-screen-row screen, 7/bg=cursor, 2/y, "||||||||   ", "F - test-trace-refresh-cursor/down-2/cursor"
    1216   # recreate trace
    1217   clear-trace t
    1218   trace-text t, "l", "line 1"
    1219   trace-text t, "l", "line 2"
    1220   trace-text t, "l", "line 3"
    1221   var y/ecx: int <- render-trace screen, t, 0/xmin, 0/ymin, 0x10/xmax, 4/ymax, 1/show-cursor
    1222   # cursor remains unchanged
    1223   check-screen-row screen,                                  0/y, "0 line 1   ", "F - test-trace-refresh-cursor/refresh-0"
    1224   check-background-color-in-screen-row screen, 7/bg=cursor, 0/y, "           ", "F - test-trace-refresh-cursor/refresh-0/cursor"
    1225   check-screen-row screen,                                  1/y, "0 line 2   ", "F - test-trace-refresh-cursor/refresh-1"
    1226   check-background-color-in-screen-row screen, 7/bg=cursor, 1/y, "           ", "F - test-trace-refresh-cursor/refresh-1/cursor"
    1227   check-screen-row screen,                                  2/y, "0 line 3   ", "F - test-trace-refresh-cursor/refresh-2"
    1228   check-background-color-in-screen-row screen, 7/bg=cursor, 2/y, "||||||||   ", "F - test-trace-refresh-cursor/refresh-2/cursor"
    1229 }
    1230
    1231 fn test-trace-preserve-cursor-on-refresh {
    1232   var t-storage: trace
    1233   var t/esi: (addr trace) <- address t-storage
    1234   initialize-trace t, 0x10, 0x10
    1235   #
    1236   trace-text t, "l", "line 1"
    1237   trace-text t, "l", "line 2"
    1238   trace-text t, "l", "line 3"
    1239   # setup: screen
    1240   var screen-on-stack: screen
    1241   var screen/edi: (addr screen) <- address screen-on-stack
    1242   initialize-screen screen, 0x10/width, 4/height, 0/no-pixel-graphics
    1243   #
    1244   var y/ecx: int <- render-trace screen, t, 0/xmin, 0/ymin, 0x10/xmax, 4/ymax, 1/show-cursor
    1245   #
    1246   check-screen-row screen,                                  0/y, "...        ", "F - test-trace-preserve-cursor-on-refresh/pre-0"
    1247   check-background-color-in-screen-row screen, 7/bg=cursor, 0/y, "|||        ", "F - test-trace-preserve-cursor-on-refresh/pre-0/cursor"
    1248   check-screen-row screen,                                  1/y, "           ", "F - test-trace-preserve-cursor-on-refresh/pre-1"
    1249   check-background-color-in-screen-row screen, 7/bg=cursor, 1/y, "           ", "F - test-trace-preserve-cursor-on-refresh/pre-1/cursor"
    1250   # expand
    1251   edit-trace t, 0xa/enter
    1252   var y/ecx: int <- render-trace screen, t, 0/xmin, 0/ymin, 0x10/xmax, 4/ymax, 1/show-cursor
    1253   #
    1254   check-screen-row screen,                                  0/y, "0 line 1   ", "F - test-trace-preserve-cursor-on-refresh/expand-0"
    1255   check-background-color-in-screen-row screen, 7/bg=cursor, 0/y, "||||||||   ", "F - test-trace-preserve-cursor-on-refresh/expand-0/cursor"
    1256   check-screen-row screen,                                  1/y, "0 line 2   ", "F - test-trace-preserve-cursor-on-refresh/expand-1"
    1257   check-background-color-in-screen-row screen, 7/bg=cursor, 1/y, "           ", "F - test-trace-preserve-cursor-on-refresh/expand-1/cursor"
    1258   check-screen-row screen,                                  2/y, "0 line 3   ", "F - test-trace-preserve-cursor-on-refresh/expand-2"
    1259   check-background-color-in-screen-row screen, 7/bg=cursor, 2/y, "              ", "F - test-trace-preserve-cursor-on-refresh/expand-2/cursor"
    1260   # cursor down
    1261   edit-trace t, 0x6a/j
    1262   edit-trace t, 0x6a/j
    1263   var y/ecx: int <- render-trace screen, t, 0/xmin, 0/ymin, 0x10/xmax, 4/ymax, 1/show-cursor
    1264   #
    1265   check-screen-row screen,                                  0/y, "0 line 1   ", "F - test-trace-preserve-cursor-on-refresh/down-0"
    1266   check-background-color-in-screen-row screen, 7/bg=cursor, 0/y, "           ", "F - test-trace-preserve-cursor-on-refresh/down-0/cursor"
    1267   check-screen-row screen,                                  1/y, "0 line 2   ", "F - test-trace-preserve-cursor-on-refresh/down-1"
    1268   check-background-color-in-screen-row screen, 7/bg=cursor, 1/y, "           ", "F - test-trace-preserve-cursor-on-refresh/down-1/cursor"
    1269   check-screen-row screen,                                  2/y, "0 line 3   ", "F - test-trace-preserve-cursor-on-refresh/down-2"
    1270   check-background-color-in-screen-row screen, 7/bg=cursor, 2/y, "||||||||   ", "F - test-trace-preserve-cursor-on-refresh/down-2/cursor"
    1271   # recreate trace with slightly different lines
    1272   clear-trace t
    1273   trace-text t, "l", "line 4"
    1274   trace-text t, "l", "line 5"
    1275   trace-text t, "l", "line 3"  # cursor line is unchanged
    1276   var y/ecx: int <- render-trace screen, t, 0/xmin, 0/ymin, 0x10/xmax, 4/ymax, 1/show-cursor
    1277   # cursor remains unchanged
    1278   check-screen-row screen,                                  0/y, "0 line 4   ", "F - test-trace-preserve-cursor-on-refresh/refresh-0"
    1279   check-background-color-in-screen-row screen, 7/bg=cursor, 0/y, "           ", "F - test-trace-preserve-cursor-on-refresh/refresh-0/cursor"
    1280   check-screen-row screen,                                  1/y, "0 line 5   ", "F - test-trace-preserve-cursor-on-refresh/refresh-1"
    1281   check-background-color-in-screen-row screen, 7/bg=cursor, 1/y, "           ", "F - test-trace-preserve-cursor-on-refresh/refresh-1/cursor"
    1282   check-screen-row screen,                                  2/y, "0 line 3   ", "F - test-trace-preserve-cursor-on-refresh/refresh-2"
    1283   check-background-color-in-screen-row screen, 7/bg=cursor, 2/y, "||||||||   ", "F - test-trace-preserve-cursor-on-refresh/refresh-2/cursor"
    1284 }
    1285
    1286 fn test-trace-keep-cursor-visible-on-refresh {
    1287   var t-storage: trace
    1288   var t/esi: (addr trace) <- address t-storage
    1289   initialize-trace t, 0x10, 0x10
    1290   #
    1291   trace-text t, "l", "line 1"
    1292   trace-text t, "l", "line 2"
    1293   trace-text t, "l", "line 3"
    1294   # setup: screen
    1295   var screen-on-stack: screen
    1296   var screen/edi: (addr screen) <- address screen-on-stack
    1297   initialize-screen screen, 0x10/width, 4/height, 0/no-pixel-graphics
    1298   #
    1299   var y/ecx: int <- render-trace screen, t, 0/xmin, 0/ymin, 0x10/xmax, 4/ymax, 1/show-cursor
    1300   #
    1301   check-screen-row screen,                                  0/y, "...        ", "F - test-trace-keep-cursor-visible-on-refresh/pre-0"
    1302   check-background-color-in-screen-row screen, 7/bg=cursor, 0/y, "|||        ", "F - test-trace-keep-cursor-visible-on-refresh/pre-0/cursor"
    1303   check-screen-row screen,                                  1/y, "           ", "F - test-trace-keep-cursor-visible-on-refresh/pre-1"
    1304   check-background-color-in-screen-row screen, 7/bg=cursor, 1/y, "           ", "F - test-trace-keep-cursor-visible-on-refresh/pre-1/cursor"
    1305   # expand
    1306   edit-trace t, 0xa/enter
    1307   var y/ecx: int <- render-trace screen, t, 0/xmin, 0/ymin, 0x10/xmax, 4/ymax, 1/show-cursor
    1308   #
    1309   check-screen-row screen,                                  0/y, "0 line 1   ", "F - test-trace-keep-cursor-visible-on-refresh/expand-0"
    1310   check-background-color-in-screen-row screen, 7/bg=cursor, 0/y, "||||||||   ", "F - test-trace-keep-cursor-visible-on-refresh/expand-0/cursor"
    1311   check-screen-row screen,                                  1/y, "0 line 2   ", "F - test-trace-keep-cursor-visible-on-refresh/expand-1"
    1312   check-background-color-in-screen-row screen, 7/bg=cursor, 1/y, "           ", "F - test-trace-keep-cursor-visible-on-refresh/expand-1/cursor"
    1313   check-screen-row screen,                                  2/y, "0 line 3   ", "F - test-trace-keep-cursor-visible-on-refresh/expand-2"
    1314   check-background-color-in-screen-row screen, 7/bg=cursor, 2/y, "              ", "F - test-trace-keep-cursor-visible-on-refresh/expand-2/cursor"
    1315   # cursor down
    1316   edit-trace t, 0x6a/j
    1317   edit-trace t, 0x6a/j
    1318   var y/ecx: int <- render-trace screen, t, 0/xmin, 0/ymin, 0x10/xmax, 4/ymax, 1/show-cursor
    1319   #
    1320   check-screen-row screen,                                  0/y, "0 line 1   ", "F - test-trace-keep-cursor-visible-on-refresh/down-0"
    1321   check-background-color-in-screen-row screen, 7/bg=cursor, 0/y, "           ", "F - test-trace-keep-cursor-visible-on-refresh/down-0/cursor"
    1322   check-screen-row screen,                                  1/y, "0 line 2   ", "F - test-trace-keep-cursor-visible-on-refresh/down-1"
    1323   check-background-color-in-screen-row screen, 7/bg=cursor, 1/y, "           ", "F - test-trace-keep-cursor-visible-on-refresh/down-1/cursor"
    1324   check-screen-row screen,                                  2/y, "0 line 3   ", "F - test-trace-keep-cursor-visible-on-refresh/down-2"
    1325   check-background-color-in-screen-row screen, 7/bg=cursor, 2/y, "||||||||   ", "F - test-trace-keep-cursor-visible-on-refresh/down-2/cursor"
    1326   # recreate trace with entirely different lines
    1327   clear-trace t
    1328   trace-text t, "l", "line 4"
    1329   trace-text t, "l", "line 5"
    1330   trace-text t, "l", "line 6"
    1331   mark-lines-dirty t
    1332   clear-screen screen
    1333   var y/ecx: int <- render-trace screen, t, 0/xmin, 0/ymin, 0x10/xmax, 4/ymax, 1/show-cursor
    1334   # trace collapses, and cursor bumps up
    1335   check-screen-row screen,                                  0/y, "...        ", "F - test-trace-keep-cursor-visible-on-refresh/refresh-0"
    1336   check-background-color-in-screen-row screen, 7/bg=cursor, 0/y, "|||        ", "F - test-trace-keep-cursor-visible-on-refresh/refresh-0/cursor"
    1337   check-screen-row screen,                                  1/y, "           ", "F - test-trace-keep-cursor-visible-on-refresh/refresh-1"
    1338   check-background-color-in-screen-row screen, 7/bg=cursor, 1/y, "           ", "F - test-trace-keep-cursor-visible-on-refresh/refresh-1/cursor"
    1339   check-screen-row screen,                                  2/y, "           ", "F - test-trace-keep-cursor-visible-on-refresh/refresh-2"
    1340   check-background-color-in-screen-row screen, 7/bg=cursor, 2/y, "           ", "F - test-trace-keep-cursor-visible-on-refresh/refresh-2/cursor"
    1341 }
    1342
    1343 fn test-trace-collapse-at-top {
    1344   var t-storage: trace
    1345   var t/esi: (addr trace) <- address t-storage
    1346   initialize-trace t, 0x10, 0x10
    1347   #
    1348   trace-text t, "l", "line 1"
    1349   trace-lower t
    1350   trace-text t, "l", "line 1.1"
    1351   trace-higher t
    1352   trace-text t, "l", "line 2"
    1353   # setup: screen
    1354   var screen-on-stack: screen
    1355   var screen/edi: (addr screen) <- address screen-on-stack
    1356   initialize-screen screen, 0x10/width, 4/height, 0/no-pixel-graphics
    1357   #
    1358   var y/ecx: int <- render-trace screen, t, 0/xmin, 0/ymin, 0x10/xmax, 4/ymax, 1/show-cursor
    1359   #
    1360   check-screen-row screen,                                  0/y, "...        ", "F - test-trace-collapse-at-top/pre-0"
    1361   check-background-color-in-screen-row screen, 7/bg=cursor, 0/y, "|||        ", "F - test-trace-collapse-at-top/pre-0/cursor"
    1362   check-screen-row screen,                                  1/y, "           ", "F - test-trace-collapse-at-top/pre-1"
    1363   check-background-color-in-screen-row screen, 7/bg=cursor, 1/y, "           ", "F - test-trace-collapse-at-top/pre-1/cursor"
    1364   # expand
    1365   edit-trace t, 0xa/enter
    1366   var y/ecx: int <- render-trace screen, t, 0/xmin, 0/ymin, 0x10/xmax, 4/ymax, 1/show-cursor
    1367   #
    1368   check-screen-row screen,                                  0/y, "0 line 1   ", "F - test-trace-collapse-at-top/expand-0"
    1369   check-background-color-in-screen-row screen, 7/bg=cursor, 0/y, "||||||||   ", "F - test-trace-collapse-at-top/expand-0/cursor"
    1370   check-screen-row screen,                                  1/y, "...        ", "F - test-trace-collapse-at-top/expand-1"
    1371   check-background-color-in-screen-row screen, 7/bg=cursor, 1/y, "           ", "F - test-trace-collapse-at-top/expand-1/cursor"
    1372   check-screen-row screen,                                  2/y, "0 line 2   ", "F - test-trace-collapse-at-top/expand-2"
    1373   check-background-color-in-screen-row screen, 7/bg=cursor, 2/y, "           ", "F - test-trace-collapse-at-top/expand-2/cursor"
    1374   # collapse
    1375   edit-trace t, 8/backspace
    1376   # hack: we need to render here to make this test pass; we're mixing state management with rendering
    1377   clear-screen screen
    1378   var y/ecx: int <- render-trace screen, t, 0/xmin, 0/ymin, 0x10/xmax, 4/ymax, 1/show-cursor
    1379   #
    1380   check-ints-equal y, 1, "F - test-trace-collapse-at-top/post-0/y"
    1381   check-screen-row screen,                                  0/y, "...        ", "F - test-trace-collapse-at-top/post-0"
    1382   check-background-color-in-screen-row screen, 7/bg=cursor, 0/y, "|||        ", "F - test-trace-collapse-at-top/post-0/cursor"
    1383   check-screen-row screen,                                  1/y, "           ", "F - test-trace-collapse-at-top/post-1"
    1384   check-background-color-in-screen-row screen, 7/bg=cursor, 1/y, "           ", "F - test-trace-collapse-at-top/post-1/cursor"
    1385 }
    1386
    1387 fn test-trace-collapse {
    1388   var t-storage: trace
    1389   var t/esi: (addr trace) <- address t-storage
    1390   initialize-trace t, 0x10, 0x10
    1391   #
    1392   trace-text t, "l", "line 1"
    1393   trace-text t, "l", "line 2"
    1394   # setup: screen
    1395   var screen-on-stack: screen
    1396   var screen/edi: (addr screen) <- address screen-on-stack
    1397   initialize-screen screen, 0x10/width, 4/height, 0/no-pixel-graphics
    1398   #
    1399   var y/ecx: int <- render-trace screen, t, 0/xmin, 0/ymin, 0x10/xmax, 4/ymax, 1/show-cursor
    1400   #
    1401   check-screen-row screen,                                  0/y, "...        ", "F - test-trace-collapse/pre-0"
    1402   check-background-color-in-screen-row screen, 7/bg=cursor, 0/y, "|||        ", "F - test-trace-collapse/pre-0/cursor"
    1403   check-screen-row screen,                                  1/y, "           ", "F - test-trace-collapse/pre-1"
    1404   check-background-color-in-screen-row screen, 7/bg=cursor, 1/y, "           ", "F - test-trace-collapse/pre-1/cursor"
    1405   # expand
    1406   edit-trace t, 0xa/enter
    1407   var y/ecx: int <- render-trace screen, t, 0/xmin, 0/ymin, 0x10/xmax, 4/ymax, 1/show-cursor
    1408   #
    1409   check-screen-row screen,                                  0/y, "0 line 1   ", "F - test-trace-collapse/expand-0"
    1410   check-background-color-in-screen-row screen, 7/bg=cursor, 0/y, "||||||||   ", "F - test-trace-collapse/expand-0/cursor"
    1411   check-screen-row screen,                                  1/y, "0 line 2   ", "F - test-trace-collapse/expand-1"
    1412   check-background-color-in-screen-row screen, 7/bg=cursor, 1/y, "           ", "F - test-trace-collapse/expand-1/cursor"
    1413   # cursor down
    1414   edit-trace t, 0x6a/j
    1415   var y/ecx: int <- render-trace screen, t, 0/xmin, 0/ymin, 0x10/xmax, 4/ymax, 1/show-cursor
    1416   # collapse
    1417   edit-trace t, 8/backspace
    1418   clear-screen screen
    1419   var y/ecx: int <- render-trace screen, t, 0/xmin, 0/ymin, 0x10/xmax, 4/ymax, 1/show-cursor
    1420   #
    1421   check-ints-equal y, 1, "F - test-trace-collapse/post-0/y"
    1422   check-screen-row screen,                                  0/y, "...        ", "F - test-trace-collapse/post-0"
    1423   check-background-color-in-screen-row screen, 7/bg=cursor, 0/y, "|||        ", "F - test-trace-collapse/post-0/cursor"
    1424   check-screen-row screen,                                  1/y, "           ", "F - test-trace-collapse/post-1"
    1425   check-background-color-in-screen-row screen, 7/bg=cursor, 1/y, "           ", "F - test-trace-collapse/post-1/cursor"
    1426 }
    1427
    1428 fn test-trace-collapse-skips-invisible-lines {
    1429   var t-storage: trace
    1430   var t/esi: (addr trace) <- address t-storage
    1431   initialize-trace t, 0x10, 0x10
    1432   #
    1433   trace-text t, "l", "line 1"
    1434   trace-lower t
    1435   trace-text t, "l", "line 1.1"
    1436   trace-higher t
    1437   trace-text t, "l", "line 2"
    1438   # setup: screen
    1439   var screen-on-stack: screen
    1440   var screen/edi: (addr screen) <- address screen-on-stack
    1441   initialize-screen screen, 0x10/width, 4/height, 0/no-pixel-graphics
    1442   #
    1443   var y/ecx: int <- render-trace screen, t, 0/xmin, 0/ymin, 0x10/xmax, 4/ymax, 1/show-cursor
    1444   #
    1445   check-screen-row screen,                                  0/y, "...        ", "F - test-trace-collapse-skips-invisible-lines/pre-0"
    1446   check-background-color-in-screen-row screen, 7/bg=cursor, 0/y, "|||        ", "F - test-trace-collapse-skips-invisible-lines/pre-0/cursor"
    1447   check-screen-row screen,                                  1/y, "           ", "F - test-trace-collapse-skips-invisible-lines/pre-1"
    1448   check-background-color-in-screen-row screen, 7/bg=cursor, 1/y, "           ", "F - test-trace-collapse-skips-invisible-lines/pre-1/cursor"
    1449   # expand
    1450   edit-trace t, 0xa/enter
    1451   var y/ecx: int <- render-trace screen, t, 0/xmin, 0/ymin, 0x10/xmax, 4/ymax, 1/show-cursor
    1452   # two visible lines with an invisible line in between
    1453   check-screen-row screen,                                  0/y, "0 line 1   ", "F - test-trace-collapse-skips-invisible-lines/expand-0"
    1454   check-background-color-in-screen-row screen, 7/bg=cursor, 0/y, "||||||||   ", "F - test-trace-collapse-skips-invisible-lines/expand-0/cursor"
    1455   check-screen-row screen,                                  1/y, "...        ", "F - test-trace-collapse-skips-invisible-lines/expand-1"
    1456   check-background-color-in-screen-row screen, 7/bg=cursor, 1/y, "           ", "F - test-trace-collapse-skips-invisible-lines/expand-1/cursor"
    1457   check-screen-row screen,                                  2/y, "0 line 2   ", "F - test-trace-collapse-skips-invisible-lines/expand-2"
    1458   check-background-color-in-screen-row screen, 7/bg=cursor, 2/y, "           ", "F - test-trace-collapse-skips-invisible-lines/expand-2/cursor"
    1459   # cursor down to second visible line
    1460   edit-trace t, 0x6a/j
    1461   var y/ecx: int <- render-trace screen, t, 0/xmin, 0/ymin, 0x10/xmax, 4/ymax, 1/show-cursor
    1462   edit-trace t, 0x6a/j
    1463   var y/ecx: int <- render-trace screen, t, 0/xmin, 0/ymin, 0x10/xmax, 4/ymax, 1/show-cursor
    1464   # collapse
    1465   edit-trace t, 8/backspace
    1466   clear-screen screen
    1467   var y/ecx: int <- render-trace screen, t, 0/xmin, 0/ymin, 0x10/xmax, 4/ymax, 1/show-cursor
    1468   #
    1469   check-ints-equal y, 1, "F - test-trace-collapse-skips-invisible-lines/post-0/y"
    1470   var cursor-y/eax: (addr int) <- get t, cursor-y
    1471   check-ints-equal *cursor-y, 0, "F - test-trace-collapse-skips-invisible-lines/post-0/cursor-y"
    1472   check-screen-row screen,                                  0/y, "...        ", "F - test-trace-collapse-skips-invisible-lines/post-0"
    1473   check-background-color-in-screen-row screen, 7/bg=cursor, 0/y, "|||        ", "F - test-trace-collapse-skips-invisible-lines/post-0/cursor"
    1474   check-screen-row screen,                                  1/y, "           ", "F - test-trace-collapse-skips-invisible-lines/post-1"
    1475   check-background-color-in-screen-row screen, 7/bg=cursor, 1/y, "           ", "F - test-trace-collapse-skips-invisible-lines/post-1/cursor"
    1476 }
    1477
    1478 fn test-trace-collapse-two-levels {
    1479   var t-storage: trace
    1480   var t/esi: (addr trace) <- address t-storage
    1481   initialize-trace t, 0x10, 0x10
    1482   #
    1483   trace-text t, "l", "line 1"
    1484   trace-lower t
    1485   trace-text t, "l", "line 1.1"
    1486   trace-higher t
    1487   trace-text t, "l", "line 2"
    1488   # setup: screen
    1489   var screen-on-stack: screen
    1490   var screen/edi: (addr screen) <- address screen-on-stack
    1491   initialize-screen screen, 0x10/width, 4/height, 0/no-pixel-graphics
    1492   #
    1493   var y/ecx: int <- render-trace screen, t, 0/xmin, 0/ymin, 0x10/xmax, 4/ymax, 1/show-cursor
    1494   #
    1495   check-screen-row screen,                                  0/y, "...        ", "F - test-trace-collapse-two-levels/pre-0"
    1496   check-background-color-in-screen-row screen, 7/bg=cursor, 0/y, "|||        ", "F - test-trace-collapse-two-levels/pre-0/cursor"
    1497   check-screen-row screen,                                  1/y, "           ", "F - test-trace-collapse-two-levels/pre-1"
    1498   check-background-color-in-screen-row screen, 7/bg=cursor, 1/y, "           ", "F - test-trace-collapse-two-levels/pre-1/cursor"
    1499   # expand
    1500   edit-trace t, 0xa/enter
    1501   var y/ecx: int <- render-trace screen, t, 0/xmin, 0/ymin, 0x10/xmax, 4/ymax, 1/show-cursor
    1502   # two visible lines with an invisible line in between
    1503   check-screen-row screen,                                  0/y, "0 line 1   ", "F - test-trace-collapse-two-levels/expand-0"
    1504   check-background-color-in-screen-row screen, 7/bg=cursor, 0/y, "||||||||   ", "F - test-trace-collapse-two-levels/expand-0/cursor"
    1505   check-screen-row screen,                                  1/y, "...        ", "F - test-trace-collapse-two-levels/expand-1"
    1506   check-background-color-in-screen-row screen, 7/bg=cursor, 1/y, "           ", "F - test-trace-collapse-two-levels/expand-1/cursor"
    1507   check-screen-row screen,                                  2/y, "0 line 2   ", "F - test-trace-collapse-two-levels/expand-2"
    1508   check-background-color-in-screen-row screen, 7/bg=cursor, 2/y, "           ", "F - test-trace-collapse-two-levels/expand-2/cursor"
    1509   # cursor down to ellipses
    1510   edit-trace t, 0x6a/j
    1511   var y/ecx: int <- render-trace screen, t, 0/xmin, 0/ymin, 0x10/xmax, 4/ymax, 1/show-cursor
    1512   # expand
    1513   edit-trace t, 0xa/enter
    1514   var y/ecx: int <- render-trace screen, t, 0/xmin, 0/ymin, 0x10/xmax, 4/ymax, 1/show-cursor
    1515   # two visible lines with an invisible line in between
    1516   check-screen-row screen,                                  0/y, "0 line 1   ", "F - test-trace-collapse-two-levels/expand2-0"
    1517   check-background-color-in-screen-row screen, 7/bg=cursor, 0/y, "           ", "F - test-trace-collapse-two-levels/expand2-0/cursor"
    1518   check-screen-row screen,                                  1/y, "1 line 1.1 ", "F - test-trace-collapse-two-levels/expand2-1"
    1519   check-background-color-in-screen-row screen, 7/bg=cursor, 1/y, "|||||||||| ", "F - test-trace-collapse-two-levels/expand2-1/cursor"
    1520   check-screen-row screen,                                  2/y, "0 line 2   ", "F - test-trace-collapse-two-levels/expand2-2"
    1521   check-background-color-in-screen-row screen, 7/bg=cursor, 2/y, "           ", "F - test-trace-collapse-two-levels/expand2-2/cursor"
    1522   # cursor down to second visible line
    1523   edit-trace t, 0x6a/j
    1524   var y/ecx: int <- render-trace screen, t, 0/xmin, 0/ymin, 0x10/xmax, 4/ymax, 1/show-cursor
    1525   # collapse
    1526   edit-trace t, 8/backspace
    1527   clear-screen screen
    1528   var y/ecx: int <- render-trace screen, t, 0/xmin, 0/ymin, 0x10/xmax, 4/ymax, 1/show-cursor
    1529   #
    1530   check-ints-equal y, 1, "F - test-trace-collapse-two-levels/post-0/y"
    1531   var cursor-y/eax: (addr int) <- get t, cursor-y
    1532   check-ints-equal *cursor-y, 0, "F - test-trace-collapse-two-levels/post-0/cursor-y"
    1533   check-screen-row screen,                                  0/y, "...        ", "F - test-trace-collapse-two-levels/post-0"
    1534   check-background-color-in-screen-row screen, 7/bg=cursor, 0/y, "|||        ", "F - test-trace-collapse-two-levels/post-0/cursor"
    1535   check-screen-row screen,                                  1/y, "           ", "F - test-trace-collapse-two-levels/post-1"
    1536   check-background-color-in-screen-row screen, 7/bg=cursor, 1/y, "           ", "F - test-trace-collapse-two-levels/post-1/cursor"
    1537 }
    1538
    1539 fn test-trace-collapse-nested-level {
    1540   var t-storage: trace
    1541   var t/esi: (addr trace) <- address t-storage
    1542   initialize-trace t, 0x10, 0x10
    1543   #
    1544   trace-text t, "l", "line 1"
    1545   trace-lower t
    1546   trace-text t, "l", "line 1.1"
    1547   trace-higher t
    1548   trace-text t, "l", "line 2"
    1549   trace-lower t
    1550   trace-text t, "l", "line 2.1"
    1551   trace-text t, "l", "line 2.2"
    1552   trace-higher t
    1553   # setup: screen
    1554   var screen-on-stack: screen
    1555   var screen/edi: (addr screen) <- address screen-on-stack
    1556   initialize-screen screen, 0x10/width, 8/height, 0/no-pixel-graphics
    1557   #
    1558   var y/ecx: int <- render-trace screen, t, 0/xmin, 0/ymin, 0x10/xmax, 8/ymax, 1/show-cursor
    1559   #
    1560   check-screen-row screen,                                  0/y, "...        ", "F - test-trace-collapse-nested-level/pre-0"
    1561   check-background-color-in-screen-row screen, 7/bg=cursor, 0/y, "|||        ", "F - test-trace-collapse-nested-level/pre-0/cursor"
    1562   check-screen-row screen,                                  1/y, "           ", "F - test-trace-collapse-nested-level/pre-1"
    1563   check-background-color-in-screen-row screen, 7/bg=cursor, 1/y, "           ", "F - test-trace-collapse-nested-level/pre-1/cursor"
    1564   # expand
    1565   edit-trace t, 0xa/enter
    1566   var y/ecx: int <- render-trace screen, t, 0/xmin, 0/ymin, 0x10/xmax, 8/ymax, 1/show-cursor
    1567   # two visible lines with an invisible line in between
    1568   check-screen-row screen,                                  0/y, "0 line 1   ", "F - test-trace-collapse-nested-level/expand-0"
    1569   check-background-color-in-screen-row screen, 7/bg=cursor, 0/y, "||||||||   ", "F - test-trace-collapse-nested-level/expand-0/cursor"
    1570   check-screen-row screen,                                  1/y, "...        ", "F - test-trace-collapse-nested-level/expand-1"
    1571   check-background-color-in-screen-row screen, 7/bg=cursor, 1/y, "           ", "F - test-trace-collapse-nested-level/expand-1/cursor"
    1572   check-screen-row screen,                                  2/y, "0 line 2   ", "F - test-trace-collapse-nested-level/expand-2"
    1573   check-background-color-in-screen-row screen, 7/bg=cursor, 2/y, "           ", "F - test-trace-collapse-nested-level/expand-2/cursor"
    1574   check-screen-row screen,                                  3/y, "...        ", "F - test-trace-collapse-nested-level/expand-3"
    1575   check-background-color-in-screen-row screen, 7/bg=cursor, 3/y, "           ", "F - test-trace-collapse-nested-level/expand-3/cursor"
    1576   # cursor down to bottom
    1577   edit-trace t, 0x6a/j
    1578   var y/ecx: int <- render-trace screen, t, 0/xmin, 0/ymin, 0x10/xmax, 8/ymax, 1/show-cursor
    1579   edit-trace t, 0x6a/j
    1580   var y/ecx: int <- render-trace screen, t, 0/xmin, 0/ymin, 0x10/xmax, 8/ymax, 1/show-cursor
    1581   edit-trace t, 0x6a/j
    1582   var y/ecx: int <- render-trace screen, t, 0/xmin, 0/ymin, 0x10/xmax, 8/ymax, 1/show-cursor
    1583   # expand
    1584   edit-trace t, 0xa/enter
    1585   var y/ecx: int <- render-trace screen, t, 0/xmin, 0/ymin, 0x10/xmax, 8/ymax, 1/show-cursor
    1586   # two visible lines with an invisible line in between
    1587   check-screen-row screen,                                  0/y, "0 line 1   ", "F - test-trace-collapse-nested-level/expand2-0"
    1588   check-background-color-in-screen-row screen, 7/bg=cursor, 0/y, "           ", "F - test-trace-collapse-nested-level/expand2-0/cursor"
    1589   check-screen-row screen,                                  1/y, "...        ", "F - test-trace-collapse-nested-level/expand2-1"
    1590   check-background-color-in-screen-row screen, 7/bg=cursor, 1/y, "           ", "F - test-trace-collapse-nested-level/expand2-1/cursor"
    1591   check-screen-row screen,                                  2/y, "0 line 2   ", "F - test-trace-collapse-nested-level/expand2-2"
    1592   check-background-color-in-screen-row screen, 7/bg=cursor, 2/y, "           ", "F - test-trace-collapse-nested-level/expand2-2/cursor"
    1593   check-screen-row screen,                                  3/y, "1 line 2.1 ", "F - test-trace-collapse-nested-level/expand2-3"
    1594   check-background-color-in-screen-row screen, 7/bg=cursor, 3/y, "|||||||||| ", "F - test-trace-collapse-nested-level/expand2-3/cursor"
    1595   check-screen-row screen,                                  4/y, "1 line 2.2 ", "F - test-trace-collapse-nested-level/expand2-4"
    1596   check-background-color-in-screen-row screen, 7/bg=cursor, 4/y, "           ", "F - test-trace-collapse-nested-level/expand2-4/cursor"
    1597   # collapse
    1598   edit-trace t, 8/backspace
    1599   clear-screen screen
    1600   var y/ecx: int <- render-trace screen, t, 0/xmin, 0/ymin, 0x10/xmax, 8/ymax, 1/show-cursor
    1601   #
    1602   check-ints-equal y, 4, "F - test-trace-collapse-nested-level/post-0/y"
    1603   var cursor-y/eax: (addr int) <- get t, cursor-y
    1604   check-ints-equal *cursor-y, 2, "F - test-trace-collapse-nested-level/post-0/cursor-y"
    1605   check-screen-row screen,                                  0/y, "0 line 1   ", "F - test-trace-collapse-nested-level/post-0"
    1606   check-background-color-in-screen-row screen, 7/bg=cursor, 0/y, "           ", "F - test-trace-collapse-nested-level/post-0/cursor"
    1607   check-screen-row screen,                                  1/y, "...        ", "F - test-trace-collapse-nested-level/post-1"
    1608   check-background-color-in-screen-row screen, 7/bg=cursor, 1/y, "           ", "F - test-trace-collapse-nested-level/post-1/cursor"
    1609   check-screen-row screen,                                  2/y, "0 line 2   ", "F - test-trace-collapse-nested-level/post-2"
    1610   check-background-color-in-screen-row screen, 7/bg=cursor, 2/y, "||||||||   ", "F - test-trace-collapse-nested-level/post-2/cursor"
    1611   check-screen-row screen,                                  3/y, "...        ", "F - test-trace-collapse-nested-level/post-3"
    1612   check-background-color-in-screen-row screen, 7/bg=cursor, 3/y, "           ", "F - test-trace-collapse-nested-level/post-3/cursor"
    1613 }