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