https://github.com/akkartik/mu/blob/main/shell/gap-buffer.mu
1
2
3 type gap-buffer {
4 left: grapheme-stack
5 right: grapheme-stack
6
7 left-read-index: int
8 right-read-index: int
9 }
10
11 fn initialize-gap-buffer _self: (addr gap-buffer), max-word-size: 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, max-word-size
15 var right/eax: (addr grapheme-stack) <- get self, right
16 initialize-grapheme-stack right, max-word-size
17 }
18
19
20 fn initialize-gap-buffer-with self: (addr gap-buffer), s: (addr array byte) {
21 initialize-gap-buffer self, 0x10/max-word-size
22 var stream-storage: (stream byte 0x10/max-word-size)
23 var stream/ecx: (addr stream byte) <- address stream-storage
24 write stream, s
25 {
26 var done?/eax: boolean <- stream-empty? stream
27 compare done?, 0/false
28 break-if-!=
29 var g/eax: grapheme <- read-grapheme stream
30 add-grapheme-at-gap self, g
31 loop
32 }
33 }
34
35 fn emit-gap-buffer _self: (addr gap-buffer), out: (addr stream byte) {
36 var self/esi: (addr gap-buffer) <- copy _self
37 clear-stream out
38 var left/eax: (addr grapheme-stack) <- get self, left
39 emit-stack-from-bottom left, out
40 var right/eax: (addr grapheme-stack) <- get self, right
41 emit-stack-from-top right, out
42 }
43
44
45 fn emit-stack-from-bottom _self: (addr grapheme-stack), out: (addr stream byte) {
46 var self/esi: (addr grapheme-stack) <- copy _self
47 var data-ah/edi: (addr handle array grapheme) <- get self, data
48 var _data/eax: (addr array grapheme) <- lookup *data-ah
49 var data/edi: (addr array grapheme) <- copy _data
50 var top-addr/ecx: (addr int) <- get self, top
51 var i/eax: int <- copy 0
52 {
53 compare i, *top-addr
54 break-if->=
55 var g/edx: (addr grapheme) <- index data, i
56 write-grapheme out, *g
57 i <- increment
58 loop
59 }
60 }
61
62
63 fn emit-stack-from-top _self: (addr grapheme-stack), out: (addr stream byte) {
64 var self/esi: (addr grapheme-stack) <- copy _self
65 var data-ah/edi: (addr handle array grapheme) <- get self, data
66 var _data/eax: (addr array grapheme) <- lookup *data-ah
67 var data/edi: (addr array grapheme) <- copy _data
68 var top-addr/ecx: (addr int) <- get self, top
69 var i/eax: int <- copy *top-addr
70 i <- decrement
71 {
72 compare i, 0
73 break-if-<
74 var g/edx: (addr grapheme) <- index data, i
75 write-grapheme out, *g
76 i <- decrement
77 loop
78 }
79 }
80
81
82
83 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 -> _/eax: int, _/ecx: int {
84 var gap/esi: (addr gap-buffer) <- copy _gap
85 var left/edx: (addr grapheme-stack) <- get gap, left
86 var x2/eax: int <- copy 0
87 var y2/ecx: int <- copy 0
88 x2, y2 <- render-stack-from-bottom-wrapping-right-then-down screen, left, xmin, ymin, xmax, ymax, xmin, ymin
89 var right/edx: (addr grapheme-stack) <- get gap, right
90 x2, y2 <- render-stack-from-top-wrapping-right-then-down screen, right, xmin, ymin, xmax, ymax, x2, y2, render-cursor?
91
92 var bg/ebx: int <- copy 0
93 compare render-cursor?, 0/false
94 {
95 break-if-=
96
97 var empty?/eax: boolean <- grapheme-stack-empty? right
98 compare empty?, 0/false
99 break-if-=
100 bg <- copy 7/cursor
101 }
102
103 var space/edx: grapheme <- copy 0x20
104 x2, y2 <- render-grapheme screen, space, xmin, ymin, xmax, ymax, x2, y2, 3/fg=cyan, bg
105 return x2, y2
106 }
107
108 fn render-gap-buffer screen: (addr screen), gap: (addr gap-buffer), x: int, y: int, render-cursor?: boolean -> _/eax: int {
109 var _width/eax: int <- copy 0
110 var _height/ecx: int <- copy 0
111 _width, _height <- screen-size screen
112 var width/edx: int <- copy _width
113 var height/ebx: int <- copy _height
114 var x2/eax: int <- copy 0
115 var y2/ecx: int <- copy 0
116 x2, y2 <- render-gap-buffer-wrapping-right-then-down screen, gap, x, y, width, height, render-cursor?
117 return x2
118 }
119
120 fn gap-buffer-length _gap: (addr gap-buffer) -> _/eax: int {
121 var gap/esi: (addr gap-buffer) <- copy _gap
122 var left/eax: (addr grapheme-stack) <- get gap, left
123 var tmp/eax: (addr int) <- get left, top
124 var left-length/ecx: int <- copy *tmp
125 var right/esi: (addr grapheme-stack) <- get gap, right
126 tmp <- get right, top
127 var result/eax: int <- copy *tmp
128 result <- add left-length
129 return result
130 }
131
132 fn add-grapheme-at-gap _self: (addr gap-buffer), g: grapheme {
133 var self/esi: (addr gap-buffer) <- copy _self
134 var left/eax: (addr grapheme-stack) <- get self, left
135 push-grapheme-stack left, g
136 }
137
138 fn gap-to-start self: (addr gap-buffer) {
139 {
140 var curr/eax: grapheme <- gap-left self
141 compare curr, -1
142 loop-if-!=
143 }
144 }
145
146 fn gap-to-end self: (addr gap-buffer) {
147 {
148 var curr/eax: grapheme <- gap-right self
149 compare curr, -1
150 loop-if-!=
151 }
152 }
153
154 fn gap-at-start? _self: (addr gap-buffer) -> _/eax: boolean {
155 var self/esi: (addr gap-buffer) <- copy _self
156 var left/eax: (addr grapheme-stack) <- get self, left
157 var result/eax: boolean <- grapheme-stack-empty? left
158 return result
159 }
160
161 fn gap-at-end? _self: (addr gap-buffer) -> _/eax: boolean {
162 var self/esi: (addr gap-buffer) <- copy _self
163 var right/eax: (addr grapheme-stack) <- get self, right
164 var result/eax: boolean <- grapheme-stack-empty? right
165 return result
166 }
167
168 fn gap-right _self: (addr gap-buffer) -> _/eax: grapheme {
169 var self/esi: (addr gap-buffer) <- copy _self
170 var g/eax: grapheme <- copy 0
171 var right/ecx: (addr grapheme-stack) <- get self, right
172 g <- pop-grapheme-stack right
173 compare g, -1
174 {
175 break-if-=
176 var left/ecx: (addr grapheme-stack) <- get self, left
177 push-grapheme-stack left, g
178 }
179 return g
180 }
181
182 fn gap-left _self: (addr gap-buffer) -> _/eax: grapheme {
183 var self/esi: (addr gap-buffer) <- copy _self
184 var g/eax: grapheme <- copy 0
185 {
186 var left/ecx: (addr grapheme-stack) <- get self, left
187 g <- pop-grapheme-stack left
188 }
189 compare g, -1
190 {
191 break-if-=
192 var right/ecx: (addr grapheme-stack) <- get self, right
193 push-grapheme-stack right, g
194 }
195 return g
196 }
197
198 fn index-of-gap _self: (addr gap-buffer) -> _/eax: int {
199 var self/eax: (addr gap-buffer) <- copy _self
200 var left/eax: (addr grapheme-stack) <- get self, left
201 var top-addr/eax: (addr int) <- get left, top
202 var result/eax: int <- copy *top-addr
203 return result
204 }
205
206 fn first-grapheme-in-gap-buffer _self: (addr gap-buffer) -> _/eax: grapheme {
207 var self/esi: (addr gap-buffer) <- copy _self
208
209 var left/eax: (addr grapheme-stack) <- get self, left
210 var top-addr/ecx: (addr int) <- get left, top
211 compare *top-addr, 0
212 {
213 break-if-<=
214 var data-ah/eax: (addr handle array grapheme) <- get left, data
215 var data/eax: (addr array grapheme) <- lookup *data-ah
216 var result-addr/eax: (addr grapheme) <- index data, 0
217 return *result-addr
218 }
219
220 var right/eax: (addr grapheme-stack) <- get self, right
221 top-addr <- get right, top
222 compare *top-addr, 0
223 {
224 break-if-<=
225 var data-ah/eax: (addr handle array grapheme) <- get right, data
226 var data/eax: (addr array grapheme) <- lookup *data-ah
227 var top/ecx: int <- copy *top-addr
228 top <- decrement
229 var result-addr/eax: (addr grapheme) <- index data, top
230 return *result-addr
231 }
232
233 return -1
234 }
235
236 fn grapheme-before-cursor-in-gap-buffer _self: (addr gap-buffer) -> _/eax: grapheme {
237 var self/esi: (addr gap-buffer) <- copy _self
238
239 var left/ecx: (addr grapheme-stack) <- get self, left
240 var top-addr/edx: (addr int) <- get left, top
241 compare *top-addr, 0
242 {
243 break-if-<=
244 var result/eax: grapheme <- pop-grapheme-stack left
245 push-grapheme-stack left, result
246 return result
247 }
248
249 return -1
250 }
251
252 fn delete-before-gap _self: (addr gap-buffer) {
253 var self/eax: (addr gap-buffer) <- copy _self
254 var left/eax: (addr grapheme-stack) <- get self, left
255 var dummy/eax: grapheme <- pop-grapheme-stack left
256 }
257
258 fn pop-after-gap _self: (addr gap-buffer) -> _/eax: grapheme {
259 var self/eax: (addr gap-buffer) <- copy _self
260 var right/eax: (addr grapheme-stack) <- get self, right
261 var result/eax: grapheme <- pop-grapheme-stack right
262 return result
263 }
264
265 fn gap-buffer-equal? _self: (addr gap-buffer), s: (addr array byte) -> _/eax: boolean {
266 var self/esi: (addr gap-buffer) <- copy _self
267
268
269
270 var stream-storage: (stream byte 0x10/max-word-size)
271 var expected-stream/ecx: (addr stream byte) <- address stream-storage
272 write expected-stream, s
273
274 var left/edx: (addr grapheme-stack) <- get self, left
275 var result/eax: boolean <- prefix-match? left, expected-stream
276 compare result, 0/false
277 {
278 break-if-!=
279 return result
280 }
281
282 var right/edx: (addr grapheme-stack) <- get self, right
283 result <- suffix-match? right, expected-stream
284 compare result, 0/false
285 {
286 break-if-!=
287 return result
288 }
289
290 result <- stream-empty? expected-stream
291 return result
292 }
293
294 fn test-gap-buffer-equal-from-end {
295 var _g: gap-buffer
296 var g/esi: (addr gap-buffer) <- address _g
297 initialize-gap-buffer g, 0x10
298
299 var c/eax: grapheme <- copy 0x61/a
300 add-grapheme-at-gap g, c
301 add-grapheme-at-gap g, c
302 add-grapheme-at-gap g, c
303
304 var result/eax: boolean <- gap-buffer-equal? g, "aaa"
305 check result, "F - test-gap-buffer-equal-from-end"
306 }
307
308 fn test-gap-buffer-equal-from-middle {
309 var _g: gap-buffer
310 var g/esi: (addr gap-buffer) <- address _g
311 initialize-gap-buffer g, 0x10
312
313 var c/eax: grapheme <- copy 0x61/a
314 add-grapheme-at-gap g, c
315 add-grapheme-at-gap g, c
316 add-grapheme-at-gap g, c
317 var dummy/eax: grapheme <- gap-left g
318
319 var result/eax: boolean <- gap-buffer-equal? g, "aaa"
320 check result, "F - test-gap-buffer-equal-from-middle"
321 }
322
323 fn test-gap-buffer-equal-from-start {
324 var _g: gap-buffer
325 var g/esi: (addr gap-buffer) <- address _g
326 initialize-gap-buffer g, 0x10
327
328 var c/eax: grapheme <- copy 0x61/a
329 add-grapheme-at-gap g, c
330 add-grapheme-at-gap g, c
331 add-grapheme-at-gap g, c
332 var dummy/eax: grapheme <- gap-left g
333 dummy <- gap-left g
334 dummy <- gap-left g
335
336 var result/eax: boolean <- gap-buffer-equal? g, "aaa"
337 check result, "F - test-gap-buffer-equal-from-start"
338 }
339
340 fn test-gap-buffer-equal-fails {
341
342 var _g: gap-buffer
343 var g/esi: (addr gap-buffer) <- address _g
344 initialize-gap-buffer g, 0x10
345 var c/eax: grapheme <- copy 0x61/a
346 add-grapheme-at-gap g, c
347 add-grapheme-at-gap g, c
348 add-grapheme-at-gap g, c
349
350 var result/eax: boolean <- gap-buffer-equal? g, "aa"
351 check-not result, "F - test-gap-buffer-equal-fails"
352 }
353
354 fn gap-buffers-equal? self: (addr gap-buffer), g: (addr gap-buffer) -> _/eax: boolean {
355 var tmp/eax: int <- gap-buffer-length self
356 var len/ecx: int <- copy tmp
357 var leng/eax: int <- gap-buffer-length g
358 compare len, leng
359 {
360 break-if-=
361 return 0/false
362 }
363 var i/edx: int <- copy 0
364 {
365 compare i, len
366 break-if->=
367 {
368 var tmp/eax: grapheme <- gap-index self, i
369 var curr/ecx: grapheme <- copy tmp
370 var currg/eax: grapheme <- gap-index g, i
371 compare curr, currg
372 break-if-=
373 return 0/false
374 }
375 i <- increment
376 loop
377 }
378 return 1/true
379 }
380
381 fn gap-index _self: (addr gap-buffer), _n: int -> _/eax: grapheme {
382 var self/esi: (addr gap-buffer) <- copy _self
383 var n/ebx: int <- copy _n
384
385 var left/edi: (addr grapheme-stack) <- get self, left
386 var left-len-a/edx: (addr int) <- get left, top
387 compare n, *left-len-a
388 {
389 break-if->=
390 var data-ah/eax: (addr handle array grapheme) <- get left, data
391 var data/eax: (addr array grapheme) <- lookup *data-ah
392 var result/eax: (addr grapheme) <- index data, n
393 return *result
394 }
395
396 n <- subtract *left-len-a
397
398 var right/edi: (addr grapheme-stack) <- get self, right
399 var right-len-a/edx: (addr int) <- get right, top
400 compare n, *right-len-a
401 {
402 break-if->=
403 var data-ah/eax: (addr handle array grapheme) <- get right, data
404 var data/eax: (addr array grapheme) <- lookup *data-ah
405
406 var idx/ebx: int <- copy n
407 idx <- subtract *right-len-a
408 idx <- negate
409 idx <- subtract 1
410 var result/eax: (addr grapheme) <- index data, idx
411 return *result
412 }
413
414 abort "gap-index: out of bounds"
415 return 0
416 }
417
418 fn test-gap-buffers-equal? {
419 var _a: gap-buffer
420 var a/esi: (addr gap-buffer) <- address _a
421 initialize-gap-buffer-with a, "abc"
422 var _b: gap-buffer
423 var b/edi: (addr gap-buffer) <- address _b
424 initialize-gap-buffer-with b, "abc"
425 var _c: gap-buffer
426 var c/ebx: (addr gap-buffer) <- address _c
427 initialize-gap-buffer-with c, "ab"
428 var _d: gap-buffer
429 var d/edx: (addr gap-buffer) <- address _d
430 initialize-gap-buffer-with d, "abd"
431
432 var result/eax: boolean <- gap-buffers-equal? a, a
433 check result, "F - test-gap-buffers-equal? - reflexive"
434 result <- gap-buffers-equal? a, b
435 check result, "F - test-gap-buffers-equal? - equal"
436
437 result <- gap-buffers-equal? a, c
438 check-not result, "F - test-gap-buffers-equal? - not equal"
439
440 result <- gap-buffers-equal? a, d
441 check-not result, "F - test-gap-buffers-equal? - not equal 2"
442 result <- gap-buffers-equal? d, a
443 check-not result, "F - test-gap-buffers-equal? - not equal 3"
444 }
445
446 fn test-gap-buffer-index {
447 var gap-storage: gap-buffer
448 var gap/esi: (addr gap-buffer) <- address gap-storage
449 initialize-gap-buffer-with gap, "abc"
450
451 var g/eax: grapheme <- gap-index gap, 0
452 var x/ecx: int <- copy g
453 check-ints-equal x, 0x61/a, "F - test-gap-index/left-1"
454 var g/eax: grapheme <- gap-index gap, 1
455 var x/ecx: int <- copy g
456 check-ints-equal x, 0x62/b, "F - test-gap-index/left-2"
457 var g/eax: grapheme <- gap-index gap, 2
458 var x/ecx: int <- copy g
459 check-ints-equal x, 0x63/c, "F - test-gap-index/left-3"
460
461 gap-to-start gap
462 rewind-gap-buffer gap
463 var g/eax: grapheme <- gap-index gap, 0
464 var x/ecx: int <- copy g
465 check-ints-equal x, 0x61/a, "F - test-gap-index/right-1"
466 var g/eax: grapheme <- gap-index gap, 1
467 var x/ecx: int <- copy g
468 check-ints-equal x, 0x62/b, "F - test-gap-index/right-2"
469 var g/eax: grapheme <- gap-index gap, 2
470 var x/ecx: int <- copy g
471 check-ints-equal x, 0x63/c, "F - test-gap-index/right-3"
472 }
473
474 fn copy-gap-buffer _src-ah: (addr handle gap-buffer), _dest-ah: (addr handle gap-buffer) {
475
476 var src-ah/eax: (addr handle gap-buffer) <- copy _src-ah
477 var _src-a/eax: (addr gap-buffer) <- lookup *src-ah
478 var src-a/esi: (addr gap-buffer) <- copy _src-a
479 var dest-ah/eax: (addr handle gap-buffer) <- copy _dest-ah
480 var _dest-a/eax: (addr gap-buffer) <- lookup *dest-ah
481 var dest-a/edi: (addr gap-buffer) <- copy _dest-a
482
483 var src/ecx: (addr grapheme-stack) <- get src-a, left
484 var dest/edx: (addr grapheme-stack) <- get dest-a, left
485 copy-grapheme-stack src, dest
486
487 src <- get src-a, right
488 dest <- get dest-a, right
489 copy-grapheme-stack src, dest
490 }
491
492 fn gap-buffer-is-decimal-integer? _self: (addr gap-buffer) -> _/eax: boolean {
493 var self/esi: (addr gap-buffer) <- copy _self
494 var curr/ecx: (addr grapheme-stack) <- get self, left
495 var result/eax: boolean <- grapheme-stack-is-decimal-integer? curr
496 {
497 compare result, 0/false
498 break-if-=
499 curr <- get self, right
500 result <- grapheme-stack-is-decimal-integer? curr
501 }
502 return result
503 }
504
505 fn test-render-gap-buffer-without-cursor {
506
507 var gap-storage: gap-buffer
508 var gap/esi: (addr gap-buffer) <- address gap-storage
509 initialize-gap-buffer-with gap, "abc"
510
511 var screen-on-stack: screen
512 var screen/edi: (addr screen) <- address screen-on-stack
513 initialize-screen screen, 5, 4
514
515 var x/eax: int <- render-gap-buffer screen, gap, 0/x, 0/y, 0/no-cursor
516 check-screen-row screen, 0/y, "abc ", "F - test-render-gap-buffer-without-cursor"
517 check-ints-equal x, 4, "F - test-render-gap-buffer-without-cursor: result"
518
519 check-background-color-in-screen-row screen, 7/bg=cursor, 0/y, " ", "F - test-render-gap-buffer-without-cursor: bg"
520 }
521
522 fn test-render-gap-buffer-with-cursor-at-end {
523
524 var gap-storage: gap-buffer
525 var gap/esi: (addr gap-buffer) <- address gap-storage
526 initialize-gap-buffer-with gap, "abc"
527 gap-to-end gap
528
529 var screen-on-stack: screen
530 var screen/edi: (addr screen) <- address screen-on-stack
531 initialize-screen screen, 5, 4
532
533 var x/eax: int <- render-gap-buffer screen, gap, 0/x, 0/y, 1/show-cursor
534 check-screen-row screen, 0/y, "abc ", "F - test-render-gap-buffer-with-cursor-at-end"
535
536 check-ints-equal x, 4, "F - test-render-gap-buffer-with-cursor-at-end: result"
537
538 check-background-color-in-screen-row screen, 7/bg=cursor, 0/y, " |", "F - test-render-gap-buffer-with-cursor-at-end: bg"
539 }
540
541 fn test-render-gap-buffer-with-cursor-in-middle {
542
543 var gap-storage: gap-buffer
544 var gap/esi: (addr gap-buffer) <- address gap-storage
545 initialize-gap-buffer-with gap, "abc"
546 gap-to-end gap
547 var dummy/eax: grapheme <- gap-left gap
548
549 var screen-on-stack: screen
550 var screen/edi: (addr screen) <- address screen-on-stack
551 initialize-screen screen, 5, 4
552
553 var x/eax: int <- render-gap-buffer screen, gap, 0/x, 0/y, 1/show-cursor
554 check-screen-row screen, 0/y, "abc ", "F - test-render-gap-buffer-with-cursor-in-middle"
555 check-ints-equal x, 4, "F - test-render-gap-buffer-with-cursor-in-middle: result"
556
557 check-background-color-in-screen-row screen, 7/bg=cursor, 0/y, " | ", "F - test-render-gap-buffer-with-cursor-in-middle: bg"
558 }
559
560 fn test-render-gap-buffer-with-cursor-at-start {
561 var gap-storage: gap-buffer
562 var gap/esi: (addr gap-buffer) <- address gap-storage
563 initialize-gap-buffer-with gap, "abc"
564 gap-to-start gap
565
566 var screen-on-stack: screen
567 var screen/edi: (addr screen) <- address screen-on-stack
568 initialize-screen screen, 5, 4
569
570 var x/eax: int <- render-gap-buffer screen, gap, 0/x, 0/y, 1/show-cursor
571 check-screen-row screen, 0/y, "abc ", "F - test-render-gap-buffer-with-cursor-at-start"
572 check-ints-equal x, 4, "F - test-render-gap-buffer-with-cursor-at-start: result"
573
574 check-background-color-in-screen-row screen, 7/bg=cursor, 0/y, "| ", "F - test-render-gap-buffer-with-cursor-at-start: bg"
575 }
576
577
578
579
580
581
582 fn rewind-gap-buffer _self: (addr gap-buffer) {
583 var self/esi: (addr gap-buffer) <- copy _self
584 var dest/eax: (addr int) <- get self, left-read-index
585 copy-to *dest, 0
586 dest <- get self, right-read-index
587 copy-to *dest, 0
588 }
589
590 fn gap-buffer-scan-done? _self: (addr gap-buffer) -> _/eax: boolean {
591 var self/esi: (addr gap-buffer) <- copy _self
592
593 var left/eax: (addr grapheme-stack) <- get self, left
594 var left-size/eax: int <- grapheme-stack-length left
595 var left-read-index/ecx: (addr int) <- get self, left-read-index
596 compare *left-read-index, left-size
597 {
598 break-if->=
599 return 0/false
600 }
601
602 var right/eax: (addr grapheme-stack) <- get self, right
603 var right-size/eax: int <- grapheme-stack-length right
604 var right-read-index/ecx: (addr int) <- get self, right-read-index
605 compare *right-read-index, right-size
606 {
607 break-if->=
608 return 0/false
609 }
610
611 return 1/true
612 }
613
614 fn peek-from-gap-buffer _self: (addr gap-buffer) -> _/eax: grapheme {
615 var self/esi: (addr gap-buffer) <- copy _self
616
617 var left/ecx: (addr grapheme-stack) <- get self, left
618 var left-size/eax: int <- grapheme-stack-length left
619 var left-read-index-a/edx: (addr int) <- get self, left-read-index
620 compare *left-read-index-a, left-size
621 {
622 break-if->=
623 var left-data-ah/eax: (addr handle array grapheme) <- get left, data
624 var left-data/eax: (addr array grapheme) <- lookup *left-data-ah
625 var left-read-index/ecx: int <- copy *left-read-index-a
626 var result/eax: (addr grapheme) <- index left-data, left-read-index
627 return *result
628 }
629
630 var right/ecx: (addr grapheme-stack) <- get self, right
631 var _right-size/eax: int <- grapheme-stack-length right
632 var right-size/ebx: int <- copy _right-size
633 var right-read-index-a/edx: (addr int) <- get self, right-read-index
634 compare *right-read-index-a, right-size
635 {
636 break-if->=
637
638 var right-data-ah/eax: (addr handle array grapheme) <- get right, data
639 var right-data/eax: (addr array grapheme) <- lookup *right-data-ah
640 var right-read-index/ebx: int <- copy right-size
641 right-read-index <- subtract *right-read-index-a
642 right-read-index <- subtract 1
643 var result/eax: (addr grapheme) <- index right-data, right-read-index
644 return *result
645 }
646
647 return 0/nul
648 }
649
650 fn read-from-gap-buffer _self: (addr gap-buffer) -> _/eax: grapheme {
651 var self/esi: (addr gap-buffer) <- copy _self
652
653 var left/ecx: (addr grapheme-stack) <- get self, left
654 var left-size/eax: int <- grapheme-stack-length left
655 var left-read-index-a/edx: (addr int) <- get self, left-read-index
656 compare *left-read-index-a, left-size
657 {
658 break-if->=
659 var left-data-ah/eax: (addr handle array grapheme) <- get left, data
660 var left-data/eax: (addr array grapheme) <- lookup *left-data-ah
661 var left-read-index/ecx: int <- copy *left-read-index-a
662 var result/eax: (addr grapheme) <- index left-data, left-read-index
663 increment *left-read-index-a
664 return *result
665 }
666
667 var right/ecx: (addr grapheme-stack) <- get self, right
668 var _right-size/eax: int <- grapheme-stack-length right
669 var right-size/ebx: int <- copy _right-size
670 var right-read-index-a/edx: (addr int) <- get self, right-read-index
671 compare *right-read-index-a, right-size
672 {
673 break-if->=
674
675 var right-data-ah/eax: (addr handle array grapheme) <- get right, data
676 var right-data/eax: (addr array grapheme) <- lookup *right-data-ah
677 var right-read-index/ebx: int <- copy right-size
678 right-read-index <- subtract *right-read-index-a
679 right-read-index <- subtract 1
680 var result/eax: (addr grapheme) <- index right-data, right-read-index
681 increment *right-read-index-a
682 return *result
683 }
684
685 return 0/nul
686 }
687
688 fn test-read-from-gap-buffer {
689 var gap-storage: gap-buffer
690 var gap/esi: (addr gap-buffer) <- address gap-storage
691 initialize-gap-buffer-with gap, "abc"
692
693 var done?/eax: boolean <- gap-buffer-scan-done? gap
694 check-not done?, "F - test-read-from-gap-buffer/left-1/done"
695 var g/eax: grapheme <- read-from-gap-buffer gap
696 var x/ecx: int <- copy g
697 check-ints-equal x, 0x61/a, "F - test-read-from-gap-buffer/left-1"
698 var done?/eax: boolean <- gap-buffer-scan-done? gap
699 check-not done?, "F - test-read-from-gap-buffer/left-2/done"
700 var g/eax: grapheme <- read-from-gap-buffer gap
701 var x/ecx: int <- copy g
702 check-ints-equal x, 0x62/b, "F - test-read-from-gap-buffer/left-2"
703 var done?/eax: boolean <- gap-buffer-scan-done? gap
704 check-not done?, "F - test-read-from-gap-buffer/left-3/done"
705 var g/eax: grapheme <- read-from-gap-buffer gap
706 var x/ecx: int <- copy g
707 check-ints-equal x, 0x63/c, "F - test-read-from-gap-buffer/left-3"
708 var done?/eax: boolean <- gap-buffer-scan-done? gap
709 check done?, "F - test-read-from-gap-buffer/left-4/done"
710 var g/eax: grapheme <- read-from-gap-buffer gap
711 var x/ecx: int <- copy g
712 check-ints-equal x, 0/nul, "F - test-read-from-gap-buffer/left-4"
713
714 gap-to-start gap
715 rewind-gap-buffer gap
716 var done?/eax: boolean <- gap-buffer-scan-done? gap
717 check-not done?, "F - test-read-from-gap-buffer/right-1/done"
718 var g/eax: grapheme <- read-from-gap-buffer gap
719 var x/ecx: int <- copy g
720 check-ints-equal x, 0x61/a, "F - test-read-from-gap-buffer/right-1"
721 var done?/eax: boolean <- gap-buffer-scan-done? gap
722 check-not done?, "F - test-read-from-gap-buffer/right-2/done"
723 var g/eax: grapheme <- read-from-gap-buffer gap
724 var x/ecx: int <- copy g
725 check-ints-equal x, 0x62/b, "F - test-read-from-gap-buffer/right-2"
726 var done?/eax: boolean <- gap-buffer-scan-done? gap
727 check-not done?, "F - test-read-from-gap-buffer/right-3/done"
728 var g/eax: grapheme <- read-from-gap-buffer gap
729 var x/ecx: int <- copy g
730 check-ints-equal x, 0x63/c, "F - test-read-from-gap-buffer/right-3"
731 var done?/eax: boolean <- gap-buffer-scan-done? gap
732 check done?, "F - test-read-from-gap-buffer/right-4/done"
733 var g/eax: grapheme <- read-from-gap-buffer gap
734 var x/ecx: int <- copy g
735 check-ints-equal x, 0/nul, "F - test-read-from-gap-buffer/right-4"
736 }
737
738 fn skip-whitespace-from-gap-buffer self: (addr gap-buffer) {
739 var done?/eax: boolean <- gap-buffer-scan-done? self
740 compare done?, 0/false
741 break-if-!=
742 var g/eax: grapheme <- peek-from-gap-buffer self
743 {
744 compare g, 0x20/space
745 break-if-=
746 compare g, 0xa/newline
747 break-if-=
748 return
749 }
750 g <- read-from-gap-buffer self
751 loop
752 }
753
754 fn edit-gap-buffer self: (addr gap-buffer), key: grapheme {
755 var g/edx: grapheme <- copy key
756 {
757 compare g, 8/backspace
758 break-if-!=
759 delete-before-gap self
760 return
761 }
762
763 {
764 compare g, 4/ctrl-d
765 break-if-!=
766
767 return
768 }
769 {
770 compare g, 0x15/ctrl-u
771 break-if-!=
772
773 return
774 }
775
776 add-grapheme-at-gap self, g
777 }
778
779 fn cursor-on-final-line? self: (addr gap-buffer) -> _/eax: boolean {
780 return 1/true
781 }