https://github.com/akkartik/mu/blob/main/514gap-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) -> _/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
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
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 fg/edi: int <- copy color
399 var bg/ebx: int <- copy background-color
400 compare render-cursor?, 0/false
401 {
402 break-if-=
403
404 var empty?/eax: boolean <- grapheme-stack-empty? right
405 compare empty?, 0/false
406 break-if-=
407
408 fg <- copy background-color
409 bg <- copy color
410 }
411
412 var space/edx: code-point <- copy 0x20
413 x2, y2 <- render-code-point 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
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
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
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
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
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
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
582
583
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
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
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
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
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
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
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
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
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
706 n <- subtract *left-len-a
707
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
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
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
747 result <- gap-buffers-equal? a, c
748 check-not result, "F - test-gap-buffers-equal? - not equal"
749
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
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
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
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
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
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
817 var gap-storage: gap-buffer
818 var gap/esi: (addr gap-buffer) <- address gap-storage
819 initialize-gap-buffer-with gap, "abc"
820
821 var screen-storage: screen
822 var screen/edi: (addr screen) <- address screen-storage
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
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
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
839 var screen-storage: screen
840 var screen/edi: (addr screen) <- address screen-storage
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
846 check-ints-equal x, 4, "F - test-render-gap-buffer-with-cursor-at-end: result"
847
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
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
859 var screen-storage: screen
860 var screen/edi: (addr screen) <- address screen-storage
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
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
876 var screen-storage: screen
877 var screen/edi: (addr screen) <- address screen-storage
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
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
893 var screen-storage: screen
894 var screen/edi: (addr screen) <- address screen-storage
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
911 var screen-storage: screen
912 var screen/edi: (addr screen) <- address screen-storage
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
928 var screen-storage: screen
929 var screen/edi: (addr screen) <- address screen-storage
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
940
941
942
943 fn highlight-matching-open-paren? _gap: (addr gap-buffer), render-cursor?: boolean -> _/ebx: boolean, _/edi: int {
944
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
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
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
1011
1012
1013
1014
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
1270 add-code-point-at-gap self, 0x20/space
1271 add-code-point-at-gap self, 0x20/space
1272 return
1273 }
1274
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
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
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
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
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
1334 var dummy/eax: grapheme <- gap-left self
1335
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
1355 var dummy/eax: grapheme <- gap-right self
1356
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
1376 var col/edx: int <- count-columns-to-start-of-line self
1377
1378 gap-to-previous-start-of-line self
1379
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
1403 var col/edx: int <- count-columns-to-start-of-line self
1404
1405 gap-to-end-of-line self
1406 var dummy/eax: grapheme <- gap-right self
1407
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
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
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 }