1
2
3
4
5
6
7 scenario editor-inserts-two-spaces-on-tab [
8 local-scope
9 assume-screen 10/width, 5/height
10 s:text <- new [ab
11 cd]
12 e:&:editor <- new-editor s, 0/left, 5/right
13 editor-render screen, e
14 $clear-trace
15 assume-console [
16 press tab
17 ]
18 run [
19 editor-event-loop screen, console, e
20 ]
21 screen-should-contain [
22 . .
23 . ab .
24 .cd .
25 ]
26
27 check-trace-count-for-label-lesser-than 10, [print-character]
28 ]
29
30 scenario editor-inserts-two-spaces-and-wraps-line-on-tab [
31 local-scope
32 assume-screen 10/width, 5/height
33 e:&:editor <- new-editor [abcd], 0/left, 5/right
34 editor-render screen, e
35 $clear-trace
36 assume-console [
37 press tab
38 ]
39 run [
40 editor-event-loop screen, console, e
41 ]
42 screen-should-contain [
43 . .
44 . ab↩ .
45 .cd .
46 ]
47
48 check-trace-count-for-label-greater-than 10, [print-character]
49 ]
50
51 after <handle-special-character> [
52 {
53 tab?:bool <- equal c, 9/tab
54 break-unless tab?
55 <begin-insert-character>
56
57
58 insert-at-cursor editor, 32/space, screen
59 go-render? <- insert-at-cursor editor, 32/space, screen
60 <end-insert-character>
61 return
62 }
63 ]
64
65
66
67 scenario editor-handles-backspace-key [
68 local-scope
69 assume-screen 10/width, 5/height
70 e:&:editor <- new-editor [abc], 0/left, 10/right
71 editor-render screen, e
72 $clear-trace
73 assume-console [
74 left-click 1, 1
75 press backspace
76 ]
77 run [
78 editor-event-loop screen, console, e
79 4:num/raw <- get *e, cursor-row:offset
80 5:num/raw <- get *e, cursor-column:offset
81 ]
82 screen-should-contain [
83 . .
84 .bc .
85 .╌╌╌╌╌╌╌╌╌╌.
86 . .
87 ]
88 memory-should-contain [
89 4 <- 1
90 5 <- 0
91 ]
92 check-trace-count-for-label 3, [print-character]
93 ]
94
95 after <handle-special-character> [
96 {
97 delete-previous-character?:bool <- equal c, 8/backspace
98 break-unless delete-previous-character?
99 <begin-backspace-character>
100 go-render?:bool, backspaced-cell:&:duplex-list:char <- delete-before-cursor editor, screen
101 <end-backspace-character>
102 return
103 }
104 ]
105
106
107
108
109 def delete-before-cursor editor:&:editor, screen:&:screen -> go-render?:bool, backspaced-cell:&:duplex-list:char, editor:&:editor, screen:&:screen [
110 local-scope
111 load-inputs
112 before-cursor:&:duplex-list:char <- get *editor, before-cursor:offset
113 data:&:duplex-list:char <- get *editor, data:offset
114
115 prev:&:duplex-list:char <- prev before-cursor
116 return-unless prev, 0/no-more-render, 0/nothing-deleted
117 trace 10, [app], [delete-before-cursor]
118 original-row:num <- get *editor, cursor-row:offset
119 scroll?:bool <- move-cursor-coordinates-left editor
120 backspaced-cell:&:duplex-list:char <- copy before-cursor
121 data <- remove before-cursor, data
122 before-cursor <- copy prev
123 *editor <- put *editor, before-cursor:offset, before-cursor
124 return-if scroll?, 1/go-render
125 screen-width:num <- screen-width screen
126 cursor-row:num <- get *editor, cursor-row:offset
127 cursor-column:num <- get *editor, cursor-column:offset
128
129 same-row?:bool <- equal cursor-row, original-row
130 return-unless same-row?, 1/go-render
131 left:num <- get *editor, left:offset
132 right:num <- get *editor, right:offset
133 curr:&:duplex-list:char <- next before-cursor
134 screen <- move-cursor screen, cursor-row, cursor-column
135 curr-column:num <- copy cursor-column
136 {
137
138 at-right?:bool <- greater-or-equal curr-column, right
139 return-if at-right?, 1/go-render
140 break-unless curr
141
142 currc:char <- get *curr, value:offset
143 at-newline?:bool <- equal currc, 10/newline
144 break-if at-newline?
145 screen <- print screen, currc
146 curr-column <- add curr-column, 1
147 curr <- next curr
148 loop
149 }
150
151 space:char <- copy 32/space
152 screen <- print screen, space
153 go-render? <- copy 0/false
154 ]
155
156 def move-cursor-coordinates-left editor:&:editor -> go-render?:bool, editor:&:editor [
157 local-scope
158 load-inputs
159 go-render?:bool <- copy 0/false
160 before-cursor:&:duplex-list:char <- get *editor, before-cursor:offset
161 cursor-row:num <- get *editor, cursor-row:offset
162 cursor-column:num <- get *editor, cursor-column:offset
163 left:num <- get *editor, left:offset
164
165 {
166 at-left-margin?:bool <- equal cursor-column, left
167 break-if at-left-margin?
168 trace 10, [app], [decrementing cursor column]
169 cursor-column <- subtract cursor-column, 1
170 *editor <- put *editor, cursor-column:offset, cursor-column
171 return
172 }
173
174 top-of-screen?:bool <- equal cursor-row, 1
175 {
176 break-if top-of-screen?
177 cursor-row <- subtract cursor-row, 1
178 *editor <- put *editor, cursor-row:offset, cursor-row
179 }
180 {
181 break-unless top-of-screen?
182 <scroll-up>
183 go-render? <- copy 1/true
184 }
185 {
186
187 previous-character:char <- get *before-cursor, value:offset
188 previous-character-is-newline?:bool <- equal previous-character, 10/newline
189 break-unless previous-character-is-newline?
190
191 trace 10, [app], [switching to previous line]
192 d:&:duplex-list:char <- get *editor, data:offset
193 end-of-line:num <- previous-line-length before-cursor, d
194 right:num <- get *editor, right:offset
195 width:num <- subtract right, left
196 wrap?:bool <- greater-than end-of-line, width
197 {
198 break-unless wrap?
199 _, column-offset:num <- divide-with-remainder end-of-line, width
200 cursor-column <- add left, column-offset
201 *editor <- put *editor, cursor-column:offset, cursor-column
202 }
203 {
204 break-if wrap?
205 cursor-column <- add left, end-of-line
206 *editor <- put *editor, cursor-column:offset, cursor-column
207 }
208 return
209 }
210
211 trace 10, [app], [wrapping to previous line]
212 right:num <- get *editor, right:offset
213 cursor-column <- subtract right, 1
214 *editor <- put *editor, cursor-column:offset, cursor-column
215 ]
216
217
218
219 def previous-line-length curr:&:duplex-list:char, start:&:duplex-list:char -> result:num [
220 local-scope
221 load-inputs
222 result:num <- copy 0
223 return-unless curr
224 at-start?:bool <- equal curr, start
225 return-if at-start?
226 {
227 curr <- prev curr
228 break-unless curr
229 at-start?:bool <- equal curr, start
230 break-if at-start?
231 c:char <- get *curr, value:offset
232 at-newline?:bool <- equal c, 10/newline
233 break-if at-newline?
234 result <- add result, 1
235 loop
236 }
237 ]
238
239 scenario editor-clears-last-line-on-backspace [
240 local-scope
241 assume-screen 10/width, 5/height
242 s:text <- new [ab
243 cd]
244 e:&:editor <- new-editor s, 0/left, 10/right
245 assume-console [
246 left-click 2, 0
247 press backspace
248 ]
249 run [
250 editor-event-loop screen, console, e
251 4:num/raw <- get *e, cursor-row:offset
252 5:num/raw <- get *e, cursor-column:offset
253 ]
254 screen-should-contain [
255 . .
256 .abcd .
257 .╌╌╌╌╌╌╌╌╌╌.
258 . .
259 ]
260 memory-should-contain [
261 4 <- 1
262 5 <- 2
263 ]
264 ]
265
266 scenario editor-joins-and-wraps-lines-on-backspace [
267 local-scope
268 assume-screen 10/width, 5/height
269
270 s:text <- new [abc def
271 ghi jkl]
272 e:&:editor <- new-editor s, 0/left, 10/right
273 editor-render screen, e
274 $clear-trace
275
276 assume-console [
277 left-click 2, 0
278 press backspace
279 ]
280 run [
281 editor-event-loop screen, console, e
282 ]
283
284 screen-should-contain [
285 . .
286 .abc defgh↩.
287 .i jkl .
288 .╌╌╌╌╌╌╌╌╌╌.
289 . .
290 ]
291 ]
292
293 scenario editor-wraps-long-lines-on-backspace [
294 local-scope
295 assume-screen 10/width, 5/height
296
297 e:&:editor <- new-editor [abc def ghij], 0/left, 8/right
298 editor-render screen, e
299
300 screen-should-contain [
301 . .
302 .abc def↩ .
303 . ghij .
304 .╌╌╌╌╌╌╌╌ .
305 ]
306 $clear-trace
307
308 assume-console [
309 left-click 1, 4
310 press backspace
311 ]
312 run [
313 editor-event-loop screen, console, e
314 ]
315
316 screen-should-contain [
317 . .
318 .abcdef ↩ .
319 .ghij .
320 .╌╌╌╌╌╌╌╌ .
321 . .
322 ]
323 ]
324
325
326
327 scenario editor-handles-delete-key [
328 local-scope
329 assume-screen 10/width, 5/height
330 e:&:editor <- new-editor [abc], 0/left, 10/right
331 editor-render screen, e
332 $clear-trace
333 assume-console [
334 press delete
335 ]
336 run [
337 editor-event-loop screen, console, e
338 ]
339 screen-should-contain [
340 . .
341 .bc .
342 .╌╌╌╌╌╌╌╌╌╌.
343 . .
344 ]
345 check-trace-count-for-label 3, [print-character]
346 $clear-trace
347 assume-console [
348 press delete
349 ]
350 run [
351 editor-event-loop screen, console, e
352 ]
353 screen-should-contain [
354 . .
355 .c .
356 .╌╌╌╌╌╌╌╌╌╌.
357 . .
358 ]
359 check-trace-count-for-label 2, [print-character]
360 ]
361
362 after <handle-special-key> [
363 {
364 delete-next-character?:bool <- equal k, 65522/delete
365 break-unless delete-next-character?
366 <begin-delete-character>
367 go-render?:bool, deleted-cell:&:duplex-list:char <- delete-at-cursor editor, screen
368 <end-delete-character>
369 return
370 }
371 ]
372
373 def delete-at-cursor editor:&:editor, screen:&:screen -> go-render?:bool, deleted-cell:&:duplex-list:char, editor:&:editor, screen:&:screen [
374 local-scope
375 load-inputs
376 before-cursor:&:duplex-list:char <- get *editor, before-cursor:offset
377 data:&:duplex-list:char <- get *editor, data:offset
378 deleted-cell:&:duplex-list:char <- next before-cursor
379 return-unless deleted-cell, 0/don't-render
380 currc:char <- get *deleted-cell, value:offset
381 data <- remove deleted-cell, data
382 deleted-newline?:bool <- equal currc, 10/newline
383 return-if deleted-newline?, 1/go-render
384
385 curr:&:duplex-list:char <- next before-cursor
386 cursor-row:num <- get *editor, cursor-row:offset
387 cursor-column:num <- get *editor, cursor-column:offset
388 screen <- move-cursor screen, cursor-row, cursor-column
389 curr-column:num <- copy cursor-column
390 screen-width:num <- screen-width screen
391 {
392
393 at-right?:bool <- greater-or-equal curr-column, screen-width
394 return-if at-right?, 1/go-render
395 break-unless curr
396 currc:char <- get *curr, value:offset
397 at-newline?:bool <- equal currc, 10/newline
398 break-if at-newline?
399 screen <- print screen, currc
400 curr-column <- add curr-column, 1
401 curr <- next curr
402 loop
403 }
404
405 space:char <- copy 32/space
406 screen <- print screen, space
407 go-render? <- copy 0/false
408 ]
409
410
411
412 scenario editor-moves-cursor-right-with-key [
413 local-scope
414 assume-screen 10/width, 5/height
415 e:&:editor <- new-editor [abc], 0/left, 10/right
416 editor-render screen, e
417 $clear-trace
418 assume-console [
419 press right-arrow
420 type [0]
421 ]
422 run [
423 editor-event-loop screen, console, e
424 ]
425 screen-should-contain [
426 . .
427 .a0bc .
428 .╌╌╌╌╌╌╌╌╌╌.
429 . .
430 ]
431 check-trace-count-for-label 3, [print-character]
432 ]
433
434 after <handle-special-key> [
435 {
436 move-to-next-character?:bool <- equal k, 65514/right-arrow
437 break-unless move-to-next-character?
438
439 next-cursor:&:duplex-list:char <- next before-cursor
440 break-unless next-cursor
441
442 <begin-move-cursor>
443 before-cursor <- copy next-cursor
444 *editor <- put *editor, before-cursor:offset, before-cursor
445 go-render?:bool <- move-cursor-coordinates-right editor, screen-height
446 screen <- move-cursor screen, cursor-row, cursor-column
447 undo-coalesce-tag:num <- copy 2/right-arrow
448 <end-move-cursor>
449 return
450 }
451 ]
452
453 def move-cursor-coordinates-right editor:&:editor, screen-height:num -> go-render?:bool, editor:&:editor [
454 local-scope
455 load-inputs
456 before-cursor:&:duplex-list:char <- get *editor before-cursor:offset
457 cursor-row:num <- get *editor, cursor-row:offset
458 cursor-column:num <- get *editor, cursor-column:offset
459 left:num <- get *editor, left:offset
460 right:num <- get *editor, right:offset
461
462 {
463 old-cursor-character:char <- get *before-cursor, value:offset
464 was-at-newline?:bool <- equal old-cursor-character, 10/newline
465 break-unless was-at-newline?
466 cursor-row <- add cursor-row, 1
467 *editor <- put *editor, cursor-row:offset, cursor-row
468 cursor-column <- copy left
469 *editor <- put *editor, cursor-column:offset, cursor-column
470 below-screen?:bool <- greater-or-equal cursor-row, screen-height
471 return-unless below-screen?, 0/don't-render
472 <scroll-down>
473 cursor-row <- subtract cursor-row, 1
474 *editor <- put *editor, cursor-row:offset, cursor-row
475 return 1/go-render
476 }
477
478 {
479
480 wrap-column:num <- subtract right, 1
481 at-wrap?:bool <- equal cursor-column, wrap-column
482 break-unless at-wrap?
483
484 next:&:duplex-list:char <- next before-cursor
485 break-unless next
486 next-character:char <- get *next, value:offset
487 newline?:bool <- equal next-character, 10/newline
488 break-if newline?
489 cursor-row <- add cursor-row, 1
490 *editor <- put *editor, cursor-row:offset, cursor-row
491 cursor-column <- copy left
492 *editor <- put *editor, cursor-column:offset, cursor-column
493 below-screen?:bool <- greater-or-equal cursor-row, screen-height
494 return-unless below-screen?, 0/no-more-render
495 <scroll-down>
496 cursor-row <- subtract cursor-row, 1
497 *editor <- put *editor, cursor-row:offset, cursor-row
498 return 1/go-render
499 }
500
501 cursor-column <- add cursor-column, 1
502 *editor <- put *editor, cursor-column:offset, cursor-column
503 go-render? <- copy 0/false
504 ]
505
506 scenario editor-moves-cursor-to-next-line-with-right-arrow [
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
515 assume-console [
516 press right-arrow
517 press right-arrow
518 press right-arrow
519 press right-arrow
520 ]
521 run [
522 editor-event-loop screen, console, e
523 ]
524 check-trace-count-for-label 0, [print-character]
525
526 assume-console [
527 type [0]
528 ]
529 run [
530 editor-event-loop screen, console, e
531 ]
532 screen-should-contain [
533 . .
534 .abc .
535 .0d .
536 .╌╌╌╌╌╌╌╌╌╌.
537 . .
538 ]
539 check-trace-count-for-label 2, [print-character]
540 ]
541
542 scenario editor-moves-cursor-to-next-line-with-right-arrow-2 [
543 local-scope
544 assume-screen 10/width, 5/height
545 s:text <- new [abc
546 d]
547 e:&:editor <- new-editor s, 1/left, 10/right
548 editor-render screen, e
549 assume-console [
550 press right-arrow
551 press right-arrow
552 press right-arrow
553 press right-arrow
554 type [0]
555 ]
556 run [
557 editor-event-loop screen, console, e
558 ]
559 screen-should-contain [
560 . .
561 . abc .
562 . 0d .
563 . ╌╌╌╌╌╌╌╌╌.
564 . .
565 ]
566 ]
567
568 scenario editor-moves-cursor-to-next-wrapped-line-with-right-arrow [
569 local-scope
570 assume-screen 10/width, 5/height
571 e:&:editor <- new-editor [abcdef], 0/left, 5/right
572 editor-render screen, e
573 $clear-trace
574 assume-console [
575 left-click 1, 3
576 press right-arrow
577 ]
578 run [
579 editor-event-loop screen, console, e
580 3:num/raw <- get *e, cursor-row:offset
581 4:num/raw <- get *e, cursor-column:offset
582 ]
583 screen-should-contain [
584 . .
585 .abcd↩ .
586 .ef .
587 .╌╌╌╌╌ .
588 . .
589 ]
590 memory-should-contain [
591 3 <- 2
592 4 <- 0
593 ]
594 check-trace-count-for-label 0, [print-character]
595 ]
596
597 scenario editor-moves-cursor-to-next-wrapped-line-with-right-arrow-2 [
598 local-scope
599 assume-screen 10/width, 5/height
600
601 e:&:editor <- new-editor [abcde], 0/left, 5/right
602 editor-render screen, e
603 $clear-trace
604
605 assume-console [
606 left-click 1, 3
607 press right-arrow
608 ]
609 run [
610 editor-event-loop screen, console, e
611 3:num/raw <- get *e, cursor-row:offset
612 4:num/raw <- get *e, cursor-column:offset
613 ]
614 memory-should-contain [
615 3 <- 2
616 4 <- 0
617 ]
618
619 assume-console [
620 press right-arrow
621 ]
622 run [
623 editor-event-loop screen, console, e
624 3:num/raw <- get *e, cursor-row:offset
625 4:num/raw <- get *e, cursor-column:offset
626 ]
627 memory-should-contain [
628 3 <- 2
629 4 <- 1
630 ]
631 check-trace-count-for-label 0, [print-character]
632 ]
633
634 scenario editor-moves-cursor-to-next-wrapped-line-with-right-arrow-3 [
635 local-scope
636 assume-screen 10/width, 5/height
637 e:&:editor <- new-editor [abcdef], 1/left, 6/right
638 editor-render screen, e
639 $clear-trace
640 assume-console [
641 left-click 1, 4
642 press right-arrow
643 ]
644 run [
645 editor-event-loop screen, console, e
646 3:num/raw <- get *e, cursor-row:offset
647 4:num/raw <- get *e, cursor-column:offset
648 ]
649 screen-should-contain [
650 . .
651 . abcd↩ .
652 . ef .
653 . ╌╌╌╌╌ .
654 . .
655 ]
656 memory-should-contain [
657 3 <- 2
658 4 <- 1
659 ]
660 check-trace-count-for-label 0, [print-character]
661 ]
662
663 scenario editor-moves-cursor-to-next-line-with-right-arrow-at-end-of-line [
664 local-scope
665 assume-screen 10/width, 5/height
666 s:text <- new [abc
667 d]
668 e:&:editor <- new-editor s, 0/left, 10/right
669 editor-render screen, e
670 $clear-trace
671
672 assume-console [
673 left-click 1, 3
674 press right-arrow
675 type [0]
676 ]
677 run [
678 editor-event-loop screen, console, e
679 ]
680
681 screen-should-contain [
682 . .
683 .abc .
684 .0d .
685 .╌╌╌╌╌╌╌╌╌╌.
686 . .
687 ]
688 check-trace-count-for-label 2, [print-character]
689 ]
690
691
692
693
694
695 scenario editor-moves-cursor-left-with-key [
696 local-scope
697 assume-screen 10/width, 5/height
698 e:&:editor <- new-editor [abc], 0/left, 10/right
699 editor-render screen, e
700 $clear-trace
701 assume-console [
702 left-click 1, 2
703 press left-arrow
704 type [0]
705 ]
706 run [
707 editor-event-loop screen, console, e
708 ]
709 screen-should-contain [
710 . .
711 .a0bc .
712 .╌╌╌╌╌╌╌╌╌╌.
713 . .
714 ]
715 check-trace-count-for-label 3, [print-character]
716 ]
717
718 after <handle-special-key> [
719 {
720 move-to-previous-character?:bool <- equal k, 65515/left-arrow
721 break-unless move-to-previous-character?
722 trace 10, [app], [left arrow]
723
724 prev:&:duplex-list:char <- prev before-cursor
725 return-unless prev, 0/don't-render
726 <begin-move-cursor>
727 go-render? <- move-cursor-coordinates-left editor
728 before-cursor <- copy prev
729 *editor <- put *editor, before-cursor:offset, before-cursor
730 undo-coalesce-tag:num <- copy 1/left-arrow
731 <end-move-cursor>
732 return
733 }
734 ]
735
736 scenario editor-moves-cursor-to-previous-line-with-left-arrow-at-start-of-line [
737 local-scope
738 assume-screen 10/width, 5/height
739
740 s:text <- new [abc
741 d]
742 e:&:editor <- new-editor s, 0/left, 10/right
743 editor-render screen, e
744 $clear-trace
745
746 assume-console [
747 left-click 2, 0
748 press left-arrow
749 ]
750 run [
751 editor-event-loop screen, console, e
752 3:num/raw <- get *e, cursor-row:offset
753 4:num/raw <- get *e, cursor-column:offset
754 ]
755 memory-should-contain [
756 3 <- 1
757 4 <- 3
758 ]
759 check-trace-count-for-label 0, [print-character]
760 ]
761
762 scenario editor-moves-cursor-to-previous-line-with-left-arrow-at-start-of-line-2 [
763 local-scope
764 assume-screen 10/width, 5/height
765
766 s:text <- new [abc
767 def
768 g]
769 e:&:editor <- new-editor s:text, 0/left, 10/right
770 editor-render screen, e
771 $clear-trace
772
773
774 assume-console [
775 left-click 3, 0
776 press left-arrow
777 type [0]
778 ]
779 run [
780 editor-event-loop screen, console, e
781 ]
782 screen-should-contain [
783 . .
784 .abc .
785 .def0 .
786 .g .
787 .╌╌╌╌╌╌╌╌╌╌.
788 ]
789 check-trace-count-for-label 1, [print-character]
790 ]
791
792 scenario editor-moves-cursor-to-previous-line-with-left-arrow-at-start-of-line-3 [
793 local-scope
794 assume-screen 10/width, 5/height
795 s:text <- new [abc
796 def
797 g]
798 e:&:editor <- new-editor s, 0/left, 10/right
799 editor-render screen, e
800 $clear-trace
801
802 assume-console [
803 left-click 1, 0
804 press left-arrow
805 type [0]
806 ]
807 run [
808 editor-event-loop screen, console, e
809 ]
810
811 screen-should-contain [
812 . .
813 .0abc .
814 .def .
815 .g .
816 .╌╌╌╌╌╌╌╌╌╌.
817 ]
818 check-trace-count-for-label 4, [print-character]
819 ]
820
821 scenario editor-moves-cursor-to-previous-line-with-left-arrow-at-start-of-line-4 [
822 local-scope
823 assume-screen 10/width, 5/height
824
825 s:text <- new [abc
826
827 d]
828 e:&:editor <- new-editor s, 0/left, 10/right
829 editor-render screen, e:&:editor
830 $clear-trace
831
832 assume-console [
833 left-click 3, 0
834 press left-arrow
835 type [0]
836 ]
837 run [
838 editor-event-loop screen, console, e
839 ]
840 screen-should-contain [
841 . .
842 .abc .
843 .0 .
844 .d .
845 .╌╌╌╌╌╌╌╌╌╌.
846 ]
847 check-trace-count-for-label 1, [print-character]
848 ]
849
850 scenario editor-moves-across-screen-lines-across-wrap-with-left-arrow [
851 local-scope
852 assume-screen 10/width, 5/height
853
854 e:&:editor <- new-editor [abcdef], 0/left, 5/right
855 editor-render screen, e
856 $clear-trace
857 screen-should-contain [
858 . .
859 .abcd↩ .
860 .ef .
861 .╌╌╌╌╌ .
862 . .
863 ]
864
865 assume-console [
866 left-click 2, 0
867 press left-arrow
868 ]
869 run [
870 editor-event-loop screen, console, e
871 3:num/raw <- get *e, cursor-row:offset
872 4:num/raw <- get *e, cursor-column:offset
873 ]
874 memory-should-contain [
875 3 <- 1
876 4 <- 3
877 ]
878 check-trace-count-for-label 0, [print-character]
879 ]
880
881 scenario editor-moves-across-screen-lines-to-wrapping-line-with-left-arrow [
882 local-scope
883 assume-screen 10/width, 5/height
884
885 s:text <- new [abcdef
886 g]
887 e:&:editor <- new-editor s, 0/left, 5/right
888 editor-render screen, e
889 $clear-trace
890 screen-should-contain [
891 . .
892 .abcd↩ .
893 .ef .
894 .g .
895 .╌╌╌╌╌ .
896 ]
897
898 assume-console [
899 left-click 3, 0
900 press left-arrow
901 ]
902 run [
903 editor-event-loop screen, console, e
904 3:num/raw <- get *e, cursor-row:offset
905 4:num/raw <- get *e, cursor-column:offset
906 ]
907 memory-should-contain [
908 3 <- 2
909 4 <- 2
910 ]
911 check-trace-count-for-label 0, [print-character]
912 ]
913
914 scenario editor-moves-across-screen-lines-to-non-wrapping-line-with-left-arrow [
915 local-scope
916 assume-screen 10/width, 5/height
917
918 s:text <- new [abcd
919 e]
920 e:&:editor <- new-editor s, 0/left, 5/right
921 editor-render screen, e
922 $clear-trace
923 screen-should-contain [
924 . .
925 .abcd .
926 .e .
927 .╌╌╌╌╌ .
928 . .
929 ]
930
931 assume-console [
932 left-click 2, 0
933 press left-arrow
934 ]
935 run [
936 editor-event-loop screen, console, e
937 3:num/raw <- get *e, cursor-row:offset
938 4:num/raw <- get *e, cursor-column:offset
939 ]
940 memory-should-contain [
941 3 <- 1
942 4 <- 4
943 ]
944 check-trace-count-for-label 0, [print-character]
945 ]
946
947
948
949
950
951 scenario editor-moves-to-previous-line-with-up-arrow [
952 local-scope
953 assume-screen 10/width, 5/height
954 s:text <- new [abc
955 def]
956 e:&:editor <- new-editor s, 0/left, 10/right
957 editor-render screen, e
958 $clear-trace
959 assume-console [
960 left-click 2, 1
961 press up-arrow
962 ]
963 run [
964 editor-event-loop screen, console, e
965 3:num/raw <- get *e, cursor-row:offset
966 4:num/raw <- get *e, cursor-column:offset
967 ]
968 memory-should-contain [
969 3 <- 1
970 4 <- 1
971 ]
972 check-trace-count-for-label 0, [print-character]
973 assume-console [
974 type [0]
975 ]
976 run [
977 editor-event-loop screen, console, e
978 ]
979 screen-should-contain [
980 . .
981 .a0bc .
982 .def .
983 .╌╌╌╌╌╌╌╌╌╌.
984 . .
985 ]
986 ]
987
988 after <handle-special-key> [
989 {
990 move-to-previous-line?:bool <- equal k, 65517/up-arrow
991 break-unless move-to-previous-line?
992 <begin-move-cursor>
993 go-render? <- move-to-previous-line editor
994 undo-coalesce-tag:num <- copy 3/up-arrow
995 <end-move-cursor>
996 return
997 }
998 ]
999
1000 def move-to-previous-line editor:&:editor -> go-render?:bool, editor:&:editor [
1001 local-scope
1002 load-inputs
1003 go-render?:bool <- copy 0/false
1004 cursor-row:num <- get *editor, cursor-row:offset
1005 cursor-column:num <- get *editor, cursor-column:offset
1006 before-cursor:&:duplex-list:char <- get *editor, before-cursor:offset
1007 left:num <- get *editor, left:offset
1008 right:num <- get *editor, right:offset
1009 already-at-top?:bool <- lesser-or-equal cursor-row, 1/top
1010 {
1011
1012 break-if already-at-top?
1013
1014
1015
1016 curr:&:duplex-list:char <- copy before-cursor
1017 old:&:duplex-list:char <- copy curr
1018 {
1019 at-left?:bool <- equal cursor-column, left
1020 break-if at-left?
1021 curr <- before-previous-screen-line curr, editor
1022 no-motion?:bool <- equal curr, old
1023 return-if no-motion?
1024 }
1025 {
1026 curr <- before-previous-screen-line curr, editor
1027 no-motion?:bool <- equal curr, old
1028 return-if no-motion?
1029 }
1030 before-cursor <- copy curr
1031 *editor <- put *editor, before-cursor:offset, before-cursor
1032 cursor-row <- subtract cursor-row, 1
1033 *editor <- put *editor, cursor-row:offset, cursor-row
1034
1035 target-column:num <- copy cursor-column
1036 cursor-column <- copy left
1037 *editor <- put *editor, cursor-column:offset, cursor-column
1038 {
1039 done?:bool <- greater-or-equal cursor-column, target-column
1040 break-if done?
1041 curr:&:duplex-list:char <- next before-cursor
1042 break-unless curr
1043 currc:char <- get *curr, value:offset
1044 at-newline?:bool <- equal currc, 10/newline
1045 break-if at-newline?
1046
1047 before-cursor <- copy curr
1048 *editor <- put *editor, before-cursor:offset, before-cursor
1049 cursor-column <- add cursor-column, 1
1050 *editor <- put *editor, cursor-column:offset, cursor-column
1051 loop
1052 }
1053 return
1054 }
1055 {
1056
1057 break-unless already-at-top?
1058 <scroll-up>
1059 return 1/go-render
1060 }
1061 ]
1062
1063
1064
1065
1066
1067 def before-previous-screen-line in:&:duplex-list:char, editor:&:editor -> out:&:duplex-list:char [
1068 local-scope
1069 load-inputs
1070 curr:&:duplex-list:char <- copy in
1071 c:char <- get *curr, value:offset
1072
1073
1074
1075 left:num <- get *editor, left:offset
1076 right:num <- get *editor, right:offset
1077 max-line-length:num <- subtract right, left, -1/exclusive-right, 1/wrap-icon
1078 sentinel:&:duplex-list:char <- get *editor, data:offset
1079 len:num <- previous-line-length curr, sentinel
1080 {
1081 break-if len
1082
1083 prev:&:duplex-list:char <- prev curr
1084 return-unless prev, curr
1085 return prev
1086 }
1087 _, max:num <- divide-with-remainder len, max-line-length
1088
1089 {
1090 break-if max
1091 max <- copy max-line-length
1092 }
1093 max <- add max, 1
1094 count:num <- copy 0
1095
1096 {
1097 done?:bool <- greater-or-equal count, max
1098 break-if done?
1099 prev:&:duplex-list:char <- prev curr
1100 break-unless prev
1101 curr <- copy prev
1102 count <- add count, 1
1103 loop
1104 }
1105 return curr
1106 ]
1107
1108 scenario editor-adjusts-column-at-previous-line [
1109 local-scope
1110 assume-screen 10/width, 5/height
1111 s:text <- new [ab
1112 def]
1113 e:&:editor <- new-editor s, 0/left, 10/right
1114 editor-render screen, e
1115 $clear-trace
1116 assume-console [
1117 left-click 2, 3
1118 press up-arrow
1119 ]
1120 run [
1121 editor-event-loop screen, console, e
1122 3:num/raw <- get *e, cursor-row:offset
1123 4:num/raw <- get *e, cursor-column:offset
1124 ]
1125 memory-should-contain [
1126 3 <- 1
1127 4 <- 2
1128 ]
1129 check-trace-count-for-label 0, [print-character]
1130 assume-console [
1131 type [0]
1132 ]
1133 run [
1134 editor-event-loop screen, console, e
1135 ]
1136 screen-should-contain [
1137 . .
1138 .ab0 .
1139 .def .
1140 .╌╌╌╌╌╌╌╌╌╌.
1141 . .
1142 ]
1143 ]
1144
1145 scenario editor-adjusts-column-at-empty-line [
1146 local-scope
1147 assume-screen 10/width, 5/height
1148 s:text <- new [
1149 def]
1150 e:&:editor <- new-editor s, 0/left, 10/right
1151 editor-render screen, e
1152 $clear-trace
1153 assume-console [
1154 left-click 2, 3
1155 press up-arrow
1156 ]
1157 run [
1158 editor-event-loop screen, console, e
1159 3:num/raw <- get *e, cursor-row:offset
1160 4:num/raw <- get *e, cursor-column:offset
1161 ]
1162 memory-should-contain [
1163 3 <- 1
1164 4 <- 0
1165 ]
1166 check-trace-count-for-label 0, [print-character]
1167 assume-console [
1168 type [0]
1169 ]
1170 run [
1171 editor-event-loop screen, console, e
1172 ]
1173 screen-should-contain [
1174 . .
1175 .0 .
1176 .def .
1177 .╌╌╌╌╌╌╌╌╌╌.
1178 . .
1179 ]
1180 ]
1181
1182 scenario editor-moves-to-previous-line-from-zero-margin [
1183 local-scope
1184 assume-screen 10/width, 5/height
1185
1186 s:text <- new [abc
1187 def
1188 ghi]
1189 e:&:editor <- new-editor s, 0/left, 10/right
1190 editor-render screen, e
1191 $clear-trace
1192
1193 assume-console [
1194 left-click 3, 0
1195 press up-arrow
1196 ]
1197 run [
1198 editor-event-loop screen, console, e
1199 3:num/raw <- get *e, cursor-row:offset
1200 4:num/raw <- get *e, cursor-column:offset
1201 ]
1202 memory-should-contain [
1203 3 <- 2
1204 4 <- 0
1205 ]
1206 check-trace-count-for-label 0, [print-character]
1207 assume-console [
1208 type [0]
1209 ]
1210 run [
1211 editor-event-loop screen, console, e
1212 ]
1213 screen-should-contain [
1214 . .
1215 .abc .
1216 .0def .
1217 .ghi .
1218 .╌╌╌╌╌╌╌╌╌╌.
1219 ]
1220 ]
1221
1222 scenario editor-moves-to-previous-line-from-left-margin [
1223 local-scope
1224 assume-screen 10/width, 5/height
1225
1226 s:text <- new [abc
1227 def
1228 ghi]
1229 e:&:editor <- new-editor s, 1/left, 10/right
1230 editor-render screen, e
1231 $clear-trace
1232
1233 assume-console [
1234 left-click 3, 1
1235 press up-arrow
1236 ]
1237 run [
1238 editor-event-loop screen, console, e
1239 3:num/raw <- get *e, cursor-row:offset
1240 4:num/raw <- get *e, cursor-column:offset
1241 ]
1242 memory-should-contain [
1243 3 <- 2
1244 4 <- 1
1245 ]
1246 check-trace-count-for-label 0, [print-character]
1247 assume-console [
1248 type [0]
1249 ]
1250 run [
1251 editor-event-loop screen, console, e
1252 ]
1253 screen-should-contain [
1254 . .
1255 . abc .
1256 . 0def .
1257 . ghi .
1258 . ╌╌╌╌╌╌╌╌╌.
1259 ]
1260 ]
1261
1262 scenario editor-moves-to-top-line-in-presence-of-wrapped-line [
1263 local-scope
1264 assume-screen 10/width, 5/height
1265 e:&:editor <- new-editor [abcde], 0/left, 5/right
1266 editor-render screen, e
1267 screen-should-contain [
1268 . .
1269 .abcd↩ .
1270 .e .
1271 .╌╌╌╌╌ .
1272 ]
1273 $clear-trace
1274 assume-console [
1275 left-click 2, 0
1276 press up-arrow
1277 ]
1278 run [
1279 editor-event-loop screen, console, e
1280 3:num/raw <- get *e, cursor-row:offset
1281 4:num/raw <- get *e, cursor-column:offset
1282 ]
1283 memory-should-contain [
1284 3 <- 1
1285 4 <- 0
1286 ]
1287 check-trace-count-for-label 0, [print-character]
1288 assume-console [
1289 type [0]
1290 ]
1291 run [
1292 editor-event-loop screen, console, e
1293 ]
1294 screen-should-contain [
1295 . .
1296 .0abc↩ .
1297 .de .
1298 .╌╌╌╌╌ .
1299 ]
1300 ]
1301
1302 scenario editor-moves-to-top-line-in-presence-of-wrapped-line-2 [
1303 local-scope
1304 assume-screen 10/width, 5/height
1305 s:text <- new [abc
1306 defgh]
1307 e:&:editor <- new-editor s, 0/left, 5/right
1308 editor-render screen, e
1309 screen-should-contain [
1310 . .
1311 .abc .
1312 .defg↩ .
1313 .h .
1314 .╌╌╌╌╌ .
1315 ]
1316 $clear-trace
1317 assume-console [
1318 left-click 3, 0
1319 press up-arrow
1320 press up-arrow
1321 ]
1322 run [
1323 editor-event-loop screen, console, e
1324 3:num/raw <- get *e, cursor-row:offset
1325 4:num/raw <- get *e, cursor-column:offset
1326 ]
1327 memory-should-contain [
1328 3 <- 1
1329 4 <- 0
1330 ]
1331 check-trace-count-for-label 0, [print-character]
1332 assume-console [
1333 type [0]
1334 ]
1335 run [
1336 editor-event-loop screen, console, e
1337 ]
1338 screen-should-contain [
1339 . .
1340 .0abc .
1341 .defg↩ .
1342 .h .
1343 .╌╌╌╌╌ .
1344 ]
1345 ]
1346
1347
1348
1349 scenario editor-moves-to-next-line-with-down-arrow [
1350 local-scope
1351 assume-screen 10/width, 5/height
1352 s:text <- new [abc
1353 def]
1354 e:&:editor <- new-editor s, 0/left, 10/right
1355 editor-render screen, e
1356 $clear-trace
1357
1358 assume-console [
1359 press down-arrow
1360 ]
1361 run [
1362 editor-event-loop screen, console, e
1363 3:num/raw <- get *e, cursor-row:offset
1364 4:num/raw <- get *e, cursor-column:offset
1365 ]
1366
1367 memory-should-contain [
1368 3 <- 2
1369 4 <- 0
1370 ]
1371 check-trace-count-for-label 0, [print-character]
1372 assume-console [
1373 type [0]
1374 ]
1375 run [
1376 editor-event-loop screen, console, e
1377 ]
1378 screen-should-contain [
1379 . .
1380 .abc .
1381 .0def .
1382 .╌╌╌╌╌╌╌╌╌╌.
1383 . .
1384 ]
1385 ]
1386
1387 after <handle-special-key> [
1388 {
1389 move-to-next-line?:bool <- equal k, 65516/down-arrow
1390 break-unless move-to-next-line?
1391 <begin-move-cursor>
1392 go-render? <- move-to-next-line editor, screen-height
1393 undo-coalesce-tag:num <- copy 4/down-arrow
1394 <end-move-cursor>
1395 return
1396 }
1397 ]
1398
1399 def move-to-next-line editor:&:editor, screen-height:num -> go-render?:bool, editor:&:editor [
1400 local-scope
1401 load-inputs
1402 cursor-row:num <- get *editor, cursor-row:offset
1403 cursor-column:num <- get *editor, cursor-column:offset
1404 before-cursor:&:duplex-list:char <- get *editor, before-cursor:offset
1405 left:num <- get *editor, left:offset
1406 right:num <- get *editor, right:offset
1407 last-line:num <- subtract screen-height, 1
1408 bottom:num <- get *editor, bottom:offset
1409 at-bottom-of-screen?:bool <- greater-or-equal bottom, last-line
1410 {
1411 break-if before-cursor
1412 {
1413 break-if at-bottom-of-screen?
1414 return 0/don't-render
1415 }
1416 {
1417 break-unless at-bottom-of-screen?
1418 jump +try-to-scroll
1419 }
1420 }
1421 next:&:duplex-list:char <- next before-cursor
1422 {
1423 break-if next
1424 {
1425 break-if at-bottom-of-screen?
1426 return 0/don't-render
1427 }
1428 {
1429 break-unless at-bottom-of-screen?
1430 jump +try-to-scroll
1431 }
1432 }
1433 already-at-bottom?:bool <- greater-or-equal cursor-row, last-line
1434 {
1435
1436 break-if already-at-bottom?
1437 target-column:num <- copy cursor-column
1438
1439 {
1440 next:&:duplex-list:char <- next before-cursor
1441 break-unless next
1442 done?:bool <- greater-or-equal cursor-column, right
1443 break-if done?
1444 cursor-column <- add cursor-column, 1
1445 before-cursor <- copy next
1446 c:char <- get *next, value:offset
1447 at-newline?:bool <- equal c, 10/newline
1448 break-if at-newline?
1449 loop
1450 }
1451 {
1452 break-if next
1453 {
1454 break-if at-bottom-of-screen?
1455 return 0/don't-render
1456 }
1457 {
1458 break-unless at-bottom-of-screen?
1459 jump +try-to-scroll
1460 }
1461 }
1462 cursor-row <- add cursor-row, 1
1463 cursor-column <- copy left
1464 {
1465 next:&:duplex-list:char <- next before-cursor
1466 break-unless next
1467 c:char <- get *next, value:offset
1468 at-newline?:bool <- equal c, 10/newline
1469 break-if at-newline?
1470 done?:bool <- greater-or-equal cursor-column, target-column
1471 break-if done?
1472 cursor-column <- add cursor-column, 1
1473 before-cursor <- copy next
1474 loop
1475 }
1476 *editor <- put *editor, before-cursor:offset, before-cursor
1477 *editor <- put *editor, cursor-column:offset, cursor-column
1478 *editor <- put *editor, cursor-row:offset, cursor-row
1479 return 0/don't-render
1480 }
1481 +try-to-scroll
1482 <scroll-down>
1483 go-render? <- copy 1/true
1484 ]
1485
1486 scenario editor-adjusts-column-at-next-line [
1487 local-scope
1488 assume-screen 10/width, 5/height
1489
1490 s:text <- new [abcde
1491 fg
1492 hi]
1493 e:&:editor <- new-editor s, 0/left, 10/right
1494 editor-render screen, e
1495 $clear-trace
1496
1497 assume-console [
1498 left-click 1, 8
1499 press down-arrow
1500 ]
1501 run [
1502 editor-event-loop screen, console, e
1503 3:num/raw <- get *e, cursor-row:offset
1504 4:num/raw <- get *e, cursor-column:offset
1505 ]
1506
1507 memory-should-contain [
1508 3 <- 2
1509 4 <- 2
1510 ]
1511 check-trace-count-for-label 0, [print-character]
1512 assume-console [
1513 type [0]
1514 ]
1515 run [
1516 editor-event-loop screen, console, e
1517 ]
1518 screen-should-contain [
1519 . .
1520 .abcde .
1521 .fg0 .
1522 .hi .
1523 .╌╌╌╌╌╌╌╌╌╌.
1524 ]
1525 ]
1526
1527 scenario editor-moves-down-within-wrapped-line [
1528 local-scope
1529 assume-screen 10/width, 5/height
1530 e:&:editor <- new-editor [abcdefghijklmno], 0/left, 10/right
1531 editor-render screen, e
1532 screen-should-contain [
1533 . .
1534 .abcdefghi↩.
1535 .jklmno .
1536 .╌╌╌╌╌╌╌╌╌╌.
1537 . .
1538 ]
1539
1540 assume-console [
1541 left-click 1, 8
1542 press down-arrow
1543 ]
1544 run [
1545 editor-event-loop screen, console, e
1546 3:num/raw <- get *e, cursor-row:offset
1547 4:num/raw <- get *e, cursor-column:offset
1548 ]
1549
1550 memory-should-contain [
1551 3 <- 2
1552 4 <- 6
1553 ]
1554 ]
1555
1556
1557
1558 scenario editor-moves-to-start-of-line-with-ctrl-a [
1559 local-scope
1560 assume-screen 10/width, 5/height
1561 s:text <- new [123
1562 456]
1563 e:&:editor <- new-editor s, 0/left, 10/right
1564 editor-render screen, e
1565 $clear-trace
1566
1567 assume-console [
1568 left-click 2, 3
1569 press ctrl-a
1570 ]
1571 run [
1572 editor-event-loop screen, console, e
1573 4:num/raw <- get *e, cursor-row:offset
1574 5:num/raw <- get *e, cursor-column:offset
1575 ]
1576
1577 memory-should-contain [
1578 4 <- 2
1579 5 <- 0
1580 ]
1581 check-trace-count-for-label 0, [print-character]
1582 ]
1583
1584 after <handle-special-character> [
1585 {
1586 move-to-start-of-line?:bool <- equal c, 1/ctrl-a
1587 break-unless move-to-start-of-line?
1588 <begin-move-cursor>
1589 move-to-start-of-screen-line editor
1590 undo-coalesce-tag:num <- copy 0/never
1591 <end-move-cursor>
1592 return 0/don't-render
1593 }
1594 ]
1595
1596 after <handle-special-key> [
1597 {
1598 move-to-start-of-line?:bool <- equal k, 65521/home
1599 break-unless move-to-start-of-line?
1600 <begin-move-cursor>
1601 move-to-start-of-screen-line editor
1602 undo-coalesce-tag:num <- copy 0/never
1603 <end-move-cursor>
1604 return 0/don't-render
1605 }
1606 ]
1607
1608
1609
1610 def move-to-start-of-screen-line editor:&:editor -> editor:&:editor [
1611 local-scope
1612 load-inputs
1613
1614 left:num <- get *editor, left:offset
1615 col:num <- get *editor, cursor-column:offset
1616
1617 curr:&:duplex-list:char <- get *editor, before-cursor:offset
1618
1619 {
1620 done?:bool <- equal col, left
1621 break-if done?
1622 assert curr, [move-to-start-of-line tried to move before start of text]
1623 curr <- prev curr
1624 col <- subtract col, 1
1625 loop
1626 }
1627 *editor <- put *editor, cursor-column:offset, col
1628 *editor <- put *editor, before-cursor:offset, curr
1629 ]
1630
1631 scenario editor-moves-to-start-of-line-with-ctrl-a-2 [
1632 local-scope
1633 assume-screen 10/width, 5/height
1634 s:text <- new [123
1635 456]
1636 e:&:editor <- new-editor s, 0/left, 10/right
1637 editor-render screen, e
1638 $clear-trace
1639
1640 assume-console [
1641 left-click 1, 3
1642 press ctrl-a
1643 ]
1644 run [
1645 editor-event-loop screen, console, e
1646 4:num/raw <- get *e, cursor-row:offset
1647 5:num/raw <- get *e, cursor-column:offset
1648 ]
1649
1650 memory-should-contain [
1651 4 <- 1
1652 5 <- 0
1653 ]
1654 check-trace-count-for-label 0, [print-character]
1655 ]
1656
1657 scenario editor-moves-to-start-of-line-with-home [
1658 local-scope
1659 assume-screen 10/width, 5/height
1660 s:text <- new [123
1661 456]
1662 e:&:editor <- new-editor s, 0/left, 10/right
1663 $clear-trace
1664
1665 assume-console [
1666 left-click 2, 3
1667 press home
1668 ]
1669 run [
1670 editor-event-loop screen, console, e
1671 3:num/raw <- get *e, cursor-row:offset
1672 4:num/raw <- get *e, cursor-column:offset
1673 ]
1674
1675 memory-should-contain [
1676 3 <- 2
1677 4 <- 0
1678 ]
1679 check-trace-count-for-label 0, [print-character]
1680 ]
1681
1682 scenario editor-moves-to-start-of-line-with-home-2 [
1683 local-scope
1684 assume-screen 10/width, 5/height
1685 s:text <- new [123
1686 456]
1687 e:&:editor <- new-editor s, 0/left, 10/right
1688 editor-render screen, e
1689 $clear-trace
1690
1691 assume-console [
1692 left-click 1, 3
1693 press home
1694 ]
1695 run [
1696 editor-event-loop screen, console, e
1697 3:num/raw <- get *e, cursor-row:offset
1698 4:num/raw <- get *e, cursor-column:offset
1699 ]
1700
1701 memory-should-contain [
1702 3 <- 1
1703 4 <- 0
1704 ]
1705 check-trace-count-for-label 0, [print-character]
1706 ]
1707
1708 scenario editor-moves-to-start-of-screen-line-with-ctrl-a [
1709 local-scope
1710 assume-screen 10/width, 5/height
1711 e:&:editor <- new-editor [123456], 0/left, 5/right
1712 editor-render screen, e
1713 screen-should-contain [
1714 . .
1715 .1234↩ .
1716 .56 .
1717 .╌╌╌╌╌ .
1718 . .
1719 ]
1720 $clear-trace
1721
1722 assume-console [
1723 left-click 2, 1
1724 press ctrl-a
1725 press up-arrow
1726 ]
1727 run [
1728 editor-event-loop screen, console, e
1729 4:num/raw <- get *e, cursor-row:offset
1730 5:num/raw <- get *e, cursor-column:offset
1731 ]
1732
1733 memory-should-contain [
1734 4 <- 1
1735 5 <- 0
1736 ]
1737 check-trace-count-for-label 0, [print-character]
1738
1739 assume-console [
1740 type [a]
1741 ]
1742 run [
1743 editor-event-loop screen, console, e
1744 4:num/raw <- get *e, cursor-row:offset
1745 5:num/raw <- get *e, cursor-column:offset
1746 ]
1747 screen-should-contain [
1748 . .
1749 .a123↩ .
1750 .456 .
1751 .╌╌╌╌╌ .
1752 . .
1753 ]
1754 memory-should-contain [
1755 4 <- 1
1756 5 <- 1
1757 ]
1758 ]
1759
1760
1761
1762 scenario editor-moves-to-end-of-line-with-ctrl-e [
1763 local-scope
1764 assume-screen 10/width, 5/height
1765 s:text <- new [123
1766 456]
1767 e:&:editor <- new-editor s, 0/left, 10/right
1768 editor-render screen, e
1769 $clear-trace
1770
1771 assume-console [
1772 left-click 1, 1
1773 press ctrl-e
1774 ]
1775 run [
1776 editor-event-loop screen, console, e
1777 4:num/raw <- get *e, cursor-row:offset
1778 5:num/raw <- get *e, cursor-column:offset
1779 ]
1780
1781 memory-should-contain [
1782 4 <- 1
1783 5 <- 3
1784 ]
1785 check-trace-count-for-label 0, [print-character]
1786
1787 assume-console [
1788 type [z]
1789 ]
1790 run [
1791 editor-event-loop screen, console, e
1792 4:num/raw <- get *e, cursor-row:offset
1793 5:num/raw <- get *e, cursor-column:offset
1794 ]
1795 memory-should-contain [
1796 4 <- 1
1797 5 <- 4
1798 ]
1799 screen-should-contain [
1800 . .
1801 .123z .
1802 .456 .
1803 .╌╌╌╌╌╌╌╌╌╌.
1804 . .
1805 ]
1806 check-trace-count-for-label 1, [print-character]
1807 ]
1808
1809 after <handle-special-character> [
1810 {
1811 move-to-end-of-line?:bool <- equal c, 5/ctrl-e
1812 break-unless move-to-end-of-line?
1813 <begin-move-cursor>
1814 move-to-end-of-line editor
1815 undo-coalesce-tag:num <- copy 0/never
1816 <end-move-cursor>
1817 return 0/don't-render
1818 }
1819 ]
1820
1821 after <handle-special-key> [
1822 {
1823 move-to-end-of-line?:bool <- equal k, 65520/end
1824 break-unless move-to-end-of-line?
1825 <begin-move-cursor>
1826 move-to-end-of-line editor
1827 undo-coalesce-tag:num <- copy 0/never
1828 <end-move-cursor>
1829 return 0/don't-render
1830 }
1831 ]
1832
1833 def move-to-end-of-line editor:&:editor -> editor:&:editor [
1834 local-scope
1835 load-inputs
1836 before-cursor:&:duplex-list:char <- get *editor, before-cursor:offset
1837 cursor-column:num <- get *editor, cursor-column:offset
1838 right:num <- get *editor, right:offset
1839
1840 {
1841 next:&:duplex-list:char <- next before-cursor
1842 break-unless next
1843 nextc:char <- get *next, value:offset
1844 at-end-of-line?:bool <- equal nextc, 10/newline
1845 break-if at-end-of-line?
1846 cursor-column <- add cursor-column, 1
1847 at-right?:bool <- equal cursor-column, right
1848 break-if at-right?
1849 *editor <- put *editor, cursor-column:offset, cursor-column
1850 before-cursor <- copy next
1851 *editor <- put *editor, before-cursor:offset, before-cursor
1852 loop
1853 }
1854 ]
1855
1856 scenario editor-moves-to-end-of-line-with-ctrl-e-2 [
1857 local-scope
1858 assume-screen 10/width, 5/height
1859 s:text <- new [123
1860 456]
1861 e:&:editor <- new-editor s, 0/left, 10/right
1862 editor-render screen, e
1863 $clear-trace
1864
1865 assume-console [
1866 left-click 2, 1
1867 press ctrl-e
1868 ]
1869 run [
1870 editor-event-loop screen, console, e
1871 4:num/raw <- get *e, cursor-row:offset
1872 5:num/raw <- get *e, cursor-column:offset
1873 ]
1874
1875 memory-should-contain [
1876 4 <- 2
1877 5 <- 3
1878 ]
1879 check-trace-count-for-label 0, [print-character]
1880 ]
1881
1882 scenario editor-moves-to-end-of-line-with-end [
1883 local-scope
1884 assume-screen 10/width, 5/height
1885 s:text <- new [123
1886 456]
1887 e:&:editor <- new-editor s, 0/left, 10/right
1888 editor-render screen, e
1889 $clear-trace
1890
1891 assume-console [
1892 left-click 1, 1
1893 press end
1894 ]
1895 run [
1896 editor-event-loop screen, console, e
1897 3:num/raw <- get *e, cursor-row:offset
1898 4:num/raw <- get *e, cursor-column:offset
1899 ]
1900
1901 memory-should-contain [
1902 3 <- 1
1903 4 <- 3
1904 ]
1905 check-trace-count-for-label 0, [print-character]
1906 ]
1907
1908 scenario editor-moves-to-end-of-line-with-end-2 [
1909 local-scope
1910 assume-screen 10/width, 5/height
1911 s:text <- new [123
1912 456]
1913 e:&:editor <- new-editor s, 0/left, 10/right
1914 editor-render screen, e
1915 $clear-trace
1916
1917 assume-console [
1918 left-click 2, 1
1919 press end
1920 ]
1921 run [
1922 editor-event-loop screen, console, e
1923 3:num/raw <- get *e, cursor-row:offset
1924 4:num/raw <- get *e, cursor-column:offset
1925 ]
1926
1927 memory-should-contain [
1928 3 <- 2
1929 4 <- 3
1930 ]
1931 check-trace-count-for-label 0, [print-character]
1932 ]
1933
1934 scenario editor-moves-to-end-of-wrapped-line [
1935 local-scope
1936 assume-screen 10/width, 5/height
1937 s:text <- new [123456
1938 789]
1939 e:&:editor <- new-editor s, 0/left, 5/right
1940 editor-render screen, e
1941 $clear-trace
1942
1943 assume-console [
1944 left-click 1, 1
1945 press end
1946 ]
1947 run [
1948 editor-event-loop screen, console, e
1949 10:num/raw <- get *e, cursor-row:offset
1950 11:num/raw <- get *e, cursor-column:offset
1951 ]
1952
1953 memory-should-contain [
1954 10 <- 1
1955 11 <- 3
1956 ]
1957
1958 check-trace-count-for-label 0, [print-character]
1959
1960 assume-console [
1961 type [a]
1962 ]
1963 run [
1964 editor-event-loop screen, console, e
1965 ]
1966 screen-should-contain [
1967 . .
1968 .123a↩ .
1969 .456 .
1970 .789 .
1971 .╌╌╌╌╌ .
1972 ]
1973 ]
1974
1975
1976
1977 scenario editor-deletes-to-start-of-line-with-ctrl-u [
1978 local-scope
1979 assume-screen 10/width, 5/height
1980 s:text <- new [123
1981 456]
1982 e:&:editor <- new-editor s, 0/left, 10/right
1983 editor-render screen, e
1984 $clear-trace
1985
1986 assume-console [
1987 left-click 2, 2
1988 press ctrl-u
1989 ]
1990 run [
1991 editor-event-loop screen, console, e
1992 ]
1993
1994 screen-should-contain [
1995 . .
1996 .123 .
1997 .6 .
1998 .╌╌╌╌╌╌╌╌╌╌.
1999 . .
2000 ]
2001 check-trace-count-for-label 10, [print-character]
2002 ]
2003
2004 after <handle-special-character> [
2005 {
2006 delete-to-start-of-line?:bool <- equal c, 21/ctrl-u
2007 break-unless delete-to-start-of-line?
2008 <begin-delete-to-start-of-line>
2009 deleted-cells:&:duplex-list:char <- delete-to-start-of-line editor
2010 <end-delete-to-start-of-line>
2011 go-render?:bool <- minimal-render-for-ctrl-u screen, editor, deleted-cells
2012 return
2013 }
2014 ]
2015
2016 def minimal-render-for-ctrl-u screen:&:screen, editor:&:editor, deleted-cells:&:duplex-list:char -> go-render?:bool, screen:&:screen [
2017 local-scope
2018 load-inputs
2019 curr-column:num <- get *editor, cursor-column:offset
2020
2021 buf:&:buffer:char <- new-buffer 30
2022 curr:&:duplex-list:char <- get *editor, before-cursor:offset
2023 i:num <- copy curr-column
2024 right:num <- get *editor, right:offset
2025 {
2026
2027 wrap?:bool <- greater-or-equal i, right
2028 return-if wrap?, 1/go-render
2029 curr <- next curr
2030 break-unless curr
2031 c:char <- get *curr, value:offset
2032 b:bool <- equal c, 10
2033 break-if b
2034 buf <- append buf, c
2035 i <- add i, 1
2036 loop
2037 }
2038
2039 num-deleted-cells:num <- length deleted-cells
2040 old-row-len:num <- add i, num-deleted-cells
2041 left:num <- get *editor, left:offset
2042 end:num <- subtract right, left
2043 wrap?:bool <- greater-or-equal old-row-len, end
2044 return-if wrap?, 1/go-render
2045 curr-line:text <- buffer-to-array buf
2046 curr-row:num <- get *editor, cursor-row:offset
2047 render-code screen, curr-line, curr-column, right, curr-row
2048 return 0/dont-render
2049 ]
2050
2051 def delete-to-start-of-line editor:&:editor -> result:&:duplex-list:char, editor:&:editor [
2052 local-scope
2053 load-inputs
2054
2055 init:&:duplex-list:char <- get *editor, data:offset
2056 top-of-screen:&:duplex-list:char <- get *editor, top-of-screen:offset
2057 update-top-of-screen?:bool <- copy 0/false
2058 before-cursor:&:duplex-list:char <- get *editor, before-cursor:offset
2059 start:&:duplex-list:char <- copy before-cursor
2060 end:&:duplex-list:char <- next before-cursor
2061 {
2062 at-start-of-text?:bool <- equal start, init
2063 break-if at-start-of-text?
2064 curr:char <- get *start, value:offset
2065 at-start-of-line?:bool <- equal curr, 10/newline
2066 break-if at-start-of-line?
2067
2068 at-top-of-screen?:bool <- equal start, top-of-screen
2069 update-top-of-screen?:bool <- or update-top-of-screen?, at-top-of-screen?
2070 start <- prev start
2071 assert start, [delete-to-start-of-line tried to move before start of text]
2072 loop
2073 }
2074
2075 result:&:duplex-list:char <- next start
2076 remove-between start, end
2077
2078 {
2079 break-unless update-top-of-screen?
2080 put *editor, top-of-screen:offset, start
2081 }
2082
2083 before-cursor <- copy start
2084 *editor <- put *editor, before-cursor:offset, before-cursor
2085 left:num <- get *editor, left:offset
2086 *editor <- put *editor, cursor-column:offset, left
2087
2088 right:num <- get *editor, right:offset
2089 width:num <- subtract right, left
2090 num-deleted:num <- length result
2091 cursor-row-adjustment:num <- divide-with-remainder num-deleted, width
2092 return-unless cursor-row-adjustment
2093 cursor-row:num <- get *editor, cursor-row:offset
2094 cursor-row-in-editor:num <- subtract cursor-row, 1
2095 at-top?:bool <- lesser-or-equal cursor-row-in-editor, cursor-row-adjustment
2096 {
2097 break-unless at-top?
2098 cursor-row <- copy 1
2099 }
2100 {
2101 break-if at-top?
2102 cursor-row <- subtract cursor-row, cursor-row-adjustment
2103 }
2104 put *editor, cursor-row:offset, cursor-row
2105 ]
2106
2107 def render-code screen:&:screen, s:text, left:num, right:num, row:num -> row:num, screen:&:screen [
2108 local-scope
2109 load-inputs
2110 return-unless s
2111 color:num <- copy 7/white
2112 column:num <- copy left
2113 screen <- move-cursor screen, row, column
2114 screen-height:num <- screen-height screen
2115 i:num <- copy 0
2116 len:num <- length *s
2117 {
2118 +next-character
2119 done?:bool <- greater-or-equal i, len
2120 break-if done?
2121 done? <- greater-or-equal row, screen-height
2122 break-if done?
2123 c:char <- index *s, i
2124 <character-c-received>
2125 {
2126
2127 newline?:bool <- equal c, 10/newline
2128 break-unless newline?
2129
2130 {
2131 done?:bool <- greater-than column, right
2132 break-if done?
2133 space:char <- copy 32/space
2134 print screen, space
2135 column <- add column, 1
2136 loop
2137 }
2138 row <- add row, 1
2139 column <- copy left
2140 screen <- move-cursor screen, row, column
2141 i <- add i, 1
2142 loop +next-character
2143 }
2144 {
2145
2146 at-right?:bool <- equal column, right
2147 break-unless at-right?
2148
2149 wrap-icon:char <- copy 8617/loop-back-to-left
2150 print screen, wrap-icon, 245/grey
2151 column <- copy left
2152 row <- add row, 1
2153 screen <- move-cursor screen, row, column
2154
2155 loop +next-character
2156 }
2157 i <- add i, 1
2158 print screen, c, color
2159 column <- add column, 1
2160 loop
2161 }
2162 was-at-left?:bool <- equal column, left
2163 clear-line-until screen, right
2164 {
2165 break-if was-at-left?
2166 row <- add row, 1
2167 }
2168 move-cursor screen, row, left
2169 ]
2170
2171 scenario editor-deletes-to-start-of-line-with-ctrl-u-2 [
2172 local-scope
2173 assume-screen 10/width, 5/height
2174 s:text <- new [123
2175 456]
2176 e:&:editor <- new-editor s, 0/left, 10/right
2177 editor-render screen, e
2178 $clear-trace
2179
2180 assume-console [
2181 left-click 1, 2
2182 press ctrl-u
2183 ]
2184 run [
2185 editor-event-loop screen, console, e
2186 ]
2187
2188 screen-should-contain [
2189 . .
2190 .3 .
2191 .456 .
2192 .╌╌╌╌╌╌╌╌╌╌.
2193 . .
2194 ]
2195 check-trace-count-for-label 10, [print-character]
2196 ]
2197
2198 scenario editor-deletes-to-start-of-line-with-ctrl-u-3 [
2199 local-scope
2200 assume-screen 10/width, 5/height
2201 s:text <- new [123
2202 456]
2203 e:&:editor <- new-editor s, 0/left, 10/right
2204 editor-render screen, e
2205 $clear-trace
2206
2207 assume-console [
2208 left-click 1, 3
2209 press ctrl-u
2210 ]
2211 run [
2212 editor-event-loop screen, console, e
2213 ]
2214
2215 screen-should-contain [
2216 . .
2217 . .
2218 .456 .
2219 .╌╌╌╌╌╌╌╌╌╌.
2220 . .
2221 ]
2222 check-trace-count-for-label 10, [print-character]
2223 ]
2224
2225 scenario editor-deletes-to-start-of-final-line-with-ctrl-u [
2226 local-scope
2227 assume-screen 10/width, 5/height
2228 s:text <- new [123
2229 456]
2230 e:&:editor <- new-editor s, 0/left, 10/right
2231 editor-render screen, e
2232 $clear-trace
2233
2234 assume-console [
2235 left-click 2, 3
2236 press ctrl-u
2237 ]
2238 run [
2239 editor-event-loop screen, console, e
2240 ]
2241
2242 screen-should-contain [
2243 . .
2244 .123 .
2245 . .
2246 .╌╌╌╌╌╌╌╌╌╌.
2247 . .
2248 ]
2249 check-trace-count-for-label 10, [print-character]
2250 ]
2251
2252 scenario editor-deletes-to-start-of-wrapped-line-with-ctrl-u [
2253 local-scope
2254 assume-screen 10/width, 10/height
2255
2256 s:text <- new [123456
2257 789]
2258 e:&:editor <- new-editor s, 0/left, 5/right
2259 editor-render screen, e
2260 screen-should-contain [
2261 . .
2262 .1234↩ .
2263 .56 .
2264 .789 .
2265 .╌╌╌╌╌ .
2266 . .
2267 ]
2268 $clear-trace
2269
2270 assume-console [
2271 left-click 1, 3
2272 press ctrl-u
2273 ]
2274 run [
2275 editor-event-loop screen, console, e
2276 ]
2277
2278 screen-should-contain [
2279 . .
2280 .456 .
2281 .789 .
2282 .╌╌╌╌╌ .
2283 . .
2284 ]
2285 check-trace-count-for-label 45, [print-character]
2286 ]
2287
2288
2289 scenario editor-deletes-to-start-of-wrapped-line-with-ctrl-u-2 [
2290 local-scope
2291 assume-screen 10/width, 10/height
2292
2293 s:text <- new [1
2294 2
2295 345678
2296 9]
2297 e:&:editor <- new-editor s, 0/left, 5/right
2298 editor-render screen, e
2299 screen-should-contain [
2300 . .
2301 .1 .
2302 .2 .
2303 .3456↩ .
2304 .78 .
2305 .9 .
2306 .╌╌╌╌╌ .
2307 . .
2308 ]
2309
2310 assume-console [
2311 left-click 4, 1
2312 press ctrl-u
2313 ]
2314 run [
2315 editor-event-loop screen, console, e
2316 10:num/raw <- get *e, cursor-row:offset
2317 11:num/raw <- get *e, cursor-column:offset
2318 ]
2319 screen-should-contain [
2320 . .
2321 .1 .
2322 .2 .
2323 .8 .
2324 .9 .
2325 .╌╌╌╌╌ .
2326 . .
2327 ]
2328
2329 memory-should-contain [
2330 10 <- 3
2331 11 <- 0
2332 ]
2333 ]
2334
2335
2336 scenario editor-deletes-to-start-of-wrapped-line-with-ctrl-u-3 [
2337 local-scope
2338 assume-screen 10/width, 10/height
2339
2340 s:text <- new [1
2341 2
2342 3456789abcd
2343 e]
2344 e:&:editor <- new-editor s, 0/left, 5/right
2345 editor-render screen, e
2346 assume-console [
2347 left-click 4, 1
2348 ]
2349 editor-event-loop screen, console, e
2350 screen-should-contain [
2351 . .
2352 .1 .
2353 .2 .
2354 .3456↩ .
2355 .789a↩ .
2356 .bcd .
2357 .e .
2358 .╌╌╌╌╌ .
2359 . .
2360 ]
2361 assume-console [
2362 left-click 5, 1
2363 press ctrl-u
2364 ]
2365 run [
2366 editor-event-loop screen, console, e
2367 10:num/raw <- get *e, cursor-row:offset
2368 11:num/raw <- get *e, cursor-column:offset
2369 ]
2370 screen-should-contain [
2371 . .
2372 .1 .
2373 .2 .
2374 .cd .
2375 .e .
2376 .╌╌╌╌╌ .
2377 . .
2378 ]
2379
2380 memory-should-contain [
2381 10 <- 3
2382 11 <- 0
2383 ]
2384 ]
2385
2386
2387 scenario editor-deletes-to-start-of-wrapped-line-with-ctrl-u-4 [
2388 local-scope
2389 assume-screen 10/width, 10/height
2390
2391 s:text <- new [1234567
2392 89]
2393 e:&:editor <- new-editor s, 0/left, 5/right
2394 editor-render screen, e
2395 screen-should-contain [
2396 . .
2397 .1234↩ .
2398 .567 .
2399 .89 .
2400 .╌╌╌╌╌ .
2401 . .
2402 ]
2403
2404 assume-console [
2405 left-click 2, 1
2406 press ctrl-u
2407 ]
2408 run [
2409 editor-event-loop screen, console, e
2410 10:num/raw <- get *e, cursor-row:offset
2411 11:num/raw <- get *e, cursor-column:offset
2412 ]
2413 screen-should-contain [
2414 . .
2415 .67 .
2416 .89 .
2417 .╌╌╌╌╌ .
2418 . .
2419 ]
2420
2421 memory-should-contain [
2422 10 <- 1
2423 11 <- 0
2424 ]
2425 ]
2426
2427
2428 scenario editor-deletes-to-start-of-wrapped-line-with-ctrl-u-5 [
2429 local-scope
2430 assume-screen 10/width, 10/height
2431
2432 s:text <- new [1
2433 2
2434 345678
2435 9]
2436 e:&:editor <- new-editor s, 0/left, 5/right
2437 editor-render screen, e
2438
2439 assume-console [
2440 left-click 4, 1
2441 press ctrl-t
2442 ]
2443 editor-event-loop screen, console, e
2444 screen-should-contain [
2445 . .
2446 .78 .
2447 .9 .
2448 .╌╌╌╌╌ .
2449 . .
2450 ]
2451 assume-console [
2452 left-click 1, 1
2453 press ctrl-u
2454 ]
2455 run [
2456 editor-event-loop screen, console, e
2457 10:num/raw <- get *e, cursor-row:offset
2458 11:num/raw <- get *e, cursor-column:offset
2459 ]
2460
2461 screen-should-contain [
2462 . .
2463 .8 .
2464 .9 .
2465 .╌╌╌╌╌ .
2466 . .
2467 ]
2468 memory-should-contain [
2469 10 <- 1
2470 11 <- 0
2471 ]
2472
2473 assume-console [
2474 press up-arrow
2475 ]
2476 run [
2477 editor-event-loop screen, console, e
2478 ]
2479 screen-should-contain [
2480 . .
2481 .2 .
2482 .8 .
2483 .9 .
2484 .╌╌╌╌╌ .
2485 . .
2486 ]
2487 ]
2488
2489
2490 scenario editor-deletes-to-start-of-wrapped-line-with-ctrl-u-6 [
2491 local-scope
2492 assume-screen 10/width, 10/height
2493
2494 s:text <- new [1
2495 2
2496 3456789abcd
2497 e]
2498 e:&:editor <- new-editor s, 0/left, 5/right
2499 editor-render screen, e
2500
2501 assume-console [
2502 left-click 4, 1
2503 press ctrl-t
2504 press ctrl-s
2505 ]
2506 editor-event-loop screen, console, e
2507 screen-should-contain [
2508 . .
2509 .bcd .
2510 .e .
2511 .╌╌╌╌╌ .
2512 . .
2513 ]
2514 assume-console [
2515 left-click 1, 1
2516 press ctrl-u
2517 ]
2518 run [
2519 editor-event-loop screen, console, e
2520 10:num/raw <- get *e, cursor-row:offset
2521 11:num/raw <- get *e, cursor-column:offset
2522 ]
2523
2524 screen-should-contain [
2525 . .
2526 .cd .
2527 .e .
2528 .╌╌╌╌╌ .
2529 . .
2530 ]
2531 memory-should-contain [
2532 10 <- 1
2533 11 <- 0
2534 ]
2535
2536 assume-console [
2537 press up-arrow
2538 ]
2539 run [
2540 editor-event-loop screen, console, e
2541 ]
2542 screen-should-contain [
2543 . .
2544 .2 .
2545 .cd .
2546 .e .
2547 .╌╌╌╌╌ .
2548 . .
2549 ]
2550 ]
2551
2552
2553
2554 scenario editor-deletes-to-end-of-line-with-ctrl-k [
2555 local-scope
2556 assume-screen 10/width, 5/height
2557 s:text <- new [123
2558 456]
2559 e:&:editor <- new-editor s, 0/left, 10/right
2560 editor-render screen, e
2561 $clear-trace
2562
2563 assume-console [
2564 left-click 1, 1
2565 press ctrl-k
2566 ]
2567 run [
2568 editor-event-loop screen, console, e
2569 ]
2570
2571 screen-should-contain [
2572 . .
2573 .1 .
2574 .456 .
2575 .╌╌╌╌╌╌╌╌╌╌.
2576 . .
2577 ]
2578 check-trace-count-for-label 9, [print-character]
2579 ]
2580
2581 after <handle-special-character> [
2582 {
2583 delete-to-end-of-line?:bool <- equal c, 11/ctrl-k
2584 break-unless delete-to-end-of-line?
2585 <begin-delete-to-end-of-line>
2586 deleted-cells:&:duplex-list:char <- delete-to-end-of-line editor
2587 <end-delete-to-end-of-line>
2588
2589 go-render?:bool <- minimal-render-for-ctrl-k screen, editor, deleted-cells
2590 return
2591 }
2592 ]
2593
2594 def minimal-render-for-ctrl-k screen:&:screen, editor:&:editor, deleted-cells:&:duplex-list:char -> go-render?:bool, screen:&:screen [
2595 local-scope
2596 load-inputs
2597
2598 return-unless deleted-cells, 0/dont-render
2599
2600 curr-column:num <- get *editor, cursor-column:offset
2601 num-deleted-cells:num <- length deleted-cells
2602 old-row-len:num <- add curr-column, num-deleted-cells
2603 left:num <- get *editor, left:offset
2604 right:num <- get *editor, right:offset
2605 end:num <- subtract right, left
2606 wrap?:bool <- greater-or-equal old-row-len, end
2607 return-if wrap?, 1/go-render
2608 clear-line-until screen, right
2609 return 0/dont-render
2610 ]
2611
2612 def delete-to-end-of-line editor:&:editor -> result:&:duplex-list:char, editor:&:editor [
2613 local-scope
2614 load-inputs
2615
2616 start:&:duplex-list:char <- get *editor, before-cursor:offset
2617 end:&:duplex-list:char <- next start
2618 {
2619 at-end-of-text?:bool <- equal end, 0/null
2620 break-if at-end-of-text?
2621 curr:char <- get *end, value:offset
2622 at-end-of-line?:bool <- equal curr, 10/newline
2623 break-if at-end-of-line?
2624 end <- next end
2625 loop
2626 }
2627
2628 result <- next start
2629 remove-between start, end
2630 ]
2631
2632 scenario editor-deletes-to-end-of-line-with-ctrl-k-2 [
2633 local-scope
2634 assume-screen 10/width, 5/height
2635 s:text <- new [123
2636 456]
2637 e:&:editor <- new-editor s, 0/left, 10/right
2638 editor-render screen, e
2639 $clear-trace
2640
2641 assume-console [
2642 left-click 2, 1
2643 press ctrl-k
2644 ]
2645 run [
2646 editor-event-loop screen, console, e
2647 ]
2648
2649 screen-should-contain [
2650 . .
2651 .123 .
2652 .4 .
2653 .╌╌╌╌╌╌╌╌╌╌.
2654 . .
2655 ]
2656 check-trace-count-for-label 9, [print-character]
2657 ]
2658
2659 scenario editor-deletes-to-end-of-line-with-ctrl-k-3 [
2660 local-scope
2661 assume-screen 10/width, 5/height
2662 s:text <- new [123
2663 456]
2664 e:&:editor <- new-editor s, 0/left, 10/right
2665 editor-render screen, e
2666 $clear-trace
2667
2668 assume-console [
2669 left-click 1, 2
2670 press ctrl-k
2671 ]
2672 run [
2673 editor-event-loop screen, console, e
2674 ]
2675
2676 screen-should-contain [
2677 . .
2678 .12 .
2679 .456 .
2680 .╌╌╌╌╌╌╌╌╌╌.
2681 . .
2682 ]
2683 check-trace-count-for-label 8, [print-character]
2684 ]
2685
2686 scenario editor-deletes-to-end-of-line-with-ctrl-k-4 [
2687 local-scope
2688 assume-screen 10/width, 5/height
2689 s:text <- new [123
2690 456]
2691 e:&:editor <- new-editor s, 0/left, 10/right
2692 editor-render screen, e
2693 $clear-trace
2694
2695 assume-console [
2696 left-click 1, 3
2697 press ctrl-k
2698 ]
2699 run [
2700 editor-event-loop screen, console, e
2701 ]
2702
2703 screen-should-contain [
2704 . .
2705 .123 .
2706 .456 .
2707 .╌╌╌╌╌╌╌╌╌╌.
2708 . .
2709 ]
2710 check-trace-count-for-label 7, [print-character]
2711 ]
2712
2713 scenario editor-deletes-to-end-of-line-with-ctrl-k-5 [
2714 local-scope
2715 assume-screen 10/width, 5/height
2716 s:text <- new [123
2717 456]
2718 e:&:editor <- new-editor s, 0/left, 10/right
2719 editor-render screen, e
2720 $clear-trace
2721
2722 assume-console [
2723 left-click 2, 2
2724 press ctrl-k
2725 ]
2726 run [
2727 editor-event-loop screen, console, e
2728 ]
2729
2730 screen-should-contain [
2731 . .
2732 .123 .
2733 .45 .
2734 .╌╌╌╌╌╌╌╌╌╌.
2735 . .
2736 ]
2737 check-trace-count-for-label 8, [print-character]
2738 ]
2739
2740 scenario editor-deletes-to-end-of-line-with-ctrl-k-6 [
2741 local-scope
2742 assume-screen 10/width, 5/height
2743 s:text <- new [123
2744 456]
2745 e:&:editor <- new-editor s, 0/left, 10/right
2746 editor-render screen, e
2747 $clear-trace
2748
2749 assume-console [
2750 left-click 2, 3
2751 press ctrl-k
2752 ]
2753 run [
2754 editor-event-loop screen, console, e
2755 ]
2756
2757 screen-should-contain [
2758 . .
2759 .123 .
2760 .456 .
2761 .╌╌╌╌╌╌╌╌╌╌.
2762 . .
2763 ]
2764
2765 check-trace-count-for-label 0, [print-character]
2766 ]
2767
2768 scenario editor-deletes-to-end-of-wrapped-line-with-ctrl-k [
2769 local-scope
2770 assume-screen 10/width, 5/height
2771
2772 s:text <- new [1234
2773 567]
2774 e:&:editor <- new-editor s, 0/left, 4/right
2775 editor-render screen, e
2776 $clear-trace
2777
2778 assume-console [
2779 press ctrl-k
2780 ]
2781 run [
2782 editor-event-loop screen, console, e
2783 ]
2784
2785 screen-should-contain [
2786 . .
2787 . .
2788 .567 .
2789 .╌╌╌╌ .
2790 . .
2791 ]
2792
2793 check-trace-count-for-label 16, [print-character]
2794 ]
2795
2796
2797
2798 scenario editor-can-scroll-down-using-arrow-keys [
2799 local-scope
2800
2801 assume-screen 10/width, 4/height
2802
2803 s:text <- new [a
2804 b
2805 c
2806 d]
2807 e:&:editor <- new-editor s, 0/left, 10/right
2808 editor-render screen, e
2809 screen-should-contain [
2810 . .
2811 .a .
2812 .b .
2813 .c .
2814 ]
2815
2816 assume-console [
2817 left-click 3, 0
2818 press down-arrow
2819 ]
2820 run [
2821 editor-event-loop screen, console, e
2822 ]
2823
2824 screen-should-contain [
2825 . .
2826 .b .
2827 .c .
2828 .d .
2829 ]
2830 ]
2831
2832 after <scroll-down> [
2833 trace 10, [app], [scroll down]
2834 top-of-screen:&:duplex-list:char <- get *editor, top-of-screen:offset
2835 left:num <- get *editor, left:offset
2836 right:num <- get *editor, right:offset
2837 max:num <- subtract right, left
2838 old-top:&:duplex-list:char <- copy top-of-screen
2839 top-of-screen <- before-start-of-next-line top-of-screen, max
2840 *editor <- put *editor, top-of-screen:offset, top-of-screen
2841 no-movement?:bool <- equal old-top, top-of-screen
2842 return-if no-movement?, 0/don't-render
2843 ]
2844
2845
2846
2847
2848
2849 def before-start-of-next-line original:&:duplex-list:char, max:num -> curr:&:duplex-list:char [
2850 local-scope
2851 load-inputs
2852 count:num <- copy 0
2853 curr:&:duplex-list:char <- copy original
2854
2855 {
2856 c:char <- get *curr, value:offset
2857 at-newline?:bool <- equal c, 10/newline
2858 break-unless at-newline?
2859 curr <- next curr
2860 count <- add count, 1
2861 }
2862 {
2863 return-unless curr, original
2864 done?:bool <- greater-or-equal count, max
2865 break-if done?
2866 c:char <- get *curr, value:offset
2867 at-newline?:bool <- equal c, 10/newline
2868 break-if at-newline?
2869 curr <- next curr
2870 count <- add count, 1
2871 loop
2872 }
2873 return-unless curr, original
2874 return curr
2875 ]
2876
2877 scenario editor-scrolls-down-past-wrapped-line-using-arrow-keys [
2878 local-scope
2879
2880 assume-screen 10/width, 4/height
2881
2882
2883 s:text <- new [abcdef
2884 g
2885 h
2886 i]
2887 e:&:editor <- new-editor s, 0/left, 5/right
2888 editor-render screen, e
2889 screen-should-contain [
2890 . .
2891 .abcd↩ .
2892 .ef .
2893 .g .
2894 ]
2895
2896 assume-console [
2897 left-click 3, 0
2898 press down-arrow
2899 ]
2900 run [
2901 editor-event-loop screen, console, e
2902 ]
2903
2904 screen-should-contain [
2905 . .
2906 .ef .
2907 .g .
2908 .h .
2909 ]
2910 ]
2911
2912 scenario editor-scrolls-down-past-wrapped-line-using-arrow-keys-2 [
2913 local-scope
2914
2915 assume-screen 10/width, 4/height
2916
2917 s:text <- new [abcdefghij
2918 k
2919 l
2920 m]
2921 e:&:editor <- new-editor s, 0/left, 5/right
2922
2923 assume-console [
2924 left-click 3, 0
2925 press down-arrow
2926 ]
2927 run [
2928 editor-event-loop screen, console, e
2929 ]
2930
2931 screen-should-contain [
2932 . .
2933 .efgh↩ .
2934 .ij .
2935 .k .
2936 ]
2937
2938 assume-console [
2939 press down-arrow
2940 ]
2941 run [
2942 editor-event-loop screen, console, e
2943 ]
2944
2945 screen-should-contain [
2946 . .
2947 .ij .
2948 .k .
2949 .l .
2950 ]
2951 ]
2952
2953 scenario editor-scrolls-down-when-line-wraps [
2954 local-scope
2955
2956 assume-screen 5/width, 4/height
2957
2958 s:text <- new [a
2959 b
2960 cdef]
2961 e:&:editor <- new-editor s, 0/left, 5/right
2962
2963 assume-console [
2964 left-click 3, 4
2965 type [g]
2966 ]
2967 run [
2968 editor-event-loop screen, console, e
2969 3:num/raw <- get *e, cursor-row:offset
2970 4:num/raw <- get *e, cursor-column:offset
2971 ]
2972
2973 screen-should-contain [
2974 . .
2975 .b .
2976 .cdef↩.
2977 .g .
2978 ]
2979 memory-should-contain [
2980 3 <- 3
2981 4 <- 1
2982 ]
2983 ]
2984
2985 scenario editor-stops-scrolling-once-bottom-is-visible [
2986 local-scope
2987
2988 assume-screen 10/width, 4/height
2989
2990 s:text <- new [a
2991 b]
2992 e:&:editor <- new-editor s, 0/left, 10/right
2993 editor-render screen, e
2994 screen-should-contain [
2995 . .
2996 .a .
2997 .b .
2998 .╌╌╌╌╌╌╌╌╌╌.
2999 ]
3000
3001 assume-console [
3002 left-click 3, 0
3003 press down-arrow
3004 ]
3005 run [
3006 editor-event-loop screen, console, e
3007 ]
3008
3009 screen-should-contain [
3010 . .
3011 .a .
3012 .b .
3013 .╌╌╌╌╌╌╌╌╌╌.
3014 ]
3015 ]
3016
3017 scenario editor-scrolls-down-on-newline [
3018 local-scope
3019 assume-screen 5/width, 4/height
3020
3021 s:text <- new [a
3022 b
3023 c]
3024 e:&:editor <- new-editor s, 0/left, 5/right
3025 assume-console [
3026 left-click 3, 4
3027 type [
3028 ]
3029 ]
3030 run [
3031 editor-event-loop screen, console, e
3032 3:num/raw <- get *e, cursor-row:offset
3033 4:num/raw <- get *e, cursor-column:offset
3034 ]
3035
3036 screen-should-contain [
3037 . .
3038 .b .
3039 .c .
3040 . .
3041 ]
3042 memory-should-contain [
3043 3 <- 3
3044 4 <- 0
3045 ]
3046 ]
3047
3048 scenario editor-scrolls-down-on-right-arrow [
3049 local-scope
3050
3051 assume-screen 5/width, 4/height
3052
3053 s:text <- new [a
3054 b
3055 cdefgh]
3056 e:&:editor <- new-editor s, 0/left, 5/right
3057
3058 assume-console [
3059 left-click 3, 3
3060 press right-arrow
3061 ]
3062 run [
3063 editor-event-loop screen, console, e
3064 3:num/raw <- get *e, cursor-row:offset
3065 4:num/raw <- get *e, cursor-column:offset
3066 ]
3067
3068 screen-should-contain [
3069 . .
3070 .b .
3071 .cdef↩.
3072 .gh .
3073 ]
3074 memory-should-contain [
3075 3 <- 3
3076 4 <- 0
3077 ]
3078 ]
3079
3080 scenario editor-scrolls-down-on-right-arrow-2 [
3081 local-scope
3082
3083 assume-screen 5/width, 4/height
3084
3085 s:text <- new [a
3086 b
3087 c
3088 d]
3089 e:&:editor <- new-editor s, 0/left, 5/right
3090
3091 assume-console [
3092 left-click 3, 3
3093 press right-arrow
3094 ]
3095 run [
3096 editor-event-loop screen, console, e
3097 3:num/raw <- get *e, cursor-row:offset
3098 4:num/raw <- get *e, cursor-column:offset
3099 ]
3100
3101 screen-should-contain [
3102 . .
3103 .b .
3104 .c .
3105 .d .
3106 ]
3107 memory-should-contain [
3108 3 <- 3
3109 4 <- 0
3110 ]
3111 ]
3112
3113 scenario editor-scrolls-at-end-on-down-arrow [
3114 local-scope
3115 assume-screen 10/width, 5/height
3116 s:text <- new [abc
3117 de]
3118 e:&:editor <- new-editor s, 0/left, 10/right
3119 editor-render screen, e
3120 $clear-trace
3121
3122 assume-console [
3123 left-click 2, 0
3124 press down-arrow
3125 ]
3126 run [
3127 editor-event-loop screen, console, e
3128 3:num/raw <- get *e, cursor-row:offset
3129 4:num/raw <- get *e, cursor-column:offset
3130 ]
3131
3132 memory-should-contain [
3133 3 <- 2
3134 4 <- 0
3135 ]
3136 ]
3137
3138 scenario editor-combines-page-and-line-scroll [
3139 local-scope
3140
3141 assume-screen 10/width, 4/height
3142
3143 s:text <- new [a
3144 b
3145 c
3146 d
3147 e
3148 f
3149 g]
3150 e:&:editor <- new-editor s, 0/left, 5/right
3151 editor-render screen, e
3152
3153 assume-console [
3154 press page-down
3155 left-click 3, 0
3156 press down-arrow
3157 ]
3158 run [
3159 editor-event-loop screen, console, e
3160 ]
3161
3162 screen-should-contain [
3163 . .
3164 .d .
3165 .e .
3166 .f .
3167 ]
3168 ]
3169
3170
3171
3172 scenario editor-can-scroll-up-using-arrow-keys [
3173 local-scope
3174
3175 assume-screen 10/width, 4/height
3176
3177 s:text <- new [a
3178 b
3179 c
3180 d]
3181 e:&:editor <- new-editor s, 0/left, 10/right
3182 editor-render screen, e
3183 screen-should-contain [
3184 . .
3185 .a .
3186 .b .
3187 .c .
3188 ]
3189
3190 assume-console [
3191 press page-down
3192 press up-arrow
3193 ]
3194 run [
3195 editor-event-loop screen, console, e
3196 ]
3197
3198 screen-should-contain [
3199 . .
3200 .b .
3201 .c .
3202 .d .
3203 ]
3204 ]
3205
3206 after <scroll-up> [
3207 trace 10, [app], [scroll up]
3208 top-of-screen:&:duplex-list:char <- get *editor, top-of-screen:offset
3209 old-top:&:duplex-list:char <- copy top-of-screen
3210 top-of-screen <- before-previous-screen-line top-of-screen, editor
3211 *editor <- put *editor, top-of-screen:offset, top-of-screen
3212 no-movement?:bool <- equal old-top, top-of-screen
3213 return-if no-movement?, 0/don't-render
3214 ]
3215
3216 scenario editor-scrolls-up-past-wrapped-line-using-arrow-keys [
3217 local-scope
3218
3219 assume-screen 10/width, 4/height
3220
3221
3222 s:text <- new [abcdef
3223 g
3224 h
3225 i]
3226 e:&:editor <- new-editor s, 0/left, 5/right
3227 editor-render screen, e
3228 screen-should-contain [
3229 . .
3230 .abcd↩ .
3231 .ef .
3232 .g .
3233 ]
3234
3235 assume-console [
3236 press page-down
3237 ]
3238 run [
3239 editor-event-loop screen, console, e
3240 ]
3241 screen-should-contain [
3242 . .
3243 .g .
3244 .h .
3245 .i .
3246 ]
3247
3248 assume-console [
3249 press up-arrow
3250 ]
3251 run [
3252 editor-event-loop screen, console, e
3253 ]
3254
3255 screen-should-contain [
3256 . .
3257 .ef .
3258 .g .
3259 .h .
3260 ]
3261 ]
3262
3263 scenario editor-scrolls-up-past-wrapped-line-using-arrow-keys-2 [
3264 local-scope
3265
3266 assume-screen 10/width, 5/height
3267
3268 s:text <- new [abcdefghij
3269 k
3270 l
3271 m]
3272 e:&:editor <- new-editor s, 0/left, 5/right
3273 editor-render screen, e
3274
3275 assume-console [
3276 press page-down
3277 ]
3278 run [
3279 editor-event-loop screen, console, e
3280 ]
3281 screen-should-contain [
3282 . .
3283 .k .
3284 .l .
3285 .m .
3286 .╌╌╌╌╌ .
3287 ]
3288
3289 assume-console [
3290 press up-arrow
3291 ]
3292 run [
3293 editor-event-loop screen, console, e
3294 ]
3295
3296 screen-should-contain [
3297 . .
3298 .ij .
3299 .k .
3300 .l .
3301 .m .
3302 ]
3303
3304 assume-console [
3305 press up-arrow
3306 ]
3307 run [
3308 editor-event-loop screen, console, e
3309 ]
3310
3311 screen-should-contain [
3312 . .
3313 .efgh↩ .
3314 .ij .
3315 .k .
3316 .l .
3317 ]
3318
3319 assume-console [
3320 press up-arrow
3321 ]
3322 run [
3323 editor-event-loop screen, console, e
3324 ]
3325
3326 screen-should-contain [
3327 . .
3328 .abcd↩ .
3329 .efgh↩ .
3330 .ij .
3331 .k .
3332 ]
3333 ]
3334
3335
3336
3337 scenario editor-scrolls-up-past-wrapped-line-using-arrow-keys-3 [
3338 local-scope
3339
3340 assume-screen 10/width, 4/height
3341
3342
3343 s:text <- new [abcdef
3344 g
3345 h
3346 i]
3347 e:&:editor <- new-editor s, 0/left, 6/right
3348 editor-render screen, e
3349 screen-should-contain [
3350 . .
3351 .abcde↩ .
3352 .f .
3353 .g .
3354 ]
3355
3356 assume-console [
3357 press page-down
3358 ]
3359 run [
3360 editor-event-loop screen, console, e
3361 ]
3362 screen-should-contain [
3363 . .
3364 .g .
3365 .h .
3366 .i .
3367 ]
3368
3369 assume-console [
3370 press up-arrow
3371 ]
3372 run [
3373 editor-event-loop screen, console, e
3374 ]
3375
3376 screen-should-contain [
3377 . .
3378 .f .
3379 .g .
3380 .h .
3381 ]
3382 ]
3383
3384
3385 scenario editor-scrolls-up-past-wrapped-line-using-arrow-keys-4 [
3386 local-scope
3387 assume-screen 10/width, 4/height
3388
3389 s:text <- new [a
3390 b
3391
3392 c
3393 d
3394 e]
3395 e:&:editor <- new-editor s, 0/left, 6/right
3396 editor-render screen, e
3397 assume-console [
3398 press page-down
3399 ]
3400 run [
3401 editor-event-loop screen, console, e
3402 ]
3403 screen-should-contain [
3404 . .
3405 . .
3406 .c .
3407 .d .
3408 ]
3409 assume-console [
3410 press page-down
3411 ]
3412 run [
3413 editor-event-loop screen, console, e
3414 ]
3415 screen-should-contain [
3416 . .
3417 .d .
3418 .e .
3419 .╌╌╌╌╌╌ .
3420 ]
3421 assume-console [
3422 press page-up
3423 ]
3424 run [
3425 editor-event-loop screen, console, e
3426 ]
3427 screen-should-contain [
3428 . .
3429 . .
3430 .c .
3431 .d .
3432 ]
3433 ]
3434
3435 scenario editor-scrolls-up-on-left-arrow [
3436 local-scope
3437
3438 assume-screen 5/width, 4/height
3439
3440 s:text <- new [a
3441 b
3442 c
3443 d
3444 e]
3445 e:&:editor <- new-editor s, 0/left, 5/right
3446 editor-render screen, e
3447
3448 assume-console [
3449 press page-down
3450 ]
3451 run [
3452 editor-event-loop screen, console, e
3453 ]
3454 screen-should-contain [
3455 . .
3456 .c .
3457 .d .
3458 .e .
3459 ]
3460
3461 assume-console [
3462 press left-arrow
3463 ]
3464 run [
3465 editor-event-loop screen, console, e
3466 3:num/raw <- get *e, cursor-row:offset
3467 4:num/raw <- get *e, cursor-column:offset
3468 ]
3469
3470 screen-should-contain [
3471 . .
3472 .b .
3473 .c .
3474 .d .
3475 ]
3476 memory-should-contain [
3477 3 <- 1
3478 4 <- 1
3479 ]
3480 ]
3481
3482 scenario editor-can-scroll-up-to-start-of-file [
3483 local-scope
3484
3485 assume-screen 10/width, 4/height
3486
3487 s:text <- new [a
3488 b
3489 c
3490 d]
3491 e:&:editor <- new-editor s, 0/left, 10/right
3492 editor-render screen, e
3493 screen-should-contain [
3494 . .
3495 .a .
3496 .b .
3497 .c .
3498 ]
3499
3500
3501 assume-console [
3502 press page-down
3503 press up-arrow
3504 press up-arrow
3505 ]
3506 run [
3507 editor-event-loop screen, console, e
3508 ]
3509
3510 screen-should-contain [
3511 . .
3512 .a .
3513 .b .
3514 .c .
3515 ]
3516
3517 assume-console [
3518 press up-arrow
3519 ]
3520 run [
3521 editor-event-loop screen, console, e
3522 ]
3523
3524 screen-should-contain [
3525 . .
3526 .a .
3527 .b .
3528 .c .
3529 ]
3530 ]
3531
3532
3533
3534 scenario editor-can-scroll [
3535 local-scope
3536 assume-screen 10/width, 4/height
3537 s:text <- new [a
3538 b
3539 c
3540 d]
3541 e:&:editor <- new-editor s, 0/left, 10/right
3542 editor-render screen, e
3543 screen-should-contain [
3544 . .
3545 .a .
3546 .b .
3547 .c .
3548 ]
3549
3550 assume-console [
3551 press page-down
3552 ]
3553 run [
3554 editor-event-loop screen, console, e
3555 ]
3556
3557 screen-should-contain [
3558 . .
3559 .c .
3560 .d .
3561 .╌╌╌╌╌╌╌╌╌╌.
3562 ]
3563 ]
3564
3565 after <handle-special-character> [
3566 {
3567 page-down?:bool <- equal c, 6/ctrl-f
3568 break-unless page-down?
3569 old-top:&:duplex-list:char <- get *editor, top-of-screen:offset
3570 <begin-move-cursor>
3571 page-down editor
3572 undo-coalesce-tag:num <- copy 0/never
3573 <end-move-cursor>
3574 top-of-screen:&:duplex-list:char <- get *editor, top-of-screen:offset
3575 movement?:bool <- not-equal top-of-screen, old-top
3576 return movement?/go-render
3577 }
3578 ]
3579
3580 after <handle-special-key> [
3581 {
3582 page-down?:bool <- equal k, 65518/page-down
3583 break-unless page-down?
3584 old-top:&:duplex-list:char <- get *editor, top-of-screen:offset
3585 <begin-move-cursor>
3586 page-down editor
3587 undo-coalesce-tag:num <- copy 0/never
3588 <end-move-cursor>
3589 top-of-screen:&:duplex-list:char <- get *editor, top-of-screen:offset
3590 movement?:bool <- not-equal top-of-screen, old-top
3591 return movement?/go-render
3592 }
3593 ]
3594
3595
3596
3597 def page-down editor:&:editor -> editor:&:editor [
3598 local-scope
3599 load-inputs
3600
3601 bottom-of-screen:&:duplex-list:char <- get *editor, bottom-of-screen:offset
3602 return-unless bottom-of-screen
3603
3604 before-cursor:&:duplex-list:char <- get *editor, before-cursor:offset
3605 before-cursor:&:duplex-list:char <- prev bottom-of-screen
3606 *editor <- put *editor, before-cursor:offset, before-cursor
3607
3608 {
3609 last:char <- get *before-cursor, value:offset
3610 newline?:bool <- equal last, 10/newline
3611 break-unless newline?:bool
3612 before-cursor <- prev before-cursor
3613 *editor <- put *editor, before-cursor:offset, before-cursor
3614 }
3615
3616 move-to-start-of-line editor
3617 before-cursor <- get *editor, before-cursor:offset
3618 *editor <- put *editor, top-of-screen:offset, before-cursor
3619 ]
3620
3621
3622 def move-to-start-of-line editor:&:editor -> editor:&:editor [
3623 local-scope
3624 load-inputs
3625
3626 left:num <- get *editor, left:offset
3627 cursor-column:num <- copy left
3628 *editor <- put *editor, cursor-column:offset, cursor-column
3629
3630 before-cursor:&:duplex-list:char <- get *editor, before-cursor:offset
3631 init:&:duplex-list:char <- get *editor, data:offset
3632
3633 {
3634 at-start-of-text?:bool <- equal before-cursor, init
3635 break-if at-start-of-text?
3636 prev:char <- get *before-cursor, value:offset
3637 at-start-of-line?:bool <- equal prev, 10/newline
3638 break-if at-start-of-line?
3639 before-cursor <- prev before-cursor
3640 *editor <- put *editor, before-cursor:offset, before-cursor
3641 assert before-cursor, [move-to-start-of-line tried to move before start of text]
3642 loop
3643 }
3644 ]
3645
3646 scenario editor-does-not-scroll-past-end [
3647 local-scope
3648 assume-screen 10/width, 4/height
3649 s:text <- new [a
3650 b]
3651 e:&:editor <- new-editor s, 0/left, 10/right
3652 editor-render screen, e
3653 screen-should-contain [
3654 . .
3655 .a .
3656 .b .
3657 .╌╌╌╌╌╌╌╌╌╌.
3658 ]
3659
3660 assume-console [
3661 press page-down
3662 ]
3663 run [
3664 editor-event-loop screen, console, e
3665 ]
3666
3667 screen-should-contain [
3668 . .
3669 .a .
3670 .b .
3671 .╌╌╌╌╌╌╌╌╌╌.
3672 ]
3673 ]
3674
3675 scenario editor-starts-next-page-at-start-of-wrapped-line [
3676 local-scope
3677
3678 assume-screen 10/width, 4/height
3679
3680 s:text <- new [a
3681 b
3682 cdefgh]
3683
3684 e:&:editor <- new-editor s, 0/left, 4/right
3685 editor-render screen, e
3686
3687 screen-should-contain [
3688 . .
3689 .a .
3690 .b .
3691 .cde↩ .
3692 ]
3693
3694 assume-console [
3695 press page-down
3696 ]
3697 run [
3698 editor-event-loop screen, console, e
3699 ]
3700
3701 screen-should-contain [
3702 . .
3703 .cde↩ .
3704 .fgh .
3705 .╌╌╌╌ .
3706 ]
3707 ]
3708
3709 scenario editor-starts-next-page-at-start-of-wrapped-line-2 [
3710 local-scope
3711
3712 assume-screen 10/width, 4/height
3713
3714
3715 s:text <- new [a
3716 bcdefgh]
3717 e:&:editor <- new-editor s, 0/left, 4/right
3718 editor-render screen, e
3719
3720 screen-should-contain [
3721 . .
3722 .a .
3723 .bcd↩ .
3724 .efg↩ .
3725 ]
3726
3727 assume-console [
3728 press page-down
3729 ]
3730 run [
3731 editor-event-loop screen, console, e
3732 ]
3733
3734 screen-should-contain [
3735 . .
3736 .bcd↩ .
3737 .efg↩ .
3738 .h .
3739 ]
3740 ]
3741
3742
3743
3744 scenario editor-can-scroll-up [
3745 local-scope
3746 assume-screen 10/width, 4/height
3747 s:text <- new [a
3748 b
3749 c
3750 d]
3751 e:&:editor <- new-editor s, 0/left, 10/right
3752 editor-render screen, e
3753 screen-should-contain [
3754 . .
3755 .a .
3756 .b .
3757 .c .
3758 ]
3759
3760 assume-console [
3761 press page-down
3762 ]
3763 run [
3764 editor-event-loop screen, console, e
3765 ]
3766
3767 screen-should-contain [
3768 . .
3769 .c .
3770 .d .
3771 .╌╌╌╌╌╌╌╌╌╌.
3772 ]
3773
3774 assume-console [
3775 press page-up
3776 ]
3777 run [
3778 editor-event-loop screen, console, e
3779 ]
3780
3781 screen-should-contain [
3782 . .
3783 .a .
3784 .b .
3785 .c .
3786 ]
3787 ]
3788
3789 after <handle-special-character> [
3790 {
3791 page-up?:bool <- equal c, 2/ctrl-b
3792 break-unless page-up?
3793 old-top:&:duplex-list:char <- get *editor, top-of-screen:offset
3794 <begin-move-cursor>
3795 editor <- page-up editor, screen-height
3796 undo-coalesce-tag:num <- copy 0/never
3797 <end-move-cursor>
3798 top-of-screen:&:duplex-list:char <- get *editor, top-of-screen:offset
3799 movement?:bool <- not-equal top-of-screen, old-top
3800 return movement?/go-render
3801 }
3802 ]
3803
3804 after <handle-special-key> [
3805 {
3806 page-up?:bool <- equal k, 65519/page-up
3807 break-unless page-up?
3808 old-top:&:duplex-list:char <- get *editor, top-of-screen:offset
3809 <begin-move-cursor>
3810 editor <- page-up editor, screen-height
3811 undo-coalesce-tag:num <- copy 0/never
3812 <end-move-cursor>
3813 top-of-screen:&:duplex-list:char <- get *editor, top-of-screen:offset
3814 movement?:bool <- not-equal top-of-screen, old-top
3815
3816 return movement?/go-render
3817 }
3818 ]
3819
3820 def page-up editor:&:editor, screen-height:num -> editor:&:editor [
3821 local-scope
3822 load-inputs
3823 max:num <- subtract screen-height, 1/menu-bar, 1/overlapping-line
3824 count:num <- copy 0
3825 top-of-screen:&:duplex-list:char <- get *editor, top-of-screen:offset
3826 {
3827 done?:bool <- greater-or-equal count, max
3828 break-if done?
3829 prev:&:duplex-list:char <- before-previous-screen-line top-of-screen, editor
3830 break-unless prev
3831 top-of-screen <- copy prev
3832 *editor <- put *editor, top-of-screen:offset, top-of-screen
3833 count <- add count, 1
3834 loop
3835 }
3836 ]
3837
3838 scenario editor-can-scroll-up-multiple-pages [
3839 local-scope
3840
3841 assume-screen 10/width, 4/height
3842
3843 s:text <- new [a
3844 b
3845 c
3846 d
3847 e
3848 f
3849 g
3850 h]
3851 e:&:editor <- new-editor s, 0/left, 10/right
3852 editor-render screen, e
3853 screen-should-contain [
3854 . .
3855 .a .
3856 .b .
3857 .c .
3858 ]
3859
3860 assume-console [
3861 press page-down
3862 press page-down
3863 ]
3864 run [
3865 editor-event-loop screen, console, e
3866 ]
3867
3868 screen-should-contain [
3869 . .
3870 .e .
3871 .f .
3872 .g .
3873 ]
3874
3875 assume-console [
3876 press page-up
3877 ]
3878 run [
3879 editor-event-loop screen, console, e
3880 ]
3881
3882 screen-should-contain [
3883 . .
3884 .c .
3885 .d .
3886 .e .
3887 ]
3888
3889 assume-console [
3890 press page-up
3891 ]
3892 run [
3893 editor-event-loop screen, console, e
3894 ]
3895
3896 screen-should-contain [
3897 . .
3898 .a .
3899 .b .
3900 .c .
3901 ]
3902 ]
3903
3904 scenario editor-can-scroll-up-wrapped-lines [
3905 local-scope
3906
3907 assume-screen 10/width, 6/height
3908
3909 s:text <- new [a
3910 b
3911 cdefgh
3912 i
3913 j
3914 k
3915 l
3916 m
3917 n
3918 o]
3919
3920 e:&:editor <- new-editor s, 0/left, 4/right
3921 editor-render screen, e
3922
3923 screen-should-contain [
3924 . .
3925 .a .
3926 .b .
3927 .cde↩ .
3928 .fgh .
3929 .i .
3930 ]
3931
3932 assume-console [
3933 press page-down
3934 left-click 5, 0
3935 press down-arrow
3936 ]
3937 run [
3938 editor-event-loop screen, console, e
3939 ]
3940
3941 screen-should-contain [
3942 . .
3943 .j .
3944 .k .
3945 .l .
3946 .m .
3947 .n .
3948 ]
3949
3950 assume-console [
3951 press page-up
3952 ]
3953 run [
3954 editor-event-loop screen, console, e
3955 ]
3956
3957 screen-should-contain [
3958 . .
3959 .b .
3960 .cde↩ .
3961 .fgh .
3962 .i .
3963 .j .
3964 ]
3965 ]
3966
3967 scenario editor-can-scroll-up-wrapped-lines-2 [
3968 local-scope
3969
3970 assume-screen 10/width, 4/height
3971
3972
3973 s:text <- new [a
3974 bcdefgh]
3975 e:&:editor <- new-editor s, 0/left, 4/right
3976 editor-render screen, e
3977
3978 screen-should-contain [
3979 . .
3980 .a .
3981 .bcd↩ .
3982 .efg↩ .
3983 ]
3984
3985 assume-console [
3986 press page-down
3987 ]
3988 run [
3989 editor-event-loop screen, console, e
3990 ]
3991
3992 screen-should-contain [
3993 . .
3994 .bcd↩ .
3995 .efg↩ .
3996 .h .
3997 ]
3998
3999 assume-console [
4000 press page-up
4001 ]
4002 run [
4003 editor-event-loop screen, console, e
4004 ]
4005
4006 screen-should-contain [
4007 . .
4008 .a .
4009 .bcd↩ .
4010 .efg↩ .
4011 ]
4012 ]
4013
4014 scenario editor-can-scroll-up-past-nonempty-lines [
4015 local-scope
4016 assume-screen 10/width, 4/height
4017
4018 s:text <- new [axx
4019 bxx
4020 cxx
4021 dxx
4022 exx
4023 fxx
4024 gxx
4025 hxx
4026 ]
4027 e:&:editor <- new-editor s, 0/left, 4/right
4028 editor-render screen, e
4029 screen-should-contain [
4030 . .
4031 .axx .
4032 .bxx .
4033 .cxx .
4034 ]
4035 assume-console [
4036 press page-down
4037 ]
4038 run [
4039 editor-event-loop screen, console, e
4040 ]
4041 screen-should-contain [
4042 . .
4043 .cxx .
4044 .dxx .
4045 .exx .
4046 ]
4047 assume-console [
4048 press page-down
4049 ]
4050 run [
4051 editor-event-loop screen, console, e
4052 ]
4053 screen-should-contain [
4054 . .
4055 .exx .
4056 .fxx .
4057 .gxx .
4058 ]
4059
4060 assume-console [
4061 press page-up
4062 ]
4063 run [
4064 editor-event-loop screen, console, e
4065 ]
4066 screen-should-contain [
4067 . .
4068 .cxx .
4069 .dxx .
4070 .exx .
4071 ]
4072 ]
4073
4074 scenario editor-can-scroll-up-past-empty-lines [
4075 local-scope
4076 assume-screen 10/width, 4/height
4077
4078 s:text <- new [axy
4079 bxy
4080 cxy
4081
4082 dxy
4083 exy
4084 fxy
4085 gxy
4086 ]
4087 e:&:editor <- new-editor s, 0/left, 4/right
4088 editor-render screen, e
4089 screen-should-contain [
4090 . .
4091 .axy .
4092 .bxy .
4093 .cxy .
4094 ]
4095 assume-console [
4096 press page-down
4097 ]
4098 run [
4099 editor-event-loop screen, console, e
4100 ]
4101 screen-should-contain [
4102 . .
4103 .cxy .
4104 . .
4105 .dxy .
4106 ]
4107 assume-console [
4108 press page-down
4109 ]
4110 run [
4111 editor-event-loop screen, console, e
4112 ]
4113 screen-should-contain [
4114 . .
4115 .dxy .
4116 .exy .
4117 .fxy .
4118 ]
4119
4120 assume-console [
4121 press page-up
4122 ]
4123 run [
4124 editor-event-loop screen, console, e
4125 ]
4126 screen-should-contain [
4127 . .
4128 .cxy .
4129 . .
4130 .dxy .
4131 ]
4132 ]
4133
4134
4135
4136
4137 after <handle-special-character> [
4138 {
4139 scroll-up?:bool <- equal c, 19/ctrl-s
4140 break-unless scroll-up?
4141 <begin-move-cursor>
4142 go-render?:bool, editor <- line-up editor, screen-height
4143 undo-coalesce-tag:num <- copy 5/line-up
4144 <end-move-cursor>
4145 return go-render?
4146 }
4147 ]
4148
4149 def line-up editor:&:editor, screen-height:num -> go-render?:bool, editor:&:editor [
4150 local-scope
4151 load-inputs
4152 left:num <- get *editor, left:offset
4153 right:num <- get *editor, right:offset
4154 max:num <- subtract right, left
4155 old-top:&:duplex-list:char <- get *editor, top-of-screen:offset
4156 new-top:&:duplex-list:char <- before-start-of-next-line old-top, max
4157 movement?:bool <- not-equal old-top, new-top
4158 {
4159 break-unless movement?
4160 *editor <- put *editor, top-of-screen:offset, new-top
4161 }
4162 return movement?
4163 ]
4164
4165
4166
4167
4168 after <handle-special-character> [
4169 {
4170 scroll-down?:bool <- equal c, 24/ctrl-x
4171 break-unless scroll-down?
4172 <begin-move-cursor>
4173 go-render?:bool, editor <- line-down editor, screen-height
4174 undo-coalesce-tag:num <- copy 6/line-down
4175 <end-move-cursor>
4176 return go-render?
4177 }
4178 ]
4179
4180 def line-down editor:&:editor, screen-height:num -> go-render?:bool, editor:&:editor [
4181 local-scope
4182 load-inputs
4183 old-top:&:duplex-list:char <- get *editor, top-of-screen:offset
4184 new-top:&:duplex-list:char <- before-previous-screen-line old-top, editor
4185 movement?:bool <- not-equal old-top, new-top
4186 {
4187 break-unless movement?
4188 *editor <- put *editor, top-of-screen:offset, new-top
4189 }
4190 return movement?
4191 ]
4192
4193
4194
4195
4196 after <handle-special-character> [
4197 {
4198 scroll-down?:bool <- equal c, 20/ctrl-t
4199 break-unless scroll-down?
4200 <begin-move-cursor>
4201 old-top:&:duplex-list:char <- get *editor, top-of-screen:offset
4202 cursor:&:duplex-list:char <- get *editor, before-cursor:offset
4203 cursor <- next cursor
4204 new-top:&:duplex-list:char <- before-previous-screen-line cursor, editor
4205 *editor <- put *editor, top-of-screen:offset, new-top
4206 *editor <- put *editor, cursor-row:offset, 1
4207 go-render?:bool <- not-equal new-top, old-top
4208 undo-coalesce-tag:num <- copy 0/never
4209 <end-move-cursor>
4210 return go-render?
4211 }
4212 ]
4213
4214
4215
4216 after <handle-special-character> [
4217 {
4218 comment-toggle?:bool <- equal c, 31/ctrl-slash
4219 break-unless comment-toggle?
4220 cursor-column:num <- get *editor, cursor-column:offset
4221 data:&:duplex-list:char <- get *editor, data:offset
4222 <begin-insert-character>
4223 before-line-start:&:duplex-list:char <- before-start-of-screen-line editor
4224 line-start:&:duplex-list:char <- next before-line-start
4225 commented-out?:bool <- match line-start, [#? ]
4226 {
4227 break-unless commented-out?
4228
4229 data <- remove line-start, 3/length-comment-prefix, data
4230 cursor-column <- subtract cursor-column, 3/length-comment-prefix
4231 *editor <- put *editor, cursor-column:offset, cursor-column
4232 go-render? <- render-line-from-start screen, editor, 3/size-of-comment-leader
4233 }
4234 {
4235 break-if commented-out?
4236
4237 insert before-line-start, [#? ]
4238 cursor-column <- add cursor-column, 3/length-comment-prefix
4239 *editor <- put *editor, cursor-column:offset, cursor-column
4240 go-render? <- render-line-from-start screen, editor, 0
4241 }
4242 <end-insert-character>
4243 return
4244 }
4245 ]
4246
4247
4248
4249
4250 def render-line-from-start screen:&:screen, editor:&:editor, right-margin:num -> go-render?:bool, screen:&:screen [
4251 local-scope
4252 load-inputs
4253 before-line-start:&:duplex-list:char <- before-start-of-screen-line editor
4254 line-start:&:duplex-list:char <- next before-line-start
4255 color:num <- copy 7/white
4256 left:num <- get *editor, left:offset
4257 cursor-row:num <- get *editor, cursor-row:offset
4258 screen <- move-cursor screen, cursor-row, left
4259 right:num <- get *editor, right:offset
4260 end:num <- subtract right, right-margin
4261 i:num <- copy 0
4262 curr:&:duplex-list:char <- copy line-start
4263 {
4264 render-all?:bool <- greater-or-equal i, end
4265 return-if render-all?, 1/go-render
4266 break-unless curr
4267 c:char <- get *curr, value:offset
4268 newline?:bool <- equal c, 10/newline
4269 break-if newline?
4270 color <- get-color color, c
4271 print screen, c, color
4272 curr <- next curr
4273 i <- add i, 1
4274 loop
4275 }
4276 clear-line-until screen, right
4277 return 0/dont-render
4278 ]
4279
4280 def before-start-of-screen-line editor:&:editor -> result:&:duplex-list:char [
4281 local-scope
4282 load-inputs
4283 cursor:&:duplex-list:char <- get *editor, before-cursor:offset
4284 {
4285 next:&:duplex-list:char <- next cursor
4286 break-unless next
4287 cursor <- copy next
4288 }
4289 result <- before-previous-screen-line cursor, editor
4290 ]
4291
4292 scenario editor-comments-empty-line [
4293 local-scope
4294 assume-screen 10/width, 5/height
4295 e:&:editor <- new-editor [], 0/left, 5/right
4296 editor-render screen, e
4297 $clear-trace
4298 assume-console [
4299 press ctrl-slash
4300 ]
4301 run [
4302 editor-event-loop screen, console, e
4303 4:num/raw <- get *e, cursor-row:offset
4304 5:num/raw <- get *e, cursor-column:offset
4305 ]
4306 screen-should-contain [
4307 . .
4308 .#? .
4309 .╌╌╌╌╌ .
4310 . .
4311 ]
4312 memory-should-contain [
4313 4 <- 1
4314 5 <- 3
4315 ]
4316 check-trace-count-for-label 5, [print-character]
4317 ]
4318
4319 scenario editor-comments-at-start-of-contents [
4320 local-scope
4321 assume-screen 10/width, 5/height
4322 e:&:editor <- new-editor [ab], 0/left, 10/right
4323 editor-render screen, e
4324 $clear-trace
4325 assume-console [
4326 press ctrl-slash
4327 ]
4328 run [
4329 editor-event-loop screen, console, e
4330 4:num/raw <- get *e, cursor-row:offset
4331 5:num/raw <- get *e, cursor-column:offset
4332 ]
4333 screen-should-contain [
4334 . .
4335 .#? ab .
4336 .╌╌╌╌╌╌╌╌╌╌.
4337 . .
4338 ]
4339 memory-should-contain [
4340 4 <- 1
4341 5 <- 3
4342 ]
4343 check-trace-count-for-label 10, [print-character]
4344 ]
4345
4346 scenario editor-comments-at-end-of-contents [
4347 local-scope
4348 assume-screen 10/width, 5/height
4349 e:&:editor <- new-editor [ab], 0/left, 10/right
4350 editor-render screen, e
4351 $clear-trace
4352 assume-console [
4353 left-click 1, 7
4354 press ctrl-slash
4355 ]
4356 run [
4357 editor-event-loop screen, console, e
4358 4:num/raw <- get *e, cursor-row:offset
4359 5:num/raw <- get *e, cursor-column:offset
4360 ]
4361 screen-should-contain [
4362 . .
4363 .#? ab .
4364 .╌╌╌╌╌╌╌╌╌╌.
4365 . .
4366 ]
4367 memory-should-contain [
4368 4 <- 1
4369 5 <- 5
4370 ]
4371 check-trace-count-for-label 10, [print-character]
4372
4373 $clear-trace
4374 assume-console [
4375 press ctrl-slash
4376 ]
4377 run [
4378 editor-event-loop screen, console, e
4379 4:num/raw <- get *e, cursor-row:offset
4380 5:num/raw <- get *e, cursor-column:offset
4381 ]
4382 screen-should-contain [
4383 . .
4384 .ab .
4385 .╌╌╌╌╌╌╌╌╌╌.
4386 . .
4387 ]
4388 check-trace-count-for-label 10, [print-character]
4389 ]
4390
4391 scenario editor-comments-almost-wrapping-line [
4392 local-scope
4393 assume-screen 10/width, 5/height
4394
4395 e:&:editor <- new-editor [abcd], 0/left, 5/right
4396 editor-render screen, e
4397 screen-should-contain [
4398 . .
4399 .abcd .
4400 .╌╌╌╌╌ .
4401 . .
4402 ]
4403 $clear-trace
4404
4405 assume-console [
4406 left-click 1, 7
4407 press ctrl-slash
4408 ]
4409 run [
4410 editor-event-loop screen, console, e
4411 ]
4412 screen-should-contain [
4413 . .
4414 .#? a↩ .
4415 .bcd .
4416 .╌╌╌╌╌ .
4417 . .
4418 ]
4419 ]
4420
4421 scenario editor-uncomments-just-wrapping-line [
4422 local-scope
4423 assume-screen 10/width, 5/height
4424
4425 e:&:editor <- new-editor [#? ab], 0/left, 5/right
4426 editor-render screen, e
4427 screen-should-contain [
4428 . .
4429 .#? a↩ .
4430 .b .
4431 .╌╌╌╌╌ .
4432 . .
4433 ]
4434 $clear-trace
4435
4436 assume-console [
4437 left-click 1, 7
4438 press ctrl-slash
4439 ]
4440 run [
4441 editor-event-loop screen, console, e
4442 ]
4443 screen-should-contain [
4444 . .
4445 .ab .
4446 .╌╌╌╌╌ .
4447 . .
4448 ]
4449 ]