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