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, 0/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 0/black
 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, 9/fg=blue, 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, 9/fg=blue, 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, 7/bg=grey
 689   draw-text-rightward-from-cursor screen, " run main  ", width, 7/fg, 0/bg
 690   draw-text-rightward-from-cursor screen, " ctrl-s ", width, 0/fg, 7/bg=grey
 691   draw-text-rightward-from-cursor screen, " run sandbox  ", width, 7/fg, 0/bg
 692   draw-text-rightward-from-cursor screen, " tab ", width, 0/fg, 0x18/bg=keyboard
 693   draw-text-rightward-from-cursor screen, " to keyboard  ", width, 7/fg, 0/bg
 694   draw-text-rightward-from-cursor screen, " j ", width, 0/fg, 7/bg=grey
 695   draw-text-rightward-from-cursor screen, " down  ", width, 7/fg, 0/bg
 696   draw-text-rightward-from-cursor screen, " k ", width, 0/fg, 7/bg=grey
 697   draw-text-rightward-from-cursor screen, " up  ", width, 7/fg, 0/bg
 698   draw-text-rightward-from-cursor screen, " enter ", width, 0/fg, 7/bg=grey
 699   draw-text-rightward-from-cursor screen, " expand  ", width, 7/fg, 0/bg
 700   draw-text-rightward-from-cursor screen, " backspace ", width, 0/fg, 7/bg=grey
 701   draw-text-rightward-from-cursor screen, " collapse  ", width, 7/fg, 0/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 }