From 1f9b16680f1190a7be4098d61ed2ef74b1906b79 Mon Sep 17 00:00:00 2001 From: Kartik Agaram Date: Tue, 9 Nov 2021 09:38:54 -0800 Subject: . --- html/shell/gap-buffer.mu.html | 1538 ----------------------------------------- 1 file changed, 1538 deletions(-) delete mode 100644 html/shell/gap-buffer.mu.html (limited to 'html/shell/gap-buffer.mu.html') 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 }
-
- - - -- cgit 1.4.1-2-gfad0