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