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