https://github.com/akkartik/mu/blob/main/405screen.mu
   1 # Wrappers for real screen primitives that can be passed a fake screen.
   2 # The tests here have been painstakingly validated against a real terminal
   3 # emulator. I believe functionality here is broadly portable across terminal
   4 # emulators.
   5 #
   6 # Remember: fake screen co-ordinates are 1-based, just like in real terminal
   7 # emulators.
   8 
   9 type screen {
  10   num-rows: int
  11   num-cols: int
  12   data: (handle array screen-cell)
  13   top-index: int  # 0-indexed
  14   cursor-row: int  # 1-indexed
  15   cursor-col: int  # 1-indexed
  16   cursor-hide?: boolean
  17   curr-attributes: screen-cell
  18 }
  19 
  20 type screen-cell {
  21   data: grapheme
  22   color: int
  23   background-color: int
  24   bold?: boolean
  25   underline?: boolean
  26   reverse?: boolean
  27   blink?: boolean
  28 }
  29 
  30 fn initialize-screen screen: (addr screen), nrows: int, ncols: int {
  31   var screen-addr/esi: (addr screen) <- copy screen
  32   var tmp/eax: int <- copy 0
  33   var dest/edi: (addr int) <- copy 0
  34   # screen->num-rows = nrows
  35   dest <- get screen-addr, num-rows
  36   tmp <- copy nrows
  37   copy-to *dest, tmp
  38   # screen->num-cols = ncols
  39   dest <- get screen-addr, num-cols
  40   tmp <- copy ncols
  41   copy-to *dest, tmp
  42   # screen->data = new screen-cell[nrows*ncols]
  43   {
  44     var data-addr/edi: (addr handle array screen-cell) <- get screen-addr, data
  45     tmp <- multiply nrows
  46     populate data-addr, tmp
  47   }
  48   # screen->cursor-row = 1
  49   dest <- get screen-addr, cursor-row
  50   copy-to *dest, 1
  51   # screen->cursor-col = 1
  52   dest <- get screen-addr, cursor-col
  53   copy-to *dest, 1
  54   # screen->curr-attributes->background-color = 7  (simulate light background)
  55   var tmp2/eax: (addr screen-cell) <- get screen-addr, curr-attributes
  56   dest <- get tmp2, background-color
  57   copy-to *dest, 7
  58 }
  59 
  60 fn screen-size screen: (addr screen) -> _/eax: int, _/ecx: int {
  61   var nrows/eax: int <- copy 0
  62   var ncols/ecx: int <- copy 0
  63   compare screen, 0
  64   {
  65     break-if-!=
  66     nrows, ncols <- real-screen-size
  67     return nrows, ncols
  68   }
  69   # fake screen
  70   var screen-addr/esi: (addr screen) <- copy screen
  71   var tmp/edx: (addr int) <- get screen-addr, num-rows
  72   nrows <- copy *tmp
  73   tmp <- get screen-addr, num-cols
  74   ncols <- copy *tmp
  75   return nrows, ncols
  76 }
  77 
  78 fn clear-screen screen: (addr screen) {
  79   compare screen, 0
  80   {
  81     break-if-!=
  82     clear-real-screen
  83     return
  84   }
  85   # fake screen
  86   var space/edi: grapheme <- copy 0x20
  87   move-cursor screen, 1, 1
  88   var screen-addr/esi: (addr screen) <- copy screen
  89   var i/eax: int <- copy 1
  90   var nrows/ecx: (addr int) <- get screen-addr, num-rows
  91   {
  92     compare i, *nrows
  93     break-if->
  94     var j/edx: int <- copy 1
  95     var ncols/ebx: (addr int) <- get screen-addr, num-cols
  96     {
  97       compare j, *ncols
  98       break-if->
  99       print-grapheme screen, space
 100       j <- increment
 101       loop
 102     }
 103     i <- increment
 104     loop
 105   }
 106   move-cursor screen, 1, 1
 107 }
 108 
 109 fn move-cursor screen: (addr screen), row: int, column: int {
 110   compare screen, 0
 111   {
 112     break-if-!=
 113     move-cursor-on-real-screen row, column
 114     return
 115   }
 116   # fake screen
 117   var screen-addr/esi: (addr screen) <- copy screen
 118   # row < 0 is ignored
 119   {
 120     compare row, 0
 121     break-if->=
 122     return
 123   }
 124   # row = 0 is treated same as 1
 125   {
 126     compare row, 0
 127     break-if-!=
 128     copy-to row, 1
 129   }
 130   # row > num-rows saturates to num-rows
 131   {
 132     var nrows-addr/eax: (addr int) <- get screen-addr, num-rows
 133     var nrows/eax: int <- copy *nrows-addr
 134     compare row, nrows
 135     break-if-<=
 136     copy-to row, nrows
 137   }
 138   # column < 0 is ignored
 139   {
 140     compare column, 0
 141     break-if->=
 142     return
 143   }
 144   # column = 0 is treated same as 1
 145   {
 146     compare column, 0
 147     break-if-!=
 148     copy-to column, 1
 149   }
 150   # column > num-cols saturates to num-cols+1 (so wrapping to next row)
 151   {
 152     var ncols-addr/eax: (addr int) <- get screen-addr, num-cols
 153     var ncols/eax: int <- copy *ncols-addr
 154     compare column, ncols
 155     break-if-<=
 156     copy-to column, ncols
 157     increment column
 158   }
 159   # screen->cursor-row = row
 160   var dest/edi: (addr int) <- get screen-addr, cursor-row
 161   var src/eax: int <- copy row
 162   copy-to *dest, src
 163   # screen->cursor-col = column
 164   dest <- get screen-addr, cursor-col
 165   src <- copy column
 166   copy-to *dest, src
 167 }
 168 
 169 fn print-string screen: (addr screen), s: (addr array byte) {
 170   compare screen, 0
 171   {
 172     break-if-!=
 173     print-string-to-real-screen s
 174     return
 175   }
 176   # fake screen
 177   var s2: (stream byte 0x100)
 178   var s2-addr/esi: (addr stream byte) <- address s2
 179   write s2-addr, s
 180   var screen-addr/edi: (addr screen) <- copy screen
 181   {
 182     var done?/eax: boolean <- stream-empty? s2-addr
 183     compare done?, 0
 184     break-if-!=
 185     var g/eax: grapheme <- read-grapheme s2-addr
 186     print-grapheme screen, g
 187     loop
 188   }
 189 }
 190 
 191 fn print-array-of-ints-in-decimal screen: (addr screen), _a: (addr array int) {
 192   var a/esi: (addr array int) <- copy _a
 193   var max/ecx: int <- length a
 194   var i/eax: int <- copy 0
 195   {
 196     compare i, max
 197     break-if->=
 198     {
 199       compare i, 0
 200       break-if-=
 201       print-string screen, " "
 202     }
 203     var x/ecx: (addr int) <- index a, i
 204     print-int32-decimal screen, *x
 205     i <- increment
 206     loop
 207   }
 208 }
 209 
 210 fn print-grapheme screen: (addr screen), c: grapheme {
 211   compare screen, 0
 212   {
 213     break-if-!=
 214     print-grapheme-to-real-screen c
 215     return
 216   }
 217   # fake screen
 218   var screen-addr/esi: (addr screen) <- copy screen
 219   var cursor-col-addr/edx: (addr int) <- get screen-addr, cursor-col
 220   # adjust cursor if necessary
 221   # to avoid premature scrolling it's important to do this lazily, at the last possible time
 222   {
 223     # next row
 224     var num-cols-addr/ecx: (addr int) <- get screen-addr, num-cols
 225     var num-cols/ecx: int <- copy *num-cols-addr
 226     compare *cursor-col-addr, num-cols
 227     break-if-<=
 228     copy-to *cursor-col-addr, 1
 229     var cursor-row-addr/ebx: (addr int) <- get screen-addr, cursor-row
 230     increment *cursor-row-addr
 231     # scroll
 232     var num-rows-addr/eax: (addr int) <- get screen-addr, num-rows
 233     var num-rows/eax: int <- copy *num-rows-addr
 234     compare *cursor-row-addr, num-rows
 235     break-if-<=
 236     copy-to *cursor-row-addr, num-rows
 237     # if (top-index > data size) top-index = 0, otherwise top-index += num-cols
 238     $print-grapheme:perform-scroll: {
 239       var top-index-addr/ebx: (addr int) <- get screen-addr, top-index
 240       var data-ah/eax: (addr handle array screen-cell) <- get screen-addr, data
 241       var data/eax: (addr array screen-cell) <- lookup *data-ah
 242       var max-index/edi: int <- length data
 243       compare *top-index-addr, max-index
 244       {
 245         break-if->=
 246         add-to *top-index-addr, num-cols
 247         break $print-grapheme:perform-scroll
 248       }
 249       {
 250         break-if-<
 251         copy-to *top-index-addr, 0
 252       }
 253     }
 254   }
 255   var idx/ecx: int <- current-screen-cell-index screen-addr
 256 #?   print-string-to-real-screen "printing grapheme at screen index "
 257 #?   print-int32-hex-to-real-screen idx
 258 #?   print-string-to-real-screen ": "
 259   var data-ah/eax: (addr handle
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
<title>Mu - factorial.mu</title>
<meta name="Generator" content="Vim/7.4">
<meta name="plugin-version" content="vim7.4_v2">
<meta name="syntax" content="none">
<meta name="settings" content="number_lines,use_css,pre_wrap,no_foldcolumn,expand_tabs,line_ids,prevent_copy=">
<meta name="colorscheme" content="minimal">
<style type="text/css">
<!--
pre { white-space: pre-wrap; font-family: monospace; color: #aaaaaa; background-color: #080808; }
body { font-size: 12pt; font-family: monospace; color: #aaaaaa; background-color: #080808; }
a { color:#eeeeee; text-decoration: none; }
a:hover { text-decoration: underline; }
* { font-size: 12pt; font-size: 1em; }
.muRecipe { color: #ff8700; }
.muScenario { color: #00af00; }
.Special { color: #c00000; }
.Conceal { color: #4e4e4e; }
.Delimiter { color: #800080; }
.Comment { color: #9090ff; }
.Comment a { color:#0000ee; text-decoration:underline; }
.Constant { color: #00a0a0; }
.LineNr { color: #444444; }
.muControl { color: #c0a020; }
-->
</style>

<script type='text/javascript'>
<!--

/* function to open any folds containing a jumped-to line before jumping to it */
function JumpToLine()
{
  var lineNum;
  lineNum = window.location.hash;
  lineNum = lineNum.substr(1); /* strip off '#' */

  if (lineNum.indexOf('L') == -1) {
    lineNum = 'L'+lineNum;
  }
  lineElem = document.getElementById(lineNum);
  /* Always jump to new location even if the line was hidden inside a fold, or
   * we corrected the raw number to a line ID.
   */
  if (lineElem) {
    lineElem.scrollIntoView(true);
  }
  return true;
}
if ('onhashchange' in window) {
  window.onhashchange = JumpToLine;
}

-->
</script>
</head>
<body onload='JumpToLine();'>
<pre id='vimCodeElement'>
<span id="L1" class="LineNr"> 1 </span><span class="Comment"># example program: compute the factorial of 5</span>
<span id="L2" class="LineNr"> 2 </span>
<span id="L3" class="LineNr"> 3 </span><span class="muRecipe">def</span> <a href='factorial.mu.html#L3'>main</a> [
<span id="L4" class="LineNr"> 4 </span>  <span class="Constant">local-scope</span>
<span id="L5" class="LineNr"> 5 </span>  x:num <span class="Special">&lt;-</span> <a href='factorial.mu.html#L10'>factorial</a><span class="Constant"> 5</span>
<span id="L6" class="LineNr"> 6 </span>  $print <span class="Constant">[result: ]</span>, x, <span class="Constant">[ </span>
<span id="L7" class="LineNr"> 7 </span><span class="Constant">]</span>
<span id="L8" class="LineNr"> 8 </span>]
<span id="L9" class="LineNr"> 9 </span>
<span id="L10" class="LineNr">10 </span><span class="muRecipe">def</span> <a href='factorial.mu.html#L10'>factorial</a> n:num<span class="muRecipe"> -&gt; </span>result:num [
<span id="L11" class="LineNr">11 </span>  <span class="Constant">local-scope</span>
<span id="L12" class="LineNr">12 </span>  <span class="Constant">load-ingredients</span>
<span id="L13" class="LineNr">13 </span>  <span class="Delimiter">{</span>
<span id="L14" class="LineNr">14 </span>  <span class="Conceal">¦</span> <span class="Comment"># if n=0 return 1</span>
<span id="L15" class="LineNr">15 </span>  <span class="Conceal">¦</span> zero?:bool <span class="Special">&lt;-</span> equal n,<span class="Constant"> 0</span>
<span id="L16" class="LineNr">16 </span>  <span class="Conceal">¦</span> <span class="muControl">break-unless</span> zero?
<span id="L17" class="LineNr">17 </span>  <span class="Conceal">¦</span> <span class="muControl">return</span><span class="Constant"> 1</span>
<span id="L18" class="LineNr">18 </span>  <span class="Delimiter">}</span>
<span id="L19" class="LineNr">19 </span>  <span class="Comment"># return n * factorial(n-1)</span>
<span id="L20" class="LineNr">20 </span>  x:num <span class="Special">&lt;-</span> subtract n,<span class="Constant"> 1</span>
<span id="L21" class="LineNr">21 </span>  subresult:num <span class="Special">&lt;-</span> <a href='factorial.mu.html#L10'>factorial</a> x
<span id="L22" class="LineNr">22 </span>  result <span class="Special">&lt;-</span> multiply subresult, n
<span id="L23" class="LineNr">23 </span>]
<span id="L24" class="LineNr">24 </span>
<span id="L25" class="LineNr">25 </span><span class="Comment"># unit test</span>
<span id="L26" class="LineNr">26 </span><span class="muScenario">scenario</span> factorial-test [
<span id="L27" class="LineNr">27 </span>  run [
<span id="L28" class="LineNr">28 </span>  <span class="Conceal">¦</span> 1:num <span class="Special">&lt;-</span> <a href='factorial.mu.html#L10'>factorial</a><span class="Constant"> 5</span>
<span id="L29" class="LineNr">29 </span>  ]
<span id="L30" class="LineNr">30 </span>  memory-should-contain [
<span id="L31" class="LineNr">31 </span>  <span class="Conceal">¦</span><span class="Constant"> 1</span> <span class="Special">&lt;-</span><span class="Constant"> 120</span>
<span id="L32" class="LineNr">32 </span>  ]
<span id="L33" class="LineNr">33 </span>]
</pre>
</body>
</html>
<!-- vim: set foldmethod=manual : -->
9" class="LineNr"> 509 # fake screen 510 var screen-addr/esi: (addr screen) <- copy screen 511 var dest/ecx: (addr screen-cell) <- get screen-addr, curr-attributes 512 var default-cell: screen-cell 513 var bg/eax: (addr int) <- get default-cell, background-color 514 copy-to *bg, 7 515 var default-cell-addr/eax: (addr screen-cell) <- address default-cell 516 copy-object default-cell-addr, dest 517 } 518 519 fn start-color screen: (addr screen), fg: int, bg: int { 520 compare screen, 0 521 { 522 break-if-!= 523 start-color-on-real-screen fg, bg 524 return 525 } 526 # fake screen 527 var screen-addr/esi: (addr screen) <- copy screen 528 var attr/ecx: (addr screen-cell) <- get screen-addr, curr-attributes 529 var dest/edx: (addr int) <- get attr, color 530 var src/eax: int <- copy fg 531 copy-to *dest, src 532 var dest/edx: (addr int) <- get attr, background-color 533 var src/eax: int <- copy bg 534 copy-to *dest, src 535 } 536 537 fn start-bold screen: (addr screen) { 538 compare screen, 0 539 { 540 break-if-!= 541 start-bold-on-real-screen 542 return 543 } 544 # fake screen 545 var screen-addr/esi: (addr screen) <- copy screen 546 var attr/ecx: (addr screen-cell) <- get screen-addr, curr-attributes 547 var dest/edx: (addr boolean) <- get attr, bold? 548 copy-to *dest, 1 549 } 550 551 fn start-underline screen: (addr screen) { 552 compare screen, 0 553 { 554 break-if-!= 555 start-underline-on-real-screen 556 return 557 } 558 # fake screen 559 var screen-addr/esi: (addr screen) <- copy screen 560 var attr/ecx: (addr screen-cell) <- get screen-addr, curr-attributes 561 var dest/edx: (addr boolean) <- get attr, underline? 562 copy-to *dest, 1 563 } 564 565 fn start-reverse-video screen: (addr screen) { 566 compare screen, 0 567 { 568 break-if-!= 569 start-reverse-video-on-real-screen 570 return 571 } 572 # fake screen 573 var screen-addr/esi: (addr screen) <- copy screen 574 var attr/ecx: (addr screen-cell) <- get screen-addr, curr-attributes 575 var dest/edx: (addr boolean) <- get attr, reverse? 576 copy-to *dest, 1 577 } 578 579 fn start-blinking screen: (addr screen) { 580 compare screen, 0 581 { 582 break-if-!= 583 start-blinking-on-real-screen 584 return 585 } 586 # fake screen 587 var screen-addr/esi: (addr screen) <- copy screen 588 var attr/ecx: (addr screen-cell) <- get screen-addr, curr-attributes 589 var dest/edx: (addr boolean) <- get attr, blink? 590 copy-to *dest, 1 591 } 592 593 fn hide-cursor screen: (addr screen) { 594 compare screen, 0 595 { 596 break-if-!= 597 hide-cursor-on-real-screen 598 return 599 } 600 # fake screen 601 var screen-addr/esi: (addr screen) <- copy screen 602 var hide?/ecx: (addr boolean) <- get screen-addr, cursor-hide? 603 copy-to *hide?, 1 604 } 605 606 fn show-cursor screen: (addr screen) { 607 compare screen, 0 608 { 609 break-if-!= 610 show-cursor-on-real-screen 611 return 612 } 613 # fake screen 614 var screen-addr/esi: (addr screen) <- copy screen 615 var hide?/ecx: (addr boolean) <- get screen-addr, cursor-hide? 616 copy-to *hide?, 0 617 } 618 619 # validate data on screen regardless of attributes (color, bold, etc.) 620 # Mu doesn't have multi-line strings, so we provide functions for rows or portions of rows. 621 # Tab characters (that translate into multiple screen cells) not supported. 622 623 fn check-screen-row screen: (addr screen), row-idx: int, expected: (addr array byte), msg: (addr array byte) { 624 check-screen-row-from screen, row-idx, 1, expected, msg 625 } 626 627 fn check-screen-row-from screen-on-stack: (addr screen), row-idx: int, col-idx: int, expected: (addr array byte), msg: (addr array byte) { 628 var screen/esi: (addr screen) <- copy screen-on-stack 629 var idx/ecx: int <- screen-cell-index screen, row-idx, col-idx 630 # compare 'expected' with the screen contents starting at 'idx', grapheme by grapheme 631 var e: (stream byte 0x100) 632 var e-addr/edx: (addr stream byte) <- address e 633 write e-addr, expected 634 { 635 var done?/eax: boolean <- stream-empty? e-addr 636 compare done?, 0 637 break-if-!= 638 var _g/eax: grapheme <- screen-grapheme-at-idx screen, idx 639 var g/ebx: grapheme <- copy _g 640 var expected-grapheme/eax: grapheme <- read-grapheme e-addr 641 # compare graphemes 642 $check-screen-row-from:compare-graphemes: { 643 # if expected-grapheme is space, null grapheme is also ok 644 { 645 compare expected-grapheme, 0x20 646 break-if-!= 647 compare g, 0 648 break-if-= $check-screen-row-from:compare-graphemes 649 } 650 # if (g == expected-grapheme) print "." 651 compare g, expected-grapheme 652 { 653 break-if-!= 654 print-string-to-real-screen "." 655 break $check-screen-row-from:compare-graphemes 656 } 657 # otherwise print an error 658 print-string-to-real-screen msg 659 print-string-to-real-screen ": expected '" 660 print-grapheme-to-real-screen expected-grapheme 661 print-string-to-real-screen "' at (" 662 print-int32-hex-to-real-screen row-idx 663 print-string-to-real-screen ", " 664 print-int32-hex-to-real-screen col-idx 665 print-string-to-real-screen ") but observed '" 666 print-grapheme-to-real-screen g 667 print-string-to-real-screen "'\n" 668 } 669 idx <- increment 670 increment col-idx 671 loop 672 } 673 } 674 675 # various variants by screen-cell attribute; spaces in the 'expected' data should not match the attribute 676 677 fn check-screen-row-in-color screen: (addr screen), fg: int, row-idx: int, expected: (addr array byte), msg: (addr array byte) { 678 check-screen-row-in-color-from screen, fg, row-idx, 1, expected, msg 679 } 680 681 fn check-screen-row-in-color-from screen-on-stack: (addr screen), fg: int, row-idx: int, col-idx: int, expected: (addr array byte), msg: (addr array byte) { 682 var screen/esi: (addr screen) <- copy screen-on-stack 683 var idx/ecx: int <- screen-cell-index screen, row-idx, col-idx 684 # compare 'expected' with the screen contents starting at 'idx', grapheme by grapheme 685 var e: (stream byte 0x100) 686 var e-addr/edx: (addr stream byte) <- address e 687 write e-addr, expected 688 { 689 var done?/eax: boolean <- stream-empty? e-addr 690 compare done?, 0 691 break-if-!= 692 var _g/eax: grapheme <- screen-grapheme-at-idx screen, idx 693 var g/ebx: grapheme <- copy _g 694 var _expected-grapheme/eax: grapheme <- read-grapheme e-addr 695 var expected-grapheme/edi: grapheme <- copy _expected-grapheme 696 $check-screen-row-in-color-from:compare-cells: { 697 # if expected-grapheme is space, null grapheme is also ok 698 { 699 compare expected-grapheme, 0x20 700 break-if-!= 701 compare g, 0 702 break-if-= $check-screen-row-in-color-from:compare-cells 703 } 704 # if expected-grapheme is space, a different color is ok 705 { 706 compare expected-grapheme, 0x20 707 break-if-!= 708 var color/eax: int <- screen-color-at-idx screen, idx 709 compare color, fg 710 break-if-!= $check-screen-row-in-color-from:compare-cells 711 } 712 # compare graphemes 713 $check-screen-row-in-color-from:compare-graphemes: { 714 # if (g == expected-grapheme) print "." 715 compare g, expected-grapheme 716 { 717 break-if-!= 718 print-string-to-real-screen "." 719 break $check-screen-row-in-color-from:compare-graphemes 720 } 721 # otherwise print an error 722 print-string-to-real-screen msg 723 print-string-to-real-screen ": expected '" 724 print-grapheme-to-real-screen expected-grapheme 725 print-string-to-real-screen "' at (" 726 print-int32-hex-to-real-screen row-idx 727 print-string-to-real-screen ", " 728 print-int32-hex-to-real-screen col-idx 729 print-string-to-real-screen ") but observed '" 730 print-grapheme-to-real-screen g 731 print-string-to-real-screen "'\n" 732 } 733 $check-screen-row-in-color-from:compare-colors: { 734 var color/eax: int <- screen-color-at-idx screen, idx 735 compare fg, color 736 { 737 break-if-!= 738 print-string-to-real-screen "." 739 break $check-screen-row-in-color-from:compare-colors 740 } 741 # otherwise print an error 742 print-string-to-real-screen msg 743 print-string-to-real-screen ": expected '" 744 print-grapheme-to-real-screen expected-grapheme 745 print-string-to-real-screen "' at (" 746 print-int32-hex-to-real-screen row-idx 747 print-string-to-real-screen ", " 748 print-int32-hex-to-real-screen col-idx 749 print-string-to-real-screen ") in color " 750 print-int32-hex-to-real-screen fg 751 print-string-to-real-screen " but observed color " 752 print-int32-hex-to-real-screen color 753 print-string-to-real-screen "\n" 754 } 755 } 756 idx <- increment 757 increment col-idx 758 loop 759 } 760 } 761 762 # background color is visible even for spaces, so 'expected' behaves as an array of booleans. 763 # non-space = given background must match; space = background must not match 764 fn check-screen-row-in-background-color screen: (addr screen), bg: int, row-idx: int, expected: (addr array byte), msg: (addr array byte) { 765 check-screen-row-in-background-color-from screen, bg, row-idx, 1, expected, msg 766 } 767 768 fn check-screen-row-in-background-color-from screen-on-stack: (addr screen), bg: int, row-idx: int, col-idx: int, expected: (addr array byte), msg: (addr array byte) { 769 var screen/esi: (addr screen) <- copy screen-on-stack 770 var idx/ecx: int <- screen-cell-index screen, row-idx, col-idx 771 # compare 'expected' with the screen contents starting at 'idx', grapheme by grapheme 772 var e: (stream byte 0x100) 773 var e-addr/edx: (addr stream byte) <- address e 774 write e-addr, expected 775 { 776 var done?/eax: boolean <- stream-empty? e-addr 777 compare done?, 0 778 break-if-!= 779 var _g/eax: grapheme <- screen-grapheme-at-idx screen, idx 780 var g/ebx: grapheme <- copy _g 781 var _expected-grapheme/eax: grapheme <- read-grapheme e-addr 782 var expected-grapheme/edx: grapheme <- copy _expected-grapheme 783 $check-screen-row-in-background-color-from:compare-cells: { 784 # if expected-grapheme is space, null grapheme is also ok 785 { 786 compare expected-grapheme, 0x20 787 break-if-!= 788 compare g, 0 789 break-if-= $check-screen-row-in-background-color-from:compare-cells 790 } 791 # if expected-grapheme is space, a different color is ok 792 { 793 compare expected-grapheme, 0x20 794 break-if-!= 795 var color/eax: int <- screen-background-color-at-idx screen, idx 796 compare color, bg 797 break-if-!= $check-screen-row-in-background-color-from:compare-cells 798 } 799 # compare graphemes 800 $check-screen-row-in-background-color-from:compare-graphemes: { 801 # if (g == expected-grapheme) print "." 802 compare g, expected-grapheme 803 { 804 break-if-!= 805 print-string-to-real-screen "." 806 break $check-screen-row-in-background-color-from:compare-graphemes 807 } 808 # otherwise print an error 809 print-string-to-real-screen msg 810 print-string-to-real-screen ": expected '" 811 print-grapheme-to-real-screen expected-grapheme 812 print-string-to-real-screen "' at (" 813 print-int32-hex-to-real-screen row-idx 814 print-string-to-real-screen ", " 815 print-int32-hex-to-real-screen col-idx 816 print-string-to-real-screen ") but observed '" 817 print-grapheme-to-real-screen g 818 print-string-to-real-screen "'\n" 819 } 820 $check-screen-row-in-background-color-from:compare-colors: { 821 var color/eax: int <- screen-background-color-at-idx screen, idx 822 compare bg, color 823 { 824 break-if-!= 825 print-string-to-real-screen "." 826 break $check-screen-row-in-background-color-from:compare-colors 827 } 828 # otherwise print an error 829 print-string-to-real-screen msg 830 print-string-to-real-screen ": expected '" 831 print-grapheme-to-real-screen expected-grapheme 832 print-string-to-real-screen "' at (" 833 print-int32-hex-to-real-screen row-idx 834 print-string-to-real-screen ", " 835 print-int32-hex-to-real-screen col-idx 836 print-string-to-real-screen ") in background color " 837 print-int32-hex-to-real-screen bg 838 print-string-to-real-screen " but observed color " 839 print-int32-hex-to-real-screen color 840 print-string-to-real-screen "\n" 841 } 842 } 843 idx <- increment 844 increment col-idx 845 loop 846 } 847 } 848 849 fn check-screen-row-in-bold screen: (addr screen), row-idx: int, expected: (addr array byte), msg: (addr array byte) { 850 check-screen-row-in-bold-from screen, row-idx, 1, expected, msg 851 } 852 853 fn check-screen-row-in-bold-from screen-on-stack: (addr screen), row-idx: int, col-idx: int, expected: (addr array byte), msg: (addr array byte) { 854 var screen/esi: (addr screen) <- copy screen-on-stack 855 var idx/ecx: int <- screen-cell-index screen, row-idx, col-idx 856 # compare 'expected' with the screen contents starting at 'idx', grapheme by grapheme 857 var e: (stream byte 0x100) 858 var e-addr/edx: (addr stream byte) <- address e 859 write e-addr, expected 860 { 861 var done?/eax: boolean <- stream-empty? e-addr 862 compare done?, 0 863 break-if-!= 864 var _g/eax: grapheme <- screen-grapheme-at-idx screen, idx 865 var g/ebx: grapheme <- copy _g 866 var _expected-grapheme/eax: grapheme <- read-grapheme e-addr 867 var expected-grapheme/edx: grapheme <- copy _expected-grapheme 868 $check-screen-row-in-bold-from:compare-cells: { 869 # if expected-grapheme is space, null grapheme is also ok 870 { 871 compare expected-grapheme, 0x20 872 break-if-!= 873 compare g, 0 874 break-if-= $check-screen-row-in-bold-from:compare-cells 875 } 876 # if expected-grapheme is space, non-bold is ok 877 { 878 compare expected-grapheme, 0x20 879 break-if-!= 880 var bold?/eax: boolean <- screen-bold-at-idx? screen, idx 881 compare bold?, 1 882 break-if-!= $check-screen-row-in-bold-from:compare-cells 883 } 884 # compare graphemes 885 $check-screen-row-in-bold-from:compare-graphemes: { 886 # if (g == expected-grapheme) print "." 887 compare g, expected-grapheme 888 { 889 break-if-!= 890 print-string-to-real-screen "." 891 break $check-screen-row-in-bold-from:compare-graphemes 892 } 893 # otherwise print an error 894 print-string-to-real-screen msg 895 print-string-to-real-screen ": expected '" 896 print-grapheme-to-real-screen expected-grapheme 897 print-string-to-real-screen "' at (" 898 print-int32-hex-to-real-screen row-idx 899 print-string-to-real-screen ", " 900 print-int32-hex-to-real-screen col-idx 901 print-string-to-real-screen ") but observed '" 902 print-grapheme-to-real-screen g 903 print-string-to-real-screen "'\n" 904 } 905 $check-screen-row-in-bold-from:compare-bold: { 906 var bold?/eax: boolean <- screen-bold-at-idx? screen, idx 907 compare bold?, 1 908 { 909 break-if-!= 910 print-string-to-real-screen "." 911 break $check-screen-row-in-bold-from:compare-bold 912 } 913 # otherwise print an error 914 print-string-to-real-screen msg 915 print-string-to-real-screen ": expected '" 916 print-grapheme-to-real-screen expected-grapheme 917 print-string-to-real-screen "' at (" 918 print-int32-hex-to-real-screen row-idx 919 print-string-to-real-screen ", " 920 print-int32-hex-to-real-screen col-idx 921 print-string-to-real-screen ") to be in bold\n" 922 } 923 } 924 idx <- increment 925 increment col-idx 926 loop 927 } 928 } 929 930 fn check-screen-row-in-underline screen: (addr screen), row-idx: int, expected: (addr array byte), msg: (addr array byte) { 931 check-screen-row-in-underline-from screen, row-idx, 1, expected, msg 932 } 933 934 fn check-screen-row-in-underline-from screen-on-stack: (addr screen), row-idx: int, col-idx: int, expected: (addr array byte), msg: (addr array byte) { 935 var screen/esi: (addr screen) <- copy screen-on-stack 936 var idx/ecx: int <- screen-cell-index screen, row-idx, col-idx 937 # compare 'expected' with the screen contents starting at 'idx', grapheme by grapheme 938 var e: (stream byte 0x100) 939 var e-addr/edx: (addr stream byte) <- address e 940 write e-addr, expected 941 { 942 var done?/eax: boolean <- stream-empty? e-addr 943 compare done?, 0 944 break-if-!= 945 var _g/eax: grapheme <- screen-grapheme-at-idx screen, idx 946 var g/ebx: grapheme <- copy _g 947 var _expected-grapheme/eax: grapheme <- read-grapheme e-addr 948 var expected-grapheme/edx: grapheme <- copy _expected-grapheme 949 $check-screen-row-in-underline-from:compare-cells: { 950 # if expected-grapheme is space, null grapheme is also ok 951 { 952 compare expected-grapheme, 0x20 953 break-if-!= 954 compare g, 0 955 break-if-= $check-screen-row-in-underline-from:compare-cells 956 } 957 # if expected-grapheme is space, non-underline is ok 958 { 959 compare expected-grapheme, 0x20 960 break-if-!= 961 var underline?/eax: boolean <- screen-underline-at-idx? screen, idx 962 compare underline?, 1 963 break-if-!= $check-screen-row-in-underline-from:compare-cells 964 } 965 # compare graphemes 966 $check-screen-row-in-underline-from:compare-graphemes: { 967 # if (g == expected-grapheme) print "." 968 compare g, expected-grapheme 969 { 970 break-if-!= 971 print-string-to-real-screen "." 972 break $check-screen-row-in-underline-from:compare-graphemes 973 } 974 # otherwise print an error 975 print-string-to-real-screen msg 976 print-string-to-real-screen ": expected '" 977 print-grapheme-to-real-screen expected-grapheme 978 print-string-to-real-screen "' at (" 979 print-int32-hex-to-real-screen row-idx 980 print-string-to-real-screen ", " 981 print-int32-hex-to-real-screen col-idx 982 print-string-to-real-screen ") but observed '" 983 print-grapheme-to-real-screen g 984 print-string-to-real-screen "'\n" 985 } 986 $check-screen-row-in-underline-from:compare-underline: { 987 var underline?/eax: boolean <- screen-underline-at-idx? screen, idx 988 compare underline?, 1 989 { 990 break-if-!= 991 print-string-to-real-screen "." 992 break $check-screen-row-in-underline-from:compare-underline 993 } 994 # otherwise print an error 995 print-string-to-real-screen msg 996 print-string-to-real-screen ": expected '" 997 print-grapheme-to-real-screen expected-grapheme 998 print-string-to-real-screen "' at (" 999 print-int32-hex-to-real-screen row-idx 1000 print-string-to-real-screen ", " 1001 print-int32-hex-to-real-screen col-idx 1002 print-string-to-real-screen ") to be underlined\n" 1003 } 1004 } 1005 idx <- increment 1006 increment col-idx 1007 loop 1008 } 1009 } 1010 1011 fn check-screen-row-in-reverse screen: (addr screen), row-idx: int, expected: (addr array byte), msg: (addr array byte) { 1012 check-screen-row-in-reverse-from screen, row-idx, 1, expected, msg 1013 } 1014 1015 fn check-screen-row-in-reverse-from screen-on-stack: (addr screen), row-idx: int, col-idx: int, expected: (addr array byte), msg: (addr array byte) { 1016 var screen/esi: (addr screen) <- copy screen-on-stack 1017 var idx/ecx: int <- screen-cell-index screen, row-idx, col-idx 1018 # compare 'expected' with the screen contents starting at 'idx', grapheme by grapheme 1019 var e: (stream byte 0x100) 1020 var e-addr/edx: (addr stream byte) <- address e 1021 write e-addr, expected 1022 { 1023 var done?/eax: boolean <- stream-empty? e-addr 1024 compare done?, 0 1025 break-if-!= 1026 var _g/eax: grapheme <- screen-grapheme-at-idx screen, idx 1027 var g/ebx: grapheme <- copy _g 1028 var _expected-grapheme/eax: grapheme <- read-grapheme e-addr 1029 var expected-grapheme/edx: grapheme <- copy _expected-grapheme 1030 $check-screen-row-in-reverse-from:compare-cells: { 1031 # if expected-grapheme is space, null grapheme is also ok 1032 { 1033 compare expected-grapheme, 0x20 1034 break-if-!= 1035 compare g, 0 1036 break-if-= $check-screen-row-in-reverse-from:compare-cells 1037 } 1038 # if expected-grapheme is space, non-reverse is ok 1039 { 1040 compare expected-grapheme, 0x20 1041 break-if-!= 1042 var reverse?/eax: boolean <- screen-reverse-at-idx? screen, idx 1043 compare reverse?, 1 1044 break-if-!= $check-screen-row-in-reverse-from:compare-cells 1045 } 1046 # compare graphemes 1047 $check-screen-row-in-reverse-from:compare-graphemes: { 1048 # if (g == expected-grapheme) print "." 1049 compare g, expected-grapheme 1050 { 1051 break-if-!= 1052 print-string-to-real-screen "." 1053 break $check-screen-row-in-reverse-from:compare-graphemes 1054 } 1055 # otherwise print an error 1056 print-string-to-real-screen msg 1057 print-string-to-real-screen ": expected '" 1058 print-grapheme-to-real-screen expected-grapheme 1059 print-string-to-real-screen "' at (" 1060 print-int32-hex-to-real-screen row-idx 1061 print-string-to-real-screen ", " 1062 print-int32-hex-to-real-screen col-idx 1063 print-string-to-real-screen ") but observed '" 1064 print-grapheme-to-real-screen g 1065 print-string-to-real-screen "'\n" 1066 } 1067 $check-screen-row-in-reverse-from:compare-reverse: { 1068 var reverse?/eax: boolean <- screen-reverse-at-idx? screen, idx 1069 compare reverse?, 1 1070 { 1071 break-if-!= 1072 print-string-to-real-screen "." 1073 break $check-screen-row-in-reverse-from:compare-reverse 1074 } 1075 # otherwise print an error 1076 print-string-to-real-screen msg 1077 print-string-to-real-screen ": expected '" 1078 print-grapheme-to-real-screen expected-grapheme 1079 print-string-to-real-screen "' at (" 1080 print-int32-hex-to-real-screen row-idx 1081 print-string-to-real-screen ", " 1082 print-int32-hex-to-real-screen col-idx 1083 print-string-to-real-screen ") to be in reverse-video\n" 1084 } 1085 } 1086 idx <- increment 1087 increment col-idx 1088 loop 1089 } 1090 } 1091 1092 fn check-screen-row-in-blinking screen: (addr screen), row-idx: int, expected: (addr array byte), msg: (addr array byte) { 1093 check-screen-row-in-blinking-from screen, row-idx, 1, expected, msg 1094 } 1095 1096 fn check-screen-row-in-blinking-from screen-on-stack: (addr screen), row-idx: int, col-idx: int, expected: (addr array byte), msg: (addr array byte) { 1097 var screen/esi: (addr screen) <- copy screen-on-stack 1098 var idx/ecx: int <- screen-cell-index screen, row-idx, col-idx 1099 # compare 'expected' with the screen contents starting at 'idx', grapheme by grapheme 1100 var e: (stream byte 0x100) 1101 var e-addr/edx: (addr stream byte) <- address e 1102 write e-addr, expected 1103 { 1104 var done?/eax: boolean <- stream-empty? e-addr 1105 compare done?, 0 1106 break-if-!= 1107 var _g/eax: grapheme <- screen-grapheme-at-idx screen, idx 1108 var g/ebx: grapheme <- copy _g 1109 var _expected-grapheme/eax: grapheme <- read-grapheme e-addr 1110 var expected-grapheme/edx: grapheme <- copy _expected-grapheme 1111 $check-screen-row-in-blinking-from:compare-cells: { 1112 # if expected-grapheme is space, null grapheme is also ok 1113 { 1114 compare expected-grapheme, 0x20 1115 break-if-!= 1116 compare g, 0 1117 break-if-= $check-screen-row-in-blinking-from:compare-cells 1118 } 1119 # if expected-grapheme is space, non-blinking is ok 1120 { 1121 compare expected-grapheme, 0x20 1122 break-if-!= 1123 var blinking?/eax: boolean <- screen-blink-at-idx? screen, idx 1124 compare blinking?, 1 1125 break-if-!= $check-screen-row-in-blinking-from:compare-cells 1126 } 1127 # compare graphemes 1128 $check-screen-row-in-blinking-from:compare-graphemes: { 1129 # if (g == expected-grapheme) print "." 1130 compare g, expected-grapheme 1131 { 1132 break-if-!= 1133 print-string-to-real-screen "." 1134 break $check-screen-row-in-blinking-from:compare-graphemes 1135 } 1136 # otherwise print an error 1137 print-string-to-real-screen msg 1138 print-string-to-real-screen ": expected '" 1139 print-grapheme-to-real-screen expected-grapheme 1140 print-string-to-real-screen "' at (" 1141 print-int32-hex-to-real-screen row-idx 1142 print-string-to-real-screen ", " 1143 print-int32-hex-to-real-screen col-idx 1144 print-string-to-real-screen ") but observed '" 1145 print-grapheme-to-real-screen g 1146 print-string-to-real-screen "'\n" 1147 } 1148 $check-screen-row-in-blinking-from:compare-blinking: { 1149 var blinking?/eax: boolean <- screen-blink-at-idx? screen, idx 1150 compare blinking?, 1 1151 { 1152 break-if-!= 1153 print-string-to-real-screen "." 1154 break $check-screen-row-in-blinking-from:compare-blinking 1155 } 1156 # otherwise print an error 1157 print-string-to-real-screen msg 1158 print-string-to-real-screen ": expected '" 1159 print-grapheme-to-real-screen expected-grapheme 1160 print-string-to-real-screen "' at (" 1161 print-int32-hex-to-real-screen row-idx 1162 print-string-to-real-screen ", " 1163 print-int32-hex-to-real-screen col-idx 1164 print-string-to-real-screen ") to be blinking\n" 1165 } 1166 } 1167 idx <- increment 1168 increment col-idx 1169 1170 loop 1171 } 1172 } 1173 1174 fn test-print-single-grapheme { 1175 var screen-on-stack: screen 1176 var screen/esi: (addr screen) <- address screen-on-stack 1177 initialize-screen screen, 5, 4 1178 var c/eax: grapheme <- copy 0x61 # 'a' 1179 print-grapheme screen, c 1180 check-screen-row screen, 1, "a", "F - test-print-single-grapheme" # top-left corner of the screen 1181 } 1182 1183 fn test-print-multiple-graphemes { 1184 var screen-on-stack: screen 1185 var screen/esi: (addr screen) <- address screen-on-stack 1186 initialize-screen screen, 5, 4 1187 print-string screen, "Hello, 世界" 1188 check-screen-row screen, 1, "Hello, 世界", "F - test-print-multiple-graphemes" 1189 } 1190 1191 fn test-move-cursor { 1192 var screen-on-stack: screen 1193 var screen/esi: (addr screen) <- address screen-on-stack 1194 initialize-screen screen, 5, 4 1195 move-cursor screen, 1, 4 1196 var c/eax: grapheme <- copy 0x61 # 'a' 1197 print-grapheme screen, c 1198 check-screen-row screen, 1, " a", "F - test-move-cursor" # top row 1199 } 1200 1201 fn test-move-cursor-zeroes { 1202 var screen-on-stack: screen 1203 var screen/esi: (addr screen) <- address screen-on-stack 1204 initialize-screen screen, 5, 4 1205 move-cursor screen, 0, 0 1206 var c/eax: grapheme <- copy 0x61 # 'a' 1207 print-grapheme screen, c 1208 check-screen-row screen, 1, "a", "F - test-move-cursor-zeroes" # top-left corner of the screen 1209 } 1210 1211 fn test-move-cursor-zero-row { 1212 var screen-on-stack: screen 1213 var screen/esi: (addr screen) <- address screen-on-stack 1214 initialize-screen screen, 5, 4 1215 move-cursor screen, 0, 2 1216 var c/eax: grapheme <- copy 0x61 # 'a' 1217 print-grapheme screen, c 1218 check-screen-row screen, 1, " a", "F - test-move-cursor-zero-row" # top row 1219 } 1220 1221 fn test-move-cursor-zero-column { 1222 var screen-on-stack: screen 1223 var screen/esi: (addr screen) <- address screen-on-stack 1224 initialize-screen screen, 5, 4 1225 move-cursor screen, 4, 0 1226 var c/eax: grapheme <- copy 0x61 # 'a' 1227 print-grapheme screen, c 1228 check-screen-row screen, 4, "a", "F - test-move-cursor-zero-column" 1229 } 1230 1231 fn test-move-cursor-negative-row { 1232 var screen-on-stack: screen 1233 var screen/esi: (addr screen) <- address screen-on-stack 1234 initialize-screen screen, 5, 3 1235 move-cursor screen, -1, 2 # row -1 1236 var c/eax: grapheme <- copy 0x61 # 'a' 1237 print-grapheme screen, c 1238 # no move 1239 check-screen-row screen, 1, "a", "F - test-move-cursor-negative-row" 1240 } 1241 1242 fn test-move-cursor-negative-column { 1243 var screen-on-stack: screen 1244 var screen/esi: (addr screen) <- address screen-on-stack 1245 initialize-screen screen, 5, 3 1246 move-cursor screen, 2, -1 # column -1 1247 var c/eax: grapheme <- copy 0x61 # 'a' 1248 print-grapheme screen, c 1249 # no move 1250 check-screen-row screen, 1, "a", "F - test-move-cursor-negative-column" 1251 } 1252 1253 fn test-move-cursor-column-too-large { 1254 var screen-on-stack: screen 1255 var screen/esi: (addr screen) <- address screen-on-stack 1256 initialize-screen screen, 5, 3 # 5 rows, 3 columns 1257 move-cursor screen, 1, 4 # row 1, column 4 (overflow) 1258 var c/eax: grapheme <- copy 0x61 # 'a' 1259 print-grapheme screen, c 1260 # top row is empty 1261 check-screen-row screen, 1, " ", "F - test-move-cursor-column-too-large" 1262 # character shows up on next row 1263 check-screen-row screen, 2, "a", "F - test-move-cursor-column-too-large" 1264 } 1265 1266 fn test-move-cursor-column-too-large-saturates { 1267 var screen-on-stack: screen 1268 var screen/esi: (addr screen) <- address screen-on-stack 1269 initialize-screen screen, 5, 3 # 5 rows, 3 columns 1270 move-cursor screen, 1, 6 # row 1, column 6 (overflow) 1271 var c/eax: grapheme <- copy 0x61 # 'a' 1272 print-grapheme screen, c 1273 # top row is empty 1274 check-screen-row screen, 1, " ", "F - test-move-cursor-column-too-large-saturates" # top-left corner of the screen 1275 # character shows up at the start of next row 1276 check-screen-row screen, 2, "a", "F - test-move-cursor-column-too-large-saturates" # top-left corner of the screen 1277 } 1278 1279 fn test-move-cursor-row-too-large { 1280 var screen-on-stack: screen 1281 var screen/esi: (addr screen) <- address screen-on-stack 1282 initialize-screen screen, 5, 3 # 5 rows 1283 move-cursor screen, 6, 2 # row 6 (overflow) 1284 var c/eax: grapheme <- copy 0x61 # 'a' 1285 print-grapheme screen, c 1286 # bottom row shows the character 1287 check-screen-row screen, 5, " a", "F - test-move-cursor-row-too-large" 1288 } 1289 1290 fn test-move-cursor-row-too-large-saturates { 1291 var screen-on-stack: screen 1292 var screen/esi: (addr screen) <- address screen-on-stack 1293 initialize-screen screen, 5, 3 # 5 rows 1294 move-cursor screen, 9, 2 # row 9 (overflow) 1295 var c/eax: grapheme <- copy 0x61 # 'a' 1296 print-grapheme screen, c 1297 # bottom row shows the character 1298 check-screen-row screen, 5, " a", "F - test-move-cursor-row-too-large-saturates" 1299 } 1300 1301 fn test-check-screen-row-from { 1302 var screen-on-stack: screen 1303 var screen/esi: (addr screen) <- address screen-on-stack 1304 initialize-screen screen, 5, 4 1305 move-cursor screen, 1, 4 1306 var c/eax: grapheme <- copy 0x61 # 'a' 1307 print-grapheme screen, c 1308 check-screen-row screen, 1, " a", "F - test-check-screen-row-from/baseline" 1309 check-screen-row-from screen, 1, 4, "a", "F - test-check-screen-row-from" 1310 } 1311 1312 fn test-print-string-overflows-to-next-row { 1313 var screen-on-stack: screen 1314 var screen/esi: (addr screen) <- address screen-on-stack 1315 initialize-screen screen, 5, 4 # 5 rows, 4 columns 1316 print-string screen, "abcdefg" 1317 check-screen-row screen, 1, "abcd", "F - test-print-string-overflows-to-next-row" 1318 check-screen-row screen, 2, "efg", "F - test-print-string-overflows-to-next-row" 1319 } 1320 1321 fn test-check-screen-scrolls-on-overflow { 1322 var screen-on-stack: screen 1323 var screen/esi: (addr screen) <- address screen-on-stack 1324 initialize-screen screen, 5, 4 1325 # single character starting at bottom right 1326 move-cursor screen, 5, 4 1327 var c/eax: grapheme <- copy 0x61 # 'a' 1328 print-grapheme screen, c 1329 check-screen-row-from screen, 5, 4, "a", "F - test-check-screen-scrolls-on-overflow/baseline" # bottom-right corner of the screen 1330 # multiple characters starting at bottom right 1331 move-cursor screen, 5, 4 1332 print-string screen, "ab" 1333 # screen scrolled up one row 1334 #? check-screen-row screen, 1, " ", "F - test-check-screen-scrolls-on-overflow/x1" 1335 #? check-screen-row screen, 2, " ", "F - test-check-screen-scrolls-on-overflow/x2" 1336 #? check-screen-row screen, 3, " ", "F - test-check-screen-scrolls-on-overflow/x3" 1337 #? check-screen-row screen, 4, " a", "F - test-check-screen-scrolls-on-overflow/x4" 1338 #? check-screen-row screen, 5, "b ", "F - test-check-screen-scrolls-on-overflow/x5" 1339 check-screen-row-from screen, 4, 4, "a", "F - test-check-screen-scrolls-on-overflow/1" 1340 check-screen-row-from screen, 5, 1, "b", "F - test-check-screen-scrolls-on-overflow/2" 1341 } 1342 1343 fn test-check-screen-color { 1344 var screen-on-stack: screen 1345 var screen/esi: (addr screen) <- address screen-on-stack 1346 initialize-screen screen, 5, 4 1347 var c/eax: grapheme <- copy 0x61 # 'a' 1348 print-grapheme screen, c 1349 start-color screen, 1, 0 # foreground=1 1350 c <- copy 0x62 # 'b' 1351 print-grapheme screen, c 1352 start-color screen, 0, 0 # back to default 1353 c <- copy 0x63 # 'c' 1354 print-grapheme screen, c 1355 check-screen-row-in-color screen, 0, 1, "a c", "F - test-check-screen-color" 1356 } 1357 1358 fn test-check-screen-background-color { 1359 var screen-on-stack: screen 1360 var screen/esi: (addr screen) <- address screen-on-stack 1361 initialize-screen screen, 5, 4 1362 var c/eax: grapheme <- copy 0x61 # 'a' 1363 print-grapheme screen, c 1364 start-color screen, 0, 1 # background=1 1365 c <- copy 0x62 # 'b' 1366 print-grapheme screen, c 1367 start-color screen, 0, 7 # back to default 1368 c <- copy 0x63 # 'c' 1369 print-grapheme screen, c 1370 check-screen-row-in-background-color screen, 7, 1, "a c", "F - test-check-screen-background-color" 1371 } 1372 1373 fn test-check-screen-bold { 1374 var screen-on-stack: screen 1375 var screen/esi: (addr screen) <- address screen-on-stack 1376 initialize-screen screen, 5, 4 1377 start-bold screen 1378 var c/eax: grapheme <- copy 0x61 # 'a' 1379 print-grapheme screen, c 1380 reset-formatting screen 1381 c <- copy 0x62 # 'b' 1382 print-grapheme screen, c 1383 start-bold screen 1384 c <- copy 0x63 # 'c' 1385 print-grapheme screen, c 1386 check-screen-row-in-bold screen, 1, "a c", "F - test-check-screen-bold" 1387 } 1388 1389 fn test-check-screen-underline { 1390 var screen-on-stack: screen 1391 var screen/esi: (addr screen) <- address screen-on-stack 1392 initialize-screen screen, 5, 4 1393 start-underline screen 1394 var c/eax: grapheme <- copy 0x61 # 'a' 1395 print-grapheme screen, c 1396 reset-formatting screen 1397 c <- copy 0x62 # 'b' 1398 print-grapheme screen, c 1399 start-underline screen 1400 c <- copy 0x63 # 'c' 1401 print-grapheme screen, c 1402 check-screen-row-in-underline screen, 1, "a c", "F - test-check-screen-underline" 1403 } 1404 1405 fn test-check-screen-reverse { 1406 var screen-on-stack: screen 1407 var screen/esi: (addr screen) <- address screen-on-stack 1408 initialize-screen screen, 5, 4 1409 start-reverse-video screen 1410 var c/eax: grapheme <- copy 0x61 # 'a' 1411 print-grapheme screen, c 1412 reset-formatting screen 1413 c <- copy 0x62 # 'b' 1414 print-grapheme screen, c 1415 start-reverse-video screen 1416 c <- copy 0x63 # 'c' 1417 print-grapheme screen, c 1418 check-screen-row-in-reverse screen, 1, "a c", "F - test-check-screen-reverse" 1419 } 1420 1421 fn test-check-screen-blinking { 1422 var screen-on-stack: screen 1423 var screen/esi: (addr screen) <- address screen-on-stack 1424 initialize-screen screen, 5, 4 1425 start-blinking screen 1426 var c/eax: grapheme <- copy 0x61 # 'a' 1427 print-grapheme screen, c 1428 reset-formatting screen 1429 c <- copy 0x62 # 'b' 1430 print-grapheme screen, c 1431 start-blinking screen 1432 c <- copy 0x63 # 'c' 1433 print-grapheme screen, c 1434 check-screen-row-in-blinking screen, 1, "a c", "F - test-check-screen-blinking" 1435 } 1436 1437 #? fn main -> _/ebx: int { 1438 #? #? test-check-screen-color 1439 #? run-tests 1440 #? return 0 1441 #? }