From 1f9b16680f1190a7be4098d61ed2ef74b1906b79 Mon Sep 17 00:00:00 2001 From: Kartik Agaram Date: Tue, 9 Nov 2021 09:38:54 -0800 Subject: [PATCH] . --- 513grapheme-stack.mu | 4 +- html/513grapheme-stack.mu.html | 1136 ++++++++++----------- html/shell/gap-buffer.mu.html | 1538 ----------------------------- html/shell/grapheme-stack.mu.html | 624 ------------ tools/update_html | 58 +- 5 files changed, 573 insertions(+), 2787 deletions(-) delete mode 100644 html/shell/gap-buffer.mu.html delete mode 100644 html/shell/grapheme-stack.mu.html diff --git a/513grapheme-stack.mu b/513grapheme-stack.mu index 5792e08c..0ce05fb6 100644 --- a/513grapheme-stack.mu +++ b/513grapheme-stack.mu @@ -1,4 +1,6 @@ -# code-point-utf8 stacks are the smallest unit of editable text +# Grapheme stacks are the smallest unit of editable text. +# +# (Currently they just support single-code-point graphemes.) type grapheme-stack { data: (handle array code-point-utf8) diff --git a/html/513grapheme-stack.mu.html b/html/513grapheme-stack.mu.html index 8476f08d..ccd0accd 100644 --- a/html/513grapheme-stack.mu.html +++ b/html/513grapheme-stack.mu.html @@ -62,577 +62,579 @@ if ('onhashchange' in window) { https://github.com/akkartik/mu/blob/main/513grapheme-stack.mu
-  1 # code-point-utf8 stacks are the smallest unit of editable text
-  2 
-  3 type grapheme-stack {
-  4   data: (handle array code-point-utf8)
-  5   top: int
-  6 }
-  7 
-  8 fn initialize-grapheme-stack _self: (addr grapheme-stack), n: int {
-  9   var self/esi: (addr grapheme-stack) <- copy _self
- 10   var d/edi: (addr handle array code-point-utf8) <- get self, data
- 11   populate d, n
- 12   var top/eax: (addr int) <- get self, top
- 13   copy-to *top, 0
- 14 }
- 15 
- 16 fn clear-grapheme-stack _self: (addr grapheme-stack) {
- 17   var self/esi: (addr grapheme-stack) <- copy _self
- 18   var top/eax: (addr int) <- get self, top
- 19   copy-to *top, 0
- 20 }
- 21 
- 22 fn grapheme-stack-empty? _self: (addr grapheme-stack) -> _/eax: boolean {
- 23   var self/esi: (addr grapheme-stack) <- copy _self
- 24   var top/eax: (addr int) <- get self, top
- 25   compare *top, 0
- 26   {
- 27     break-if-!=
- 28     return 1/true
- 29   }
- 30   return 0/false
- 31 }
- 32 
- 33 fn grapheme-stack-length _self: (addr grapheme-stack) -> _/eax: int {
- 34   var self/esi: (addr grapheme-stack) <- copy _self
- 35   var top/eax: (addr int) <- get self, top
- 36   return *top
- 37 }
- 38 
- 39 fn push-grapheme-stack _self: (addr grapheme-stack), _val: code-point-utf8 {
- 40   var self/esi: (addr grapheme-stack) <- copy _self
- 41   var top-addr/ecx: (addr int) <- get self, top
- 42   var data-ah/edx: (addr handle array code-point-utf8) <- get self, data
- 43   var data/eax: (addr array code-point-utf8) <- lookup *data-ah
- 44   var top/edx: int <- copy *top-addr
- 45   var dest-addr/edx: (addr code-point-utf8) <- index data, top
- 46   var val/eax: code-point-utf8 <- copy _val
- 47   copy-to *dest-addr, val
- 48   add-to *top-addr, 1
- 49 }
- 50 
- 51 fn pop-grapheme-stack _self: (addr grapheme-stack) -> _/eax: code-point-utf8 {
- 52   var self/esi: (addr grapheme-stack) <- copy _self
- 53   var top-addr/ecx: (addr int) <- get self, top
- 54   {
- 55     compare *top-addr, 0
- 56     break-if->
- 57     return -1
- 58   }
- 59   subtract-from *top-addr, 1
- 60   var data-ah/edx: (addr handle array code-point-utf8) <- get self, data
- 61   var data/eax: (addr array code-point-utf8) <- lookup *data-ah
- 62   var top/edx: int <- copy *top-addr
- 63   var result-addr/eax: (addr code-point-utf8) <- index data, top
- 64   return *result-addr
- 65 }
- 66 
- 67 fn copy-grapheme-stack _src: (addr grapheme-stack), dest: (addr grapheme-stack) {
- 68   var src/esi: (addr grapheme-stack) <- copy _src
- 69   var data-ah/edi: (addr handle array code-point-utf8) <- get src, data
- 70   var _data/eax: (addr array code-point-utf8) <- lookup *data-ah
- 71   var data/edi: (addr array code-point-utf8) <- copy _data
- 72   var top-addr/ecx: (addr int) <- get src, top
- 73   var i/eax: int <- copy 0
- 74   {
- 75     compare i, *top-addr
- 76     break-if->=
- 77     var g/edx: (addr code-point-utf8) <- index data, i
- 78     push-grapheme-stack dest, *g
- 79     i <- increment
- 80     loop
- 81   }
- 82 }
- 83 
- 84 # dump stack to screen from bottom to top
- 85 # hardcoded colors:
- 86 #   matching paren
- 87 fn render-stack-from-bottom-wrapping-right-then-down screen: (addr screen), _self: (addr grapheme-stack), xmin: int, ymin: int, xmax: int, ymax: int, _x: int, _y: int, highlight-matching-open-paren?: boolean, open-paren-depth: int, color: int, background-color: int -> _/eax: int, _/ecx: int {
- 88   var self/esi: (addr grapheme-stack) <- copy _self
- 89   var matching-open-paren-index/edx: int <- get-matching-open-paren-index self, highlight-matching-open-paren?, open-paren-depth
- 90   var data-ah/edi: (addr handle array code-point-utf8) <- get self, data
- 91   var _data/eax: (addr array code-point-utf8) <- lookup *data-ah
- 92   var data/edi: (addr array code-point-utf8) <- copy _data
- 93   var x/eax: int <- copy _x
- 94   var y/ecx: int <- copy _y
- 95   var top-addr/esi: (addr int) <- get self, top
- 96   var i/ebx: int <- copy 0
- 97   {
- 98     compare i, *top-addr
- 99     break-if->=
-100     {
-101       var c: code-point
-102       {
-103         var g/eax: (addr code-point-utf8) <- index data, i
-104         var tmp/eax: code-point <- to-code-point *g
-105         copy-to c, tmp
-106       }
-107       var fg: int
-108       {
-109         var tmp/eax: int <- copy color
-110         copy-to fg, tmp
-111       }
-112       {
-113         compare i, matching-open-paren-index
-114         break-if-!=
-115         copy-to fg, 0xf/highlight
-116       }
-117       x, y <- render-code-point screen, c, xmin, ymin, xmax, ymax, x, y, fg, background-color  # TODO: handle combining characters
-118     }
-119     i <- increment
-120     loop
-121   }
-122   return x, y
-123 }
-124 
-125 # helper for small words
-126 fn render-stack-from-bottom screen: (addr screen), self: (addr grapheme-stack), x: int, y: int, highlight-matching-open-paren?: boolean, open-paren-depth: int -> _/eax: int {
-127   var _width/eax: int <- copy 0
-128   var _height/ecx: int <- copy 0
-129   _width, _height <- screen-size screen
-130   var width/edx: int <- copy _width
-131   var height/ebx: int <- copy _height
-132   var x2/eax: int <- copy 0
-133   var y2/ecx: int <- copy 0
-134   x2, y2 <- render-stack-from-bottom-wrapping-right-then-down screen, self, x, y, width, height, x, y, highlight-matching-open-paren?, open-paren-depth, 3/fg=cyan, 0xc5/bg=blue-bg
-135   return x2  # y2? yolo
-136 }
-137 
-138 # dump stack to screen from top to bottom
-139 # optionally render a 'cursor' with the top code-point-utf8
-140 # hard-coded colors:
-141 #   matching paren
-142 #   cursor
-143 fn render-stack-from-top-wrapping-right-then-down screen: (addr screen), _self: (addr grapheme-stack), xmin: int, ymin: int, xmax: int, ymax: int, _x: int, _y: int, render-cursor?: boolean, color: int, background-color: int -> _/eax: int, _/ecx: int {
-144   var self/esi: (addr grapheme-stack) <- copy _self
-145   var matching-close-paren-index/edx: int <- get-matching-close-paren-index self, render-cursor?
-146   var data-ah/eax: (addr handle array code-point-utf8) <- get self, data
-147   var _data/eax: (addr array code-point-utf8) <- lookup *data-ah
-148   var data/edi: (addr array code-point-utf8) <- copy _data
-149   var x/eax: int <- copy _x
-150   var y/ecx: int <- copy _y
-151   var top-addr/ebx: (addr int) <- get self, top
-152   var i/ebx: int <- copy *top-addr
-153   i <- decrement
-154   # if render-cursor?, peel off first iteration
-155   {
-156     compare render-cursor?, 0/false
-157     break-if-=
-158     compare i, 0
-159     break-if-<
-160     var c: code-point
-161     {
-162       var g/eax: (addr code-point-utf8) <- index data, i
-163       var tmp/eax: code-point <- to-code-point *g
-164       copy-to c, tmp
-165     }
-166     x, y <- render-code-point screen, c, xmin, ymin, xmax, ymax, x, y, background-color, color
-167     i <- decrement
-168   }
-169   # remaining iterations
-170   {
-171     compare i, 0
-172     break-if-<
-173     # highlight matching paren if needed
-174     var fg: int
-175     {
-176       var tmp/eax: int <- copy color
-177       copy-to fg, tmp
-178     }
-179     compare i, matching-close-paren-index
-180     {
-181       break-if-!=
-182       copy-to fg, 0xf/highlight
-183     }
-184     #
-185     var c: code-point
-186     {
-187       var g/eax: (addr code-point-utf8) <- index data, i
-188       var tmp/eax: code-point <- to-code-point *g
-189       copy-to c, tmp
-190     }
-191     x, y <- render-code-point screen, c, xmin, ymin, xmax, ymax, x, y, fg, background-color
-192     i <- decrement
-193     loop
-194   }
-195   return x, y
-196 }
-197 
-198 # helper for small words
-199 fn render-stack-from-top screen: (addr screen), self: (addr grapheme-stack), x: int, y: int, render-cursor?: boolean -> _/eax: int {
-200   var _width/eax: int <- copy 0
-201   var _height/ecx: int <- copy 0
-202   _width, _height <- screen-size screen
-203   var width/edx: int <- copy _width
-204   var height/ebx: int <- copy _height
-205   var x2/eax: int <- copy 0
-206   var y2/ecx: int <- copy 0
-207   x2, y2 <- render-stack-from-top-wrapping-right-then-down screen, self, x, y, width, height, x, y, render-cursor?, 3/fg=cyan, 0xc5/bg=blue-bg
-208   return x2  # y2? yolo
-209 }
-210 
-211 fn test-render-grapheme-stack {
-212   # setup: gs = "abc"
-213   var gs-storage: grapheme-stack
-214   var gs/edi: (addr grapheme-stack) <- address gs-storage
-215   initialize-grapheme-stack gs, 5
-216   var g/eax: code-point-utf8 <- copy 0x61/a
-217   push-grapheme-stack gs, g
-218   g <- copy 0x62/b
-219   push-grapheme-stack gs, g
-220   g <- copy 0x63/c
-221   push-grapheme-stack gs, g
-222   # setup: screen
-223   var screen-storage: screen
-224   var screen/esi: (addr screen) <- address screen-storage
-225   initialize-screen screen, 5, 4, 0/no-pixel-graphics
-226   #
-227   var x/eax: int <- render-stack-from-bottom screen, gs, 0/x, 0/y, 0/no-highlight-matching-open-paren, 0/open-paren-depth
-228   check-screen-row screen, 0/y, "abc ", "F - test-render-grapheme-stack from bottom"
-229   check-ints-equal x, 3, "F - test-render-grapheme-stack from bottom: result"
-230   check-background-color-in-screen-row screen, 3/bg=reverse, 0/y, "   ", "F - test-render-grapheme-stack from bottom: bg"
-231   #
-232   var x/eax: int <- render-stack-from-top screen, gs, 0/x, 1/y, 0/cursor=false
-233   check-screen-row screen, 1/y, "cba ", "F - test-render-grapheme-stack from top without cursor"
-234   check-ints-equal x, 3, "F - test-render-grapheme-stack from top without cursor: result"
-235   check-background-color-in-screen-row screen, 3/bg=reverse, 1/y, "   ", "F - test-render-grapheme-stack from top without cursor: bg"
-236   #
-237   var x/eax: int <- render-stack-from-top screen, gs, 0/x, 2/y, 1/cursor=true
-238   check-screen-row screen, 2/y, "cba ", "F - test-render-grapheme-stack from top with cursor"
-239   check-ints-equal x, 3, "F - test-render-grapheme-stack from top with cursor: result"
-240   check-background-color-in-screen-row screen, 3/bg=reverse, 2/y, "|   ", "F - test-render-grapheme-stack from top with cursor: bg"
-241 }
-242 
-243 fn test-render-grapheme-stack-while-highlighting-matching-close-paren {
-244   # setup: gs = "(b)"
-245   var gs-storage: grapheme-stack
-246   var gs/edi: (addr grapheme-stack) <- address gs-storage
-247   initialize-grapheme-stack gs, 5
-248   var g/eax: code-point-utf8 <- copy 0x29/close-paren
-249   push-grapheme-stack gs, g
-250   g <- copy 0x62/b
-251   push-grapheme-stack gs, g
-252   g <- copy 0x28/open-paren
-253   push-grapheme-stack gs, g
-254   # setup: screen
-255   var screen-storage: screen
-256   var screen/esi: (addr screen) <- address screen-storage
-257   initialize-screen screen, 5, 4, 0/no-pixel-graphics
-258   #
-259   var x/eax: int <- render-stack-from-top screen, gs, 0/x, 2/y, 1/cursor=true
-260   check-screen-row                      screen,               2/y, "(b) ", "F - test-render-grapheme-stack-while-highlighting-matching-close-paren"
-261   check-background-color-in-screen-row  screen, 3/bg=reverse,  2/y, "|   ", "F - test-render-grapheme-stack-while-highlighting-matching-close-paren: cursor"
-262   check-screen-row-in-color             screen, 0xf/fg=white, 2/y, "  ) ", "F - test-render-grapheme-stack-while-highlighting-matching-close-paren: matching paren"
-263 }
-264 
-265 fn test-render-grapheme-stack-while-highlighting-matching-close-paren-2 {
-266   # setup: gs = "(a (b)) c"
-267   var gs-storage: grapheme-stack
-268   var gs/edi: (addr grapheme-stack) <- address gs-storage
-269   initialize-grapheme-stack gs, 0x10
-270   var g/eax: code-point-utf8 <- copy 0x63/c
-271   push-grapheme-stack gs, g
-272   g <- copy 0x20/space
-273   push-grapheme-stack gs, g
-274   g <- copy 0x29/close-paren
-275   push-grapheme-stack gs, g
+  1 # Grapheme stacks are the smallest unit of editable text.
+  2 #
+  3 # (Currently they just support single-code-point graphemes.)
+  4 
+  5 type grapheme-stack {
+  6   data: (handle array code-point-utf8)
+  7   top: int
+  8 }
+  9 
+ 10 fn initialize-grapheme-stack _self: (addr grapheme-stack), n: int {
+ 11   var self/esi: (addr grapheme-stack) <- copy _self
+ 12   var d/edi: (addr handle array code-point-utf8) <- get self, data
+ 13   populate d, n
+ 14   var top/eax: (addr int) <- get self, top
+ 15   copy-to *top, 0
+ 16 }
+ 17 
+ 18 fn clear-grapheme-stack _self: (addr grapheme-stack) {
+ 19   var self/esi: (addr grapheme-stack) <- copy _self
+ 20   var top/eax: (addr int) <- get self, top
+ 21   copy-to *top, 0
+ 22 }
+ 23 
+ 24 fn grapheme-stack-empty? _self: (addr grapheme-stack) -> _/eax: boolean {
+ 25   var self/esi: (addr grapheme-stack) <- copy _self
+ 26   var top/eax: (addr int) <- get self, top
+ 27   compare *top, 0
+ 28   {
+ 29     break-if-!=
+ 30     return 1/true
+ 31   }
+ 32   return 0/false
+ 33 }
+ 34 
+ 35 fn grapheme-stack-length _self: (addr grapheme-stack) -> _/eax: int {
+ 36   var self/esi: (addr grapheme-stack) <- copy _self
+ 37   var top/eax: (addr int) <- get self, top
+ 38   return *top
+ 39 }
+ 40 
+ 41 fn push-grapheme-stack _self: (addr grapheme-stack), _val: code-point-utf8 {
+ 42   var self/esi: (addr grapheme-stack) <- copy _self
+ 43   var top-addr/ecx: (addr int) <- get self, top
+ 44   var data-ah/edx: (addr handle array code-point-utf8) <- get self, data
+ 45   var data/eax: (addr array code-point-utf8) <- lookup *data-ah
+ 46   var top/edx: int <- copy *top-addr
+ 47   var dest-addr/edx: (addr code-point-utf8) <- index data, top
+ 48   var val/eax: code-point-utf8 <- copy _val
+ 49   copy-to *dest-addr, val
+ 50   add-to *top-addr, 1
+ 51 }
+ 52 
+ 53 fn pop-grapheme-stack _self: (addr grapheme-stack) -> _/eax: code-point-utf8 {
+ 54   var self/esi: (addr grapheme-stack) <- copy _self
+ 55   var top-addr/ecx: (addr int) <- get self, top
+ 56   {
+ 57     compare *top-addr, 0
+ 58     break-if->
+ 59     return -1
+ 60   }
+ 61   subtract-from *top-addr, 1
+ 62   var data-ah/edx: (addr handle array code-point-utf8) <- get self, data
+ 63   var data/eax: (addr array code-point-utf8) <- lookup *data-ah
+ 64   var top/edx: int <- copy *top-addr
+ 65   var result-addr/eax: (addr code-point-utf8) <- index data, top
+ 66   return *result-addr
+ 67 }
+ 68 
+ 69 fn copy-grapheme-stack _src: (addr grapheme-stack), dest: (addr grapheme-stack) {
+ 70   var src/esi: (addr grapheme-stack) <- copy _src
+ 71   var data-ah/edi: (addr handle array code-point-utf8) <- get src, data
+ 72   var _data/eax: (addr array code-point-utf8) <- lookup *data-ah
+ 73   var data/edi: (addr array code-point-utf8) <- copy _data
+ 74   var top-addr/ecx: (addr int) <- get src, top
+ 75   var i/eax: int <- copy 0
+ 76   {
+ 77     compare i, *top-addr
+ 78     break-if->=
+ 79     var g/edx: (addr code-point-utf8) <- index data, i
+ 80     push-grapheme-stack dest, *g
+ 81     i <- increment
+ 82     loop
+ 83   }
+ 84 }
+ 85 
+ 86 # dump stack to screen from bottom to top
+ 87 # hardcoded colors:
+ 88 #   matching paren
+ 89 fn render-stack-from-bottom-wrapping-right-then-down screen: (addr screen), _self: (addr grapheme-stack), xmin: int, ymin: int, xmax: int, ymax: int, _x: int, _y: int, highlight-matching-open-paren?: boolean, open-paren-depth: int, color: int, background-color: int -> _/eax: int, _/ecx: int {
+ 90   var self/esi: (addr grapheme-stack) <- copy _self
+ 91   var matching-open-paren-index/edx: int <- get-matching-open-paren-index self, highlight-matching-open-paren?, open-paren-depth
+ 92   var data-ah/edi: (addr handle array code-point-utf8) <- get self, data
+ 93   var _data/eax: (addr array code-point-utf8) <- lookup *data-ah
+ 94   var data/edi: (addr array code-point-utf8) <- copy _data
+ 95   var x/eax: int <- copy _x
+ 96   var y/ecx: int <- copy _y
+ 97   var top-addr/esi: (addr int) <- get self, top
+ 98   var i/ebx: int <- copy 0
+ 99   {
+100     compare i, *top-addr
+101     break-if->=
+102     {
+103       var c: code-point
+104       {
+105         var g/eax: (addr code-point-utf8) <- index data, i
+106         var tmp/eax: code-point <- to-code-point *g
+107         copy-to c, tmp
+108       }
+109       var fg: int
+110       {
+111         var tmp/eax: int <- copy color
+112         copy-to fg, tmp
+113       }
+114       {
+115         compare i, matching-open-paren-index
+116         break-if-!=
+117         copy-to fg, 0xf/highlight
+118       }
+119       x, y <- render-code-point screen, c, xmin, ymin, xmax, ymax, x, y, fg, background-color  # TODO: handle combining characters
+120     }
+121     i <- increment
+122     loop
+123   }
+124   return x, y
+125 }
+126 
+127 # helper for small words
+128 fn render-stack-from-bottom screen: (addr screen), self: (addr grapheme-stack), x: int, y: int, highlight-matching-open-paren?: boolean, open-paren-depth: int -> _/eax: int {
+129   var _width/eax: int <- copy 0
+130   var _height/ecx: int <- copy 0
+131   _width, _height <- screen-size screen
+132   var width/edx: int <- copy _width
+133   var height/ebx: int <- copy _height
+134   var x2/eax: int <- copy 0
+135   var y2/ecx: int <- copy 0
+136   x2, y2 <- render-stack-from-bottom-wrapping-right-then-down screen, self, x, y, width, height, x, y, highlight-matching-open-paren?, open-paren-depth, 3/fg=cyan, 0xc5/bg=blue-bg
+137   return x2  # y2? yolo
+138 }
+139 
+140 # dump stack to screen from top to bottom
+141 # optionally render a 'cursor' with the top code-point-utf8
+142 # hard-coded colors:
+143 #   matching paren
+144 #   cursor
+145 fn render-stack-from-top-wrapping-right-then-down screen: (addr screen), _self: (addr grapheme-stack), xmin: int, ymin: int, xmax: int, ymax: int, _x: int, _y: int, render-cursor?: boolean, color: int, background-color: int -> _/eax: int, _/ecx: int {
+146   var self/esi: (addr grapheme-stack) <- copy _self
+147   var matching-close-paren-index/edx: int <- get-matching-close-paren-index self, render-cursor?
+148   var data-ah/eax: (addr handle array code-point-utf8) <- get self, data
+149   var _data/eax: (addr array code-point-utf8) <- lookup *data-ah
+150   var data/edi: (addr array code-point-utf8) <- copy _data
+151   var x/eax: int <- copy _x
+152   var y/ecx: int <- copy _y
+153   var top-addr/ebx: (addr int) <- get self, top
+154   var i/ebx: int <- copy *top-addr
+155   i <- decrement
+156   # if render-cursor?, peel off first iteration
+157   {
+158     compare render-cursor?, 0/false
+159     break-if-=
+160     compare i, 0
+161     break-if-<
+162     var c: code-point
+163     {
+164       var g/eax: (addr code-point-utf8) <- index data, i
+165       var tmp/eax: code-point <- to-code-point *g
+166       copy-to c, tmp
+167     }
+168     x, y <- render-code-point screen, c, xmin, ymin, xmax, ymax, x, y, background-color, color
+169     i <- decrement
+170   }
+171   # remaining iterations
+172   {
+173     compare i, 0
+174     break-if-<
+175     # highlight matching paren if needed
+176     var fg: int
+177     {
+178       var tmp/eax: int <- copy color
+179       copy-to fg, tmp
+180     }
+181     compare i, matching-close-paren-index
+182     {
+183       break-if-!=
+184       copy-to fg, 0xf/highlight
+185     }
+186     #
+187     var c: code-point
+188     {
+189       var g/eax: (addr code-point-utf8) <- index data, i
+190       var tmp/eax: code-point <- to-code-point *g
+191       copy-to c, tmp
+192     }
+193     x, y <- render-code-point screen, c, xmin, ymin, xmax, ymax, x, y, fg, background-color
+194     i <- decrement
+195     loop
+196   }
+197   return x, y
+198 }
+199 
+200 # helper for small words
+201 fn render-stack-from-top screen: (addr screen), self: (addr grapheme-stack), x: int, y: int, render-cursor?: boolean -> _/eax: int {
+202   var _width/eax: int <- copy 0
+203   var _height/ecx: int <- copy 0
+204   _width, _height <- screen-size screen
+205   var width/edx: int <- copy _width
+206   var height/ebx: int <- copy _height
+207   var x2/eax: int <- copy 0
+208   var y2/ecx: int <- copy 0
+209   x2, y2 <- render-stack-from-top-wrapping-right-then-down screen, self, x, y, width, height, x, y, render-cursor?, 3/fg=cyan, 0xc5/bg=blue-bg
+210   return x2  # y2? yolo
+211 }
+212 
+213 fn test-render-grapheme-stack {
+214   # setup: gs = "abc"
+215   var gs-storage: grapheme-stack
+216   var gs/edi: (addr grapheme-stack) <- address gs-storage
+217   initialize-grapheme-stack gs, 5
+218   var g/eax: code-point-utf8 <- copy 0x61/a
+219   push-grapheme-stack gs, g
+220   g <- copy 0x62/b
+221   push-grapheme-stack gs, g
+222   g <- copy 0x63/c
+223   push-grapheme-stack gs, g
+224   # setup: screen
+225   var screen-storage: screen
+226   var screen/esi: (addr screen) <- address screen-storage
+227   initialize-screen screen, 5, 4, 0/no-pixel-graphics
+228   #
+229   var x/eax: int <- render-stack-from-bottom screen, gs, 0/x, 0/y, 0/no-highlight-matching-open-paren, 0/open-paren-depth
+230   check-screen-row screen, 0/y, "abc ", "F - test-render-grapheme-stack from bottom"
+231   check-ints-equal x, 3, "F - test-render-grapheme-stack from bottom: result"
+232   check-background-color-in-screen-row screen, 3/bg=reverse, 0/y, "   ", "F - test-render-grapheme-stack from bottom: bg"
+233   #
+234   var x/eax: int <- render-stack-from-top screen, gs, 0/x, 1/y, 0/cursor=false
+235   check-screen-row screen, 1/y, "cba ", "F - test-render-grapheme-stack from top without cursor"
+236   check-ints-equal x, 3, "F - test-render-grapheme-stack from top without cursor: result"
+237   check-background-color-in-screen-row screen, 3/bg=reverse, 1/y, "   ", "F - test-render-grapheme-stack from top without cursor: bg"
+238   #
+239   var x/eax: int <- render-stack-from-top screen, gs, 0/x, 2/y, 1/cursor=true
+240   check-screen-row screen, 2/y, "cba ", "F - test-render-grapheme-stack from top with cursor"
+241   check-ints-equal x, 3, "F - test-render-grapheme-stack from top with cursor: result"
+242   check-background-color-in-screen-row screen, 3/bg=reverse, 2/y, "|   ", "F - test-render-grapheme-stack from top with cursor: bg"
+243 }
+244 
+245 fn test-render-grapheme-stack-while-highlighting-matching-close-paren {
+246   # setup: gs = "(b)"
+247   var gs-storage: grapheme-stack
+248   var gs/edi: (addr grapheme-stack) <- address gs-storage
+249   initialize-grapheme-stack gs, 5
+250   var g/eax: code-point-utf8 <- copy 0x29/close-paren
+251   push-grapheme-stack gs, g
+252   g <- copy 0x62/b
+253   push-grapheme-stack gs, g
+254   g <- copy 0x28/open-paren
+255   push-grapheme-stack gs, g
+256   # setup: screen
+257   var screen-storage: screen
+258   var screen/esi: (addr screen) <- address screen-storage
+259   initialize-screen screen, 5, 4, 0/no-pixel-graphics
+260   #
+261   var x/eax: int <- render-stack-from-top screen, gs, 0/x, 2/y, 1/cursor=true
+262   check-screen-row                      screen,               2/y, "(b) ", "F - test-render-grapheme-stack-while-highlighting-matching-close-paren"
+263   check-background-color-in-screen-row  screen, 3/bg=reverse,  2/y, "|   ", "F - test-render-grapheme-stack-while-highlighting-matching-close-paren: cursor"
+264   check-screen-row-in-color             screen, 0xf/fg=white, 2/y, "  ) ", "F - test-render-grapheme-stack-while-highlighting-matching-close-paren: matching paren"
+265 }
+266 
+267 fn test-render-grapheme-stack-while-highlighting-matching-close-paren-2 {
+268   # setup: gs = "(a (b)) c"
+269   var gs-storage: grapheme-stack
+270   var gs/edi: (addr grapheme-stack) <- address gs-storage
+271   initialize-grapheme-stack gs, 0x10
+272   var g/eax: code-point-utf8 <- copy 0x63/c
+273   push-grapheme-stack gs, g
+274   g <- copy 0x20/space
+275   push-grapheme-stack gs, g
 276   g <- copy 0x29/close-paren
-277   push-grapheme-stack gs, g
-278   g <- copy 0x62/b
-279   push-grapheme-stack gs, g
-280   g <- copy 0x28/open-paren
-281   push-grapheme-stack gs, g
-282   g <- copy 0x20/space
-283   push-grapheme-stack gs, g
-284   g <- copy 0x61/a
-285   push-grapheme-stack gs, g
-286   g <- copy 0x28/open-paren
-287   push-grapheme-stack gs, g
-288   # setup: screen
-289   var screen-storage: screen
-290   var screen/esi: (addr screen) <- address screen-storage
-291   initialize-screen screen, 5, 4, 0/no-pixel-graphics
-292   #
-293   var x/eax: int <- render-stack-from-top screen, gs, 0/x, 2/y, 1/cursor=true
-294   check-screen-row                      screen,               2/y, "(a (b)) c ", "F - test-render-grapheme-stack-while-highlighting-matching-close-paren-2"
-295   check-background-color-in-screen-row  screen, 3/bg=reverse,  2/y, "|         ", "F - test-render-grapheme-stack-while-highlighting-matching-close-paren-2: cursor"
-296   check-screen-row-in-color             screen, 0xf/fg=white, 2/y, "      )   ", "F - test-render-grapheme-stack-while-highlighting-matching-close-paren-2: matching paren"
-297 }
-298 
-299 fn test-render-grapheme-stack-while-highlighting-matching-open-paren-with-close-paren-at-end {
-300   # setup: gs = "(b)"
-301   var gs-storage: grapheme-stack
-302   var gs/edi: (addr grapheme-stack) <- address gs-storage
-303   initialize-grapheme-stack gs, 5
-304   var g/eax: code-point-utf8 <- copy 0x28/open-paren
-305   push-grapheme-stack gs, g
-306   g <- copy 0x62/b
-307   push-grapheme-stack gs, g
-308   g <- copy 0x29/close-paren
-309   push-grapheme-stack gs, g
-310   # setup: screen
-311   var screen-storage: screen
-312   var screen/esi: (addr screen) <- address screen-storage
-313   initialize-screen screen, 5, 4, 0/no-pixel-graphics
-314   #
-315   var x/eax: int <- render-stack-from-bottom screen, gs, 0/x, 2/y, 1/highlight-matching-open-paren, 1/open-paren-depth
-316   check-screen-row          screen,               2/y, "(b) ", "F - test-render-grapheme-stack-while-highlighting-matching-open-paren-with-close-paren-at-end"
-317   check-screen-row-in-color screen, 0xf/fg=white, 2/y, "(   ", "F - test-render-grapheme-stack-while-highlighting-matching-open-paren-with-close-paren-at-end: matching paren"
-318 }
-319 
-320 fn test-render-grapheme-stack-while-highlighting-matching-open-paren-with-close-paren-at-end-2 {
-321   # setup: gs = "a((b))"
-322   var gs-storage: grapheme-stack
-323   var gs/edi: (addr grapheme-stack) <- address gs-storage
-324   initialize-grapheme-stack gs, 0x10
-325   var g/eax: code-point-utf8 <- copy 0x61/a
-326   push-grapheme-stack gs, g
-327   g <- copy 0x28/open-paren
-328   push-grapheme-stack gs, g
+277   push-grapheme-stack gs, g
+278   g <- copy 0x29/close-paren
+279   push-grapheme-stack gs, g
+280   g <- copy 0x62/b
+281   push-grapheme-stack gs, g
+282   g <- copy 0x28/open-paren
+283   push-grapheme-stack gs, g
+284   g <- copy 0x20/space
+285   push-grapheme-stack gs, g
+286   g <- copy 0x61/a
+287   push-grapheme-stack gs, g
+288   g <- copy 0x28/open-paren
+289   push-grapheme-stack gs, g
+290   # setup: screen
+291   var screen-storage: screen
+292   var screen/esi: (addr screen) <- address screen-storage
+293   initialize-screen screen, 5, 4, 0/no-pixel-graphics
+294   #
+295   var x/eax: int <- render-stack-from-top screen, gs, 0/x, 2/y, 1/cursor=true
+296   check-screen-row                      screen,               2/y, "(a (b)) c ", "F - test-render-grapheme-stack-while-highlighting-matching-close-paren-2"
+297   check-background-color-in-screen-row  screen, 3/bg=reverse,  2/y, "|         ", "F - test-render-grapheme-stack-while-highlighting-matching-close-paren-2: cursor"
+298   check-screen-row-in-color             screen, 0xf/fg=white, 2/y, "      )   ", "F - test-render-grapheme-stack-while-highlighting-matching-close-paren-2: matching paren"
+299 }
+300 
+301 fn test-render-grapheme-stack-while-highlighting-matching-open-paren-with-close-paren-at-end {
+302   # setup: gs = "(b)"
+303   var gs-storage: grapheme-stack
+304   var gs/edi: (addr grapheme-stack) <- address gs-storage
+305   initialize-grapheme-stack gs, 5
+306   var g/eax: code-point-utf8 <- copy 0x28/open-paren
+307   push-grapheme-stack gs, g
+308   g <- copy 0x62/b
+309   push-grapheme-stack gs, g
+310   g <- copy 0x29/close-paren
+311   push-grapheme-stack gs, g
+312   # setup: screen
+313   var screen-storage: screen
+314   var screen/esi: (addr screen) <- address screen-storage
+315   initialize-screen screen, 5, 4, 0/no-pixel-graphics
+316   #
+317   var x/eax: int <- render-stack-from-bottom screen, gs, 0/x, 2/y, 1/highlight-matching-open-paren, 1/open-paren-depth
+318   check-screen-row          screen,               2/y, "(b) ", "F - test-render-grapheme-stack-while-highlighting-matching-open-paren-with-close-paren-at-end"
+319   check-screen-row-in-color screen, 0xf/fg=white, 2/y, "(   ", "F - test-render-grapheme-stack-while-highlighting-matching-open-paren-with-close-paren-at-end: matching paren"
+320 }
+321 
+322 fn test-render-grapheme-stack-while-highlighting-matching-open-paren-with-close-paren-at-end-2 {
+323   # setup: gs = "a((b))"
+324   var gs-storage: grapheme-stack
+325   var gs/edi: (addr grapheme-stack) <- address gs-storage
+326   initialize-grapheme-stack gs, 0x10
+327   var g/eax: code-point-utf8 <- copy 0x61/a
+328   push-grapheme-stack gs, g
 329   g <- copy 0x28/open-paren
-330   push-grapheme-stack gs, g
-331   g <- copy 0x62/b
-332   push-grapheme-stack gs, g
-333   g <- copy 0x29/close-paren
-334   push-grapheme-stack gs, g
+330   push-grapheme-stack gs, g
+331   g <- copy 0x28/open-paren
+332   push-grapheme-stack gs, g
+333   g <- copy 0x62/b
+334   push-grapheme-stack gs, g
 335   g <- copy 0x29/close-paren
-336   push-grapheme-stack gs, g
-337   # setup: screen
-338   var screen-storage: screen
-339   var screen/esi: (addr screen) <- address screen-storage
-340   initialize-screen screen, 5, 4, 0/no-pixel-graphics
-341   #
-342   var x/eax: int <- render-stack-from-bottom screen, gs, 0/x, 2/y, 1/highlight-matching-open-paren, 1/open-paren-depth
-343   check-screen-row          screen,               2/y, "a((b)) ", "F - test-render-grapheme-stack-while-highlighting-matching-open-paren-with-close-paren-at-end-2"
-344   check-screen-row-in-color screen, 0xf/fg=white, 2/y, " (     ", "F - test-render-grapheme-stack-while-highlighting-matching-open-paren-with-close-paren-at-end-2: matching paren"
-345 }
-346 
-347 fn test-render-grapheme-stack-while-highlighting-matching-open-paren {
-348   # setup: gs = "(b"
-349   var gs-storage: grapheme-stack
-350   var gs/edi: (addr grapheme-stack) <- address gs-storage
-351   initialize-grapheme-stack gs, 5
-352   var g/eax: code-point-utf8 <- copy 0x28/open-paren
-353   push-grapheme-stack gs, g
-354   g <- copy 0x62/b
-355   push-grapheme-stack gs, g
-356   # setup: screen
-357   var screen-storage: screen
-358   var screen/esi: (addr screen) <- address screen-storage
-359   initialize-screen screen, 5, 4, 0/no-pixel-graphics
-360   #
-361   var x/eax: int <- render-stack-from-bottom screen, gs, 0/x, 2/y, 1/highlight-matching-open-paren, 0/open-paren-depth
-362   check-screen-row          screen,               2/y, "(b ", "F - test-render-grapheme-stack-while-highlighting-matching-open-paren"
-363   check-screen-row-in-color screen, 0xf/fg=white, 2/y, "(  ", "F - test-render-grapheme-stack-while-highlighting-matching-open-paren: matching paren"
-364 }
-365 
-366 fn test-render-grapheme-stack-while-highlighting-matching-open-paren-2 {
-367   # setup: gs = "a((b)"
-368   var gs-storage: grapheme-stack
-369   var gs/edi: (addr grapheme-stack) <- address gs-storage
-370   initialize-grapheme-stack gs, 0x10
-371   var g/eax: code-point-utf8 <- copy 0x61/a
-372   push-grapheme-stack gs, g
-373   g <- copy 0x28/open-paren
-374   push-grapheme-stack gs, g
+336   push-grapheme-stack gs, g
+337   g <- copy 0x29/close-paren
+338   push-grapheme-stack gs, g
+339   # setup: screen
+340   var screen-storage: screen
+341   var screen/esi: (addr screen) <- address screen-storage
+342   initialize-screen screen, 5, 4, 0/no-pixel-graphics
+343   #
+344   var x/eax: int <- render-stack-from-bottom screen, gs, 0/x, 2/y, 1/highlight-matching-open-paren, 1/open-paren-depth
+345   check-screen-row          screen,               2/y, "a((b)) ", "F - test-render-grapheme-stack-while-highlighting-matching-open-paren-with-close-paren-at-end-2"
+346   check-screen-row-in-color screen, 0xf/fg=white, 2/y, " (     ", "F - test-render-grapheme-stack-while-highlighting-matching-open-paren-with-close-paren-at-end-2: matching paren"
+347 }
+348 
+349 fn test-render-grapheme-stack-while-highlighting-matching-open-paren {
+350   # setup: gs = "(b"
+351   var gs-storage: grapheme-stack
+352   var gs/edi: (addr grapheme-stack) <- address gs-storage
+353   initialize-grapheme-stack gs, 5
+354   var g/eax: code-point-utf8 <- copy 0x28/open-paren
+355   push-grapheme-stack gs, g
+356   g <- copy 0x62/b
+357   push-grapheme-stack gs, g
+358   # setup: screen
+359   var screen-storage: screen
+360   var screen/esi: (addr screen) <- address screen-storage
+361   initialize-screen screen, 5, 4, 0/no-pixel-graphics
+362   #
+363   var x/eax: int <- render-stack-from-bottom screen, gs, 0/x, 2/y, 1/highlight-matching-open-paren, 0/open-paren-depth
+364   check-screen-row          screen,               2/y, "(b ", "F - test-render-grapheme-stack-while-highlighting-matching-open-paren"
+365   check-screen-row-in-color screen, 0xf/fg=white, 2/y, "(  ", "F - test-render-grapheme-stack-while-highlighting-matching-open-paren: matching paren"
+366 }
+367 
+368 fn test-render-grapheme-stack-while-highlighting-matching-open-paren-2 {
+369   # setup: gs = "a((b)"
+370   var gs-storage: grapheme-stack
+371   var gs/edi: (addr grapheme-stack) <- address gs-storage
+372   initialize-grapheme-stack gs, 0x10
+373   var g/eax: code-point-utf8 <- copy 0x61/a
+374   push-grapheme-stack gs, g
 375   g <- copy 0x28/open-paren
-376   push-grapheme-stack gs, g
-377   g <- copy 0x62/b
-378   push-grapheme-stack gs, g
-379   g <- copy 0x29/close-paren
-380   push-grapheme-stack gs, g
-381   # setup: screen
-382   var screen-storage: screen
-383   var screen/esi: (addr screen) <- address screen-storage
-384   initialize-screen screen, 5, 4, 0/no-pixel-graphics
-385   #
-386   var x/eax: int <- render-stack-from-bottom screen, gs, 0/x, 2/y, 1/highlight-matching-open-paren, 0/open-paren-depth
-387   check-screen-row          screen,               2/y, "a((b) ", "F - test-render-grapheme-stack-while-highlighting-matching-open-paren-2"
-388   check-screen-row-in-color screen, 0xf/fg=white, 2/y, " (    ", "F - test-render-grapheme-stack-while-highlighting-matching-open-paren-2: matching paren"
-389 }
-390 
-391 # return the index of the matching close-paren of the code-point-utf8 at cursor (top of stack)
-392 # or top index if there's no matching close-paren
-393 fn get-matching-close-paren-index _self: (addr grapheme-stack), render-cursor?: boolean -> _/edx: int {
-394   var self/esi: (addr grapheme-stack) <- copy _self
-395   var top-addr/edx: (addr int) <- get self, top
-396   # if not rendering cursor, return
-397   compare render-cursor?, 0/false
-398   {
-399     break-if-!=
-400     return *top-addr
-401   }
-402   var data-ah/eax: (addr handle array code-point-utf8) <- get self, data
-403   var data/eax: (addr array code-point-utf8) <- lookup *data-ah
-404   var i/ecx: int <- copy *top-addr
-405   # if stack is empty, return
-406   compare i, 0
-407   {
-408     break-if->
-409     return *top-addr
-410   }
-411   # if cursor is not '(' return
-412   i <- decrement
-413   var g/esi: (addr code-point-utf8) <- index data, i
-414   compare *g, 0x28/open-paren
-415   {
-416     break-if-=
-417     return *top-addr
-418   }
-419   # otherwise scan to matching paren
-420   var paren-count/ebx: int <- copy 1
-421   i <- decrement
-422   {
-423     compare i, 0
-424     break-if-<
-425     var g/esi: (addr code-point-utf8) <- index data, i
-426     compare *g, 0x28/open-paren
-427     {
-428       break-if-!=
-429       paren-count <- increment
-430     }
-431     compare *g, 0x29/close-paren
-432     {
-433       break-if-!=
-434       compare paren-count, 1
-435       {
-436         break-if-!=
-437         return i
-438       }
-439       paren-count <- decrement
-440     }
-441     i <- decrement
-442     loop
-443   }
-444   return *top-addr
-445 }
-446 
-447 # return the index of the first open-paren at the given depth
-448 # or top index if there's no matching close-paren
-449 fn get-matching-open-paren-index _self: (addr grapheme-stack), control: boolean, depth: int -> _/edx: int {
-450   var self/esi: (addr grapheme-stack) <- copy _self
-451   var top-addr/edx: (addr int) <- get self, top
-452   # if not rendering cursor, return
-453   compare control, 0/false
-454   {
-455     break-if-!=
-456     return *top-addr
-457   }
-458   var data-ah/eax: (addr handle array code-point-utf8) <- get self, data
-459   var data/eax: (addr array code-point-utf8) <- lookup *data-ah
-460   var i/ecx: int <- copy *top-addr
-461   # if stack is empty, return
-462   compare i, 0
-463   {
-464     break-if->
-465     return *top-addr
-466   }
-467   # scan to matching open paren
-468   var paren-count/ebx: int <- copy 0
-469   i <- decrement
-470   {
-471     compare i, 0
-472     break-if-<
-473     var g/esi: (addr code-point-utf8) <- index data, i
-474     compare *g, 0x29/close-paren
-475     {
-476       break-if-!=
-477       paren-count <- increment
-478     }
-479     compare *g, 0x28/open-paren
-480     {
-481       break-if-!=
-482       compare paren-count, depth
-483       {
-484         break-if-!=
-485         return i
-486       }
-487       paren-count <- decrement
-488     }
-489     i <- decrement
-490     loop
-491   }
-492   return *top-addr
-493 }
-494 
-495 # compare from bottom
-496 # beware: modifies 'stream', which must be disposed of after a false result
-497 fn prefix-match? _self: (addr grapheme-stack), s: (addr stream byte) -> _/eax: boolean {
-498   var self/esi: (addr grapheme-stack) <- copy _self
-499   var data-ah/edi: (addr handle array code-point-utf8) <- get self, data
-500   var _data/eax: (addr array code-point-utf8) <- lookup *data-ah
-501   var data/edi: (addr array code-point-utf8) <- copy _data
-502   var top-addr/ecx: (addr int) <- get self, top
-503   var i/ebx: int <- copy 0
-504   {
-505     compare i, *top-addr
-506     break-if->=
-507     # if curr != expected, return false
-508     {
-509       var curr-a/edx: (addr code-point-utf8) <- index data, i
-510       var expected/eax: code-point-utf8 <- read-code-point-utf8 s
-511       {
-512         compare expected, *curr-a
-513         break-if-=
-514         return 0/false
-515       }
-516     }
-517     i <- increment
-518     loop
-519   }
-520   return 1   # true
-521 }
-522 
-523 # compare from bottom
-524 # beware: modifies 'stream', which must be disposed of after a false result
-525 fn suffix-match? _self: (addr grapheme-stack), s: (addr stream byte) -> _/eax: boolean {
-526   var self/esi: (addr grapheme-stack) <- copy _self
-527   var data-ah/edi: (addr handle array code-point-utf8) <- get self, data
-528   var _data/eax: (addr array code-point-utf8) <- lookup *data-ah
-529   var data/edi: (addr array code-point-utf8) <- copy _data
-530   var top-addr/eax: (addr int) <- get self, top
-531   var i/ebx: int <- copy *top-addr
-532   i <- decrement
-533   {
-534     compare i, 0
-535     break-if-<
-536     {
-537       var curr-a/edx: (addr code-point-utf8) <- index data, i
-538       var expected/eax: code-point-utf8 <- read-code-point-utf8 s
-539       # if curr != expected, return false
-540       {
-541         compare expected, *curr-a
-542         break-if-=
-543         return 0/false
-544       }
-545     }
-546     i <- decrement
-547     loop
-548   }
-549   return 1   # true
-550 }
-551 
-552 fn grapheme-stack-is-decimal-integer? _self: (addr grapheme-stack) -> _/eax: boolean {
-553   var self/esi: (addr grapheme-stack) <- copy _self
-554   var data-ah/eax: (addr handle array code-point-utf8) <- get self, data
-555   var _data/eax: (addr array code-point-utf8) <- lookup *data-ah
-556   var data/edx: (addr array code-point-utf8) <- copy _data
-557   var top-addr/ecx: (addr int) <- get self, top
-558   var i/ebx: int <- copy 0
-559   var result/eax: boolean <- copy 1/true
-560   $grapheme-stack-is-integer?:loop: {
-561     compare i, *top-addr
-562     break-if->=
-563     var g/edx: (addr code-point-utf8) <- index data, i
-564     result <- decimal-digit? *g
-565     compare result, 0/false
-566     break-if-=
-567     i <- increment
-568     loop
-569   }
-570   return result
-571 }
+376   push-grapheme-stack gs, g
+377   g <- copy 0x28/open-paren
+378   push-grapheme-stack gs, g
+379   g <- copy 0x62/b
+380   push-grapheme-stack gs, g
+381   g <- copy 0x29/close-paren
+382   push-grapheme-stack gs, g
+383   # setup: screen
+384   var screen-storage: screen
+385   var screen/esi: (addr screen) <- address screen-storage
+386   initialize-screen screen, 5, 4, 0/no-pixel-graphics
+387   #
+388   var x/eax: int <- render-stack-from-bottom screen, gs, 0/x, 2/y, 1/highlight-matching-open-paren, 0/open-paren-depth
+389   check-screen-row          screen,               2/y, "a((b) ", "F - test-render-grapheme-stack-while-highlighting-matching-open-paren-2"
+390   check-screen-row-in-color screen, 0xf/fg=white, 2/y, " (    ", "F - test-render-grapheme-stack-while-highlighting-matching-open-paren-2: matching paren"
+391 }
+392 
+393 # return the index of the matching close-paren of the code-point-utf8 at cursor (top of stack)
+394 # or top index if there's no matching close-paren
+395 fn get-matching-close-paren-index _self: (addr grapheme-stack), render-cursor?: boolean -> _/edx: int {
+396   var self/esi: (addr grapheme-stack) <- copy _self
+397   var top-addr/edx: (addr int) <- get self, top
+398   # if not rendering cursor, return
+399   compare render-cursor?, 0/false
+400   {
+401     break-if-!=
+402     return *top-addr
+403   }
+404   var data-ah/eax: (addr handle array code-point-utf8) <- get self, data
+405   var data/eax: (addr array code-point-utf8) <- lookup *data-ah
+406   var i/ecx: int <- copy *top-addr
+407   # if stack is empty, return
+408   compare i, 0
+409   {
+410     break-if->
+411     return *top-addr
+412   }
+413   # if cursor is not '(' return
+414   i <- decrement
+415   var g/esi: (addr code-point-utf8) <- index data, i
+416   compare *g, 0x28/open-paren
+417   {
+418     break-if-=
+419     return *top-addr
+420   }
+421   # otherwise scan to matching paren
+422   var paren-count/ebx: int <- copy 1
+423   i <- decrement
+424   {
+425     compare i, 0
+426     break-if-<
+427     var g/esi: (addr code-point-utf8) <- index data, i
+428     compare *g, 0x28/open-paren
+429     {
+430       break-if-!=
+431       paren-count <- increment
+432     }
+433     compare *g, 0x29/close-paren
+434     {
+435       break-if-!=
+436       compare paren-count, 1
+437       {
+438         break-if-!=
+439         return i
+440       }
+441       paren-count <- decrement
+442     }
+443     i <- decrement
+444     loop
+445   }
+446   return *top-addr
+447 }
+448 
+449 # return the index of the first open-paren at the given depth
+450 # or top index if there's no matching close-paren
+451 fn get-matching-open-paren-index _self: (addr grapheme-stack), control: boolean, depth: int -> _/edx: int {
+452   var self/esi: (addr grapheme-stack) <- copy _self
+453   var top-addr/edx: (addr int) <- get self, top
+454   # if not rendering cursor, return
+455   compare control, 0/false
+456   {
+457     break-if-!=
+458     return *top-addr
+459   }
+460   var data-ah/eax: (addr handle array code-point-utf8) <- get self, data
+461   var data/eax: (addr array code-point-utf8) <- lookup *data-ah
+462   var i/ecx: int <- copy *top-addr
+463   # if stack is empty, return
+464   compare i, 0
+465   {
+466     break-if->
+467     return *top-addr
+468   }
+469   # scan to matching open paren
+470   var paren-count/ebx: int <- copy 0
+471   i <- decrement
+472   {
+473     compare i, 0
+474     break-if-<
+475     var g/esi: (addr code-point-utf8) <- index data, i
+476     compare *g, 0x29/close-paren
+477     {
+478       break-if-!=
+479       paren-count <- increment
+480     }
+481     compare *g, 0x28/open-paren
+482     {
+483       break-if-!=
+484       compare paren-count, depth
+485       {
+486         break-if-!=
+487         return i
+488       }
+489       paren-count <- decrement
+490     }
+491     i <- decrement
+492     loop
+493   }
+494   return *top-addr
+495 }
+496 
+497 # compare from bottom
+498 # beware: modifies 'stream', which must be disposed of after a false result
+499 fn prefix-match? _self: (addr grapheme-stack), s: (addr stream byte) -> _/eax: boolean {
+500   var self/esi: (addr grapheme-stack) <- copy _self
+501   var data-ah/edi: (addr handle array code-point-utf8) <- get self, data
+502   var _data/eax: (addr array code-point-utf8) <- lookup *data-ah
+503   var data/edi: (addr array code-point-utf8) <- copy _data
+504   var top-addr/ecx: (addr int) <- get self, top
+505   var i/ebx: int <- copy 0
+506   {
+507     compare i, *top-addr
+508     break-if->=
+509     # if curr != expected, return false
+510     {
+511       var curr-a/edx: (addr code-point-utf8) <- index data, i
+512       var expected/eax: code-point-utf8 <- read-code-point-utf8 s
+513       {
+514         compare expected, *curr-a
+515         break-if-=
+516         return 0/false
+517       }
+518     }
+519     i <- increment
+520     loop
+521   }
+522   return 1   # true
+523 }
+524 
+525 # compare from bottom
+526 # beware: modifies 'stream', which must be disposed of after a false result
+527 fn suffix-match? _self: (addr grapheme-stack), s: (addr stream byte) -> _/eax: boolean {
+528   var self/esi: (addr grapheme-stack) <- copy _self
+529   var data-ah/edi: (addr handle array code-point-utf8) <- get self, data
+530   var _data/eax: (addr array code-point-utf8) <- lookup *data-ah
+531   var data/edi: (addr array code-point-utf8) <- copy _data
+532   var top-addr/eax: (addr int) <- get self, top
+533   var i/ebx: int <- copy *top-addr
+534   i <- decrement
+535   {
+536     compare i, 0
+537     break-if-<
+538     {
+539       var curr-a/edx: (addr code-point-utf8) <- index data, i
+540       var expected/eax: code-point-utf8 <- read-code-point-utf8 s
+541       # if curr != expected, return false
+542       {
+543         compare expected, *curr-a
+544         break-if-=
+545         return 0/false
+546       }
+547     }
+548     i <- decrement
+549     loop
+550   }
+551   return 1   # true
+552 }
+553 
+554 fn grapheme-stack-is-decimal-integer? _self: (addr grapheme-stack) -> _/eax: boolean {
+555   var self/esi: (addr grapheme-stack) <- copy _self
+556   var data-ah/eax: (addr handle array code-point-utf8) <- get self, data
+557   var _data/eax: (addr array code-point-utf8) <- lookup *data-ah
+558   var data/edx: (addr array code-point-utf8) <- copy _data
+559   var top-addr/ecx: (addr int) <- get self, top
+560   var i/ebx: int <- copy 0
+561   var result/eax: boolean <- copy 1/true
+562   $grapheme-stack-is-integer?:loop: {
+563     compare i, *top-addr
+564     break-if->=
+565     var g/edx: (addr code-point-utf8) <- index data, i
+566     result <- decimal-digit? *g
+567     compare result, 0/false
+568     break-if-=
+569     i <- increment
+570     loop
+571   }
+572   return result
+573 }
 
diff --git a/html/shell/gap-buffer.mu.html b/html/shell/gap-buffer.mu.html deleted file mode 100644 index 8359674f..00000000 --- a/html/shell/gap-buffer.mu.html +++ /dev/null @@ -1,1538 +0,0 @@ - - - - -Mu - shell/gap-buffer.mu - - - - - - - - - - -https://github.com/akkartik/mu/blob/main/shell/gap-buffer.mu -
-   1 # primitive for editing text
-   2 
-   3 type gap-buffer {
-   4   left: grapheme-stack
-   5   right: grapheme-stack
-   6   # some fields for scanning incrementally through a gap-buffer
-   7   left-read-index: int
-   8   right-read-index: int
-   9 }
-  10 
-  11 fn initialize-gap-buffer _self: (addr gap-buffer), capacity: int {
-  12   var self/esi: (addr gap-buffer) <- copy _self
-  13   var left/eax: (addr grapheme-stack) <- get self, left
-  14   initialize-grapheme-stack left, capacity
-  15   var right/eax: (addr grapheme-stack) <- get self, right
-  16   initialize-grapheme-stack right, capacity
-  17 }
-  18 
-  19 fn clear-gap-buffer _self: (addr gap-buffer) {
-  20   var self/esi: (addr gap-buffer) <- copy _self
-  21   var left/eax: (addr grapheme-stack) <- get self, left
-  22   clear-grapheme-stack left
-  23   var right/eax: (addr grapheme-stack) <- get self, right
-  24   clear-grapheme-stack right
-  25 }
-  26 
-  27 fn gap-buffer-empty? _self: (addr gap-buffer) -> _/eax: boolean {
-  28   var self/esi: (addr gap-buffer) <- copy _self
-  29   # if !empty?(left) return false
-  30   {
-  31     var left/eax: (addr grapheme-stack) <- get self, left
-  32     var result/eax: boolean <- grapheme-stack-empty? left
-  33     compare result, 0/false
-  34     break-if-!=
-  35     return 0/false
-  36   }
-  37   # return empty?(right)
-  38   var left/eax: (addr grapheme-stack) <- get self, left
-  39   var result/eax: boolean <- grapheme-stack-empty? left
-  40   return result
-  41 }
-  42 
-  43 fn gap-buffer-capacity _gap: (addr gap-buffer) -> _/edx: int {
-  44   var gap/esi: (addr gap-buffer) <- copy _gap
-  45   var left/eax: (addr grapheme-stack) <- get gap, left
-  46   var left-data-ah/eax: (addr handle array grapheme) <- get left, data
-  47   var left-data/eax: (addr array grapheme) <- lookup *left-data-ah
-  48   var result/eax: int <- length left-data
-  49   return result
-  50 }
-  51 
-  52 # just for tests
-  53 fn initialize-gap-buffer-with self: (addr gap-buffer), keys: (addr array byte) {
-  54   initialize-gap-buffer self, 0x40/capacity
-  55   var input-stream-storage: (stream byte 0x40/capacity)
-  56   var input-stream/ecx: (addr stream byte) <- address input-stream-storage
-  57   write input-stream, keys
-  58   {
-  59     var done?/eax: boolean <- stream-empty? input-stream
-  60     compare done?, 0/false
-  61     break-if-!=
-  62     var g/eax: grapheme <- read-grapheme input-stream
-  63     add-grapheme-at-gap self, g
-  64     loop
-  65   }
-  66 }
-  67 
-  68 fn load-gap-buffer-from-stream self: (addr gap-buffer), in: (addr stream byte) {
-  69   rewind-stream in
-  70   {
-  71     var done?/eax: boolean <- stream-empty? in
-  72     compare done?, 0/false
-  73     break-if-!=
-  74     var key/eax: byte <- read-byte in
-  75     compare key, 0/null
-  76     break-if-=
-  77     var g/eax: grapheme <- copy key
-  78     edit-gap-buffer self, g
-  79     loop
-  80   }
-  81 }
-  82 
-  83 fn emit-gap-buffer self: (addr gap-buffer), out: (addr stream byte) {
-  84   clear-stream out
-  85   append-gap-buffer self, out
-  86 }
-  87 
-  88 fn append-gap-buffer _self: (addr gap-buffer), out: (addr stream byte) {
-  89   var self/esi: (addr gap-buffer) <- copy _self
-  90   var left/eax: (addr grapheme-stack) <- get self, left
-  91   emit-stack-from-bottom left, out
-  92   var right/eax: (addr grapheme-stack) <- get self, right
-  93   emit-stack-from-top right, out
-  94 }
-  95 
-  96 # dump stack from bottom to top
-  97 fn emit-stack-from-bottom _self: (addr grapheme-stack), out: (addr stream byte) {
-  98   var self/esi: (addr grapheme-stack) <- copy _self
-  99   var data-ah/edi: (addr handle array grapheme) <- get self, data
- 100   var _data/eax: (addr array grapheme) <- lookup *data-ah
- 101   var data/edi: (addr array grapheme) <- copy _data
- 102   var top-addr/ecx: (addr int) <- get self, top
- 103   var i/eax: int <- copy 0
- 104   {
- 105     compare i, *top-addr
- 106     break-if->=
- 107     var g/edx: (addr grapheme) <- index data, i
- 108     write-grapheme out, *g
- 109     i <- increment
- 110     loop
- 111   }
- 112 }
- 113 
- 114 # dump stack from top to bottom
- 115 fn emit-stack-from-top _self: (addr grapheme-stack), out: (addr stream byte) {
- 116   var self/esi: (addr grapheme-stack) <- copy _self
- 117   var data-ah/edi: (addr handle array grapheme) <- get self, data
- 118   var _data/eax: (addr array grapheme) <- lookup *data-ah
- 119   var data/edi: (addr array grapheme) <- copy _data
- 120   var top-addr/ecx: (addr int) <- get self, top
- 121   var i/eax: int <- copy *top-addr
- 122   i <- decrement
- 123   {
- 124     compare i, 0
- 125     break-if-<
- 126     var g/edx: (addr grapheme) <- index data, i
- 127     write-grapheme out, *g
- 128     i <- decrement
- 129     loop
- 130   }
- 131 }
- 132 
- 133 fn word-at-gap _self: (addr gap-buffer), out: (addr stream byte) {
- 134   var self/esi: (addr gap-buffer) <- copy _self
- 135   clear-stream out
- 136   {
- 137     var g/eax: grapheme <- grapheme-at-gap self
- 138     var at-word?/eax: boolean <- is-ascii-word-grapheme? g
- 139     compare at-word?, 0/false
- 140     break-if-!=
- 141     return
- 142   }
- 143   var left/ecx: (addr grapheme-stack) <- get self, left
- 144   var left-index/eax: int <- top-most-word left
- 145   emit-stack-from-index left, left-index, out
- 146   var right/ecx: (addr grapheme-stack) <- get self, right
- 147   var right-index/eax: int <- top-most-word right
- 148   emit-stack-to-index right, right-index, out
- 149 }
- 150 
- 151 fn test-word-at-gap-single-word-with-gap-at-end {
- 152   var _g: gap-buffer
- 153   var g/esi: (addr gap-buffer) <- address _g
- 154   initialize-gap-buffer-with g, "abc"
- 155   # gap is at end (right is empty)
- 156   var out-storage: (stream byte 0x10)
- 157   var out/eax: (addr stream byte) <- address out-storage
- 158   word-at-gap g, out
- 159   check-stream-equal out, "abc", "F - test-word-at-gap-single-word-with-gap-at-end"
- 160 }
- 161 
- 162 fn test-word-at-gap-single-word-with-gap-at-start {
- 163   var _g: gap-buffer
- 164   var g/esi: (addr gap-buffer) <- address _g
- 165   initialize-gap-buffer-with g, "abc"
- 166   gap-to-start g
- 167   #
- 168   var out-storage: (stream byte 0x10)
- 169   var out/eax: (addr stream byte) <- address out-storage
- 170   word-at-gap g, out
- 171   check-stream-equal out, "abc", "F - test-word-at-gap-single-word-with-gap-at-start"
- 172 }
- 173 
- 174 fn test-word-at-gap-multiple-words-with-gap-at-non-word-grapheme-at-end {
- 175   var _g: gap-buffer
- 176   var g/esi: (addr gap-buffer) <- address _g
- 177   initialize-gap-buffer-with g, "abc "
- 178   # gap is at end (right is empty)
- 179   var out-storage: (stream byte 0x10)
- 180   var out/eax: (addr stream byte) <- address out-storage
- 181   word-at-gap g, out
- 182   check-stream-equal out, "", "F - test-word-at-gap-multiple-words-with-gap-at-non-word-grapheme-at-end"
- 183 }
- 184 
- 185 fn test-word-at-gap-multiple-words-with-gap-at-non-word-grapheme-at-start {
- 186   var _g: gap-buffer
- 187   var g/esi: (addr gap-buffer) <- address _g
- 188   initialize-gap-buffer-with g, " abc"
- 189   gap-to-start g
- 190   #
- 191   var out-storage: (stream byte 0x10)
- 192   var out/eax: (addr stream byte) <- address out-storage
- 193   word-at-gap g, out
- 194   check-stream-equal out, "", "F - test-word-at-gap-multiple-words-with-gap-at-non-word-grapheme-at-start"
- 195 }
- 196 
- 197 fn test-word-at-gap-multiple-words-with-gap-at-end {
- 198   var _g: gap-buffer
- 199   var g/esi: (addr gap-buffer) <- address _g
- 200   initialize-gap-buffer-with g, "a bc d"
- 201   # gap is at end (right is empty)
- 202   var out-storage: (stream byte 0x10)
- 203   var out/eax: (addr stream byte) <- address out-storage
- 204   word-at-gap g, out
- 205   check-stream-equal out, "d", "F - test-word-at-gap-multiple-words-with-gap-at-end"
- 206 }
- 207 
- 208 fn test-word-at-gap-multiple-words-with-gap-at-initial-word {
- 209   var _g: gap-buffer
- 210   var g/esi: (addr gap-buffer) <- address _g
- 211   initialize-gap-buffer-with g, "a bc d"
- 212   gap-to-start g
- 213   #
- 214   var out-storage: (stream byte 0x10)
- 215   var out/eax: (addr stream byte) <- address out-storage
- 216   word-at-gap g, out
- 217   check-stream-equal out, "a", "F - test-word-at-gap-multiple-words-with-gap-at-initial-word"
- 218 }
- 219 
- 220 fn test-word-at-gap-multiple-words-with-gap-at-final-word {
- 221   var _g: gap-buffer
- 222   var g/esi: (addr gap-buffer) <- address _g
- 223   initialize-gap-buffer-with g, "a bc d"
- 224   var dummy/eax: grapheme <- gap-left g
- 225   # gap is at final word
- 226   var out-storage: (stream byte 0x10)
- 227   var out/eax: (addr stream byte) <- address out-storage
- 228   word-at-gap g, out
- 229   check-stream-equal out, "d", "F - test-word-at-gap-multiple-words-with-gap-at-final-word"
- 230 }
- 231 
- 232 fn test-word-at-gap-multiple-words-with-gap-at-final-non-word {
- 233   var _g: gap-buffer
- 234   var g/esi: (addr gap-buffer) <- address _g
- 235   initialize-gap-buffer-with g, "abc "
- 236   var dummy/eax: grapheme <- gap-left g
- 237   # gap is at final word
- 238   var out-storage: (stream byte 0x10)
- 239   var out/eax: (addr stream byte) <- address out-storage
- 240   word-at-gap g, out
- 241   check-stream-equal out, "", "F - test-word-at-gap-multiple-words-with-gap-at-final-non-word"
- 242 }
- 243 
- 244 fn grapheme-at-gap _self: (addr gap-buffer) -> _/eax: grapheme {
- 245   # send top of right most of the time
- 246   var self/esi: (addr gap-buffer) <- copy _self
- 247   var right/edi: (addr grapheme-stack) <- get self, right
- 248   var data-ah/eax: (addr handle array grapheme) <- get right, data
- 249   var data/eax: (addr array grapheme) <- lookup *data-ah
- 250   var top-addr/ecx: (addr int) <- get right, top
- 251   {
- 252     compare *top-addr, 0
- 253     break-if-<=
- 254     var top/ecx: int <- copy *top-addr
- 255     top <- decrement
- 256     var result/eax: (addr grapheme) <- index data, top
- 257     return *result
- 258   }
- 259   # send top of left only if right is empty
- 260   var left/edi: (addr grapheme-stack) <- get self, left
- 261   var data-ah/eax: (addr handle array grapheme) <- get left, data
- 262   var data/eax: (addr array grapheme) <- lookup *data-ah
- 263   var top-addr/ecx: (addr int) <- get left, top
- 264   {
- 265     compare *top-addr, 0
- 266     break-if-<=
- 267     var top/ecx: int <- copy *top-addr
- 268     top <- decrement
- 269     var result/eax: (addr grapheme) <- index data, top
- 270     return *result
- 271   }
- 272   # send null if everything is empty
- 273   return 0
- 274 }
- 275 
- 276 fn top-most-word _self: (addr grapheme-stack) -> _/eax: int {
- 277   var self/esi: (addr grapheme-stack) <- copy _self
- 278   var data-ah/edi: (addr handle array grapheme) <- get self, data
- 279   var _data/eax: (addr array grapheme) <- lookup *data-ah
- 280   var data/edi: (addr array grapheme) <- copy _data
- 281   var top-addr/ecx: (addr int) <- get self, top
- 282   var i/ebx: int <- copy *top-addr
- 283   i <- decrement
- 284   {
- 285     compare i, 0
- 286     break-if-<
- 287     var g/edx: (addr grapheme) <- index data, i
- 288     var is-word?/eax: boolean <- is-ascii-word-grapheme? *g
- 289     compare is-word?, 0/false
- 290     break-if-=
- 291     i <- decrement
- 292     loop
- 293   }
- 294   i <- increment
- 295   return i
- 296 }
- 297 
- 298 fn emit-stack-from-index _self: (addr grapheme-stack), start: int, out: (addr stream byte) {
- 299   var self/esi: (addr grapheme-stack) <- copy _self
- 300   var data-ah/edi: (addr handle array grapheme) <- get self, data
- 301   var _data/eax: (addr array grapheme) <- lookup *data-ah
- 302   var data/edi: (addr array grapheme) <- copy _data
- 303   var top-addr/ecx: (addr int) <- get self, top
- 304   var i/eax: int <- copy start
- 305   {
- 306     compare i, *top-addr
- 307     break-if->=
- 308     var g/edx: (addr grapheme) <- index data, i
- 309     write-grapheme out, *g
- 310     i <- increment
- 311     loop
- 312   }
- 313 }
- 314 
- 315 fn emit-stack-to-index _self: (addr grapheme-stack), end: int, out: (addr stream byte) {
- 316   var self/esi: (addr grapheme-stack) <- copy _self
- 317   var data-ah/edi: (addr handle array grapheme) <- get self, data
- 318   var _data/eax: (addr array grapheme) <- lookup *data-ah
- 319   var data/edi: (addr array grapheme) <- copy _data
- 320   var top-addr/ecx: (addr int) <- get self, top
- 321   var i/eax: int <- copy *top-addr
- 322   i <- decrement
- 323   {
- 324     compare i, 0
- 325     break-if-<
- 326     compare i, end
- 327     break-if-<
- 328     var g/edx: (addr grapheme) <- index data, i
- 329     write-grapheme out, *g
- 330     i <- decrement
- 331     loop
- 332   }
- 333 }
- 334 
- 335 fn is-ascii-word-grapheme? g: grapheme -> _/eax: boolean {
- 336   compare g, 0x21/!
- 337   {
- 338     break-if-!=
- 339     return 1/true
- 340   }
- 341   compare g, 0x30/0
- 342   {
- 343     break-if->=
- 344     return 0/false
- 345   }
- 346   compare g, 0x39/9
- 347   {
- 348     break-if->
- 349     return 1/true
- 350   }
- 351   compare g, 0x3f/?
- 352   {
- 353     break-if-!=
- 354     return 1/true
- 355   }
- 356   compare g, 0x41/A
- 357   {
- 358     break-if->=
- 359     return 0/false
- 360   }
- 361   compare g, 0x5a/Z
- 362   {
- 363     break-if->
- 364     return 1/true
- 365   }
- 366   compare g, 0x5f/_
- 367   {
- 368     break-if-!=
- 369     return 1/true
- 370   }
- 371   compare g, 0x61/a
- 372   {
- 373     break-if->=
- 374     return 0/false
- 375   }
- 376   compare g, 0x7a/z
- 377   {
- 378     break-if->
- 379     return 1/true
- 380   }
- 381   return 0/false
- 382 }
- 383 
- 384 # We implicitly render everything editable in a single color, and assume the
- 385 # cursor is a single other color.
- 386 fn render-gap-buffer-wrapping-right-then-down screen: (addr screen), _gap: (addr gap-buffer), xmin: int, ymin: int, xmax: int, ymax: int, render-cursor?: boolean, color: int, background-color: int -> _/eax: int, _/ecx: int {
- 387   var gap/esi: (addr gap-buffer) <- copy _gap
- 388   var left/edx: (addr grapheme-stack) <- get gap, left
- 389   var highlight-matching-open-paren?/ebx: boolean <- copy 0/false
- 390   var matching-open-paren-depth/edi: int <- copy 0
- 391   highlight-matching-open-paren?, matching-open-paren-depth <- highlight-matching-open-paren? gap, render-cursor?
- 392   var x2/eax: int <- copy 0
- 393   var y2/ecx: int <- copy 0
- 394   x2, y2 <- render-stack-from-bottom-wrapping-right-then-down screen, left, xmin, ymin, xmax, ymax, xmin, ymin, highlight-matching-open-paren?, matching-open-paren-depth, color, background-color
- 395   var right/edx: (addr grapheme-stack) <- get gap, right
- 396   x2, y2 <- render-stack-from-top-wrapping-right-then-down screen, right, xmin, ymin, xmax, ymax, x2, y2, render-cursor?, color, background-color
- 397   # decide whether we still need to print a cursor
- 398   var fg/edi: int <- copy color
- 399   var bg/ebx: int <- copy background-color
- 400   compare render-cursor?, 0/false
- 401   {
- 402     break-if-=
- 403     # if the right side is empty, grapheme stack didn't print the cursor
- 404     var empty?/eax: boolean <- grapheme-stack-empty? right
- 405     compare empty?, 0/false
- 406     break-if-=
- 407     # swap foreground and background
- 408     fg <- copy background-color
- 409     bg <- copy color
- 410   }
- 411   # print a grapheme either way so that cursor position doesn't affect printed width
- 412   var space/edx: grapheme <- copy 0x20
- 413   x2, y2 <- render-grapheme screen, space, xmin, ymin, xmax, ymax, x2, y2, fg, bg
- 414   return x2, y2
- 415 }
- 416 
- 417 fn render-gap-buffer screen: (addr screen), gap: (addr gap-buffer), x: int, y: int, render-cursor?: boolean, color: int, background-color: int -> _/eax: int {
- 418   var _width/eax: int <- copy 0
- 419   var _height/ecx: int <- copy 0
- 420   _width, _height <- screen-size screen
- 421   var width/edx: int <- copy _width
- 422   var height/ebx: int <- copy _height
- 423   var x2/eax: int <- copy 0
- 424   var y2/ecx: int <- copy 0
- 425   x2, y2 <- render-gap-buffer-wrapping-right-then-down screen, gap, x, y, width, height, render-cursor?, color, background-color
- 426   return x2  # y2? yolo
- 427 }
- 428 
- 429 fn gap-buffer-length _gap: (addr gap-buffer) -> _/eax: int {
- 430   var gap/esi: (addr gap-buffer) <- copy _gap
- 431   var left/eax: (addr grapheme-stack) <- get gap, left
- 432   var tmp/eax: (addr int) <- get left, top
- 433   var left-length/ecx: int <- copy *tmp
- 434   var right/esi: (addr grapheme-stack) <- get gap, right
- 435   tmp <- get right, top
- 436   var result/eax: int <- copy *tmp
- 437   result <- add left-length
- 438   return result
- 439 }
- 440 
- 441 fn add-grapheme-at-gap _self: (addr gap-buffer), g: grapheme {
- 442   var self/esi: (addr gap-buffer) <- copy _self
- 443   var left/eax: (addr grapheme-stack) <- get self, left
- 444   push-grapheme-stack left, g
- 445 }
- 446 
- 447 fn add-code-point-at-gap self: (addr gap-buffer), c: code-point {
- 448   var g/eax: grapheme <- copy c
- 449   add-grapheme-at-gap self, g
- 450 }
- 451 
- 452 fn gap-to-start self: (addr gap-buffer) {
- 453   {
- 454     var curr/eax: grapheme <- gap-left self
- 455     compare curr, -1
- 456     loop-if-!=
- 457   }
- 458 }
- 459 
- 460 fn gap-to-end self: (addr gap-buffer) {
- 461   {
- 462     var curr/eax: grapheme <- gap-right self
- 463     compare curr, -1
- 464     loop-if-!=
- 465   }
- 466 }
- 467 
- 468 fn gap-at-start? _self: (addr gap-buffer) -> _/eax: boolean {
- 469   var self/esi: (addr gap-buffer) <- copy _self
- 470   var left/eax: (addr grapheme-stack) <- get self, left
- 471   var result/eax: boolean <- grapheme-stack-empty? left
- 472   return result
- 473 }
- 474 
- 475 fn gap-at-end? _self: (addr gap-buffer) -> _/eax: boolean {
- 476   var self/esi: (addr gap-buffer) <- copy _self
- 477   var right/eax: (addr grapheme-stack) <- get self, right
- 478   var result/eax: boolean <- grapheme-stack-empty? right
- 479   return result
- 480 }
- 481 
- 482 fn gap-right _self: (addr gap-buffer) -> _/eax: grapheme {
- 483   var self/esi: (addr gap-buffer) <- copy _self
- 484   var g/eax: grapheme <- copy 0
- 485   var right/ecx: (addr grapheme-stack) <- get self, right
- 486   g <- pop-grapheme-stack right
- 487   compare g, -1
- 488   {
- 489     break-if-=
- 490     var left/ecx: (addr grapheme-stack) <- get self, left
- 491     push-grapheme-stack left, g
- 492   }
- 493   return g
- 494 }
- 495 
- 496 fn gap-left _self: (addr gap-buffer) -> _/eax: grapheme {
- 497   var self/esi: (addr gap-buffer) <- copy _self
- 498   var g/eax: grapheme <- copy 0
- 499   {
- 500     var left/ecx: (addr grapheme-stack) <- get self, left
- 501     g <- pop-grapheme-stack left
- 502   }
- 503   compare g, -1
- 504   {
- 505     break-if-=
- 506     var right/ecx: (addr grapheme-stack) <- get self, right
- 507     push-grapheme-stack right, g
- 508   }
- 509   return g
- 510 }
- 511 
- 512 fn index-of-gap _self: (addr gap-buffer) -> _/eax: int {
- 513   var self/eax: (addr gap-buffer) <- copy _self
- 514   var left/eax: (addr grapheme-stack) <- get self, left
- 515   var top-addr/eax: (addr int) <- get left, top
- 516   var result/eax: int <- copy *top-addr
- 517   return result
- 518 }
- 519 
- 520 fn first-grapheme-in-gap-buffer _self: (addr gap-buffer) -> _/eax: grapheme {
- 521   var self/esi: (addr gap-buffer) <- copy _self
- 522   # try to read from left
- 523   var left/eax: (addr grapheme-stack) <- get self, left
- 524   var top-addr/ecx: (addr int) <- get left, top
- 525   compare *top-addr, 0
- 526   {
- 527     break-if-<=
- 528     var data-ah/eax: (addr handle array grapheme) <- get left, data
- 529     var data/eax: (addr array grapheme) <- lookup *data-ah
- 530     var result-addr/eax: (addr grapheme) <- index data, 0
- 531     return *result-addr
- 532   }
- 533   # try to read from right
- 534   var right/eax: (addr grapheme-stack) <- get self, right
- 535   top-addr <- get right, top
- 536   compare *top-addr, 0
- 537   {
- 538     break-if-<=
- 539     var data-ah/eax: (addr handle array grapheme) <- get right, data
- 540     var data/eax: (addr array grapheme) <- lookup *data-ah
- 541     var top/ecx: int <- copy *top-addr
- 542     top <- decrement
- 543     var result-addr/eax: (addr grapheme) <- index data, top
- 544     return *result-addr
- 545   }
- 546   # give up
- 547   return -1
- 548 }
- 549 
- 550 fn grapheme-before-cursor-in-gap-buffer _self: (addr gap-buffer) -> _/eax: grapheme {
- 551   var self/esi: (addr gap-buffer) <- copy _self
- 552   # try to read from left
- 553   var left/ecx: (addr grapheme-stack) <- get self, left
- 554   var top-addr/edx: (addr int) <- get left, top
- 555   compare *top-addr, 0
- 556   {
- 557     break-if-<=
- 558     var result/eax: grapheme <- pop-grapheme-stack left
- 559     push-grapheme-stack left, result
- 560     return result
- 561   }
- 562   # give up
- 563   return -1
- 564 }
- 565 
- 566 fn delete-before-gap _self: (addr gap-buffer) {
- 567   var self/eax: (addr gap-buffer) <- copy _self
- 568   var left/eax: (addr grapheme-stack) <- get self, left
- 569   var dummy/eax: grapheme <- pop-grapheme-stack left
- 570 }
- 571 
- 572 fn pop-after-gap _self: (addr gap-buffer) -> _/eax: grapheme {
- 573   var self/eax: (addr gap-buffer) <- copy _self
- 574   var right/eax: (addr grapheme-stack) <- get self, right
- 575   var result/eax: grapheme <- pop-grapheme-stack right
- 576   return result
- 577 }
- 578 
- 579 fn gap-buffer-equal? _self: (addr gap-buffer), s: (addr array byte) -> _/eax: boolean {
- 580   var self/esi: (addr gap-buffer) <- copy _self
- 581   # complication: graphemes may be multiple bytes
- 582   # so don't rely on length
- 583   # instead turn the expected result into a stream and arrange to read from it in order
- 584   var stream-storage: (stream byte 0x10/capacity)
- 585   var expected-stream/ecx: (addr stream byte) <- address stream-storage
- 586   write expected-stream, s
- 587   # compare left
- 588   var left/edx: (addr grapheme-stack) <- get self, left
- 589   var result/eax: boolean <- prefix-match? left, expected-stream
- 590   compare result, 0/false
- 591   {
- 592     break-if-!=
- 593     return result
- 594   }
- 595   # compare right
- 596   var right/edx: (addr grapheme-stack) <- get self, right
- 597   result <- suffix-match? right, expected-stream
- 598   compare result, 0/false
- 599   {
- 600     break-if-!=
- 601     return result
- 602   }
- 603   # ensure there's nothing left over
- 604   result <- stream-empty? expected-stream
- 605   return result
- 606 }
- 607 
- 608 fn test-gap-buffer-equal-from-end {
- 609   var _g: gap-buffer
- 610   var g/esi: (addr gap-buffer) <- address _g
- 611   initialize-gap-buffer g, 0x10
- 612   #
- 613   add-code-point-at-gap g, 0x61/a
- 614   add-code-point-at-gap g, 0x61/a
- 615   add-code-point-at-gap g, 0x61/a
- 616   # gap is at end (right is empty)
- 617   var result/eax: boolean <- gap-buffer-equal? g, "aaa"
- 618   check result, "F - test-gap-buffer-equal-from-end"
- 619 }
- 620 
- 621 fn test-gap-buffer-equal-from-middle {
- 622   var _g: gap-buffer
- 623   var g/esi: (addr gap-buffer) <- address _g
- 624   initialize-gap-buffer g, 0x10
- 625   #
- 626   add-code-point-at-gap g, 0x61/a
- 627   add-code-point-at-gap g, 0x61/a
- 628   add-code-point-at-gap g, 0x61/a
- 629   var dummy/eax: grapheme <- gap-left g
- 630   # gap is in the middle
- 631   var result/eax: boolean <- gap-buffer-equal? g, "aaa"
- 632   check result, "F - test-gap-buffer-equal-from-middle"
- 633 }
- 634 
- 635 fn test-gap-buffer-equal-from-start {
- 636   var _g: gap-buffer
- 637   var g/esi: (addr gap-buffer) <- address _g
- 638   initialize-gap-buffer g, 0x10
- 639   #
- 640   add-code-point-at-gap g, 0x61/a
- 641   add-code-point-at-gap g, 0x61/a
- 642   add-code-point-at-gap g, 0x61/a
- 643   var dummy/eax: grapheme <- gap-left g
- 644   dummy <- gap-left g
- 645   dummy <- gap-left g
- 646   # gap is at the start
- 647   var result/eax: boolean <- gap-buffer-equal? g, "aaa"
- 648   check result, "F - test-gap-buffer-equal-from-start"
- 649 }
- 650 
- 651 fn test-gap-buffer-equal-fails {
- 652   # g = "aaa"
- 653   var _g: gap-buffer
- 654   var g/esi: (addr gap-buffer) <- address _g
- 655   initialize-gap-buffer g, 0x10
- 656   add-code-point-at-gap g, 0x61/a
- 657   add-code-point-at-gap g, 0x61/a
- 658   add-code-point-at-gap g, 0x61/a
- 659   #
- 660   var result/eax: boolean <- gap-buffer-equal? g, "aa"
- 661   check-not result, "F - test-gap-buffer-equal-fails"
- 662 }
- 663 
- 664 fn gap-buffers-equal? self: (addr gap-buffer), g: (addr gap-buffer) -> _/eax: boolean {
- 665   var tmp/eax: int <- gap-buffer-length self
- 666   var len/ecx: int <- copy tmp
- 667   var leng/eax: int <- gap-buffer-length g
- 668   compare len, leng
- 669   {
- 670     break-if-=
- 671     return 0/false
- 672   }
- 673   var i/edx: int <- copy 0
- 674   {
- 675     compare i, len
- 676     break-if->=
- 677     {
- 678       var tmp/eax: grapheme <- gap-index self, i
- 679       var curr/ecx: grapheme <- copy tmp
- 680       var currg/eax: grapheme <- gap-index g, i
- 681       compare curr, currg
- 682       break-if-=
- 683       return 0/false
- 684     }
- 685     i <- increment
- 686     loop
- 687   }
- 688   return 1/true
- 689 }
- 690 
- 691 fn gap-index _self: (addr gap-buffer), _n: int -> _/eax: grapheme {
- 692   var self/esi: (addr gap-buffer) <- copy _self
- 693   var n/ebx: int <- copy _n
- 694   # if n < left->length, index into left
- 695   var left/edi: (addr grapheme-stack) <- get self, left
- 696   var left-len-a/edx: (addr int) <- get left, top
- 697   compare n, *left-len-a
- 698   {
- 699     break-if->=
- 700     var data-ah/eax: (addr handle array grapheme) <- get left, data
- 701     var data/eax: (addr array grapheme) <- lookup *data-ah
- 702     var result/eax: (addr grapheme) <- index data, n
- 703     return *result
- 704   }
- 705   # shrink n
- 706   n <- subtract *left-len-a
- 707   # if n < right->length, index into right
- 708   var right/edi: (addr grapheme-stack) <- get self, right
- 709   var right-len-a/edx: (addr int) <- get right, top
- 710   compare n, *right-len-a
- 711   {
- 712     break-if->=
- 713     var data-ah/eax: (addr handle array grapheme) <- get right, data
- 714     var data/eax: (addr array grapheme) <- lookup *data-ah
- 715     # idx = right->len - n - 1
- 716     var idx/ebx: int <- copy n
- 717     idx <- subtract *right-len-a
- 718     idx <- negate
- 719     idx <- subtract 1
- 720     var result/eax: (addr grapheme) <- index data, idx
- 721     return *result
- 722   }
- 723   # error
- 724   abort "gap-index: out of bounds"
- 725   return 0
- 726 }
- 727 
- 728 fn test-gap-buffers-equal? {
- 729   var _a: gap-buffer
- 730   var a/esi: (addr gap-buffer) <- address _a
- 731   initialize-gap-buffer-with a, "abc"
- 732   var _b: gap-buffer
- 733   var b/edi: (addr gap-buffer) <- address _b
- 734   initialize-gap-buffer-with b, "abc"
- 735   var _c: gap-buffer
- 736   var c/ebx: (addr gap-buffer) <- address _c
- 737   initialize-gap-buffer-with c, "ab"
- 738   var _d: gap-buffer
- 739   var d/edx: (addr gap-buffer) <- address _d
- 740   initialize-gap-buffer-with d, "abd"
- 741   #
- 742   var result/eax: boolean <- gap-buffers-equal? a, a
- 743   check result, "F - test-gap-buffers-equal? - reflexive"
- 744   result <- gap-buffers-equal? a, b
- 745   check result, "F - test-gap-buffers-equal? - equal"
- 746   # length not equal
- 747   result <- gap-buffers-equal? a, c
- 748   check-not result, "F - test-gap-buffers-equal? - not equal"
- 749   # contents not equal
- 750   result <- gap-buffers-equal? a, d
- 751   check-not result, "F - test-gap-buffers-equal? - not equal 2"
- 752   result <- gap-buffers-equal? d, a
- 753   check-not result, "F - test-gap-buffers-equal? - not equal 3"
- 754 }
- 755 
- 756 fn test-gap-buffer-index {
- 757   var gap-storage: gap-buffer
- 758   var gap/esi: (addr gap-buffer) <- address gap-storage
- 759   initialize-gap-buffer-with gap, "abc"
- 760   # gap is at end, all contents are in left
- 761   var g/eax: grapheme <- gap-index gap, 0
- 762   var x/ecx: int <- copy g
- 763   check-ints-equal x, 0x61/a, "F - test-gap-index/left-1"
- 764   var g/eax: grapheme <- gap-index gap, 1
- 765   var x/ecx: int <- copy g
- 766   check-ints-equal x, 0x62/b, "F - test-gap-index/left-2"
- 767   var g/eax: grapheme <- gap-index gap, 2
- 768   var x/ecx: int <- copy g
- 769   check-ints-equal x, 0x63/c, "F - test-gap-index/left-3"
- 770   # now check when everything is to the right
- 771   gap-to-start gap
- 772   rewind-gap-buffer gap
- 773   var g/eax: grapheme <- gap-index gap, 0
- 774   var x/ecx: int <- copy g
- 775   check-ints-equal x, 0x61/a, "F - test-gap-index/right-1"
- 776   var g/eax: grapheme <- gap-index gap, 1
- 777   var x/ecx: int <- copy g
- 778   check-ints-equal x, 0x62/b, "F - test-gap-index/right-2"
- 779   var g/eax: grapheme <- gap-index gap, 2
- 780   var x/ecx: int <- copy g
- 781   check-ints-equal x, 0x63/c, "F - test-gap-index/right-3"
- 782 }
- 783 
- 784 fn copy-gap-buffer _src-ah: (addr handle gap-buffer), _dest-ah: (addr handle gap-buffer) {
- 785   # obtain src-a, dest-a
- 786   var src-ah/eax: (addr handle gap-buffer) <- copy _src-ah
- 787   var _src-a/eax: (addr gap-buffer) <- lookup *src-ah
- 788   var src-a/esi: (addr gap-buffer) <- copy _src-a
- 789   var dest-ah/eax: (addr handle gap-buffer) <- copy _dest-ah
- 790   var _dest-a/eax: (addr gap-buffer) <- lookup *dest-ah
- 791   var dest-a/edi: (addr gap-buffer) <- copy _dest-a
- 792   # copy left grapheme-stack
- 793   var src/ecx: (addr grapheme-stack) <- get src-a, left
- 794   var dest/edx: (addr grapheme-stack) <- get dest-a, left
- 795   copy-grapheme-stack src, dest
- 796   # copy right grapheme-stack
- 797   src <- get src-a, right
- 798   dest <- get dest-a, right
- 799   copy-grapheme-stack src, dest
- 800 }
- 801 
- 802 fn gap-buffer-is-decimal-integer? _self: (addr gap-buffer) -> _/eax: boolean {
- 803   var self/esi: (addr gap-buffer) <- copy _self
- 804   var curr/ecx: (addr grapheme-stack) <- get self, left
- 805   var result/eax: boolean <- grapheme-stack-is-decimal-integer? curr
- 806   {
- 807     compare result, 0/false
- 808     break-if-=
- 809     curr <- get self, right
- 810     result <- grapheme-stack-is-decimal-integer? curr
- 811   }
- 812   return result
- 813 }
- 814 
- 815 fn test-render-gap-buffer-without-cursor {
- 816   # setup
- 817   var gap-storage: gap-buffer
- 818   var gap/esi: (addr gap-buffer) <- address gap-storage
- 819   initialize-gap-buffer-with gap, "abc"
- 820   # setup: screen
- 821   var screen-on-stack: screen
- 822   var screen/edi: (addr screen) <- address screen-on-stack
- 823   initialize-screen screen, 5, 4, 0/no-pixel-graphics
- 824   #
- 825   var x/eax: int <- render-gap-buffer screen, gap, 0/x, 0/y, 0/no-cursor, 3/fg, 0xc5/bg=blue-bg
- 826   check-screen-row screen, 0/y, "abc ", "F - test-render-gap-buffer-without-cursor"
- 827   check-ints-equal x, 4, "F - test-render-gap-buffer-without-cursor: result"
- 828                                                                 # abc
- 829   check-background-color-in-screen-row screen, 3/bg=reverse, 0/y, "    ", "F - test-render-gap-buffer-without-cursor: bg"
- 830 }
- 831 
- 832 fn test-render-gap-buffer-with-cursor-at-end {
- 833   # setup
- 834   var gap-storage: gap-buffer
- 835   var gap/esi: (addr gap-buffer) <- address gap-storage
- 836   initialize-gap-buffer-with gap, "abc"
- 837   gap-to-end gap
- 838   # setup: screen
- 839   var screen-on-stack: screen
- 840   var screen/edi: (addr screen) <- address screen-on-stack
- 841   initialize-screen screen, 5, 4, 0/no-pixel-graphics
- 842   #
- 843   var x/eax: int <- render-gap-buffer screen, gap, 0/x, 0/y, 1/show-cursor, 3/fg, 0xc5/bg=blue-bg
- 844   check-screen-row screen, 0/y, "abc ", "F - test-render-gap-buffer-with-cursor-at-end"
- 845   # we've drawn one extra grapheme for the cursor
- 846   check-ints-equal x, 4, "F - test-render-gap-buffer-with-cursor-at-end: result"
- 847                                                                 # abc
- 848   check-background-color-in-screen-row screen, 3/bg=reverse, 0/y, "   |", "F - test-render-gap-buffer-with-cursor-at-end: bg"
- 849 }
- 850 
- 851 fn test-render-gap-buffer-with-cursor-in-middle {
- 852   # setup
- 853   var gap-storage: gap-buffer
- 854   var gap/esi: (addr gap-buffer) <- address gap-storage
- 855   initialize-gap-buffer-with gap, "abc"
- 856   gap-to-end gap
- 857   var dummy/eax: grapheme <- gap-left gap
- 858   # setup: screen
- 859   var screen-on-stack: screen
- 860   var screen/edi: (addr screen) <- address screen-on-stack
- 861   initialize-screen screen, 5, 4, 0/no-pixel-graphics
- 862   #
- 863   var x/eax: int <- render-gap-buffer screen, gap, 0/x, 0/y, 1/show-cursor, 3/fg, 0xc5/bg=blue-bg
- 864   check-screen-row screen, 0/y, "abc ", "F - test-render-gap-buffer-with-cursor-in-middle"
- 865   check-ints-equal x, 4, "F - test-render-gap-buffer-with-cursor-in-middle: result"
- 866                                                                 # abc
- 867   check-background-color-in-screen-row screen, 3/bg=reverse, 0/y, "  | ", "F - test-render-gap-buffer-with-cursor-in-middle: bg"
- 868 }
- 869 
- 870 fn test-render-gap-buffer-with-cursor-at-start {
- 871   var gap-storage: gap-buffer
- 872   var gap/esi: (addr gap-buffer) <- address gap-storage
- 873   initialize-gap-buffer-with gap, "abc"
- 874   gap-to-start gap
- 875   # setup: screen
- 876   var screen-on-stack: screen
- 877   var screen/edi: (addr screen) <- address screen-on-stack
- 878   initialize-screen screen, 5, 4, 0/no-pixel-graphics
- 879   #
- 880   var x/eax: int <- render-gap-buffer screen, gap, 0/x, 0/y, 1/show-cursor, 3/fg, 0xc5/bg=blue-bg
- 881   check-screen-row screen, 0/y, "abc ", "F - test-render-gap-buffer-with-cursor-at-start"
- 882   check-ints-equal x, 4, "F - test-render-gap-buffer-with-cursor-at-start: result"
- 883                                                                 # abc
- 884   check-background-color-in-screen-row screen, 3/bg=reverse, 0/y, "|   ", "F - test-render-gap-buffer-with-cursor-at-start: bg"
- 885 }
- 886 
- 887 fn test-render-gap-buffer-highlight-matching-close-paren {
- 888   var gap-storage: gap-buffer
- 889   var gap/esi: (addr gap-buffer) <- address gap-storage
- 890   initialize-gap-buffer-with gap, "(a)"
- 891   gap-to-start gap
- 892   # setup: screen
- 893   var screen-on-stack: screen
- 894   var screen/edi: (addr screen) <- address screen-on-stack
- 895   initialize-screen screen, 5, 4, 0/no-pixel-graphics
- 896   #
- 897   var x/eax: int <- render-gap-buffer screen, gap, 0/x, 0/y, 1/show-cursor, 3/fg, 0xc5/bg=blue-bg
- 898   check-screen-row                     screen, 0/y,                   "(a) ", "F - test-render-gap-buffer-highlight-matching-close-paren"
- 899   check-ints-equal x, 4, "F - test-render-gap-buffer-highlight-matching-close-paren: result"
- 900   check-background-color-in-screen-row screen, 3/bg=reverse,      0/y, "|   ", "F - test-render-gap-buffer-highlight-matching-close-paren: cursor"
- 901   check-screen-row-in-color            screen, 0xf/fg=highlight, 0/y, "  ) ", "F - test-render-gap-buffer-highlight-matching-close-paren: matching paren"
- 902 }
- 903 
- 904 fn test-render-gap-buffer-highlight-matching-open-paren {
- 905   var gap-storage: gap-buffer
- 906   var gap/esi: (addr gap-buffer) <- address gap-storage
- 907   initialize-gap-buffer-with gap, "(a)"
- 908   gap-to-end gap
- 909   var dummy/eax: grapheme <- gap-left gap
- 910   # setup: screen
- 911   var screen-on-stack: screen
- 912   var screen/edi: (addr screen) <- address screen-on-stack
- 913   initialize-screen screen, 5, 4, 0/no-pixel-graphics
- 914   #
- 915   var x/eax: int <- render-gap-buffer screen, gap, 0/x, 0/y, 1/show-cursor, 3/fg, 0xc5/bg=blue-bg
- 916   check-screen-row                     screen, 0/y,                   "(a) ", "F - test-render-gap-buffer-highlight-matching-open-paren"
- 917   check-ints-equal x, 4, "F - test-render-gap-buffer-highlight-matching-open-paren: result"
- 918   check-background-color-in-screen-row screen, 3/bg=reverse,      0/y, "  | ", "F - test-render-gap-buffer-highlight-matching-open-paren: cursor"
- 919   check-screen-row-in-color            screen, 0xf/fg=highlight, 0/y, "(   ", "F - test-render-gap-buffer-highlight-matching-open-paren: matching paren"
- 920 }
- 921 
- 922 fn test-render-gap-buffer-highlight-matching-open-paren-of-end {
- 923   var gap-storage: gap-buffer
- 924   var gap/esi: (addr gap-buffer) <- address gap-storage
- 925   initialize-gap-buffer-with gap, "(a)"
- 926   gap-to-end gap
- 927   # setup: screen
- 928   var screen-on-stack: screen
- 929   var screen/edi: (addr screen) <- address screen-on-stack
- 930   initialize-screen screen, 5, 4, 0/no-pixel-graphics
- 931   #
- 932   var x/eax: int <- render-gap-buffer screen, gap, 0/x, 0/y, 1/show-cursor, 3/fg, 0xc5/bg=blue-bg
- 933   check-screen-row                     screen, 0/y,                   "(a) ", "F - test-render-gap-buffer-highlight-matching-open-paren-of-end"
- 934   check-ints-equal x, 4, "F - test-render-gap-buffer-highlight-matching-open-paren-of-end: result"
- 935   check-background-color-in-screen-row screen, 3/bg=reverse,      0/y, "   |", "F - test-render-gap-buffer-highlight-matching-open-paren-of-end: cursor"
- 936   check-screen-row-in-color            screen, 0xf/fg=highlight, 0/y, "(   ", "F - test-render-gap-buffer-highlight-matching-open-paren-of-end: matching paren"
- 937 }
- 938 
- 939 # should I highlight a matching open paren? And if so, at what depth from top of left?
- 940 # basically there are two cases to disambiguate here:
- 941 #   Usually the cursor is at top of right. Highlight first '(' at depth 0 from top of left.
- 942 #   If right is empty, match the ')' _before_ cursor. Highlight first '(' at depth _1_ from top of left.
- 943 fn highlight-matching-open-paren? _gap: (addr gap-buffer), render-cursor?: boolean -> _/ebx: boolean, _/edi: int {
- 944   # if not rendering cursor, return
- 945   compare render-cursor?, 0/false
- 946   {
- 947     break-if-!=
- 948     return 0/false, 0
- 949   }
- 950   var gap/esi: (addr gap-buffer) <- copy _gap
- 951   var stack/edi: (addr grapheme-stack) <- get gap, right
- 952   var top-addr/eax: (addr int) <- get stack, top
- 953   var top-index/ecx: int <- copy *top-addr
- 954   compare top-index, 0
- 955   {
- 956     break-if->
- 957     # if cursor at end, return (char before cursor == ')', 1)
- 958     stack <- get gap, left
- 959     top-addr <- get stack, top
- 960     top-index <- copy *top-addr
- 961     compare top-index, 0
- 962     {
- 963       break-if->
- 964       return 0/false, 0
- 965     }
- 966     top-index <- decrement
- 967     var data-ah/eax: (addr handle array grapheme) <- get stack, data
- 968     var data/eax: (addr array grapheme) <- lookup *data-ah
- 969     var g/eax: (addr grapheme) <- index data, top-index
- 970     compare *g, 0x29/close-paren
- 971     {
- 972       break-if-=
- 973       return 0/false, 0
- 974     }
- 975     return 1/true, 1
- 976   }
- 977   # cursor is not at end; return (char at cursor == ')')
- 978   top-index <- decrement
- 979   var data-ah/eax: (addr handle array grapheme) <- get stack, data
- 980   var data/eax: (addr array grapheme) <- lookup *data-ah
- 981   var g/eax: (addr grapheme) <- index data, top-index
- 982   compare *g, 0x29/close-paren
- 983   {
- 984     break-if-=
- 985     return 0/false, 0
- 986   }
- 987   return 1/true, 0
- 988 }
- 989 
- 990 fn test-highlight-matching-open-paren {
- 991   var gap-storage: gap-buffer
- 992   var gap/esi: (addr gap-buffer) <- address gap-storage
- 993   initialize-gap-buffer-with gap, "(a)"
- 994   gap-to-end gap
- 995   var highlight-matching-open-paren?/ebx: boolean <- copy 0/false
- 996   var open-paren-depth/edi: int <- copy 0
- 997   highlight-matching-open-paren?, open-paren-depth <- highlight-matching-open-paren? gap, 0/no-cursor
- 998   check-not highlight-matching-open-paren?, "F - test-highlight-matching-open-paren: no cursor"
- 999   highlight-matching-open-paren?, open-paren-depth <- highlight-matching-open-paren? gap, 1/render-cursor
-1000   check highlight-matching-open-paren?, "F - test-highlight-matching-open-paren: at end immediately after ')'"
-1001   check-ints-equal open-paren-depth, 1, "F - test-highlight-matching-open-paren: depth at end immediately after ')'"
-1002   var dummy/eax: grapheme <- gap-left gap
-1003   highlight-matching-open-paren?, open-paren-depth <- highlight-matching-open-paren? gap, 1/render-cursor
-1004   check highlight-matching-open-paren?, "F - test-highlight-matching-open-paren: on ')'"
-1005   dummy <- gap-left gap
-1006   highlight-matching-open-paren?, open-paren-depth <- highlight-matching-open-paren? gap, 1/render-cursor
-1007   check-not highlight-matching-open-paren?, "F - test-highlight-matching-open-paren: not on ')'"
-1008 }
-1009 
-1010 ## some primitives for scanning through a gap buffer
-1011 # don't modify the gap buffer while scanning
-1012 # this includes moving the cursor around
-1013 
-1014 # restart scan without affecting gap-buffer contents
-1015 fn rewind-gap-buffer _self: (addr gap-buffer) {
-1016   var self/esi: (addr gap-buffer) <- copy _self
-1017   var dest/eax: (addr int) <- get self, left-read-index
-1018   copy-to *dest, 0
-1019   dest <- get self, right-read-index
-1020   copy-to *dest, 0
-1021 }
-1022 
-1023 fn gap-buffer-scan-done? _self: (addr gap-buffer) -> _/eax: boolean {
-1024   var self/esi: (addr gap-buffer) <- copy _self
-1025   # more in left?
-1026   var left/eax: (addr grapheme-stack) <- get self, left
-1027   var left-size/eax: int <- grapheme-stack-length left
-1028   var left-read-index/ecx: (addr int) <- get self, left-read-index
-1029   compare *left-read-index, left-size
-1030   {
-1031     break-if->=
-1032     return 0/false
-1033   }
-1034   # more in right?
-1035   var right/eax: (addr grapheme-stack) <- get self, right
-1036   var right-size/eax: int <- grapheme-stack-length right
-1037   var right-read-index/ecx: (addr int) <- get self, right-read-index
-1038   compare *right-read-index, right-size
-1039   {
-1040     break-if->=
-1041     return 0/false
-1042   }
-1043   #
-1044   return 1/true
-1045 }
-1046 
-1047 fn peek-from-gap-buffer _self: (addr gap-buffer) -> _/eax: grapheme {
-1048   var self/esi: (addr gap-buffer) <- copy _self
-1049   # more in left?
-1050   var left/ecx: (addr grapheme-stack) <- get self, left
-1051   var left-size/eax: int <- grapheme-stack-length left
-1052   var left-read-index-a/edx: (addr int) <- get self, left-read-index
-1053   compare *left-read-index-a, left-size
-1054   {
-1055     break-if->=
-1056     var left-data-ah/eax: (addr handle array grapheme) <- get left, data
-1057     var left-data/eax: (addr array grapheme) <- lookup *left-data-ah
-1058     var left-read-index/ecx: int <- copy *left-read-index-a
-1059     var result/eax: (addr grapheme) <- index left-data, left-read-index
-1060     return *result
-1061   }
-1062   # more in right?
-1063   var right/ecx: (addr grapheme-stack) <- get self, right
-1064   var _right-size/eax: int <- grapheme-stack-length right
-1065   var right-size/ebx: int <- copy _right-size
-1066   var right-read-index-a/edx: (addr int) <- get self, right-read-index
-1067   compare *right-read-index-a, right-size
-1068   {
-1069     break-if->=
-1070     # read the right from reverse
-1071     var right-data-ah/eax: (addr handle array grapheme) <- get right, data
-1072     var right-data/eax: (addr array grapheme) <- lookup *right-data-ah
-1073     var right-read-index/ebx: int <- copy right-size
-1074     right-read-index <- subtract *right-read-index-a
-1075     right-read-index <- subtract 1
-1076     var result/eax: (addr grapheme) <- index right-data, right-read-index
-1077     return *result
-1078   }
-1079   # if we get here there's nothing left
-1080   return 0/nul
-1081 }
-1082 
-1083 fn read-from-gap-buffer _self: (addr gap-buffer) -> _/eax: grapheme {
-1084   var self/esi: (addr gap-buffer) <- copy _self
-1085   # more in left?
-1086   var left/ecx: (addr grapheme-stack) <- get self, left
-1087   var left-size/eax: int <- grapheme-stack-length left
-1088   var left-read-index-a/edx: (addr int) <- get self, left-read-index
-1089   compare *left-read-index-a, left-size
-1090   {
-1091     break-if->=
-1092     var left-data-ah/eax: (addr handle array grapheme) <- get left, data
-1093     var left-data/eax: (addr array grapheme) <- lookup *left-data-ah
-1094     var left-read-index/ecx: int <- copy *left-read-index-a
-1095     var result/eax: (addr grapheme) <- index left-data, left-read-index
-1096     increment *left-read-index-a
-1097     return *result
-1098   }
-1099   # more in right?
-1100   var right/ecx: (addr grapheme-stack) <- get self, right
-1101   var _right-size/eax: int <- grapheme-stack-length right
-1102   var right-size/ebx: int <- copy _right-size
-1103   var right-read-index-a/edx: (addr int) <- get self, right-read-index
-1104   compare *right-read-index-a, right-size
-1105   {
-1106     break-if->=
-1107     # read the right from reverse
-1108     var right-data-ah/eax: (addr handle array grapheme) <- get right, data
-1109     var right-data/eax: (addr array grapheme) <- lookup *right-data-ah
-1110     var right-read-index/ebx: int <- copy right-size
-1111     right-read-index <- subtract *right-read-index-a
-1112     right-read-index <- subtract 1
-1113     var result/eax: (addr grapheme) <- index right-data, right-read-index
-1114     increment *right-read-index-a
-1115     return *result
-1116   }
-1117   # if we get here there's nothing left
-1118   return 0/nul
-1119 }
-1120 
-1121 fn put-back-from-gap-buffer _self: (addr gap-buffer) {
-1122   var self/esi: (addr gap-buffer) <- copy _self
-1123   # more in right?
-1124   var right/eax: (addr grapheme-stack) <- get self, right
-1125   var right-size/eax: int <- grapheme-stack-length right
-1126   var right-read-index-a/eax: (addr int) <- get self, right-read-index
-1127   compare *right-read-index-a, 0
-1128   {
-1129     break-if-<=
-1130     decrement *right-read-index-a
-1131     return
-1132   }
-1133   # more in left?
-1134   var left/eax: (addr grapheme-stack) <- get self, left
-1135   var left-size/eax: int <- grapheme-stack-length left
-1136   var left-read-index-a/eax: (addr int) <- get self, left-read-index
-1137   decrement *left-read-index-a
-1138 }
-1139 
-1140 fn test-read-from-gap-buffer {
-1141   var gap-storage: gap-buffer
-1142   var gap/esi: (addr gap-buffer) <- address gap-storage
-1143   initialize-gap-buffer-with gap, "abc"
-1144   # gap is at end, all contents are in left
-1145   var done?/eax: boolean <- gap-buffer-scan-done? gap
-1146   check-not done?, "F - test-read-from-gap-buffer/left-1/done"
-1147   var g/eax: grapheme <- read-from-gap-buffer gap
-1148   var x/ecx: int <- copy g
-1149   check-ints-equal x, 0x61/a, "F - test-read-from-gap-buffer/left-1"
-1150   var done?/eax: boolean <- gap-buffer-scan-done? gap
-1151   check-not done?, "F - test-read-from-gap-buffer/left-2/done"
-1152   var g/eax: grapheme <- read-from-gap-buffer gap
-1153   var x/ecx: int <- copy g
-1154   check-ints-equal x, 0x62/b, "F - test-read-from-gap-buffer/left-2"
-1155   var done?/eax: boolean <- gap-buffer-scan-done? gap
-1156   check-not done?, "F - test-read-from-gap-buffer/left-3/done"
-1157   var g/eax: grapheme <- read-from-gap-buffer gap
-1158   var x/ecx: int <- copy g
-1159   check-ints-equal x, 0x63/c, "F - test-read-from-gap-buffer/left-3"
-1160   var done?/eax: boolean <- gap-buffer-scan-done? gap
-1161   check done?, "F - test-read-from-gap-buffer/left-4/done"
-1162   var g/eax: grapheme <- read-from-gap-buffer gap
-1163   var x/ecx: int <- copy g
-1164   check-ints-equal x, 0/nul, "F - test-read-from-gap-buffer/left-4"
-1165   # now check when everything is to the right
-1166   gap-to-start gap
-1167   rewind-gap-buffer gap
-1168   var done?/eax: boolean <- gap-buffer-scan-done? gap
-1169   check-not done?, "F - test-read-from-gap-buffer/right-1/done"
-1170   var g/eax: grapheme <- read-from-gap-buffer gap
-1171   var x/ecx: int <- copy g
-1172   check-ints-equal x, 0x61/a, "F - test-read-from-gap-buffer/right-1"
-1173   var done?/eax: boolean <- gap-buffer-scan-done? gap
-1174   check-not done?, "F - test-read-from-gap-buffer/right-2/done"
-1175   var g/eax: grapheme <- read-from-gap-buffer gap
-1176   var x/ecx: int <- copy g
-1177   check-ints-equal x, 0x62/b, "F - test-read-from-gap-buffer/right-2"
-1178   var done?/eax: boolean <- gap-buffer-scan-done? gap
-1179   check-not done?, "F - test-read-from-gap-buffer/right-3/done"
-1180   var g/eax: grapheme <- read-from-gap-buffer gap
-1181   var x/ecx: int <- copy g
-1182   check-ints-equal x, 0x63/c, "F - test-read-from-gap-buffer/right-3"
-1183   var done?/eax: boolean <- gap-buffer-scan-done? gap
-1184   check done?, "F - test-read-from-gap-buffer/right-4/done"
-1185   var g/eax: grapheme <- read-from-gap-buffer gap
-1186   var x/ecx: int <- copy g
-1187   check-ints-equal x, 0/nul, "F - test-read-from-gap-buffer/right-4"
-1188 }
-1189 
-1190 fn skip-spaces-from-gap-buffer self: (addr gap-buffer) {
-1191   var done?/eax: boolean <- gap-buffer-scan-done? self
-1192   compare done?, 0/false
-1193   break-if-!=
-1194   var g/eax: grapheme <- peek-from-gap-buffer self
-1195   {
-1196     compare g, 0x20/space
-1197     break-if-=
-1198     return
-1199   }
-1200   g <- read-from-gap-buffer self
-1201   loop
-1202 }
-1203 
-1204 fn edit-gap-buffer self: (addr gap-buffer), key: grapheme {
-1205   var g/edx: grapheme <- copy key
-1206   {
-1207     compare g, 8/backspace
-1208     break-if-!=
-1209     delete-before-gap self
-1210     return
-1211   }
-1212   {
-1213     compare g, 0x80/left-arrow
-1214     break-if-!=
-1215     var dummy/eax: grapheme <- gap-left self
-1216     return
-1217   }
-1218   {
-1219     compare g, 0x83/right-arrow
-1220     break-if-!=
-1221     var dummy/eax: grapheme <- gap-right self
-1222     return
-1223   }
-1224   {
-1225     compare g, 6/ctrl-f
-1226     break-if-!=
-1227     gap-to-start-of-next-word self
-1228     return
-1229   }
-1230   {
-1231     compare g, 2/ctrl-b
-1232     break-if-!=
-1233     gap-to-end-of-previous-word self
-1234     return
-1235   }
-1236   {
-1237     compare g, 1/ctrl-a
-1238     break-if-!=
-1239     gap-to-previous-start-of-line self
-1240     return
-1241   }
-1242   {
-1243     compare g, 5/ctrl-e
-1244     break-if-!=
-1245     gap-to-next-end-of-line self
-1246     return
-1247   }
-1248   {
-1249     compare g, 0x81/down-arrow
-1250     break-if-!=
-1251     gap-down self
-1252     return
-1253   }
-1254   {
-1255     compare g, 0x82/up-arrow
-1256     break-if-!=
-1257     gap-up self
-1258     return
-1259   }
-1260   {
-1261     compare g, 0x15/ctrl-u
-1262     break-if-!=
-1263     clear-gap-buffer self
-1264     return
-1265   }
-1266   {
-1267     compare g, 9/tab
-1268     break-if-!=
-1269     # tab = 2 spaces
-1270     add-code-point-at-gap self, 0x20/space
-1271     add-code-point-at-gap self, 0x20/space
-1272     return
-1273   }
-1274   # default: insert character
-1275   add-grapheme-at-gap self, g
-1276 }
-1277 
-1278 fn gap-to-start-of-next-word self: (addr gap-buffer) {
-1279   var curr/eax: grapheme <- copy 0
-1280   # skip to next space
-1281   {
-1282     curr <- gap-right self
-1283     compare curr, -1
-1284     break-if-=
-1285     compare curr, 0x20/space
-1286     break-if-=
-1287     compare curr, 0xa/newline
-1288     break-if-=
-1289     loop
-1290   }
-1291   # skip past spaces
-1292   {
-1293     curr <- gap-right self
-1294     compare curr, -1
-1295     break-if-=
-1296     compare curr, 0x20/space
-1297     loop-if-=
-1298     compare curr, 0xa/space
-1299     loop-if-=
-1300     curr <- gap-left self
-1301     break
-1302   }
-1303 }
-1304 
-1305 fn gap-to-end-of-previous-word self: (addr gap-buffer) {
-1306   var curr/eax: grapheme <- copy 0
-1307   # skip to previous space
-1308   {
-1309     curr <- gap-left self
-1310     compare curr, -1
-1311     break-if-=
-1312     compare curr, 0x20/space
-1313     break-if-=
-1314     compare curr, 0xa/newline
-1315     break-if-=
-1316     loop
-1317   }
-1318   # skip past all spaces but one
-1319   {
-1320     curr <- gap-left self
-1321     compare curr, -1
-1322     break-if-=
-1323     compare curr, 0x20/space
-1324     loop-if-=
-1325     compare curr, 0xa/space
-1326     loop-if-=
-1327     curr <- gap-right self
-1328     break
-1329   }
-1330 }
-1331 
-1332 fn gap-to-previous-start-of-line self: (addr gap-buffer) {
-1333   # skip past immediate newline
-1334   var dummy/eax: grapheme <- gap-left self
-1335   # skip to previous newline
-1336   {
-1337     dummy <- gap-left self
-1338     {
-1339       compare dummy, -1
-1340       break-if-!=
-1341       return
-1342     }
-1343     {
-1344       compare dummy, 0xa/newline
-1345       break-if-!=
-1346       dummy <- gap-right self
-1347       return
-1348     }
-1349     loop
-1350   }
-1351 }
-1352 
-1353 fn gap-to-next-end-of-line self: (addr gap-buffer) {
-1354   # skip past immediate newline
-1355   var dummy/eax: grapheme <- gap-right self
-1356   # skip to next newline
-1357   {
-1358     dummy <- gap-right self
-1359     {
-1360       compare dummy, -1
-1361       break-if-!=
-1362       return
-1363     }
-1364     {
-1365       compare dummy, 0xa/newline
-1366       break-if-!=
-1367       dummy <- gap-left self
-1368       return
-1369     }
-1370     loop
-1371   }
-1372 }
-1373 
-1374 fn gap-up self: (addr gap-buffer) {
-1375   # compute column
-1376   var col/edx: int <- count-columns-to-start-of-line self
-1377   #
-1378   gap-to-previous-start-of-line self
-1379   # skip ahead by up to col on previous line
-1380   var i/ecx: int <- copy 0
-1381   {
-1382     compare i, col
-1383     break-if->=
-1384     var curr/eax: grapheme <- gap-right self
-1385     {
-1386       compare curr, -1
-1387       break-if-!=
-1388       return
-1389     }
-1390     compare curr, 0xa/newline
-1391     {
-1392       break-if-!=
-1393       curr <- gap-left self
-1394       return
-1395     }
-1396     i <- increment
-1397     loop
-1398   }
-1399 }
-1400 
-1401 fn gap-down self: (addr gap-buffer) {
-1402   # compute column
-1403   var col/edx: int <- count-columns-to-start-of-line self
-1404   # skip to start of next line
-1405   gap-to-end-of-line self
-1406   var dummy/eax: grapheme <- gap-right self
-1407   # skip ahead by up to col on previous line
-1408   var i/ecx: int <- copy 0
-1409   {
-1410     compare i, col
-1411     break-if->=
-1412     var curr/eax: grapheme <- gap-right self
-1413     {
-1414       compare curr, -1
-1415       break-if-!=
-1416       return
-1417     }
-1418     compare curr, 0xa/newline
-1419     {
-1420       break-if-!=
-1421       curr <- gap-left self
-1422       return
-1423     }
-1424     i <- increment
-1425     loop
-1426   }
-1427 }
-1428 
-1429 fn count-columns-to-start-of-line self: (addr gap-buffer) -> _/edx: int {
-1430   var count/edx: int <- copy 0
-1431   var dummy/eax: grapheme <- copy 0
-1432   # skip to previous newline
-1433   {
-1434     dummy <- gap-left self
-1435     {
-1436       compare dummy, -1
-1437       break-if-!=
-1438       return count
-1439     }
-1440     {
-1441       compare dummy, 0xa/newline
-1442       break-if-!=
-1443       dummy <- gap-right self
-1444       return count
-1445     }
-1446     count <- increment
-1447     loop
-1448   }
-1449   return count
-1450 }
-1451 
-1452 fn gap-to-end-of-line self: (addr gap-buffer) {
-1453   var dummy/eax: grapheme <- copy 0
-1454   # skip to next newline
-1455   {
-1456     dummy <- gap-right self
-1457     {
-1458       compare dummy, -1
-1459       break-if-!=
-1460       return
-1461     }
-1462     {
-1463       compare dummy, 0xa/newline
-1464       break-if-!=
-1465       dummy <- gap-left self
-1466       return
-1467     }
-1468     loop
-1469   }
-1470 }
-
- - - diff --git a/html/shell/grapheme-stack.mu.html b/html/shell/grapheme-stack.mu.html deleted file mode 100644 index 2138dcba..00000000 --- a/html/shell/grapheme-stack.mu.html +++ /dev/null @@ -1,624 +0,0 @@ - - - - -Mu - shell/grapheme-stack.mu - - - - - - - - - - -https://github.com/akkartik/mu/blob/main/shell/grapheme-stack.mu -
-  1 # grapheme stacks are the smallest unit of editable text
-  2 
-  3 type grapheme-stack {
-  4   data: (handle array grapheme)
-  5   top: int
-  6 }
-  7 
-  8 fn initialize-grapheme-stack _self: (addr grapheme-stack), n: int {
-  9   var self/esi: (addr grapheme-stack) <- copy _self
- 10   var d/edi: (addr handle array grapheme) <- get self, data
- 11   populate d, n
- 12   var top/eax: (addr int) <- get self, top
- 13   copy-to *top, 0
- 14 }
- 15 
- 16 fn clear-grapheme-stack _self: (addr grapheme-stack) {
- 17   var self/esi: (addr grapheme-stack) <- copy _self
- 18   var top/eax: (addr int) <- get self, top
- 19   copy-to *top, 0
- 20 }
- 21 
- 22 fn grapheme-stack-empty? _self: (addr grapheme-stack) -> _/eax: boolean {
- 23   var self/esi: (addr grapheme-stack) <- copy _self
- 24   var top/eax: (addr int) <- get self, top
- 25   compare *top, 0
- 26   {
- 27     break-if-!=
- 28     return 1/true
- 29   }
- 30   return 0/false
- 31 }
- 32 
- 33 fn grapheme-stack-length _self: (addr grapheme-stack) -> _/eax: int {
- 34   var self/esi: (addr grapheme-stack) <- copy _self
- 35   var top/eax: (addr int) <- get self, top
- 36   return *top
- 37 }
- 38 
- 39 fn push-grapheme-stack _self: (addr grapheme-stack), _val: grapheme {
- 40   var self/esi: (addr grapheme-stack) <- copy _self
- 41   var top-addr/ecx: (addr int) <- get self, top
- 42   var data-ah/edx: (addr handle array grapheme) <- get self, data
- 43   var data/eax: (addr array grapheme) <- lookup *data-ah
- 44   var top/edx: int <- copy *top-addr
- 45   var dest-addr/edx: (addr grapheme) <- index data, top
- 46   var val/eax: grapheme <- copy _val
- 47   copy-to *dest-addr, val
- 48   add-to *top-addr, 1
- 49 }
- 50 
- 51 fn pop-grapheme-stack _self: (addr grapheme-stack) -> _/eax: grapheme {
- 52   var self/esi: (addr grapheme-stack) <- copy _self
- 53   var top-addr/ecx: (addr int) <- get self, top
- 54   {
- 55     compare *top-addr, 0
- 56     break-if->
- 57     return -1
- 58   }
- 59   subtract-from *top-addr, 1
- 60   var data-ah/edx: (addr handle array grapheme) <- get self, data
- 61   var data/eax: (addr array grapheme) <- lookup *data-ah
- 62   var top/edx: int <- copy *top-addr
- 63   var result-addr/eax: (addr grapheme) <- index data, top
- 64   return *result-addr
- 65 }
- 66 
- 67 fn copy-grapheme-stack _src: (addr grapheme-stack), dest: (addr grapheme-stack) {
- 68   var src/esi: (addr grapheme-stack) <- copy _src
- 69   var data-ah/edi: (addr handle array grapheme) <- get src, data
- 70   var _data/eax: (addr array grapheme) <- lookup *data-ah
- 71   var data/edi: (addr array grapheme) <- copy _data
- 72   var top-addr/ecx: (addr int) <- get src, top
- 73   var i/eax: int <- copy 0
- 74   {
- 75     compare i, *top-addr
- 76     break-if->=
- 77     var g/edx: (addr grapheme) <- index data, i
- 78     push-grapheme-stack dest, *g
- 79     i <- increment
- 80     loop
- 81   }
- 82 }
- 83 
- 84 # dump stack to screen from bottom to top
- 85 # hardcoded colors:
- 86 #   matching paren
- 87 fn render-stack-from-bottom-wrapping-right-then-down screen: (addr screen), _self: (addr grapheme-stack), xmin: int, ymin: int, xmax: int, ymax: int, _x: int, _y: int, highlight-matching-open-paren?: boolean, open-paren-depth: int, color: int, background-color: int -> _/eax: int, _/ecx: int {
- 88   var self/esi: (addr grapheme-stack) <- copy _self
- 89   var matching-open-paren-index/edx: int <- get-matching-open-paren-index self, highlight-matching-open-paren?, open-paren-depth
- 90   var data-ah/edi: (addr handle array grapheme) <- get self, data
- 91   var _data/eax: (addr array grapheme) <- lookup *data-ah
- 92   var data/edi: (addr array grapheme) <- copy _data
- 93   var x/eax: int <- copy _x
- 94   var y/ecx: int <- copy _y
- 95   var top-addr/esi: (addr int) <- get self, top
- 96   var i/ebx: int <- copy 0
- 97   {
- 98     compare i, *top-addr
- 99     break-if->=
-100     {
-101       var g/esi: (addr grapheme) <- index data, i
-102       var fg: int
-103       {
-104         var tmp/eax: int <- copy color
-105         copy-to fg, tmp
-106       }
-107       {
-108         compare i, matching-open-paren-index
-109         break-if-!=
-110         copy-to fg, 0xf/highlight
-111       }
-112       x, y <- render-grapheme screen, *g, xmin, ymin, xmax, ymax, x, y, fg, background-color
-113     }
-114     i <- increment
-115     loop
-116   }
-117   return x, y
-118 }
-119 
-120 # helper for small words
-121 fn render-stack-from-bottom screen: (addr screen), self: (addr grapheme-stack), x: int, y: int, highlight-matching-open-paren?: boolean, open-paren-depth: int -> _/eax: int {
-122   var _width/eax: int <- copy 0
-123   var _height/ecx: int <- copy 0
-124   _width, _height <- screen-size screen
-125   var width/edx: int <- copy _width
-126   var height/ebx: int <- copy _height
-127   var x2/eax: int <- copy 0
-128   var y2/ecx: int <- copy 0
-129   x2, y2 <- render-stack-from-bottom-wrapping-right-then-down screen, self, x, y, width, height, x, y, highlight-matching-open-paren?, open-paren-depth, 3/fg=cyan, 0xc5/bg=blue-bg
-130   return x2  # y2? yolo
-131 }
-132 
-133 # dump stack to screen from top to bottom
-134 # optionally render a 'cursor' with the top grapheme
-135 # hard-coded colors:
-136 #   matching paren
-137 #   cursor
-138 fn render-stack-from-top-wrapping-right-then-down screen: (addr screen), _self: (addr grapheme-stack), xmin: int, ymin: int, xmax: int, ymax: int, _x: int, _y: int, render-cursor?: boolean, color: int, background-color: int -> _/eax: int, _/ecx: int {
-139   var self/esi: (addr grapheme-stack) <- copy _self
-140   var matching-close-paren-index/edx: int <- get-matching-close-paren-index self, render-cursor?
-141   var data-ah/eax: (addr handle array grapheme) <- get self, data
-142   var _data/eax: (addr array grapheme) <- lookup *data-ah
-143   var data/edi: (addr array grapheme) <- copy _data
-144   var x/eax: int <- copy _x
-145   var y/ecx: int <- copy _y
-146   var top-addr/ebx: (addr int) <- get self, top
-147   var i/ebx: int <- copy *top-addr
-148   i <- decrement
-149   # if render-cursor?, peel off first iteration
-150   {
-151     compare render-cursor?, 0/false
-152     break-if-=
-153     compare i, 0
-154     break-if-<
-155     var g/esi: (addr grapheme) <- index data, i
-156     x, y <- render-grapheme screen, *g, xmin, ymin, xmax, ymax, x, y, background-color, color
-157     i <- decrement
-158   }
-159   # remaining iterations
-160   {
-161     compare i, 0
-162     break-if-<
-163     # highlight matching paren if needed
-164     var fg: int
-165     {
-166       var tmp/eax: int <- copy color
-167       copy-to fg, tmp
-168     }
-169     compare i, matching-close-paren-index
-170     {
-171       break-if-!=
-172       copy-to fg, 0xf/highlight
-173     }
-174     #
-175     var g/esi: (addr grapheme) <- index data, i
-176     x, y <- render-grapheme screen, *g, xmin, ymin, xmax, ymax, x, y, fg, background-color
-177     i <- decrement
-178     loop
-179   }
-180   return x, y
-181 }
-182 
-183 # helper for small words
-184 fn render-stack-from-top screen: (addr screen), self: (addr grapheme-stack), x: int, y: int, render-cursor?: boolean -> _/eax: int {
-185   var _width/eax: int <- copy 0
-186   var _height/ecx: int <- copy 0
-187   _width, _height <- screen-size screen
-188   var width/edx: int <- copy _width
-189   var height/ebx: int <- copy _height
-190   var x2/eax: int <- copy 0
-191   var y2/ecx: int <- copy 0
-192   x2, y2 <- render-stack-from-top-wrapping-right-then-down screen, self, x, y, width, height, x, y, render-cursor?, 3/fg=cyan, 0xc5/bg=blue-bg
-193   return x2  # y2? yolo
-194 }
-195 
-196 fn test-render-grapheme-stack {
-197   # setup: gs = "abc"
-198   var gs-storage: grapheme-stack
-199   var gs/edi: (addr grapheme-stack) <- address gs-storage
-200   initialize-grapheme-stack gs, 5
-201   var g/eax: grapheme <- copy 0x61/a
-202   push-grapheme-stack gs, g
-203   g <- copy 0x62/b
-204   push-grapheme-stack gs, g
-205   g <- copy 0x63/c
-206   push-grapheme-stack gs, g
-207   # setup: screen
-208   var screen-on-stack: screen
-209   var screen/esi: (addr screen) <- address screen-on-stack
-210   initialize-screen screen, 5, 4, 0/no-pixel-graphics
-211   #
-212   var x/eax: int <- render-stack-from-bottom screen, gs, 0/x, 0/y, 0/no-highlight-matching-open-paren, 0/open-paren-depth
-213   check-screen-row screen, 0/y, "abc ", "F - test-render-grapheme-stack from bottom"
-214   check-ints-equal x, 3, "F - test-render-grapheme-stack from bottom: result"
-215   check-background-color-in-screen-row screen, 3/bg=reverse, 0/y, "   ", "F - test-render-grapheme-stack from bottom: bg"
-216   #
-217   var x/eax: int <- render-stack-from-top screen, gs, 0/x, 1/y, 0/cursor=false
-218   check-screen-row screen, 1/y, "cba ", "F - test-render-grapheme-stack from top without cursor"
-219   check-ints-equal x, 3, "F - test-render-grapheme-stack from top without cursor: result"
-220   check-background-color-in-screen-row screen, 3/bg=reverse, 1/y, "   ", "F - test-render-grapheme-stack from top without cursor: bg"
-221   #
-222   var x/eax: int <- render-stack-from-top screen, gs, 0/x, 2/y, 1/cursor=true
-223   check-screen-row screen, 2/y, "cba ", "F - test-render-grapheme-stack from top with cursor"
-224   check-ints-equal x, 3, "F - test-render-grapheme-stack from top with cursor: result"
-225   check-background-color-in-screen-row screen, 3/bg=reverse, 2/y, "|   ", "F - test-render-grapheme-stack from top with cursor: bg"
-226 }
-227 
-228 fn test-render-grapheme-stack-while-highlighting-matching-close-paren {
-229   # setup: gs = "(b)"
-230   var gs-storage: grapheme-stack
-231   var gs/edi: (addr grapheme-stack) <- address gs-storage
-232   initialize-grapheme-stack gs, 5
-233   var g/eax: grapheme <- copy 0x29/close-paren
-234   push-grapheme-stack gs, g
-235   g <- copy 0x62/b
-236   push-grapheme-stack gs, g
-237   g <- copy 0x28/open-paren
-238   push-grapheme-stack gs, g
-239   # setup: screen
-240   var screen-on-stack: screen
-241   var screen/esi: (addr screen) <- address screen-on-stack
-242   initialize-screen screen, 5, 4, 0/no-pixel-graphics
-243   #
-244   var x/eax: int <- render-stack-from-top screen, gs, 0/x, 2/y, 1/cursor=true
-245   check-screen-row                      screen,               2/y, "(b) ", "F - test-render-grapheme-stack-while-highlighting-matching-close-paren"
-246   check-background-color-in-screen-row  screen, 3/bg=reverse,  2/y, "|   ", "F - test-render-grapheme-stack-while-highlighting-matching-close-paren: cursor"
-247   check-screen-row-in-color             screen, 0xf/fg=white, 2/y, "  ) ", "F - test-render-grapheme-stack-while-highlighting-matching-close-paren: matching paren"
-248 }
-249 
-250 fn test-render-grapheme-stack-while-highlighting-matching-close-paren-2 {
-251   # setup: gs = "(a (b)) c"
-252   var gs-storage: grapheme-stack
-253   var gs/edi: (addr grapheme-stack) <- address gs-storage
-254   initialize-grapheme-stack gs, 0x10
-255   var g/eax: grapheme <- copy 0x63/c
-256   push-grapheme-stack gs, g
-257   g <- copy 0x20/space
-258   push-grapheme-stack gs, g
-259   g <- copy 0x29/close-paren
-260   push-grapheme-stack gs, g
-261   g <- copy 0x29/close-paren
-262   push-grapheme-stack gs, g
-263   g <- copy 0x62/b
-264   push-grapheme-stack gs, g
-265   g <- copy 0x28/open-paren
-266   push-grapheme-stack gs, g
-267   g <- copy 0x20/space
-268   push-grapheme-stack gs, g
-269   g <- copy 0x61/a
-270   push-grapheme-stack gs, g
-271   g <- copy 0x28/open-paren
-272   push-grapheme-stack gs, g
-273   # setup: screen
-274   var screen-on-stack: screen
-275   var screen/esi: (addr screen) <- address screen-on-stack
-276   initialize-screen screen, 5, 4, 0/no-pixel-graphics
-277   #
-278   var x/eax: int <- render-stack-from-top screen, gs, 0/x, 2/y, 1/cursor=true
-279   check-screen-row                      screen,               2/y, "(a (b)) c ", "F - test-render-grapheme-stack-while-highlighting-matching-close-paren-2"
-280   check-background-color-in-screen-row  screen, 3/bg=reverse,  2/y, "|         ", "F - test-render-grapheme-stack-while-highlighting-matching-close-paren-2: cursor"
-281   check-screen-row-in-color             screen, 0xf/fg=white, 2/y, "      )   ", "F - test-render-grapheme-stack-while-highlighting-matching-close-paren-2: matching paren"
-282 }
-283 
-284 fn test-render-grapheme-stack-while-highlighting-matching-open-paren-with-close-paren-at-end {
-285   # setup: gs = "(b)"
-286   var gs-storage: grapheme-stack
-287   var gs/edi: (addr grapheme-stack) <- address gs-storage
-288   initialize-grapheme-stack gs, 5
-289   var g/eax: grapheme <- copy 0x28/open-paren
-290   push-grapheme-stack gs, g
-291   g <- copy 0x62/b
-292   push-grapheme-stack gs, g
-293   g <- copy 0x29/close-paren
-294   push-grapheme-stack gs, g
-295   # setup: screen
-296   var screen-on-stack: screen
-297   var screen/esi: (addr screen) <- address screen-on-stack
-298   initialize-screen screen, 5, 4, 0/no-pixel-graphics
-299   #
-300   var x/eax: int <- render-stack-from-bottom screen, gs, 0/x, 2/y, 1/highlight-matching-open-paren, 1/open-paren-depth
-301   check-screen-row          screen,               2/y, "(b) ", "F - test-render-grapheme-stack-while-highlighting-matching-open-paren-with-close-paren-at-end"
-302   check-screen-row-in-color screen, 0xf/fg=white, 2/y, "(   ", "F - test-render-grapheme-stack-while-highlighting-matching-open-paren-with-close-paren-at-end: matching paren"
-303 }
-304 
-305 fn test-render-grapheme-stack-while-highlighting-matching-open-paren-with-close-paren-at-end-2 {
-306   # setup: gs = "a((b))"
-307   var gs-storage: grapheme-stack
-308   var gs/edi: (addr grapheme-stack) <- address gs-storage
-309   initialize-grapheme-stack gs, 0x10
-310   var g/eax: grapheme <- copy 0x61/a
-311   push-grapheme-stack gs, g
-312   g <- copy 0x28/open-paren
-313   push-grapheme-stack gs, g
-314   g <- copy 0x28/open-paren
-315   push-grapheme-stack gs, g
-316   g <- copy 0x62/b
-317   push-grapheme-stack gs, g
-318   g <- copy 0x29/close-paren
-319   push-grapheme-stack gs, g
-320   g <- copy 0x29/close-paren
-321   push-grapheme-stack gs, g
-322   # setup: screen
-323   var screen-on-stack: screen
-324   var screen/esi: (addr screen) <- address screen-on-stack
-325   initialize-screen screen, 5, 4, 0/no-pixel-graphics
-326   #
-327   var x/eax: int <- render-stack-from-bottom screen, gs, 0/x, 2/y, 1/highlight-matching-open-paren, 1/open-paren-depth
-328   check-screen-row          screen,               2/y, "a((b)) ", "F - test-render-grapheme-stack-while-highlighting-matching-open-paren-with-close-paren-at-end-2"
-329   check-screen-row-in-color screen, 0xf/fg=white, 2/y, " (     ", "F - test-render-grapheme-stack-while-highlighting-matching-open-paren-with-close-paren-at-end-2: matching paren"
-330 }
-331 
-332 fn test-render-grapheme-stack-while-highlighting-matching-open-paren {
-333   # setup: gs = "(b"
-334   var gs-storage: grapheme-stack
-335   var gs/edi: (addr grapheme-stack) <- address gs-storage
-336   initialize-grapheme-stack gs, 5
-337   var g/eax: grapheme <- copy 0x28/open-paren
-338   push-grapheme-stack gs, g
-339   g <- copy 0x62/b
-340   push-grapheme-stack gs, g
-341   # setup: screen
-342   var screen-on-stack: screen
-343   var screen/esi: (addr screen) <- address screen-on-stack
-344   initialize-screen screen, 5, 4, 0/no-pixel-graphics
-345   #
-346   var x/eax: int <- render-stack-from-bottom screen, gs, 0/x, 2/y, 1/highlight-matching-open-paren, 0/open-paren-depth
-347   check-screen-row          screen,               2/y, "(b ", "F - test-render-grapheme-stack-while-highlighting-matching-open-paren"
-348   check-screen-row-in-color screen, 0xf/fg=white, 2/y, "(  ", "F - test-render-grapheme-stack-while-highlighting-matching-open-paren: matching paren"
-349 }
-350 
-351 fn test-render-grapheme-stack-while-highlighting-matching-open-paren-2 {
-352   # setup: gs = "a((b)"
-353   var gs-storage: grapheme-stack
-354   var gs/edi: (addr grapheme-stack) <- address gs-storage
-355   initialize-grapheme-stack gs, 0x10
-356   var g/eax: grapheme <- copy 0x61/a
-357   push-grapheme-stack gs, g
-358   g <- copy 0x28/open-paren
-359   push-grapheme-stack gs, g
-360   g <- copy 0x28/open-paren
-361   push-grapheme-stack gs, g
-362   g <- copy 0x62/b
-363   push-grapheme-stack gs, g
-364   g <- copy 0x29/close-paren
-365   push-grapheme-stack gs, g
-366   # setup: screen
-367   var screen-on-stack: screen
-368   var screen/esi: (addr screen) <- address screen-on-stack
-369   initialize-screen screen, 5, 4, 0/no-pixel-graphics
-370   #
-371   var x/eax: int <- render-stack-from-bottom screen, gs, 0/x, 2/y, 1/highlight-matching-open-paren, 0/open-paren-depth
-372   check-screen-row          screen,               2/y, "a((b) ", "F - test-render-grapheme-stack-while-highlighting-matching-open-paren-2"
-373   check-screen-row-in-color screen, 0xf/fg=white, 2/y, " (    ", "F - test-render-grapheme-stack-while-highlighting-matching-open-paren-2: matching paren"
-374 }
-375 
-376 # return the index of the matching close-paren of the grapheme at cursor (top of stack)
-377 # or top index if there's no matching close-paren
-378 fn get-matching-close-paren-index _self: (addr grapheme-stack), render-cursor?: boolean -> _/edx: int {
-379   var self/esi: (addr grapheme-stack) <- copy _self
-380   var top-addr/edx: (addr int) <- get self, top
-381   # if not rendering cursor, return
-382   compare render-cursor?, 0/false
-383   {
-384     break-if-!=
-385     return *top-addr
-386   }
-387   var data-ah/eax: (addr handle array grapheme) <- get self, data
-388   var data/eax: (addr array grapheme) <- lookup *data-ah
-389   var i/ecx: int <- copy *top-addr
-390   # if stack is empty, return
-391   compare i, 0
-392   {
-393     break-if->
-394     return *top-addr
-395   }
-396   # if cursor is not '(' return
-397   i <- decrement
-398   var g/esi: (addr grapheme) <- index data, i
-399   compare *g, 0x28/open-paren
-400   {
-401     break-if-=
-402     return *top-addr
-403   }
-404   # otherwise scan to matching paren
-405   var paren-count/ebx: int <- copy 1
-406   i <- decrement
-407   {
-408     compare i, 0
-409     break-if-<
-410     var g/esi: (addr grapheme) <- index data, i
-411     compare *g, 0x28/open-paren
-412     {
-413       break-if-!=
-414       paren-count <- increment
-415     }
-416     compare *g, 0x29/close-paren
-417     {
-418       break-if-!=
-419       compare paren-count, 1
-420       {
-421         break-if-!=
-422         return i
-423       }
-424       paren-count <- decrement
-425     }
-426     i <- decrement
-427     loop
-428   }
-429   return *top-addr
-430 }
-431 
-432 # return the index of the first open-paren at the given depth
-433 # or top index if there's no matching close-paren
-434 fn get-matching-open-paren-index _self: (addr grapheme-stack), control: boolean, depth: int -> _/edx: int {
-435   var self/esi: (addr grapheme-stack) <- copy _self
-436   var top-addr/edx: (addr int) <- get self, top
-437   # if not rendering cursor, return
-438   compare control, 0/false
-439   {
-440     break-if-!=
-441     return *top-addr
-442   }
-443   var data-ah/eax: (addr handle array grapheme) <- get self, data
-444   var data/eax: (addr array grapheme) <- lookup *data-ah
-445   var i/ecx: int <- copy *top-addr
-446   # if stack is empty, return
-447   compare i, 0
-448   {
-449     break-if->
-450     return *top-addr
-451   }
-452   # scan to matching open paren
-453   var paren-count/ebx: int <- copy 0
-454   i <- decrement
-455   {
-456     compare i, 0
-457     break-if-<
-458     var g/esi: (addr grapheme) <- index data, i
-459     compare *g, 0x29/close-paren
-460     {
-461       break-if-!=
-462       paren-count <- increment
-463     }
-464     compare *g, 0x28/open-paren
-465     {
-466       break-if-!=
-467       compare paren-count, depth
-468       {
-469         break-if-!=
-470         return i
-471       }
-472       paren-count <- decrement
-473     }
-474     i <- decrement
-475     loop
-476   }
-477   return *top-addr
-478 }
-479 
-480 # compare from bottom
-481 # beware: modifies 'stream', which must be disposed of after a false result
-482 fn prefix-match? _self: (addr grapheme-stack), s: (addr stream byte) -> _/eax: boolean {
-483   var self/esi: (addr grapheme-stack) <- copy _self
-484   var data-ah/edi: (addr handle array grapheme) <- get self, data
-485   var _data/eax: (addr array grapheme) <- lookup *data-ah
-486   var data/edi: (addr array grapheme) <- copy _data
-487   var top-addr/ecx: (addr int) <- get self, top
-488   var i/ebx: int <- copy 0
-489   {
-490     compare i, *top-addr
-491     break-if->=
-492     # if curr != expected, return false
-493     {
-494       var curr-a/edx: (addr grapheme) <- index data, i
-495       var expected/eax: grapheme <- read-grapheme s
-496       {
-497         compare expected, *curr-a
-498         break-if-=
-499         return 0/false
-500       }
-501     }
-502     i <- increment
-503     loop
-504   }
-505   return 1   # true
-506 }
-507 
-508 # compare from bottom
-509 # beware: modifies 'stream', which must be disposed of after a false result
-510 fn suffix-match? _self: (addr grapheme-stack), s: (addr stream byte) -> _/eax: boolean {
-511   var self/esi: (addr grapheme-stack) <- copy _self
-512   var data-ah/edi: (addr handle array grapheme) <- get self, data
-513   var _data/eax: (addr array grapheme) <- lookup *data-ah
-514   var data/edi: (addr array grapheme) <- copy _data
-515   var top-addr/eax: (addr int) <- get self, top
-516   var i/ebx: int <- copy *top-addr
-517   i <- decrement
-518   {
-519     compare i, 0
-520     break-if-<
-521     {
-522       var curr-a/edx: (addr grapheme) <- index data, i
-523       var expected/eax: grapheme <- read-grapheme s
-524       # if curr != expected, return false
-525       {
-526         compare expected, *curr-a
-527         break-if-=
-528         return 0/false
-529       }
-530     }
-531     i <- decrement
-532     loop
-533   }
-534   return 1   # true
-535 }
-536 
-537 fn grapheme-stack-is-decimal-integer? _self: (addr grapheme-stack) -> _/eax: boolean {
-538   var self/esi: (addr grapheme-stack) <- copy _self
-539   var data-ah/eax: (addr handle array grapheme) <- get self, data
-540   var _data/eax: (addr array grapheme) <- lookup *data-ah
-541   var data/edx: (addr array grapheme) <- copy _data
-542   var top-addr/ecx: (addr int) <- get self, top
-543   var i/ebx: int <- copy 0
-544   var result/eax: boolean <- copy 1/true
-545   $grapheme-stack-is-integer?:loop: {
-546     compare i, *top-addr
-547     break-if->=
-548     var g/edx: (addr grapheme) <- index data, i
-549     result <- decimal-digit? *g
-550     compare result, 0/false
-551     break-if-=
-552     i <- increment
-553     loop
-554   }
-555   return result
-556 }
-
- - - diff --git a/tools/update_html b/tools/update_html index 8110b010..5f7c2c90 100755 --- a/tools/update_html +++ b/tools/update_html @@ -19,7 +19,7 @@ process() { URL_BASE='https://github.com/akkartik/mu/blob/main' convert_html() { - vim -c "set number" -c TOhtml -c write -c qall $1 + vim -u $MYVIM/vimrc.vim -c "set number" -c TOhtml -c write -c qall $1 sed -i 's,.*/mu/,<title>Mu - ,' $1.html sed -i 's,\.html,,' $1.html @@ -74,60 +74,4 @@ do process $f done -( cd linux - ctags -x [0-9]*.subx [0-9]*.mu > /tmp/tags -) -for f in linux/[0-9]*.subx linux/[0-9]*.mu -do - process $f -done - -for f in linux/[^0-9]*.subx linux/[^0-9]*.mu -do - ( cd $(dirname $f) - ctags -x [0-9]*.subx [0-9]*.mu $(basename $f) > /tmp/tags - ) - process $f -done - -for f in linux/apps/*.subx linux/apps/*.mu -do - ( cd $(dirname $f) - ctags -x ../[0-9]*.subx ../[0-9]*.mu $(basename $f) > /tmp/tags - ) - process $f -done - -for f in linux/apps/advent2020/*.mu linux/apps/advent2017/*.mu -do - ( cd $(dirname $f) - ctags -x ../../[0-9]*.subx ../../[0-9]*.mu $(basename $f) > /tmp/tags - ) - process $f -done - -( cd linux/tile - ctags -x ../[0-9]*.subx ../[0-9]*.mu *.mu > /tmp/tags -) -for f in linux/tile/*.mu -do - process $f -done - -( cd linux/apps/raytracing - ctags -x ../../[0-9]*.subx ../../[0-9]*.mu *.mu > /tmp/tags -) -for f in linux/apps/raytracing/*.mu -do - process $f -done - -( cd linux/bootstrap - ctags -x *.cc |grep -v '^. ' > /tmp/tags # don't hyperlink every 'i' to the integer register variant -) -for f in linux/bootstrap/*.cc -do - process $f -done - rm /tmp/tags