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