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), 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
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
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) -> _/ecx: 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
53 fn initialize-gap-buffer-with self: (addr gap-buffer), s: (addr array byte) {
54 initialize-gap-buffer self, 0x40/capacity
55 var stream-storage: (stream byte 0x40/capacity)
56 var stream/ecx: (addr stream byte) <- address stream-storage
57 write stream, s
58 {
59 var done?/eax: boolean <- stream-empty? stream
60 compare done?, 0/false
61 break-if-!=
62 var g/eax: grapheme <- read-grapheme 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
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
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
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
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
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
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
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
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
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
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
385
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
398 var bg/ebx: int <- copy background-color
399 compare render-cursor?, 0/false
400 {
401 break-if-=
402
403 var empty?/eax: boolean <- grapheme-stack-empty? right
404 compare empty?, 0/false
405 break-if-=
406 bg <- copy 7/cursor
407 }
408
409 var space/edx: grapheme <- copy 0x20
410 x2, y2 <- render-grapheme screen, space, xmin, ymin, xmax, ymax, x2, y2, color, bg
411 return x2, y2
412 }
413
414 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 {
415 var _width/eax: int <- copy 0
416 var _height/ecx: int <- copy 0
417 _width, _height <- screen-size screen
418 var width/edx: int <- copy _width
419 var height/ebx: int <- copy _height
420 var x2/eax: int <- copy 0
421 var y2/ecx: int <- copy 0
422 x2, y2 <- render-gap-buffer-wrapping-right-then-down screen, gap, x, y, width, height, render-cursor?, color, background-color
423 return x2
424 }
425
426 fn gap-buffer-length _gap: (addr gap-buffer) -> _/eax: int {
427 var gap/esi: (addr gap-buffer) <- copy _gap
428 var left/eax: (addr grapheme-stack) <- get gap, left
429 var tmp/eax: (addr int) <- get left, top
430 var left-length/ecx: int <- copy *tmp
431 var right/esi: (addr grapheme-stack) <- get gap, right
432 tmp <- get right, top
433 var result/eax: int <- copy *tmp
434 result <- add left-length
435 return result
436 }
437
438 fn add-grapheme-at-gap _self: (addr gap-buffer), g: grapheme {
439 var self/esi: (addr gap-buffer) <- copy _self
440 var left/eax: (addr grapheme-stack) <- get self, left
441 push-grapheme-stack left, g
442 }
443
444 fn add-code-point-at-gap self: (addr gap-buffer), c: code-point {
445 var g/eax: grapheme <- copy c
446 add-grapheme-at-gap self, g
447 }
448
449 fn gap-to-start self: (addr gap-buffer) {
450 {
451 var curr/eax: grapheme <- gap-left self
452 compare curr, -1
453 loop-if-!=
454 }
455 }
456
457 fn gap-to-end self: (addr gap-buffer) {
458 {
459 var curr/eax: grapheme <- gap-right self
460 compare curr, -1
461 loop-if-!=
462 }
463 }
464
465 fn gap-at-start? _self: (addr gap-buffer) -> _/eax: boolean {
466 var self/esi: (addr gap-buffer) <- copy _self
467 var left/eax: (addr grapheme-stack) <- get self, left
468 var result/eax: boolean <- grapheme-stack-empty? left
469 return result
470 }
471
472 fn gap-at-end? _self: (addr gap-buffer) -> _/eax: boolean {
473 var self/esi: (addr gap-buffer) <- copy _self
474 var right/eax: (addr grapheme-stack) <- get self, right
475 var result/eax: boolean <- grapheme-stack-empty? right
476 return result
477 }
478
479 fn gap-right _self: (addr gap-buffer) -> _/eax: grapheme {
480 var self/esi: (addr gap-buffer) <- copy _self
481 var g/eax: grapheme <- copy 0
482 var right/ecx: (addr grapheme-stack) <- get self, right
483 g <- pop-grapheme-stack right
484 compare g, -1
485 {
486 break-if-=
487 var left/ecx: (addr grapheme-stack) <- get self, left
488 push-grapheme-stack left, g
489 }
490 return g
491 }
492
493 fn gap-left _self: (addr gap-buffer) -> _/eax: grapheme {
494 var self/esi: (addr gap-buffer) <- copy _self
495 var g/eax: grapheme <- copy 0
496 {
497 var left/ecx: (addr grapheme-stack) <- get self, left
498 g <- pop-grapheme-stack left
499 }
500 compare g, -1
501 {
502 break-if-=
503 var right/ecx: (addr grapheme-stack) <- get self, right
504 push-grapheme-stack right, g
505 }
506 return g
507 }
508
509 fn index-of-gap _self: (addr gap-buffer) -> _/eax: int {
510 var self/eax: (addr gap-buffer) <- copy _self
511 var left/eax: (addr grapheme-stack) <- get self, left
512 var top-addr/eax: (addr int) <- get left, top
513 var result/eax: int <- copy *top-addr
514 return result
515 }
516
517 fn first-grapheme-in-gap-buffer _self: (addr gap-buffer) -> _/eax: grapheme {
518 var self/esi: (addr gap-buffer) <- copy _self
519
520 var left/eax: (addr grapheme-stack) <- get self, left
521 var top-addr/ecx: (addr int) <- get left, top
522 compare *top-addr, 0
523 {
524 break-if-<=
525 var data-ah/eax: (addr handle array grapheme) <- get left, data
526 var data/eax: (addr array grapheme) <- lookup *data-ah
527 var result-addr/eax: (addr grapheme) <- index data, 0
528 return *result-addr
529 }
530
531 var right/eax: (addr grapheme-stack) <- get self, right
532 top-addr <- get right, top
533 compare *top-addr, 0
534 {
535 break-if-<=
536 var data-ah/eax: (addr handle array grapheme) <- get right, data
537 var data/eax: (addr array grapheme) <- lookup *data-ah
538 var top/ecx: int <- copy *top-addr
539 top <- decrement
540 var result-addr/eax: (addr grapheme) <- index data, top
541 return *result-addr
542 }
543
544 return -1
545 }
546
547 fn grapheme-before-cursor-in-gap-buffer _self: (addr gap-buffer) -> _/eax: grapheme {
548 var self/esi: (addr gap-buffer) <- copy _self
549
550 var left/ecx: (addr grapheme-stack) <- get self, left
551 var top-addr/edx: (addr int) <- get left, top
552 compare *top-addr, 0
553 {
554 break-if-<=
555 var result/eax: grapheme <- pop-grapheme-stack left
556 push-grapheme-stack left, result
557 return result
558 }
559
560 return -1
561 }
562
563 fn delete-before-gap _self: (addr gap-buffer) {
564 var self/eax: (addr gap-buffer) <- copy _self
565 var left/eax: (addr grapheme-stack) <- get self, left
566 var dummy/eax: grapheme <- pop-grapheme-stack left
567 }
568
569 fn pop-after-gap _self: (addr gap-buffer) -> _/eax: grapheme {
570 var self/eax: (addr gap-buffer) <- copy _self
571 var right/eax: (addr grapheme-stack) <- get self, right
572 var result/eax: grapheme <- pop-grapheme-stack right
573 return result
574 }
575
576 fn gap-buffer-equal? _self: (addr gap-buffer), s: (addr array byte) -> _/eax: boolean {
577 var self/esi: (addr gap-buffer) <- copy _self
578
579
580
581 var stream-storage: (stream byte 0x10/capacity)
582 var expected-stream/ecx: (addr stream byte) <- address stream-storage
583 write expected-stream, s
584
585 var left/edx: (addr grapheme-stack) <- get self, left
586 var result/eax: boolean <- prefix-match? left, expected-stream
587 compare result, 0/false
588 {
589 break-if-!=
590 return result
591 }
592
593 var right/edx: (addr grapheme-stack) <- get self, right
594 result <- suffix-match? right, expected-stream
595 compare result, 0/false
596 {
597 break-if-!=
598 return result
599 }
600
601 result <- stream-empty? expected-stream
602 return result
603 }
604
605 fn test-gap-buffer-equal-from-end {
606 var _g: gap-buffer
607 var g/esi: (addr gap-buffer) <- address _g
608 initialize-gap-buffer g, 0x10
609
610 add-code-point-at-gap g, 0x61/a
611 add-code-point-at-gap g, 0x61/a
612 add-code-point-at-gap g, 0x61/a
613
614 var result/eax: boolean <- gap-buffer-equal? g, "aaa"
615 check result, "F - test-gap-buffer-equal-from-end"
616 }
617
618 fn test-gap-buffer-equal-from-middle {
619 var _g: gap-buffer
620 var g/esi: (addr gap-buffer) <- address _g
621 initialize-gap-buffer g, 0x10
622
623 add-code-point-at-gap g, 0x61/a
624 add-code-point-at-gap g, 0x61/a
625 add-code-point-at-gap g, 0x61/a
626 var dummy/eax: grapheme <- gap-left g
627
628 var result/eax: boolean <- gap-buffer-equal? g, "aaa"
629 check result, "F - test-gap-buffer-equal-from-middle"
630 }
631
632 fn test-gap-buffer-equal-from-start {
633 var _g: gap-buffer
634 var g/esi: (addr gap-buffer) <- address _g
635 initialize-gap-buffer g, 0x10
636
637 add-code-point-at-gap g, 0x61/a
638 add-code-point-at-gap g, 0x61/a
639 add-code-point-at-gap g, 0x61/a
640 var dummy/eax: grapheme <- gap-left g
641 dummy <- gap-left g
642 dummy <- gap-left g
643
644 var result/eax: boolean <- gap-buffer-equal? g, "aaa"
645 check result, "F - test-gap-buffer-equal-from-start"
646 }
647
648 fn test-gap-buffer-equal-fails {
649
650 var _g: gap-buffer
651 var g/esi: (addr gap-buffer) <- address _g
652 initialize-gap-buffer g, 0x10
653 add-code-point-at-gap g, 0x61/a
654 add-code-point-at-gap g, 0x61/a
655 add-code-point-at-gap g, 0x61/a
656
657 var result/eax: boolean <- gap-buffer-equal? g, "aa"
658 check-not result, "F - test-gap-buffer-equal-fails"
659 }
660
661 fn gap-buffers-equal? self: (addr gap-buffer), g: (addr gap-buffer) -> _/eax: boolean {
662 var tmp/eax: int <- gap-buffer-length self
663 var len/ecx: int <- copy tmp
664 var leng/eax: int <- gap-buffer-length g
665 compare len, leng
666 {
667 break-if-=
668 return 0/false
669 }
670 var i/edx: int <- copy 0
671 {
672 compare i, len
673 break-if->=
674 {
675 var tmp/eax: grapheme <- gap-index self, i
676 var curr/ecx: grapheme <- copy tmp
677 var currg/eax: grapheme <- gap-index g, i
678 compare curr, currg
679 break-if-=
680 return 0/false
681 }
682 i <- increment
683 loop
684 }
685 return 1/true
686 }
687
688 fn gap-index _self: (addr gap-buffer), _n: int -> _/eax: grapheme {
689 var self/esi: (addr gap-buffer) <- copy _self
690 var n/ebx: int <- copy _n
691
692 var left/edi: (addr grapheme-stack) <- get self, left
693 var left-len-a/edx: (addr int) <- get left, top
694 compare n, *left-len-a
695 {
696 break-if->=
697 var data-ah/eax: (addr handle array grapheme) <- get left, data
698 var data/eax: (addr array grapheme) <- lookup *data-ah
699 var result/eax: (addr grapheme) <- index data, n
700 return *result
701 }
702
703 n <- subtract *left-len-a
704
705 var right/edi: (addr grapheme-stack) <- get self, right
706 var right-len-a/edx: (addr int) <- get right, top
707 compare n, *right-len-a
708 {
709 break-if->=
710 var data-ah/eax: (addr handle array grapheme) <- get right, data
711 var data/eax: (addr array grapheme) <- lookup *data-ah
712
713 var idx/ebx: int <- copy n
714 idx <- subtract *right-len-a
715 idx <- negate
716 idx <- subtract 1
717 var result/eax: (addr grapheme) <- index data, idx
718 return *result
719 }
720
721 abort "gap-index: out of bounds"
722 return 0
723 }
724
725 fn test-gap-buffers-equal? {
726 var _a: gap-buffer
727 var a/esi: (addr gap-buffer) <- address _a
728 initialize-gap-buffer-with a, "abc"
729 var _b: gap-buffer
730 var b/edi: (addr gap-buffer) <- address _b
731 initialize-gap-buffer-with b, "abc"
732 var _c: gap-buffer
733 var c/ebx: (addr gap-buffer) <- address _c
734 initialize-gap-buffer-with c, "ab"
735 var _d: gap-buffer
736 var d/edx: (addr gap-buffer) <- address _d
737 initialize-gap-buffer-with d, "abd"
738
739 var result/eax: boolean <- gap-buffers-equal? a, a
740 check result, "F - test-gap-buffers-equal? - reflexive"
741 result <- gap-buffers-equal? a, b
742 check result, "F - test-gap-buffers-equal? - equal"
743
744 result <- gap-buffers-equal? a, c
745 check-not result, "F - test-gap-buffers-equal? - not equal"
746
747 result <- gap-buffers-equal? a, d
748 check-not result, "F - test-gap-buffers-equal? - not equal 2"
749 result <- gap-buffers-equal? d, a
750 check-not result, "F - test-gap-buffers-equal? - not equal 3"
751 }
752
753 fn test-gap-buffer-index {
754 var gap-storage: gap-buffer
755 var gap/esi: (addr gap-buffer) <- address gap-storage
756 initialize-gap-buffer-with gap, "abc"
757
758 var g/eax: grapheme <- gap-index gap, 0
759 var x/ecx: int <- copy g
760 check-ints-equal x, 0x61/a, "F - test-gap-index/left-1"
761 var g/eax: grapheme <- gap-index gap, 1
762 var x/ecx: int <- copy g
763 check-ints-equal x, 0x62/b, "F - test-gap-index/left-2"
764 var g/eax: grapheme <- gap-index gap, 2
765 var x/ecx: int <- copy g
766 check-ints-equal x, 0x63/c, "F - test-gap-index/left-3"
767
768 gap-to-start gap
769 rewind-gap-buffer gap
770 var g/eax: grapheme <- gap-index gap, 0
771 var x/ecx: int <- copy g
772 check-ints-equal x, 0x61/a, "F - test-gap-index/right-1"
773 var g/eax: grapheme <- gap-index gap, 1
774 var x/ecx: int <- copy g
775 check-ints-equal x, 0x62/b, "F - test-gap-index/right-2"
776 var g/eax: grapheme <- gap-index gap, 2
777 var x/ecx: int <- copy g
778 check-ints-equal x, 0x63/c, "F - test-gap-index/right-3"
779 }
780
781 fn copy-gap-buffer _src-ah: (addr handle gap-buffer), _dest-ah: (addr handle gap-buffer) {
782
783 var src-ah/eax: (addr handle gap-buffer) <- copy _src-ah
784 var _src-a/eax: (addr gap-buffer) <- lookup *src-ah
785 var src-a/esi: (addr gap-buffer) <- copy _src-a
786 var dest-ah/eax: (addr handle gap-buffer) <- copy _dest-ah
787 var _dest-a/eax: (addr gap-buffer) <- lookup *dest-ah
788 var dest-a/edi: (addr gap-buffer) <- copy _dest-a
789
790 var src/ecx: (addr grapheme-stack) <- get src-a, left
791 var dest/edx: (addr grapheme-stack) <- get dest-a, left
792 copy-grapheme-stack src, dest
793
794 src <- get src-a, right
795 dest <- get dest-a, right
796 copy-grapheme-stack src, dest
797 }
798
799 fn gap-buffer-is-decimal-integer? _self: (addr gap-buffer) -> _/eax: boolean {
800 var self/esi: (addr gap-buffer) <- copy _self
801 var curr/ecx: (addr grapheme-stack) <- get self, left
802 var result/eax: boolean <- grapheme-stack-is-decimal-integer? curr
803 {
804 compare result, 0/false
805 break-if-=
806 curr <- get self, right
807 result <- grapheme-stack-is-decimal-integer? curr
808 }
809 return result
810 }
811
812 fn test-render-gap-buffer-without-cursor {
813
814 var gap-storage: gap-buffer
815 var gap/esi: (addr gap-buffer) <- address gap-storage
816 initialize-gap-buffer-with gap, "abc"
817
818 var screen-on-stack: screen
819 var screen/edi: (addr screen) <- address screen-on-stack
820 initialize-screen screen, 5, 4, 0/no-pixel-graphics
821
822 var x/eax: int <- render-gap-buffer screen, gap, 0/x, 0/y, 0/no-cursor, 3/fg, 0xc5/bg=blue-bg
823 check-screen-row screen, 0/y, "abc ", "F - test-render-gap-buffer-without-cursor"
824 check-ints-equal x, 4, "F - test-render-gap-buffer-without-cursor: result"
825
826 check-background-color-in-screen-row screen, 7/bg=cursor, 0/y, " ", "F - test-render-gap-buffer-without-cursor: bg"
827 }
828
829 fn test-render-gap-buffer-with-cursor-at-end {
830
831 var gap-storage: gap-buffer
832 var gap/esi: (addr gap-buffer) <- address gap-storage
833 initialize-gap-buffer-with gap, "abc"
834 gap-to-end gap
835
836 var screen-on-stack: screen
837 var screen/edi: (addr screen) <- address screen-on-stack
838 initialize-screen screen, 5, 4, 0/no-pixel-graphics
839
840 var x/eax: int <- render-gap-buffer screen, gap, 0/x, 0/y, 1/show-cursor, 3/fg, 0xc5/bg=blue-bg
841 check-screen-row screen, 0/y, "abc ", "F - test-render-gap-buffer-with-cursor-at-end"
842
843 check-ints-equal x, 4, "F - test-render-gap-buffer-with-cursor-at-end: result"
844
845 check-background-color-in-screen-row screen, 7/bg=cursor, 0/y, " |", "F - test-render-gap-buffer-with-cursor-at-end: bg"
846 }
847
848 fn test-render-gap-buffer-with-cursor-in-middle {
849
850 var gap-storage: gap-buffer
851 var gap/esi: (addr gap-buffer) <- address gap-storage
852 initialize-gap-buffer-with gap, "abc"
853 gap-to-end gap
854 var dummy/eax: grapheme <- gap-left gap
855
856 var screen-on-stack: screen
857 var screen/edi: (addr screen) <- address screen-on-stack
858 initialize-screen screen, 5, 4, 0/no-pixel-graphics
859
860 var x/eax: int <- render-gap-buffer screen, gap, 0/x, 0/y, 1/show-cursor, 3/fg, 0xc5/bg=blue-bg
861 check-screen-row screen, 0/y, "abc ", "F - test-render-gap-buffer-with-cursor-in-middle"
862 check-ints-equal x, 4, "F - test-render-gap-buffer-with-cursor-in-middle: result"
863
864 check-background-color-in-screen-row screen, 7/bg=cursor, 0/y, " | ", "F - test-render-gap-buffer-with-cursor-in-middle: bg"
865 }
866
867 fn test-render-gap-buffer-with-cursor-at-start {
868 var gap-storage: gap-buffer
869 var gap/esi: (addr gap-buffer) <- address gap-storage
870 initialize-gap-buffer-with gap, "abc"
871 gap-to-start gap
872
873 var screen-on-stack: screen
874 var screen/edi: (addr screen) <- address screen-on-stack
875 initialize-screen screen, 5, 4, 0/no-pixel-graphics
876
877 var x/eax: int <- render-gap-buffer screen, gap, 0/x, 0/y, 1/show-cursor, 3/fg, 0xc5/bg=blue-bg
878 check-screen-row screen, 0/y, "abc ", "F - test-render-gap-buffer-with-cursor-at-start"
879 check-ints-equal x, 4, "F - test-render-gap-buffer-with-cursor-at-start: result"
880
881 check-background-color-in-screen-row screen, 7/bg=cursor, 0/y, "| ", "F - test-render-gap-buffer-with-cursor-at-start: bg"
882 }
883
884 fn test-render-gap-buffer-highlight-matching-close-paren {
885 var gap-storage: gap-buffer
886 var gap/esi: (addr gap-buffer) <- address gap-storage
887 initialize-gap-buffer-with gap, "(a)"
888 gap-to-start gap
889
890 var screen-on-stack: screen
891 var screen/edi: (addr screen) <- address screen-on-stack
892 initialize-screen screen, 5, 4, 0/no-pixel-graphics
893
894 var x/eax: int <- render-gap-buffer screen, gap, 0/x, 0/y, 1/show-cursor, 3/fg, 0xc5/bg=blue-bg
895 check-screen-row screen, 0/y, "(a) ", "F - test-render-gap-buffer-highlight-matching-close-paren"
896 check-ints-equal x, 4, "F - test-render-gap-buffer-highlight-matching-close-paren: result"
897 check-background-color-in-screen-row screen, 7/bg=cursor, 0/y, "| ", "F - test-render-gap-buffer-highlight-matching-close-paren: cursor"
898 check-screen-row-in-color screen, 0xf/fg=highlight, 0/y, " ) ", "F - test-render-gap-buffer-highlight-matching-close-paren: matching paren"
899 }
900
901 fn test-render-gap-buffer-highlight-matching-open-paren {
902 var gap-storage: gap-buffer
903 var gap/esi: (addr gap-buffer) <- address gap-storage
904 initialize-gap-buffer-with gap, "(a)"
905 gap-to-end gap
906 var dummy/eax: grapheme <- gap-left gap
907
908 var screen-on-stack: screen
909 var screen/edi: (addr screen) <- address screen-on-stack
910 initialize-screen screen, 5, 4, 0/no-pixel-graphics
911
912 var x/eax: int <- render-gap-buffer screen, gap, 0/x, 0/y, 1/show-cursor, 3/fg, 0xc5/bg=blue-bg
913 check-screen-row screen, 0/y, "(a) ", "F - test-render-gap-buffer-highlight-matching-open-paren"
914 check-ints-equal x, 4, "F - test-render-gap-buffer-highlight-matching-open-paren: result"
915 check-background-color-in-screen-row screen, 7/bg=cursor, 0/y, " | ", "F - test-render-gap-buffer-highlight-matching-open-paren: cursor"
916 check-screen-row-in-color screen, 0xf/fg=highlight, 0/y, "( ", "F - test-render-gap-buffer-highlight-matching-open-paren: matching paren"
917 }
918
919 fn test-render-gap-buffer-highlight-matching-open-paren-of-end {
920 var gap-storage: gap-buffer
921 var gap/esi: (addr gap-buffer) <- address gap-storage
922 initialize-gap-buffer-with gap, "(a)"
923 gap-to-end gap
924
925 var screen-on-stack: screen
926 var screen/edi: (addr screen) <- address screen-on-stack
927 initialize-screen screen, 5, 4, 0/no-pixel-graphics
928
929 var x/eax: int <- render-gap-buffer screen, gap, 0/x, 0/y, 1/show-cursor, 3/fg, 0xc5/bg=blue-bg
930 check-screen-row screen, 0/y, "(a) ", "F - test-render-gap-buffer-highlight-matching-open-paren-of-end"
931 check-ints-equal x, 4, "F - test-render-gap-buffer-highlight-matching-open-paren-of-end: result"
932 check-background-color-in-screen-row screen, 7/bg=cursor, 0/y, " |", "F - test-render-gap-buffer-highlight-matching-open-paren-of-end: cursor"
933 check-screen-row-in-color screen, 0xf/fg=highlight, 0/y, "( ", "F - test-render-gap-buffer-highlight-matching-open-paren-of-end: matching paren"
934 }
935
936
937
938
939
940 fn highlight-matching-open-paren? _gap: (addr gap-buffer), render-cursor?: boolean -> _/ebx: boolean, _/edi: int {
941
942 compare render-cursor?, 0/false
943 {
944 break-if-!=
945 return 0/false, 0
946 }
947 var gap/esi: (addr gap-buffer) <- copy _gap
948 var stack/edi: (addr grapheme-stack) <- get gap, right
949 var top-addr/eax: (addr int) <- get stack, top
950 var top-index/ecx: int <- copy *top-addr
951 compare top-index, 0
952 {
953 break-if->
954
955 stack <- get gap, left
956 top-addr <- get stack, top
957 top-index <- copy *top-addr
958 compare top-index, 0
959 {
960 break-if->
961 return 0/false, 0
962 }
963 top-index <- decrement
964 var data-ah/eax: (addr handle array grapheme) <- get stack, data
965 var data/eax: (addr array grapheme) <- lookup *data-ah
966 var g/eax: (addr grapheme) <- index data, top-index
967 compare *g, 0x29/close-paren
968 {
969 break-if-=
970 return 0/false, 0
971 }
972 return 1/true, 1
973 }
974
975 top-index <- decrement
976 var data-ah/eax: (addr handle array grapheme) <- get stack, data
977 var data/eax: (addr array grapheme) <- lookup *data-ah
978 var g/eax: (addr grapheme) <- index data, top-index
979 compare *g, 0x29/close-paren
980 {
981 break-if-=
982 return 0/false, 0
983 }
984 return 1/true, 0
985 }
986
987 fn test-highlight-matching-open-paren {
988 var gap-storage: gap-buffer
989 var gap/esi: (addr gap-buffer) <- address gap-storage
990 initialize-gap-buffer-with gap, "(a)"
991 gap-to-end gap
992 var highlight-matching-open-paren?/ebx: boolean <- copy 0/false
993 var open-paren-depth/edi: int <- copy 0
994 highlight-matching-open-paren?, open-paren-depth <- highlight-matching-open-paren? gap, 0/no-cursor
995 check-not highlight-matching-open-paren?, "F - test-highlight-matching-open-paren: no cursor"
996 highlight-matching-open-paren?, open-paren-depth <- highlight-matching-open-paren? gap, 1/render-cursor
997 check highlight-matching-open-paren?, "F - test-highlight-matching-open-paren: at end immediately after ')'"
998 check-ints-equal open-paren-depth, 1, "F - test-highlight-matching-open-paren: depth at end immediately after ')'"
999 var dummy/eax: grapheme <- gap-left gap
1000 highlight-matching-open-paren?, open-paren-depth <- highlight-matching-open-paren? gap, 1/render-cursor
1001 check highlight-matching-open-paren?, "F - test-highlight-matching-open-paren: on ')'"
1002 dummy <- gap-left gap
1003 highlight-matching-open-paren?, open-paren-depth <- highlight-matching-open-paren? gap, 1/render-cursor
1004 check-not highlight-matching-open-paren?, "F - test-highlight-matching-open-paren: not on ')'"
1005 }
1006
1007
1008
1009
1010
1011
1012 fn rewind-gap-buffer _self: (addr gap-buffer) {
1013 var self/esi: (addr gap-buffer) <- copy _self
1014 var dest/eax: (addr int) <- get self, left-read-index
1015 copy-to *dest, 0
1016 dest <- get self, right-read-index
1017 copy-to *dest, 0
1018 }
1019
1020 fn gap-buffer-scan-done? _self: (addr gap-buffer) -> _/eax: boolean {
1021 var self/esi: (addr gap-buffer) <- copy _self
1022
1023 var left/eax: (addr grapheme-stack) <- get self, left
1024 var left-size/eax: int <- grapheme-stack-length left
1025 var left-read-index/ecx: (addr int) <- get self, left-read-index
1026 compare *left-read-index, left-size
1027 {
1028 break-if->=
1029 return 0/false
1030 }
1031
1032 var right/eax: (addr grapheme-stack) <- get self, right
1033 var right-size/eax: int <- grapheme-stack-length right
1034 var right-read-index/ecx: (addr int) <- get self, right-read-index
1035 compare *right-read-index, right-size
1036 {
1037 break-if->=
1038 return 0/false
1039 }
1040
1041 return 1/true
1042 }
1043
1044 fn peek-from-gap-buffer _self: (addr gap-buffer) -> _/eax: grapheme {
1045 var self/esi: (addr gap-buffer) <- copy _self
1046
1047 var left/ecx: (addr grapheme-stack) <- get self, left
1048 var left-size/eax: int <- grapheme-stack-length left
1049 var left-read-index-a/edx: (addr int) <- get self, left-read-index
1050 compare *left-read-index-a, left-size
1051 {
1052 break-if->=
1053 var left-data-ah/eax: (addr handle array grapheme) <- get left, data
1054 var left-data/eax: (addr array grapheme) <- lookup *left-data-ah
1055 var left-read-index/ecx: int <- copy *left-read-index-a
1056 var result/eax: (addr grapheme) <- index left-data, left-read-index
1057 return *result
1058 }
1059
1060 var right/ecx: (addr grapheme-stack) <- get self, right
1061 var _right-size/eax: int <- grapheme-stack-length right
1062 var right-size/ebx: int <- copy _right-size
1063 var right-read-index-a/edx: (addr int) <- get self, right-read-index
1064 compare *right-read-index-a, right-size
1065 {
1066 break-if->=
1067
1068 var right-data-ah/eax: (addr handle array grapheme) <- get right, data
1069 var right-data/eax: (addr array grapheme) <- lookup *right-data-ah
1070 var right-read-index/ebx: int <- copy right-size
1071 right-read-index <- subtract *right-read-index-a
1072 right-read-index <- subtract 1
1073 var result/eax: (addr grapheme) <- index right-data, right-read-index
1074 return *result
1075 }
1076
1077 return 0/nul
1078 }
1079
1080 fn read-from-gap-buffer _self: (addr gap-buffer) -> _/eax: grapheme {
1081 var self/esi: (addr gap-buffer) <- copy _self
1082
1083 var left/ecx: (addr grapheme-stack) <- get self, left
1084 var left-size/eax: int <- grapheme-stack-length left
1085 var left-read-index-a/edx: (addr int) <- get self, left-read-index
1086 compare *left-read-index-a, left-size
1087 {
1088 break-if->=
1089 var left-data-ah/eax: (addr handle array grapheme) <- get left, data
1090 var left-data/eax: (addr array grapheme) <- lookup *left-data-ah
1091 var left-read-index/ecx: int <- copy *left-read-index-a
1092 var result/eax: (addr grapheme) <- index left-data, left-read-index
1093 increment *left-read-index-a
1094 return *result
1095 }
1096
1097 var right/ecx: (addr grapheme-stack) <- get self, right
1098 var _right-size/eax: int <- grapheme-stack-length right
1099 var right-size/ebx: int <- copy _right-size
1100 var right-read-index-a/edx: (addr int) <- get self, right-read-index
1101 compare *right-read-index-a, right-size
1102 {
1103 break-if->=
1104
1105 var right-data-ah/eax: (addr handle array grapheme) <- get right, data
1106 var right-data/eax: (addr array grapheme) <- lookup *right-data-ah
1107 var right-read-index/ebx: int <- copy right-size
1108 right-read-index <- subtract *right-read-index-a
1109 right-read-index <- subtract 1
1110 var result/eax: (addr grapheme) <- index right-data, right-read-index
1111 increment *right-read-index-a
1112 return *result
1113 }
1114
1115 return 0/nul
1116 }
1117
1118 fn test-read-from-gap-buffer {
1119 var gap-storage: gap-buffer
1120 var gap/esi: (addr gap-buffer) <- address gap-storage
1121 initialize-gap-buffer-with gap, "abc"
1122
1123 var done?/eax: boolean <- gap-buffer-scan-done? gap
1124 check-not done?, "F - test-read-from-gap-buffer/left-1/done"
1125 var g/eax: grapheme <- read-from-gap-buffer gap
1126 var x/ecx: int <- copy g
1127 check-ints-equal x, 0x61/a, "F - test-read-from-gap-buffer/left-1"
1128 var done?/eax: boolean <- gap-buffer-scan-done? gap
1129 check-not done?, "F - test-read-from-gap-buffer/left-2/done"
1130 var g/eax: grapheme <- read-from-gap-buffer gap
1131 var x/ecx: int <- copy g
1132 check-ints-equal x, 0x62/b, "F - test-read-from-gap-buffer/left-2"
1133 var done?/eax: boolean <- gap-buffer-scan-done? gap
1134 check-not done?, "F - test-read-from-gap-buffer/left-3/done"
1135 var g/eax: grapheme <- read-from-gap-buffer gap
1136 var x/ecx: int <- copy g
1137 check-ints-equal x, 0x63/c, "F - test-read-from-gap-buffer/left-3"
1138 var done?/eax: boolean <- gap-buffer-scan-done? gap
1139 check done?, "F - test-read-from-gap-buffer/left-4/done"
1140 var g/eax: grapheme <- read-from-gap-buffer gap
1141 var x/ecx: int <- copy g
1142 check-ints-equal x, 0/nul, "F - test-read-from-gap-buffer/left-4"
1143
1144 gap-to-start gap
1145 rewind-gap-buffer gap
1146 var done?/eax: boolean <- gap-buffer-scan-done? gap
1147 check-not done?, "F - test-read-from-gap-buffer/right-1/done"
1148 var g/eax: grapheme <- read-from-gap-buffer gap
1149 var x/ecx: int <- copy g
1150 check-ints-equal x, 0x61/a, "F - test-read-from-gap-buffer/right-1"
1151 var done?/eax: boolean <- gap-buffer-scan-done? gap
1152 check-not done?, "F - test-read-from-gap-buffer/right-2/done"
1153 var g/eax: grapheme <- read-from-gap-buffer gap
1154 var x/ecx: int <- copy g
1155 check-ints-equal x, 0x62/b, "F - test-read-from-gap-buffer/right-2"
1156 var done?/eax: boolean <- gap-buffer-scan-done? gap
1157 check-not done?, "F - test-read-from-gap-buffer/right-3/done"
1158 var g/eax: grapheme <- read-from-gap-buffer gap
1159 var x/ecx: int <- copy g
1160 check-ints-equal x, 0x63/c, "F - test-read-from-gap-buffer/right-3"
1161 var done?/eax: boolean <- gap-buffer-scan-done? gap
1162 check done?, "F - test-read-from-gap-buffer/right-4/done"
1163 var g/eax: grapheme <- read-from-gap-buffer gap
1164 var x/ecx: int <- copy g
1165 check-ints-equal x, 0/nul, "F - test-read-from-gap-buffer/right-4"
1166 }
1167
1168 fn skip-whitespace-from-gap-buffer self: (addr gap-buffer) {
1169 var done?/eax: boolean <- gap-buffer-scan-done? self
1170 compare done?, 0/false
1171 break-if-!=
1172 var g/eax: grapheme <- peek-from-gap-buffer self
1173 {
1174 compare g, 0x20/space
1175 break-if-=
1176 compare g, 0xa/newline
1177 break-if-=
1178 return
1179 }
1180 g <- read-from-gap-buffer self
1181 loop
1182 }
1183
1184 fn edit-gap-buffer self: (addr gap-buffer), key: grapheme {
1185 var g/edx: grapheme <- copy key
1186 {
1187 compare g, 8/backspace
1188 break-if-!=
1189 delete-before-gap self
1190 return
1191 }
1192 {
1193 compare g, 0x80/left-arrow
1194 break-if-!=
1195 var dummy/eax: grapheme <- gap-left self
1196 return
1197 }
1198 {
1199 compare g, 0x83/right-arrow
1200 break-if-!=
1201 var dummy/eax: grapheme <- gap-right self
1202 return
1203 }
1204 {
1205 compare g, 6/ctrl-f
1206 break-if-!=
1207 gap-to-start-of-next-word self
1208 return
1209 }
1210 {
1211 compare g, 2/ctrl-b
1212 break-if-!=
1213 gap-to-end-of-previous-word self
1214 return
1215 }
1216 {
1217 compare g, 1/ctrl-a
1218 break-if-!=
1219 gap-to-previous-start-of-line self
1220 return
1221 }
1222 {
1223 compare g, 5/ctrl-e
1224 break-if-!=
1225 gap-to-next-end-of-line self
1226 return
1227 }
1228 {
1229 compare g, 0x81/down-arrow
1230 break-if-!=
1231 gap-down self
1232 return
1233 }
1234 {
1235 compare g, 0x82/up-arrow
1236 break-if-!=
1237 gap-up self
1238 return
1239 }
1240 {
1241 compare g, 0x15/ctrl-u
1242 break-if-!=
1243 clear-gap-buffer self
1244 return
1245 }
1246 {
1247 compare g, 9/tab
1248 break-if-!=
1249
1250 add-code-point-at-gap self, 0x20/space
1251 add-code-point-at-gap self, 0x20/space
1252 return
1253 }
1254
1255 add-grapheme-at-gap self, g
1256 }
1257
1258 fn gap-to-start-of-next-word self: (addr gap-buffer) {
1259 var curr/eax: grapheme <- copy 0
1260
1261 {
1262 curr <- gap-right self
1263 compare curr, -1
1264 break-if-=
1265 compare curr, 0x20/space
1266 break-if-=
1267 compare curr, 0xa/newline
1268 break-if-=
1269 loop
1270 }
1271
1272 {
1273 curr <- gap-right self
1274 compare curr, -1
1275 break-if-=
1276 compare curr, 0x20/space
1277 loop-if-=
1278 compare curr, 0xa/space
1279 loop-if-=
1280 curr <- gap-left self
1281 break
1282 }
1283 }
1284
1285 fn gap-to-end-of-previous-word self: (addr gap-buffer) {
1286 var curr/eax: grapheme <- copy 0
1287
1288 {
1289 curr <- gap-left self
1290 compare curr, -1
1291 break-if-=
1292 compare curr, 0x20/space
1293 break-if-=
1294 compare curr, 0xa/newline
1295 break-if-=
1296 loop
1297 }
1298
1299 {
1300 curr <- gap-left self
1301 compare curr, -1
1302 break-if-=
1303 compare curr, 0x20/space
1304 loop-if-=
1305 compare curr, 0xa/space
1306 loop-if-=
1307 curr <- gap-right self
1308 break
1309 }
1310 }
1311
1312 fn gap-to-previous-start-of-line self: (addr gap-buffer) {
1313
1314 var dummy/eax: grapheme <- gap-left self
1315
1316 {
1317 dummy <- gap-left self
1318 {
1319 compare dummy, -1
1320 break-if-!=
1321 return
1322 }
1323 {
1324 compare dummy, 0xa/newline
1325 break-if-!=
1326 dummy <- gap-right self
1327 return
1328 }
1329 loop
1330 }
1331 }
1332
1333 fn gap-to-next-end-of-line self: (addr gap-buffer) {
1334
1335 var dummy/eax: grapheme <- gap-right self
1336
1337 {
1338 dummy <- gap-right self
1339 {
1340 compare dummy, -1
1341 break-if-!=
1342 return
1343 }
1344 {
1345 compare dummy, 0xa/newline
1346 break-if-!=
1347 dummy <- gap-left self
1348 return
1349 }
1350 loop
1351 }
1352 }
1353
1354 fn gap-up self: (addr gap-buffer) {
1355
1356 var col/edx: int <- count-columns-to-start-of-line self
1357
1358 gap-to-previous-start-of-line self
1359
1360 var i/ecx: int <- copy 0
1361 {
1362 compare i, col
1363 break-if->=
1364 var curr/eax: grapheme <- gap-right self
1365 {
1366 compare curr, -1
1367 break-if-!=
1368 return
1369 }
1370 compare curr, 0xa/newline
1371 {
1372 break-if-!=
1373 curr <- gap-left self
1374 return
1375 }
1376 i <- increment
1377 loop
1378 }
1379 }
1380
1381 fn gap-down self: (addr gap-buffer) {
1382
1383 var col/edx: int <- count-columns-to-start-of-line self
1384
1385 gap-to-end-of-line self
1386 var dummy/eax: grapheme <- gap-right self
1387
1388 var i/ecx: int <- copy 0
1389 {
1390 compare i, col
1391 break-if->=
1392 var curr/eax: grapheme <- gap-right self
1393 {
1394 compare curr, -1
1395 break-if-!=
1396 return
1397 }
1398 compare curr, 0xa/newline
1399 {
1400 break-if-!=
1401 curr <- gap-left self
1402 return
1403 }
1404 i <- increment
1405 loop
1406 }
1407 }
1408
1409 fn count-columns-to-start-of-line self: (addr gap-buffer) -> _/edx: int {
1410 var count/edx: int <- copy 0
1411 var dummy/eax: grapheme <- copy 0
1412
1413 {
1414 dummy <- gap-left self
1415 {
1416 compare dummy, -1
1417 break-if-!=
1418 return count
1419 }
1420 {
1421 compare dummy, 0xa/newline
1422 break-if-!=
1423 dummy <- gap-right self
1424 return count
1425 }
1426 count <- increment
1427 loop
1428 }
1429 return count
1430 }
1431
1432 fn gap-to-end-of-line self: (addr gap-buffer) {
1433 var dummy/eax: grapheme <- copy 0
1434
1435 {
1436 dummy <- gap-right self
1437 {
1438 compare dummy, -1
1439 break-if-!=
1440 return
1441 }
1442 {
1443 compare dummy, 0xa/newline
1444 break-if-!=
1445 dummy <- gap-left self
1446 return
1447 }
1448 loop
1449 }
1450 }