1
2
3
4
5 def! main text:text [
6 local-scope
7 load-inputs
8 open-console
9 clear-screen 0/screen
10 editor:&:editor <- new-editor text, 5/left, 45/right
11 editor-render 0/screen, editor
12 editor-event-loop 0/screen, 0/console, editor
13 close-console
14 ]
15
16 def editor-event-loop screen:&:screen, console:&:console, editor:&:editor -> screen:&:screen, console:&:console, editor:&:editor [
17 local-scope
18 load-inputs
19 {
20
21 +next-event
22 cursor-row:num <- get *editor, cursor-row:offset
23 cursor-column:num <- get *editor, cursor-column:offset
24 screen <- move-cursor screen, cursor-row, cursor-column
25 e:event, found?:bool, quit?:bool, console <- read-event console
26 loop-unless found?
27 break-if quit?
28 trace 10, [app], [next-event]
29
30 t:touch-event, is-touch?:bool <- maybe-convert e, touch:variant
31 {
32 break-unless is-touch?
33 move-cursor editor, screen, t
34 loop +next-event
35 }
36
37 {
38 break-if is-touch?
39 go-render?:bool <- handle-keyboard-event screen, editor, e
40 {
41 break-unless go-render?
42 screen <- editor-render screen, editor
43 }
44 }
45 loop
46 }
47 ]
48
49
50 def move-cursor editor:&:editor, screen:&:screen, t:touch-event -> in-focus?:bool, editor:&:editor [
51 local-scope
52 load-inputs
53 return-unless editor, 0/false
54 click-row:num <- get t, row:offset
55 return-unless click-row, 0/false
56 click-column:num <- get t, column:offset
57 left:num <- get *editor, left:offset
58 too-far-left?:bool <- lesser-than click-column, left
59 return-if too-far-left?, 0/false
60 right:num <- get *editor, right:offset
61 too-far-right?:bool <- greater-than click-column, right
62 return-if too-far-right?, 0/false
63
64 <begin-move-cursor>
65 editor <- snap-cursor editor, screen, click-row, click-column
66 undo-coalesce-tag:num <- copy 0/never
67 <end-move-cursor>
68
69 return 1/true
70 ]
71
72
73
74
75 def snap-cursor editor:&:editor, screen:&:screen, target-row:num, target-column:num -> editor:&:editor [
76 local-scope
77 load-inputs
78 return-unless editor
79 left:num <- get *editor, left:offset
80 right:num <- get *editor, right:offset
81 screen-height:num <- screen-height screen
82
83 curr:&:duplex-list:char <- get *editor, top-of-screen:offset
84 prev:&:duplex-list:char <- copy curr
85 curr <- next curr
86 row:num <- copy 1/top
87 column:num <- copy left
88 *editor <- put *editor, cursor-row:offset, target-row
89 cursor-row:num <- copy target-row
90 *editor <- put *editor, cursor-column:offset, target-column
91 cursor-column:num <- copy target-column
92 before-cursor:&:duplex-list:char <- get *editor, before-cursor:offset
93 {
94 +next-character
95 break-unless curr
96 off-screen?:bool <- greater-or-equal row, screen-height
97 break-if off-screen?
98
99
100
101 {
102 at-cursor-row?:bool <- equal row, cursor-row
103 break-unless at-cursor-row?
104 at-cursor?:bool <- equal column, cursor-column
105 break-unless at-cursor?
106 before-cursor <- copy prev
107 *editor <- put *editor, before-cursor:offset, before-cursor
108 }
109 c:char <- get *curr, value:offset
110 {
111
112 newline?:bool <- equal c, 10/newline
113 break-unless newline?
114
115 {
116 at-cursor-row?:bool <- equal row, cursor-row
117 break-unless at-cursor-row?
118 left-of-cursor?:bool <- lesser-than column, cursor-column
119 break-unless left-of-cursor?
120 cursor-column <- copy column
121 *editor <- put *editor, cursor-column:offset, cursor-column
122 before-cursor <- copy prev
123 *editor <- put *editor, before-cursor:offset, before-cursor
124 }
125
126 row <- add row, 1
127 column <- copy left
128 curr <- next curr
129 prev <- next prev
130 loop +next-character
131 }
132 {
133
134
135 at-right?:bool <- equal column, right
136 break-unless at-right?
137 column <- copy left
138 row <- add row, 1
139
140 loop +next-character
141 }
142 curr <- next curr
143 prev <- next prev
144 column <- add column, 1
145 loop
146 }
147
148 {
149 at-cursor-row?:bool <- equal row, cursor-row
150 cursor-outside-line?:bool <- lesser-or-equal column, cursor-column
151 before-cursor-on-same-line?:bool <- and at-cursor-row?, cursor-outside-line?
152 above-cursor-row?:bool <- lesser-than row, cursor-row
153 before-cursor?:bool <- or before-cursor-on-same-line?, above-cursor-row?
154 break-unless before-cursor?
155 cursor-row <- copy row
156 *editor <- put *editor, cursor-row:offset, cursor-row
157 cursor-column <- copy column
158 *editor <- put *editor, cursor-column:offset, cursor-column
159 before-cursor <- copy prev
160 *editor <- put *editor, before-cursor:offset, before-cursor
161 }
162 ]
163
164
165
166 def handle-keyboard-event screen:&:screen, editor:&:editor, e:event -> go-render?:bool, screen:&:screen, editor:&:editor [
167 local-scope
168 load-inputs
169 return-unless editor, 0/don't-render
170 screen-width:num <- screen-width screen
171 screen-height:num <- screen-height screen
172 left:num <- get *editor, left:offset
173 right:num <- get *editor, right:offset
174 before-cursor:&:duplex-list:char <- get *editor, before-cursor:offset
175 cursor-row:num <- get *editor, cursor-row:offset
176 cursor-column:num <- get *editor, cursor-column:offset
177 save-row:num <- copy cursor-row
178 save-column:num <- copy cursor-column
179
180 {
181 c:char, is-unicode?:bool <- maybe-convert e, text:variant
182 break-unless is-unicode?
183 trace 10, [app], [handle-keyboard-event: special character]
184
185 <handle-special-character>
186
187 regular-character?:bool <- greater-or-equal c, 32/space
188 return-unless regular-character?, 0/don't-render
189
190 <begin-insert-character>
191 go-render? <- insert-at-cursor editor, c, screen
192 <end-insert-character>
193 return
194 }
195
196 k:num, is-keycode?:bool <- maybe-convert e:event, keycode:variant
197 assert is-keycode?, [event was of unknown type; neither keyboard nor mouse]
198
199 <handle-special-key>
200 return 1/go-render
201 ]
202
203 def insert-at-cursor editor:&:editor, c:char, screen:&:screen -> go-render?:bool, editor:&:editor, screen:&:screen [
204 local-scope
205 load-inputs
206 before-cursor:&:duplex-list:char <- get *editor, before-cursor:offset
207 insert c, before-cursor
208 before-cursor <- next before-cursor
209 *editor <- put *editor, before-cursor:offset, before-cursor
210 cursor-row:num <- get *editor, cursor-row:offset
211 cursor-column:num <- get *editor, cursor-column:offset
212 left:num <- get *editor, left:offset
213 right:num <- get *editor, right:offset
214 save-row:num <- copy cursor-row
215 save-column:num <- copy cursor-column
216 screen-width:num <- screen-width screen
217 screen-height:num <- screen-height screen
218
219 <insert-character-special-case>
220
221 cursor-column <- add cursor-column, 1
222 *editor <- put *editor, cursor-column:offset, cursor-column
223 next:&:duplex-list:char <- next before-cursor
224 {
225
226 at-end?:bool <- equal next, 0/null
227 break-unless at-end?
228 bottom:num <- subtract screen-height, 1
229 at-bottom?:bool <- equal save-row, bottom
230 at-right?:bool <- equal save-column, right
231 overflow?:bool <- and at-bottom?, at-right?
232 break-if overflow?
233 move-cursor screen, save-row, save-column
234 print screen, c
235 return 0/don't-render
236 }
237 {
238
239 break-unless next
240 at-right?:bool <- greater-or-equal cursor-column, screen-width
241 break-if at-right?
242 curr:&:duplex-list:char <- copy before-cursor
243 move-cursor screen, save-row, save-column
244 curr-column:num <- copy save-column
245 {
246
247 at-right?:bool <- greater-than curr-column, right
248 return-if at-right?, 1/go-render
249 break-unless curr
250
251 currc:char <- get *curr, value:offset
252 at-newline?:bool <- equal currc, 10/newline
253 break-if at-newline?
254 print screen, currc
255 curr-column <- add curr-column, 1
256 curr <- next curr
257 loop
258 }
259 return 0/don't-render
260 }
261 return 1/go-render
262 ]
263
264
265 def editor-render screen:&:screen, editor:&:editor -> screen:&:screen, editor:&:editor [
266 local-scope
267 load-inputs
268 old-top-idx:num <- save-top-idx screen
269 left:num <- get *editor, left:offset
270 right:num <- get *editor, right:offset
271 row:num, column:num <- render screen, editor
272 clear-line-until screen, right
273 row <- add row, 1
274 draw-horizontal screen, row, left, right, 9480/horizontal-dotted
275 row <- add row, 1
276 clear-screen-from screen, row, left, left, right
277 assert-no-scroll screen, old-top-idx
278 ]
279
280 scenario editor-handles-empty-event-queue [
281 local-scope
282 assume-screen 10/width, 5/height
283 e:&:editor <- new-editor [abc], 0/left, 10/right
284 editor-render screen, e
285 assume-console []
286 run [
287 editor-event-loop screen, console, e
288 ]
289 screen-should-contain [
290 . .
291 .abc .
292 .╌╌╌╌╌╌╌╌╌╌.
293 . .
294 ]
295 ]
296
297 scenario editor-handles-mouse-clicks [
298 local-scope
299 assume-screen 10/width, 5/height
300 e:&:editor <- new-editor [abc], 0/left, 10/right
301 editor-render screen, e
302 $clear-trace
303 assume-console [
304 left-click 1, 1
305 ]
306 run [
307 editor-event-loop screen, console, e
308 3:num/raw <- get *e, cursor-row:offset
309 4:num/raw <- get *e, cursor-column:offset
310 ]
311 screen-should-contain [
312 . .
313 .abc .
314 .╌╌╌╌╌╌╌╌╌╌.
315 . .
316 ]
317 memory-should-contain [
318 3 <- 1
319 4 <- 1
320 ]
321 check-trace-count-for-label 0, [print-character]
322 ]
323
324 scenario editor-handles-mouse-clicks-outside-text [
325 local-scope
326 assume-screen 10/width, 5/height
327 e:&:editor <- new-editor [abc], 0/left, 10/right
328 $clear-trace
329 assume-console [
330 left-click 1, 7
331 ]
332 run [
333 editor-event-loop screen, console, e
334 3:num/raw <- get *e, cursor-row:offset
335 4:num/raw <- get *e, cursor-column:offset
336 ]
337 memory-should-contain [
338 3 <- 1
339 4 <- 3
340 ]
341 check-trace-count-for-label 0, [print-character]
342 ]
343
344 scenario editor-handles-mouse-clicks-outside-text-2 [
345 local-scope
346 assume-screen 10/width, 5/height
347 s:text <- new [abc
348 def]
349 e:&:editor <- new-editor s, 0/left, 10/right
350 $clear-trace
351 assume-console [
352 left-click 1, 7
353 ]
354 run [
355 editor-event-loop screen, console, e
356 3:num/raw <- get *e, cursor-row:offset
357 4:num/raw <- get *e, cursor-column:offset
358 ]
359 memory-should-contain [
360 3 <- 1
361 4 <- 3
362 ]
363 check-trace-count-for-label 0, [print-character]
364 ]
365
366 scenario editor-handles-mouse-clicks-outside-text-3 [
367 local-scope
368 assume-screen 10/width, 5/height
369 s:text <- new [abc
370 def]
371 e:&:editor <- new-editor s, 0/left, 10/right
372 $clear-trace
373 assume-console [
374 left-click 3, 7
375 ]
376 run [
377 editor-event-loop screen, console, e
378 3:num/raw <- get *e, cursor-row:offset
379 4:num/raw <- get *e, cursor-column:offset
380 ]
381 memory-should-contain [
382 3 <- 2
383 4 <- 3
384 ]
385 check-trace-count-for-label 0, [print-character]
386 ]
387
388 scenario editor-handles-mouse-clicks-outside-column [
389 local-scope
390 assume-screen 10/width, 5/height
391
392 e:&:editor <- new-editor [abc], 0/left, 5/right
393 editor-render screen, e
394 $clear-trace
395 assume-console [
396
397 left-click 3, 8
398 ]
399 run [
400 editor-event-loop screen, console, e
401 3:num/raw <- get *e, cursor-row:offset
402 4:num/raw <- get *e, cursor-column:offset
403 ]
404 screen-should-contain [
405 . .
406 .abc .
407 .╌╌╌╌╌ .
408 . .
409 ]
410 memory-should-contain [
411 3 <- 1
412 4 <- 0
413 ]
414 check-trace-count-for-label 0, [print-character]
415 ]
416
417 scenario editor-handles-mouse-clicks-in-menu-area [
418 local-scope
419 assume-screen 10/width, 5/height
420 e:&:editor <- new-editor [abc], 0/left, 5/right
421 editor-render screen, e
422 $clear-trace
423 assume-console [
424
425 left-click 0, 3
426 ]
427 run [
428 editor-event-loop screen, console, e
429 3:num/raw <- get *e, cursor-row:offset
430 4:num/raw <- get *e, cursor-column:offset
431 ]
432
433 memory-should-contain [
434 3 <- 1
435 4 <- 0
436 ]
437 ]
438
439 scenario editor-inserts-characters-into-empty-editor [
440 local-scope
441 assume-screen 10/width, 5/height
442 e:&:editor <- new-editor [], 0/left, 5/right
443 editor-render screen, e
444 $clear-trace
445 assume-console [
446 type [abc]
447 ]
448 run [
449 editor-event-loop screen, console, e
450 ]
451 screen-should-contain [
452 . .
453 .abc .
454 .╌╌╌╌╌ .
455 . .
456 ]
457 check-trace-count-for-label 3, [print-character]
458 ]
459
460 scenario editor-inserts-characters-at-cursor [
461 local-scope
462 assume-screen 10/width, 5/height
463 e:&:editor <- new-editor [abc], 0/left, 10/right
464 editor-render screen, e
465 $clear-trace
466
467 assume-console [
468 type [0]
469 left-click 1, 2
470 type [d]
471 ]
472 run [
473 editor-event-loop screen, console, e
474 ]
475 screen-should-contain [
476 . .
477 .0adbc .
478 .╌╌╌╌╌╌╌╌╌╌.
479 . .
480 ]
481 check-trace-count-for-label 7, [print-character]
482 ]
483
484 scenario editor-inserts-characters-at-cursor-2 [
485 local-scope
486 assume-screen 10/width, 5/height
487 e:&:editor <- new-editor [abc], 0/left, 10/right
488 editor-render screen, e
489 $clear-trace
490 assume-console [
491 left-click 1, 5
492 type [d]
493 ]
494 run [
495 editor-event-loop screen, console, e
496 ]
497 screen-should-contain [
498 . .
499 .abcd .
500 .╌╌╌╌╌╌╌╌╌╌.
501 . .
502 ]
503 check-trace-count-for-label 1, [print-character]
504 ]
505
506 scenario editor-inserts-characters-at-cursor-5 [
507 local-scope
508 assume-screen 10/width, 5/height
509 s:text <- new [abc
510 d]
511 e:&:editor <- new-editor s, 0/left, 10/right
512 editor-render screen, e
513 $clear-trace
514 assume-console [
515 left-click 1, 5
516 type [e]
517 ]
518 run [
519 editor-event-loop screen, console, e
520 ]
521 screen-should-contain [
522 . .
523 .abce .
524 .d .
525 .╌╌╌╌╌╌╌╌╌╌.
526 . .
527 ]
528 check-trace-count-for-label 1, [print-character]
529 ]
530
531 scenario editor-inserts-characters-at-cursor-3 [
532 local-scope
533 assume-screen 10/width, 5/height
534 e:&:editor <- new-editor [abc], 0/left, 10/right
535 editor-render screen, e
536 $clear-trace
537 assume-console [
538 left-click 3, 5
539 type [d]
540 ]
541 run [
542 editor-event-loop screen, console, e
543 ]
544 screen-should-contain [
545 . .
546 .abcd .
547 .╌╌╌╌╌╌╌╌╌╌.
548 . .
549 ]
550 check-trace-count-for-label 1, [print-character]
551 ]
552
553 scenario editor-inserts-characters-at-cursor-4 [
554 local-scope
555 assume-screen 10/width, 5/height
556 s:text <- new [abc
557 d]
558 e:&:editor <- new-editor s, 0/left, 10/right
559 editor-render screen, e
560 $clear-trace
561 assume-console [
562 left-click 3, 5
563 type [e]
564 ]
565 run [
566 editor-event-loop screen, console, e
567 ]
568 screen-should-contain [
569 . .
570 .abc .
571 .de .
572 .╌╌╌╌╌╌╌╌╌╌.
573 . .
574 ]
575 check-trace-count-for-label 1, [print-character]
576 ]
577
578 scenario editor-inserts-characters-at-cursor-6 [
579 local-scope
580 assume-screen 10/width, 5/height
581 s:text <- new [abc
582 d]
583 e:&:editor <- new-editor s, 0/left, 10/right
584 editor-render screen, e
585 $clear-trace
586 assume-console [
587 left-click 3, 5
588 type [ef]
589 ]
590 run [
591 editor-event-loop screen, console, e
592 ]
593 screen-should-contain [
594 . .
595 .abc .
596 .def .
597 .╌╌╌╌╌╌╌╌╌╌.
598 . .
599 ]
600 check-trace-count-for-label 2, [print-character]
601 ]
602
603 scenario editor-moves-cursor-after-inserting-characters [
604 local-scope
605 assume-screen 10/width, 5/height
606 e:&:editor <- new-editor [ab], 0/left, 5/right
607 editor-render screen, e
608 assume-console [
609 type [01]
610 ]
611 run [
612 editor-event-loop screen, console, e
613 ]
614 screen-should-contain [
615 . .
616 .01ab .
617 .╌╌╌╌╌ .
618 . .
619 ]
620 ]
621
622
623
624 scenario editor-wraps-line-on-insert [
625 local-scope
626 assume-screen 5/width, 5/height
627 e:&:editor <- new-editor [abc], 0/left, 5/right
628 editor-render screen, e
629
630 assume-console [
631 type [e]
632 ]
633 run [
634 editor-event-loop screen, console, e
635 ]
636
637 screen-should-contain [
638 . .
639 .eabc .
640 .╌╌╌╌╌.
641 . .
642 . .
643 ]
644
645 assume-console [
646 type [f]
647 ]
648 run [
649 editor-event-loop screen, console, e
650 ]
651
652 screen-should-contain [
653 . .
654 .efab↩.
655 .c .
656 .╌╌╌╌╌.
657 . .
658 ]
659 ]
660
661 scenario editor-wraps-line-on-insert-2 [
662 local-scope
663
664 assume-screen 10/width, 5/height
665 s:text <- new [abcdefg
666 defg]
667 e:&:editor <- new-editor s, 0/left, 5/right
668 editor-render screen, e
669
670 assume-console [
671 left-click 3, 0
672 type [abc]
673 ]
674 run [
675 editor-event-loop screen, console, e
676 3:num/raw <- get *e, cursor-row:offset
677 4:num/raw <- get *e, cursor-column:offset
678 ]
679
680 memory-should-contain [
681 3 <- 3
682 4 <- 3
683 ]
684
685 screen-should-contain [
686 . .
687 .abcd↩ .
688 .efg .
689 .abcd↩ .
690 .efg .
691 ]
692 ]
693
694 after <insert-character-special-case> [
695
696 {
697
698
699
700 wrap-column:num <- copy right
701 before-wrap-column:num <- subtract wrap-column, 1
702 at-wrap?:bool <- greater-or-equal cursor-column, wrap-column
703 just-before-wrap?:bool <- greater-or-equal cursor-column, before-wrap-column
704 next:&:duplex-list:char <- next before-cursor
705
706 at-end-of-line?:bool <- equal next, 0
707 {
708 break-if at-end-of-line?
709 next-character:char <- get *next, value:offset
710 at-end-of-line? <- equal next-character, 10/newline
711 }
712
713 move-cursor-to-next-line?:bool <- copy 0/false
714 {
715 break-if at-end-of-line?
716 move-cursor-to-next-line? <- copy just-before-wrap?
717
718
719 potential-new-cursor-column:num <- copy left
720 }
721 {
722 break-unless at-end-of-line?
723 move-cursor-to-next-line? <- copy at-wrap?
724
725
726
727 potential-new-cursor-column:num <- add left, 1/make-room-for-wrap-indicator
728 }
729 break-unless move-cursor-to-next-line?
730 cursor-column <- copy potential-new-cursor-column
731 *editor <- put *editor, cursor-column:offset, cursor-column
732 cursor-row <- add cursor-row, 1
733 *editor <- put *editor, cursor-row:offset, cursor-row
734
735 {
736 below-screen?:bool <- greater-or-equal cursor-row, screen-height
737 break-unless below-screen?
738 <scroll-down>
739 }
740 return 1/go-render
741 }
742 ]
743
744 scenario editor-wraps-cursor-after-inserting-characters-in-middle-of-line [
745 local-scope
746 assume-screen 10/width, 5/height
747 e:&:editor <- new-editor [abcde], 0/left, 5/right
748 assume-console [
749 left-click 1, 3
750 type [f]
751 ]
752 run [
753 editor-event-loop screen, console, e
754 3:num/raw <- get *e, cursor-row:offset
755 4:num/raw <- get *e, cursor-column:offset
756 ]
757 screen-should-contain [
758 . .
759 .abcf↩ .
760 .de .
761 .╌╌╌╌╌ .
762 . .
763 ]
764 memory-should-contain [
765 3 <- 2
766 4 <- 0
767 ]
768 ]
769
770 scenario editor-wraps-cursor-after-inserting-characters-at-end-of-line [
771 local-scope
772 assume-screen 10/width, 5/height
773
774 s:text <- new [abc
775 xyz]
776 e:&:editor <- new-editor s, 0/left, 5/right
777 editor-render screen, e
778 screen-should-contain [
779 . .
780 .abc .
781 .xyz .
782 .╌╌╌╌╌ .
783 . .
784 ]
785 assume-console [
786 left-click 1, 4
787 type [de]
788 ]
789 run [
790 editor-event-loop screen, console, e
791 ]
792 screen-should-contain [
793 . .
794 .abcd↩ .
795 .e .
796 .xyz .
797 .╌╌╌╌╌ .
798 ]
799 ]
800
801 scenario editor-wraps-cursor-to-left-margin [
802 local-scope
803 assume-screen 10/width, 5/height
804 e:&:editor <- new-editor [abcde], 2/left, 7/right
805 assume-console [
806 left-click 1, 5
807 type [01]
808 ]
809 run [
810 editor-event-loop screen, console, e
811 3:num/raw <- get *e, cursor-row:offset
812 4:num/raw <- get *e, cursor-column:offset
813 ]
814 screen-should-contain [
815 . .
816 . abc0↩ .
817 . 1de .
818 . ╌╌╌╌╌ .
819 . .
820 ]
821 memory-should-contain [
822 3 <- 2
823 4 <- 3
824 ]
825 ]
826
827
828
829 container editor [
830 indent?:bool
831 ]
832
833 after <editor-initialization> [
834 *result <- put *result, indent?:offset, 1/true
835 ]
836
837 scenario editor-moves-cursor-down-after-inserting-newline [
838 local-scope
839 assume-screen 10/width, 5/height
840 e:&:editor <- new-editor [abc], 0/left, 10/right
841 assume-console [
842 type [0
843 1]
844 ]
845 run [
846 editor-event-loop screen, console, e
847 ]
848 screen-should-contain [
849 . .
850 .0 .
851 .1abc .
852 .╌╌╌╌╌╌╌╌╌╌.
853 . .
854 ]
855 ]
856
857 after <handle-special-character> [
858 {
859 newline?:bool <- equal c, 10/newline
860 break-unless newline?
861 <begin-insert-enter>
862 insert-new-line-and-indent editor, screen
863 <end-insert-enter>
864 return 1/go-render
865 }
866 ]
867
868 def insert-new-line-and-indent editor:&:editor, screen:&:screen -> editor:&:editor, screen:&:screen [
869 local-scope
870 load-inputs
871 cursor-row:num <- get *editor, cursor-row:offset
872 cursor-column:num <- get *editor, cursor-column:offset
873 before-cursor:&:duplex-list:char <- get *editor, before-cursor:offset
874 left:num <- get *editor, left:offset
875 right:num <- get *editor, right:offset
876 screen-height:num <- screen-height screen
877
878 at-start-of-wrapped-line?:bool <- at-start-of-wrapped-line? editor
879 {
880 break-if at-start-of-wrapped-line?
881 cursor-row <- add cursor-row, 1
882 *editor <- put *editor, cursor-row:offset, cursor-row
883 }
884 cursor-column <- copy left
885 *editor <- put *editor, cursor-column:offset, cursor-column
886
887 {
888 below-screen?:bool <- greater-or-equal cursor-row, screen-height
889 break-unless below-screen?
890 <scroll-down>
891 cursor-row <- subtract cursor-row, 1
892 *editor <- put *editor, cursor-row:offset, cursor-row
893 }
894
895 insert 10/newline, before-cursor
896 before-cursor <- next before-cursor
897 *editor <- put *editor, before-cursor:offset, before-cursor
898
899 indent?:bool <- get *editor, indent?:offset
900 return-unless indent?
901 d:&:duplex-list:char <- get *editor, data:offset
902 end-of-previous-line:&:duplex-list:char <- prev before-cursor
903 indent:num <- line-indent end-of-previous-line, d
904 i:num <- copy 0
905 {
906 indent-done?:bool <- greater-or-equal i, indent
907 break-if indent-done?
908 insert-at-cursor editor, 32/space, screen
909 i <- add i, 1
910 loop
911 }
912 ]
913
914 def at-start-of-wrapped-line? editor:&:editor -> result:bool [
915 local-scope
916 load-inputs
917 left:num <- get *editor, left:offset
918 cursor-column:num <- get *editor, cursor-column:offset
919 cursor-at-left?:bool <- equal cursor-column, left
920 return-unless cursor-at-left?, 0/false
921 before-cursor:&:duplex-list:char <- get *editor, before-cursor:offset
922 before-before-cursor:&:duplex-list:char <- prev before-cursor
923 return-unless before-before-cursor, 0/false
924 char-before-cursor:char <- get *before-cursor, value:offset
925 cursor-after-newline?:bool <- equal char-before-cursor, 10/newline
926 return-if cursor-after-newline?, 0/false
927
928
929 return 1/true
930 ]
931
932
933
934 def line-indent curr:&:duplex-list:char, start:&:duplex-list:char -> result:num [
935 local-scope
936 load-inputs
937 result:num <- copy 0
938 return-unless curr
939 at-start?:bool <- equal curr, start
940 return-if at-start?
941 {
942 curr <- prev curr
943 break-unless curr
944 at-start?:bool <- equal curr, start
945 break-if at-start?
946 c:char <- get *curr, value:offset
947 at-newline?:bool <- equal c, 10/newline
948 break-if at-newline?
949
950 is-space?:bool <- equal c, 32/space
951 {
952 break-unless is-space?
953 result <- add result, 1
954 }
955
956 {
957 break-if is-space?
958 result <- copy 0
959 }
960 loop
961 }
962 ]
963
964 scenario editor-moves-cursor-down-after-inserting-newline-2 [
965 local-scope
966 assume-screen 10/width, 5/height
967 e:&:editor <- new-editor [abc], 1/left, 10/right
968 assume-console [
969 type [0
970 1]
971 ]
972 run [
973 editor-event-loop screen, console, e
974 ]
975 screen-should-contain [
976 . .
977 . 0 .
978 . 1abc .
979 . ╌╌╌╌╌╌╌╌╌.
980 . .
981 ]
982 ]
983
984 scenario editor-clears-previous-line-completely-after-inserting-newline [
985 local-scope
986 assume-screen 10/width, 5/height
987 e:&:editor <- new-editor [abcde], 0/left, 5/right
988 editor-render screen, e
989 screen-should-contain [
990 . .
991 .abcd↩ .
992 .e .
993 .╌╌╌╌╌ .
994 . .
995 ]
996 assume-console [
997 press enter
998 ]
999 run [
1000 editor-event-loop screen, console, e
1001 ]
1002
1003 screen-should-contain [
1004 . .
1005 . .
1006 .abcd↩ .
1007 .e .
1008 .╌╌╌╌╌ .
1009 ]
1010 ]
1011
1012 scenario editor-splits-wrapped-line-after-inserting-newline [
1013 local-scope
1014 assume-screen 10/width, 5/height
1015 e:&:editor <- new-editor [abcdef], 0/left, 5/right
1016 editor-render screen, e
1017 screen-should-contain [
1018 . .
1019 .abcd↩ .
1020 .ef .
1021 .╌╌╌╌╌ .
1022 . .
1023 ]
1024 assume-console [
1025 left-click 2, 0
1026 press enter
1027 ]
1028 run [
1029 editor-event-loop screen, console, e
1030 10:num/raw <- get *e, cursor-row:offset
1031 11:num/raw <- get *e, cursor-column:offset
1032 ]
1033 screen-should-contain [
1034 . .
1035 .abcd .
1036 .ef .
1037 .╌╌╌╌╌ .
1038 ]
1039 memory-should-contain [
1040 10 <- 2
1041 11 <- 0
1042 ]
1043 ]
1044
1045 scenario editor-inserts-indent-after-newline [
1046 local-scope
1047 assume-screen 10/width, 10/height
1048 s:text <- new [ab
1049 cd
1050 ef]
1051 e:&:editor <- new-editor s, 0/left, 10/right
1052
1053 assume-console [
1054 left-click 2, 8
1055 type [
1056 ]
1057 ]
1058 run [
1059 editor-event-loop screen, console, e
1060 3:num/raw <- get *e, cursor-row:offset
1061 4:num/raw <- get *e, cursor-column:offset
1062 ]
1063
1064 memory-should-contain [
1065 3 <- 3
1066 4 <- 2
1067 ]
1068 ]
1069
1070 scenario editor-skips-indent-around-paste [
1071 local-scope
1072 assume-screen 10/width, 10/height
1073 s:text <- new [ab
1074 cd
1075 ef]
1076 e:&:editor <- new-editor s, 0/left, 10/right
1077
1078 assume-console [
1079 left-click 2, 8
1080 press 65507
1081 press enter
1082 press 65506
1083 ]
1084 run [
1085 editor-event-loop screen, console, e
1086 3:num/raw <- get *e, cursor-row:offset
1087 4:num/raw <- get *e, cursor-column:offset
1088 ]
1089
1090 memory-should-contain [
1091 3 <- 3
1092 4 <- 0
1093 ]
1094 ]
1095
1096 after <handle-special-key> [
1097 {
1098 paste-start?:bool <- equal k, 65507/paste-start
1099 break-unless paste-start?
1100 *editor <- put *editor, indent?:offset, 0/false
1101 return 1/go-render
1102 }
1103 ]
1104
1105 after <handle-special-key> [
1106 {
1107 paste-end?:bool <- equal k, 65506/paste-end
1108 break-unless paste-end?
1109 *editor <- put *editor, indent?:offset, 1/true
1110 return 1/go-render
1111 }
1112 ]
1113
1114
1115
1116 def draw-horizontal screen:&:screen, row:num, x:num, right:num -> screen:&:screen [
1117 local-scope
1118 load-inputs
1119 height:num <- screen-height screen
1120 past-bottom?:bool <- greater-or-equal row, height
1121 return-if past-bottom?
1122 style:char, style-found?:bool <- next-input
1123 {
1124 break-if style-found?
1125 style <- copy 9472/horizontal
1126 }
1127 color:num, color-found?:bool <- next-input
1128 {
1129
1130 break-if color-found?
1131 color <- copy 245/grey
1132 }
1133 bg-color:num, bg-color-found?:bool <- next-input
1134 {
1135 break-if bg-color-found?
1136 bg-color <- copy 0/black
1137 }
1138 screen <- move-cursor screen, row, x
1139 {
1140 continue?:bool <- lesser-or-equal x, right
1141 break-unless continue?
1142 print screen, style, color, bg-color
1143 x <- add x, 1
1144 loop
1145 }
1146 ]