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
11 s:text <- new [ab
12 cd]
13 e:&:editor <- new-editor s, 0/left, 5/right
14 assume-console [
15 press tab
16 ]
17 run [
18 editor-event-loop screen, console, e
19 ]
20 screen-should-contain [
21 . .
22 . ab .
23 .cd .
24 ]
25 ]
26
27 after <handle-special-character> [
28 {
29 tab?:bool <- equal c, 9/tab
30 break-unless tab?
31 <insert-character-begin>
32 insert-at-cursor editor, 32/space, screen
33 insert-at-cursor editor, 32/space, screen
34 <insert-character-end>
35 return 1/go-render
36 }
37 ]
38
39
40
41 scenario editor-handles-backspace-key [
42 local-scope
43 assume-screen 10/width, 5/height
44 e:&:editor <- new-editor [abc], 0/left, 10/right
45 editor-render screen, e
46 $clear-trace
47 assume-console [
48 left-click 1, 1
49 press backspace
50 ]
51 run [
52 editor-event-loop screen, console, e
53 4:num/raw <- get *e, cursor-row:offset
54 5:num/raw <- get *e, cursor-column:offset
55 ]
56 screen-should-contain [
57 . .
58 .bc .
59 .╌╌╌╌╌╌╌╌╌╌.
60 . .
61 ]
62 memory-should-contain [
63 4 <- 1
64 5 <- 0
65 ]
66 check-trace-count-for-label 3, [print-character]
67 ]
68
69 after <handle-special-character> [
70 {
71 delete-previous-character?:bool <- equal c, 8/backspace
72 break-unless delete-previous-character?
73 <backspace-character-begin>
74 go-render?:bool, backspaced-cell:&:duplex-list:char <- delete-before-cursor editor, screen
75 <backspace-character-end>
76 return
77 }
78 ]
79
80
81
82
83 def delete-before-cursor editor:&:editor, screen:&:screen -> go-render?:bool, backspaced-cell:&:duplex-list:char, editor:&:editor, screen:&:screen [
84 local-scope
85 load-ingredients
86 before-cursor:&:duplex-list:char <- get *editor, before-cursor:offset
87 data:&:duplex-list:char <- get *editor, data:offset
88
89 prev:&:duplex-list:char <- prev before-cursor
90 return-unless prev, 0/no-more-render, 0/nothing-deleted
91 trace 10, [app], [delete-before-cursor]
92 original-row:num <- get *editor, cursor-row:offset
93 scroll?:bool <- move-cursor-coordinates-left editor
94 backspaced-cell:&:duplex-list:char <- copy before-cursor
95 data <- remove before-cursor, data
96 before-cursor <- copy prev
97 *editor <- put *editor, before-cursor:offset, before-cursor
98 return-if scroll?, 1/go-render
99 screen-width:num <- screen-width screen
100 cursor-row:num <- get *editor, cursor-row:offset
101 cursor-column:num <- get *editor, cursor-column:offset
102
103 same-row?:bool <- equal cursor-row, original-row
104 return-unless same-row?, 1/go-render
105 left:num <- get *editor, left:offset
106 right:num <- get *editor, right:offset
107 curr:&:duplex-list:char <- next before-cursor
108 screen <- move-cursor screen, cursor-row, cursor-column
109 curr-column:num <- copy cursor-column
110 {
111
112 at-right?:bool <- greater-or-equal curr-column, right
113 return-if at-right?, 1/go-render
114 break-unless curr
115
116 currc:char <- get *curr, value:offset
117 at-newline?:bool <- equal currc, 10/newline
118 break-if at-newline?
119 screen <- print screen, currc
120 curr-column <- add curr-column, 1
121 curr <- next curr
122 loop
123 }
124
125 space:char <- copy 32/space
126 screen <- print screen, space
127 go-render? <- copy 0/false
128 ]
129
130 def move-cursor-coordinates-left editor:&:editor -> go-render?:bool, editor:&:editor [
131 local-scope
132 load-ingredients
133 go-render?:bool <- copy 0/false
134 before-cursor:&:duplex-list:char <- get *editor, before-cursor:offset
135 cursor-row:num <- get *editor, cursor-row:offset
136 cursor-column:num <- get *editor, cursor-column:offset
137 left:num <- get *editor, left:offset
138
139 {
140 at-left-margin?:bool <- equal cursor-column, left
141 break-if at-left-margin?
142 trace 10, [app], [decrementing cursor column]
143 cursor-column <- subtract cursor-column, 1
144 *editor <- put *editor, cursor-column:offset, cursor-column
145 return
146 }
147
148 top-of-screen?:bool <- equal cursor-row, 1
149 {
150 break-if top-of-screen?
151 cursor-row <- subtract cursor-row, 1
152 *editor <- put *editor, cursor-row:offset, cursor-row
153 }
154 {
155 break-unless top-of-screen?
156 <scroll-up>
157 go-render? <- copy 1/true
158 }
159 {
160
161 previous-character:char <- get *before-cursor, value:offset
162 previous-character-is-newline?:bool <- equal previous-character, 10/newline
163 break-unless previous-character-is-newline?
164
165 trace 10, [app], [switching to previous line]
166 d:&:duplex-list:char <- get *editor, data:offset
167 end-of-line:num <- previous-line-length before-cursor, d
168 right:num <- get *editor, right:offset
169 width:num <- subtract right, left
170 wrap?:bool <- greater-than end-of-line, width
171 {
172 break-unless wrap?
173 _, column-offset:num <- divide-with-remainder end-of-line, width
174 cursor-column <- add left, column-offset
175 *editor <- put *editor, cursor-column:offset, cursor-column
176 }
177 {
178 break-if wrap?
179 cursor-column <- add left, end-of-line
180 *editor <- put *editor, cursor-column:offset, cursor-column
181 }
182 return
183 }
184
185 trace 10, [app], [wrapping to previous line]
186 right:num <- get *editor, right:offset
187 cursor-column <- subtract right, 1
188 *editor <- put *editor, cursor-column:offset, cursor-column
189 ]
190
191
192
193 def previous-line-length curr:&:duplex-list:char, start:&:duplex-list:char -> result:num [
194 local-scope
195 load-ingredients
196 result:num <- copy 0
197 return-unless curr
198 at-start?:bool <- equal curr, start
199 return-if at-start?
200 {
201 curr <- prev curr
202 break-unless curr
203 at-start?:bool <- equal curr, start
204 break-if at-start?
205 c:char <- get *curr, value:offset
206 at-newline?:bool <- equal c, 10/newline
207 break-if at-newline?
208 result <- add result, 1
209 loop
210 }
211 ]
212
213 scenario editor-clears-last-line-on-backspace [
214 local-scope
215 assume-screen 10/width, 5/height
216
217 s:text <- new [ab
218 cd]
219 e:&:editor <- new-editor s, 0/left, 10/right
220 assume-console [
221 left-click 2, 0
222 press backspace
223 ]
224 run [
225 editor-event-loop screen, console, e
226 4:num/raw <- get *e, cursor-row:offset
227 5:num/raw <- get *e, cursor-column:offset
228 ]
229 screen-should-contain [
230 . .
231 .abcd .
232 .╌╌╌╌╌╌╌╌╌╌.
233 . .
234 ]
235 memory-should-contain [
236 4 <- 1
237 5 <- 2
238 ]
239 ]
240
241 scenario editor-joins-and-wraps-lines-on-backspace [
242 local-scope
243 assume-screen 10/width, 5/height
244
245 s:text <- new [abc def
246 ghi jkl]
247 e:&:editor <- new-editor s, 0/left, 10/right
248 editor-render screen, e
249 $clear-trace
250
251 assume-console [
252 left-click 2, 0
253 press backspace
254 ]
255 run [
256 editor-event-loop screen, console, e
257 ]
258
259 screen-should-contain [
260 . .
261 .abc defgh↩.
262 .i jkl .
263 .╌╌╌╌╌╌╌╌╌╌.
264 . .
265 ]
266 ]
267
268 scenario editor-wraps-long-lines-on-backspace [
269 local-scope
270 assume-screen 10/width, 5/height
271
272 e:&:editor <- new-editor [abc def ghij], 0/left, 8/right
273 editor-render screen, e
274
275 screen-should-contain [
276 . .
277 .abc def↩ .
278 . ghij .
279 .╌╌╌╌╌╌╌╌ .
280 ]
281 $clear-trace
282
283 assume-console [
284 left-click 1, 4
285 press backspace
286 ]
287 run [
288 editor-event-loop screen, console, e
289 ]
290
291 screen-should-contain [
292 . .
293 .abcdef ↩ .
294 .ghij .
295 .╌╌╌╌╌╌╌╌ .
296 . .
297 ]
298 ]
299
300
301
302 scenario editor-handles-delete-key [
303 local-scope
304 assume-screen 10/width, 5/height
305 e:&:editor <- new-editor [abc], 0/left, 10/right
306 editor-render screen, e
307 $clear-trace
308 assume-console [
309 press delete
310 ]
311 run [
312 editor-event-loop screen, console, e
313 ]
314 screen-should-contain [
315 . .
316 .bc .
317 .╌╌╌╌╌╌╌╌╌╌.
318 . .
319 ]
320 check-trace-count-for-label 3, [print-character]
321 $clear-trace
322 assume-console [
323 press delete
324 ]
325 run [
326 editor-event-loop screen, console, e
327 ]
328 screen-should-contain [
329 . .
330 .c .
331 .╌╌╌╌╌╌╌╌╌╌.
332 . .
333 ]
334 check-trace-count-for-label 2, [print-character]
335 ]
336
337 after <handle-special-key> [
338 {
339 delete-next-character?:bool <- equal k, 65522/delete
340 break-unless delete-next-character?
341 <delete-character-begin>
342 go-render?:bool, deleted-cell:&:duplex-list:char <- delete-at-cursor editor, screen
343 <delete-character-end>
344 return
345 }
346 ]
347
348 def delete-at-cursor editor:&:editor, screen:&:screen -> go-render?:bool, deleted-cell:&:duplex-list:char, editor:&:editor, screen:&:screen [
349 local-scope
350 load-ingredients
351 before-cursor:&:duplex-list:char <- get *editor, before-cursor:offset
352 data:&:duplex-list:char <- get *editor, data:offset
353 deleted-cell:&:duplex-list:char <- next before-cursor
354 return-unless deleted-cell, 0/don't-render
355 currc:char <- get *deleted-cell, value:offset
356 data <- remove deleted-cell, data
357 deleted-newline?:bool <- equal currc, 10/newline
358 return-if deleted-newline?, 1/go-render
359
360 curr:&:duplex-list:char <- next before-cursor
361 cursor-row:num <- get *editor, cursor-row:offset
362 cursor-column:num <- get *editor, cursor-column:offset
363 screen <- move-cursor screen, cursor-row, cursor-column
364 curr-column:num <- copy cursor-column
365 screen-width:num <- screen-width screen
366 {
367
368 at-right?:bool <- greater-or-equal curr-column, screen-width
369 return-if at-right?, 1/go-render
370 break-unless curr
371
372 currc:char <- get *curr, value:offset
373 at-newline?:bool <- equal currc, 10/newline
374 break-if at-newline?
375 screen <- print screen, currc
376 curr-column <- add curr-column, 1
377 curr <- next curr
378 loop
379 }
380
381 space:char <- copy 32/space
382 screen <- print screen, space
383 go-render? <- copy 0/false
384 ]
385
386
387
388 scenario editor-moves-cursor-right-with-key [
389 local-scope
390 assume-screen 10/width, 5/height
391 e:&:editor <- new-editor [abc], 0/left, 10/right
392 editor-render screen, e
393 $clear-trace
394 assume-console [
395 press right-arrow
396 type [0]
397 ]
398 run [
399 editor-event-loop screen, console, e
400 ]
401 screen-should-contain [
402 . .
403 .a0bc .
404 .╌╌╌╌╌╌╌╌╌╌.
405 . .
406 ]
407 check-trace-count-for-label 3, [print-character]
408 ]
409
410 after <handle-special-key> [
411 {
412 move-to-next-character?:bool <- equal k, 65514/right-arrow
413 break-unless move-to-next-character?
414
415 next-cursor:&:duplex-list:char <- next before-cursor
416 break-unless next-cursor
417
418 <move-cursor-begin>
419 before-cursor <- copy next-cursor
420 *editor <- put *editor, before-cursor:offset, before-cursor
421 go-render?:bool <- move-cursor-coordinates-right editor, screen-height
422 screen <- move-cursor screen, cursor-row, cursor-column
423 undo-coalesce-tag:num <- copy 2/right-arrow
424 <move-cursor-end>
425 return
426 }
427 ]
428
429 def move-cursor-coordinates-right editor:&:editor, screen-height:num -> go-render?:bool, editor:&:editor [
430 local-scope
431 load-ingredients
432 before-cursor:&:duplex-list:char <- get *editor before-cursor:offset
433 cursor-row:num <- get *editor, cursor-row:offset
434 cursor-column:num <- get *editor, cursor-column:offset
435 left:num <- get *editor, left:offset
436 right:num <- get *editor, right:offset
437
438 {
439 old-cursor-character:char <- get *before-cursor, value:offset
440 was-at-newline?:bool <- equal old-cursor-character, 10/newline
441 break-unless was-at-newline?
442 cursor-row <- add cursor-row, 1
443 *editor <- put *editor, cursor-row:offset, cursor-row
444 cursor-column <- copy left
445 *editor <- put *editor, cursor-column:offset, cursor-column
446 below-screen?:bool <- greater-or-equal cursor-row, screen-height
447 return-unless below-screen?, 0/don't-render
448 <scroll-down>
449 cursor-row <- subtract cursor-row, 1
450 *editor <- put *editor, cursor-row:offset, cursor-row
451 return 1/go-render
452 }
453
454 {
455
456 wrap-column:num <- subtract right, 1
457 at-wrap?:bool <- equal cursor-column, wrap-column
458 break-unless at-wrap?
459
460 next:&:duplex-list:char <- next before-cursor
461 break-unless next
462 next-character:char <- get *next, value:offset
463 newline?:bool <- equal next-character, 10/newline
464 break-if newline?
465 cursor-row <- add cursor-row, 1
466 *editor <- put *editor, cursor-row:offset, cursor-row
467 cursor-column <- copy left
468 *editor <- put *editor, cursor-column:offset, cursor-column
469 below-screen?:bool <- greater-or-equal cursor-row, screen-height
470 return-unless below-screen?, 0/no-more-render
471 <scroll-down>
472 cursor-row <- subtract cursor-row, 1
473 *editor <- put *editor, cursor-row:offset, cursor-row
474 return 1/go-render
475 }
476
477 cursor-column <- add cursor-column, 1
478 *editor <- put *editor, cursor-column:offset, cursor-column
479 go-render? <- copy 0/false
480 ]
481
482 scenario editor-moves-cursor-to-next-line-with-right-arrow [
483 local-scope
484 assume-screen 10/width, 5/height
485 s:text <- new [abc
486 d]
487 e:&:editor <- new-editor s, 0/left, 10/right
488 editor-render screen, e
489 $clear-trace
490
491 assume-console [
492 press right-arrow
493 press right-arrow
494 press right-arrow
495 press right-arrow
496 ]
497 run [
498 editor-event-loop screen, console, e
499 ]
500 check-trace-count-for-label 0, [print-character]
501
502 assume-console [
503 type [0]
504 ]
505 run [
506 editor-event-loop screen, console, e
507 ]
508 screen-should-contain [
509 . .
510 .abc .
511 .0d .
512 .╌╌╌╌╌╌╌╌╌╌.
513 . .
514 ]
515 check-trace-count-for-label 2, [print-character]
516 ]
517
518 scenario editor-moves-cursor-to-next-line-with-right-arrow-2 [
519 local-scope
520 assume-screen 10/width, 5/height
521 s:text <- new [abc
522 d]
523 e:&:editor <- new-editor s, 1/left, 10/right
524 editor-render screen, e
525 assume-console [
526 press right-arrow
527 press right-arrow
528 press right-arrow
529 press right-arrow
530 type [0]
531 ]
532 run [
533 editor-event-loop screen, console, e
534 ]
535 screen-should-contain [
536 . .
537 . abc .
538 . 0d .
539 . ╌╌╌╌╌╌╌╌╌.
540 . .
541 ]
542 ]
543
544 scenario editor-moves-cursor-to-next-wrapped-line-with-right-arrow [
545 local-scope
546 assume-screen 10/width, 5/height
547 e:&:editor <- new-editor [abcdef], 0/left, 5/right
548 editor-render screen, e
549 $clear-trace
550 assume-console [
551 left-click 1, 3
552 press right-arrow
553 ]
554 run [
555 editor-event-loop screen, console, e
556 3:num/raw <- get *e, cursor-row:offset
557 4:num/raw <- get *e, cursor-column:offset
558 ]
559 screen-should-contain [
560 . .
561 .abcd↩ .
562 .ef .
563 .╌╌╌╌╌ .
564 . .
565 ]
566 memory-should-contain [
567 3 <- 2
568 4 <- 0
569 ]
570 check-trace-count-for-label 0, [print-character]
571 ]
572
573 scenario editor-moves-cursor-to-next-wrapped-line-with-right-arrow-2 [
574 local-scope
575 assume-screen 10/width, 5/height
576
577 e:&:editor <- new-editor [abcde], 0/left, 5/right
578 editor-render screen, e
579 $clear-trace
580
581 assume-console [
582 left-click 1, 3
583 press right-arrow
584 ]
585 run [
586 editor-event-loop screen, console, e
587 3:num/raw <- get *e, cursor-row:offset
588 4:num/raw <- get *e, cursor-column:offset
589 ]
590 memory-should-contain [
591 3 <- 2
592 4 <- 0
593 ]
594
595 assume-console [
596 press right-arrow
597 ]
598 run [
599 editor-event-loop screen, console, e
600 3:num/raw <- get *e, cursor-row:offset
601 4:num/raw <- get *e, cursor-column:offset
602 ]
603 memory-should-contain [
604 3 <- 2
605 4 <- 1
606 ]
607 check-trace-count-for-label 0, [print-character]
608 ]
609
610 scenario editor-moves-cursor-to-next-wrapped-line-with-right-arrow-3 [
611 local-scope
612 assume-screen 10/width, 5/height
613 e:&:editor <- new-editor [abcdef], 1/left, 6/right
614 editor-render screen, e
615 $clear-trace
616 assume-console [
617 left-click 1, 4
618 press right-arrow
619 ]
620 run [
621 editor-event-loop screen, console, e
622 3:num/raw <- get *e, cursor-row:offset
623 4:num/raw <- get *e, cursor-column:offset
624 ]
625 screen-should-contain [
626 . .
627 . abcd↩ .
628 . ef .
629 . ╌╌╌╌╌ .
630 . .
631 ]
632 memory-should-contain [
633 3 <- 2
634 4 <- 1
635 ]
636 check-trace-count-for-label 0, [print-character]
637 ]
638
639 scenario editor-moves-cursor-to-next-line-with-right-arrow-at-end-of-line [
640 local-scope
641 assume-screen 10/width, 5/height
642 s:text <- new [abc
643 d]
644 e:&:editor <- new-editor s, 0/left, 10/right
645 editor-render screen, e
646 $clear-trace
647
648 assume-console [
649 left-click 1, 3
650 press right-arrow
651 type [0]
652 ]
653 run [
654 editor-event-loop screen, console, e
655 ]
656
657 screen-should-contain [
658 . .
659 .abc .
660 .0d .
661 .╌╌╌╌╌╌╌╌╌╌.
662 . .
663 ]
664 check-trace-count-for-label 2, [print-character]
665 ]
666
667
668
669
670
671 scenario editor-moves-cursor-left-with-key [
672 local-scope
673 assume-screen 10/width, 5/height
674 e:&:editor <- new-editor [abc], 0/left, 10/right
675 editor-render screen, e
676 $clear-trace
677 assume-console [
678 left-click 1, 2
679 press left-arrow
680 type [0]
681 ]
682 run [
683 editor-event-loop screen, console, e
684 ]
685 screen-should-contain [
686 . .
687 .a0bc .
688 .╌╌╌╌╌╌╌╌╌╌.
689 . .
690 ]
691 check-trace-count-for-label 3, [print-character]
692 ]
693
694 after <handle-special-key> [
695 {
696 move-to-previous-character?:bool <- equal k, 65515/left-arrow
697 break-unless move-to-previous-character?
698 trace 10, [app], [left arrow]
699
700 prev:&:duplex-list:char <- prev before-cursor
701 return-unless prev, 0/don't-render
702 <move-cursor-begin>
703 go-render? <- move-cursor-coordinates-left editor
704 before-cursor <- copy prev
705 *editor <- put *editor, before-cursor:offset, before-cursor
706 undo-coalesce-tag:num <- copy 1/left-arrow
707 <move-cursor-end>
708 return
709 }
710 ]
711
712 scenario editor-moves-cursor-to-previous-line-with-left-arrow-at-start-of-line [
713 local-scope
714 assume-screen 10/width, 5/height
715
716 s:text <- new [abc
717 d]
718 e:&:editor <- new-editor s, 0/left, 10/right
719 editor-render screen, e
720 $clear-trace
721
722 assume-console [
723 left-click 2, 0
724 press left-arrow
725 ]
726 run [
727 editor-event-loop screen, console, e
728 3:num/raw <- get *e, cursor-row:offset
729 4:num/raw <- get *e, cursor-column:offset
730 ]
731 memory-should-contain [
732 3 <- 1
733 4 <- 3
734 ]
735 check-trace-count-for-label 0, [print-character]
736 ]
737
738 scenario editor-moves-cursor-to-previous-line-with-left-arrow-at-start-of-line-2 [
739 local-scope
740 assume-screen 10/width, 5/height
741
742 s:text <- new [abc
743 def
744 g]
745 e:&:editor <- new-editor s:text, 0/left, 10/right
746 editor-render screen, e
747 $clear-trace
748
749
750 assume-console [
751 left-click 3, 0
752 press left-arrow
753 type [0]
754 ]
755 run [
756 editor-event-loop screen, console, e
757 ]
758 screen-should-contain [
759 . .
760 .abc .
761 .def0 .
762 .g .
763 .╌╌╌╌╌╌╌╌╌╌.
764 ]
765 check-trace-count-for-label 1, [print-character]
766 ]
767
768 scenario editor-moves-cursor-to-previous-line-with-left-arrow-at-start-of-line-3 [
769 local-scope
770 assume-screen 10/width, 5/height
771 s:text <- new [abc
772 def
773 g]
774 e:&:editor <- new-editor s, 0/left, 10/right
775 editor-render screen, e
776 $clear-trace
777
778 assume-console [
779 left-click 1, 0
780 press left-arrow
781 type [0]
782 ]
783 run [
784 editor-event-loop screen, console, e
785 ]
786
787 screen-should-contain [
788 . .
789 .0abc .
790 .def .
791 .g .
792 .╌╌╌╌╌╌╌╌╌╌.
793 ]
794 check-trace-count-for-label 4, [print-character]
795 ]
796
797 scenario editor-moves-cursor-to-previous-line-with-left-arrow-at-start-of-line-4 [
798 local-scope
799 assume-screen 10/width, 5/height
800
801 s:text <- new [abc
802
803 d]
804 e:&:editor <- new-editor s, 0/left, 10/right
805 editor-render screen, e:&:editor
806 $clear-trace
807
808 assume-console [
809 left-click 3, 0
810 press left-arrow
811 type [0]
812 ]
813 run [
814 editor-event-loop screen, console, e
815 ]
816 screen-should-contain [
817 . .
818 .abc .
819 .0 .
820 .d .
821 .╌╌╌╌╌╌╌╌╌╌.
822 ]
823 check-trace-count-for-label 1, [print-character]
824 ]
825
826 scenario editor-moves-across-screen-lines-across-wrap-with-left-arrow [
827 local-scope
828 assume-screen 10/width, 5/height
829
830 e:&:editor <- new-editor [abcdef], 0/left, 5/right
831 editor-render screen, e
832 $clear-trace
833 screen-should-contain [
834 . .
835 .abcd↩ .
836 .ef .
837 .╌╌╌╌╌ .
838 . .
839 ]
840
841 assume-console [
842 left-click 2, 0
843 press left-arrow
844 ]
845 run [
846 editor-event-loop screen, console, e
847 3:num/raw <- get *e, cursor-row:offset
848 4:num/raw <- get *e, cursor-column:offset
849 ]
850 memory-should-contain [
851 3 <- 1
852 4 <- 3
853 ]
854 check-trace-count-for-label 0, [print-character]
855 ]
856
857 scenario editor-moves-across-screen-lines-to-wrapping-line-with-left-arrow [
858 local-scope
859 assume-screen 10/width, 5/height
860
861 s:text <- new [abcdef
862 g]
863 e:&:editor <- new-editor s, 0/left, 5/right
864 editor-render screen, e
865 $clear-trace
866 screen-should-contain [
867 . .
868 .abcd↩ .
869 .ef .
870 .g .
871 .╌╌╌╌╌ .
872 ]
873
874 assume-console [
875 left-click 3, 0
876 press left-arrow
877 ]
878 run [
879 editor-event-loop screen, console, e
880 3:num/raw <- get *e, cursor-row:offset
881 4:num/raw <- get *e, cursor-column:offset
882 ]
883 memory-should-contain [
884 3 <- 2
885 4 <- 2
886 ]
887 check-trace-count-for-label 0, [print-character]
888 ]
889
890 scenario editor-moves-across-screen-lines-to-non-wrapping-line-with-left-arrow [
891 local-scope
892 assume-screen 10/width, 5/height
893
894 s:text <- new [abcd
895 e]
896 e:&:editor <- new-editor s, 0/left, 5/right
897 editor-render screen, e
898 $clear-trace
899 screen-should-contain [
900 . .
901 .abcd .
902 .e .
903 .╌╌╌╌╌ .
904 . .
905 ]
906
907 assume-console [
908 left-click 2, 0
909 press left-arrow
910 ]
911 run [
912 editor-event-loop screen, console, e
913 3:num/raw <- get *e, cursor-row:offset
914 4:num/raw <- get *e, cursor-column:offset
915 ]
916 memory-should-contain [
917 3 <- 1
918 4 <- 4
919 ]
920 check-trace-count-for-label 0, [print-character]
921 ]
922
923
924
925
926
927 scenario editor-moves-to-previous-line-with-up-arrow [
928 local-scope
929 assume-screen 10/width, 5/height
930 s:text <- new [abc
931 def]
932 e:&:editor <- new-editor s, 0/left, 10/right
933 editor-render screen, e
934 $clear-trace
935 assume-console [
936 left-click 2, 1
937 press up-arrow
938 ]
939 run [
940 editor-event-loop screen, console, e
941 3:num/raw <- get *e, cursor-row:offset
942 4:num/raw <- get *e, cursor-column:offset
943 ]
944 memory-should-contain [
945 3 <- 1
946 4 <- 1
947 ]
948 check-trace-count-for-label 0, [print-character]
949 assume-console [
950 type [0]
951 ]
952 run [
953 editor-event-loop screen, console, e
954 ]
955 screen-should-contain [
956 . .
957 .a0bc .
958 .def .
959 .╌╌╌╌╌╌╌╌╌╌.
960 . .
961 ]
962 ]
963
964 after <handle-special-key> [
965 {
966 move-to-previous-line?:bool <- equal k, 65517/up-arrow
967 break-unless move-to-previous-line?
968 <move-cursor-begin>
969 go-render? <- move-to-previous-line editor
970 undo-coalesce-tag:num <- copy 3/up-arrow
971 <move-cursor-end>
972 return
973 }
974 ]
975
976 def move-to-previous-line editor:&:editor -> go-render?:bool, editor:&:editor [
977 local-scope
978 load-ingredients
979 go-render?:bool <- copy 0/false
980 cursor-row:num <- get *editor, cursor-row:offset
981 cursor-column:num <- get *editor, cursor-column:offset
982 before-cursor:&:duplex-list:char <- get *editor, before-cursor:offset
983 left:num <- get *editor, left:offset
984 right:num <- get *editor, right:offset
985 already-at-top?:bool <- lesser-or-equal cursor-row, 1/top
986 {
987
988 break-if already-at-top?
989
990
991
992 curr:&:duplex-list:char <- copy before-cursor
993 {
994 old:&:duplex-list:char <- copy curr
995 c2:char <- get *curr, value:offset
996 at-newline?:bool <- equal c2, 10/newline
997 break-if at-newline?
998 curr:&:duplex-list:char <- before-previous-line curr, editor
999 no-motion?:bool <- equal curr, old
1000 return-if no-motion?
1001 }
1002 {
1003 old <- copy curr
1004 curr <- before-previous-line curr, editor
1005 no-motion?:bool <- equal curr, old
1006 return-if no-motion?
1007 }
1008 before-cursor <- copy curr
1009 *editor <- put *editor, before-cursor:offset, before-cursor
1010 cursor-row <- subtract cursor-row, 1
1011 *editor <- put *editor, cursor-row:offset, cursor-row
1012
1013 target-column:num <- copy cursor-column
1014 cursor-column <- copy left
1015 *editor <- put *editor, cursor-column:offset, cursor-column
1016 {
1017 done?:bool <- greater-or-equal cursor-column, target-column
1018 break-if done?
1019 curr:&:duplex-list:char <- next before-cursor
1020 break-unless curr
1021 currc:char <- get *curr, value:offset
1022 at-newline?:bool <- equal currc, 10/newline
1023 break-if at-newline?
1024
1025 before-cursor <- copy curr
1026 *editor <- put *editor, before-cursor:offset, before-cursor
1027 cursor-column <- add cursor-column, 1
1028 *editor <- put *editor, cursor-column:offset, cursor-column
1029 loop
1030 }
1031 return
1032 }
1033 {
1034
1035 break-unless already-at-top?
1036 <scroll-up>
1037 return 1/go-render
1038 }
1039 ]
1040
1041 scenario editor-adjusts-column-at-previous-line [
1042 local-scope
1043 assume-screen 10/width, 5/height
1044 s:text <- new [ab
1045 def]
1046 e:&:editor <- new-editor s, 0/left, 10/right
1047 editor-render screen, e
1048 $clear-trace
1049 assume-console [
1050 left-click 2, 3
1051 press up-arrow
1052 ]
1053 run [
1054 editor-event-loop screen, console, e
1055 3:num/raw <- get *e, cursor-row:offset
1056 4:num/raw <- get *e, cursor-column:offset
1057 ]
1058 memory-should-contain [
1059 3 <- 1
1060 4 <- 2
1061 ]
1062 check-trace-count-for-label 0, [print-character]
1063 assume-console [
1064 type [0]
1065 ]
1066 run [
1067 editor-event-loop screen, console, e
1068 ]
1069 screen-should-contain [
1070 . .
1071 .ab0 .
1072 .def .
1073 .╌╌╌╌╌╌╌╌╌╌.
1074 . .
1075 ]
1076 ]
1077
1078 scenario editor-adjusts-column-at-empty-line [
1079 local-scope
1080 assume-screen 10/width, 5/height
1081 s:text <- new [
1082 def]
1083 e:&:editor <- new-editor s, 0/left, 10/right
1084 editor-render screen, e
1085 $clear-trace
1086 assume-console [
1087 left-click 2, 3
1088 press up-arrow
1089 ]
1090 run [
1091 editor-event-loop screen, console, e
1092 3:num/raw <- get *e, cursor-row:offset
1093 4:num/raw <- get *e, cursor-column:offset
1094 ]
1095 memory-should-contain [
1096 3 <- 1
1097 4 <- 0
1098 ]
1099 check-trace-count-for-label 0, [print-character]
1100 assume-console [
1101 type [0]
1102 ]
1103 run [
1104 editor-event-loop screen, console, e
1105 ]
1106 screen-should-contain [
1107 . .
1108 .0 .
1109 .def .
1110 .╌╌╌╌╌╌╌╌╌╌.
1111 . .
1112 ]
1113 ]
1114
1115 scenario editor-moves-to-previous-line-from-left-margin [
1116 local-scope
1117 assume-screen 10/width, 5/height
1118
1119 s:text <- new [abc
1120 def
1121 ghi]
1122 e:&:editor <- new-editor s, 0/left, 10/right
1123 editor-render screen, e
1124 $clear-trace
1125
1126 assume-console [
1127 left-click 3, 0
1128 press up-arrow
1129 ]
1130 run [
1131 editor-event-loop screen, console, e
1132 3:num/raw <- get *e, cursor-row:offset
1133 4:num/raw <- get *e, cursor-column:offset
1134 ]
1135 memory-should-contain [
1136 3 <- 2
1137 4 <- 0
1138 ]
1139 check-trace-count-for-label 0, [print-character]
1140 assume-console [
1141 type [0]
1142 ]
1143 run [
1144 editor-event-loop screen, console, e
1145 ]
1146 screen-should-contain [
1147 . .
1148 .abc .
1149 .0def .
1150 .ghi .
1151 .╌╌╌╌╌╌╌╌╌╌.
1152 ]
1153 ]
1154
1155
1156
1157 scenario editor-moves-to-next-line-with-down-arrow [
1158 local-scope
1159 assume-screen 10/width, 5/height
1160 s:text <- new [abc
1161 def]
1162 e:&:editor <- new-editor s, 0/left, 10/right
1163 editor-render screen, e
1164 $clear-trace
1165
1166 assume-console [
1167 press down-arrow
1168 ]
1169 run [
1170 editor-event-loop screen, console, e
1171 3:num/raw <- get *e, cursor-row:offset
1172 4:num/raw <- get *e, cursor-column:offset
1173 ]
1174
1175 memory-should-contain [
1176 3 <- 2
1177 4 <- 0
1178 ]
1179 check-trace-count-for-label 0, [print-character]
1180 assume-console [
1181 type [0]
1182 ]
1183 run [
1184 editor-event-loop screen, console, e
1185 ]
1186 screen-should-contain [
1187 . .
1188 .abc .
1189 .0def .
1190 .╌╌╌╌╌╌╌╌╌╌.
1191 . .
1192 ]
1193 ]
1194
1195 after <handle-special-key> [
1196 {
1197 move-to-next-line?:bool <- equal k, 65516/down-arrow
1198 break-unless move-to-next-line?
1199 <move-cursor-begin>
1200 go-render? <- move-to-next-line editor, screen-height
1201 undo-coalesce-tag:num <- copy 4/down-arrow
1202 <move-cursor-end>
1203 return
1204 }
1205 ]
1206
1207 def move-to-next-line editor:&:editor, screen-height:num -> go-render?:bool, editor:&:editor [
1208 local-scope
1209 load-ingredients
1210 cursor-row:num <- get *editor, cursor-row:offset
1211 cursor-column:num <- get *editor, cursor-column:offset
1212 before-cursor:&:duplex-list:char <- get *editor, before-cursor:offset
1213 left:num <- get *editor, left:offset
1214 right:num <- get *editor, right:offset
1215 last-line:num <- subtract screen-height, 1
1216 already-at-bottom?:bool <- greater-or-equal cursor-row, last-line
1217 {
1218
1219 break-if already-at-bottom?
1220
1221 max:num <- subtract right, left
1222 next-line:&:duplex-list:char <- before-start-of-next-line before-cursor, max
1223 {
1224
1225
1226 no-motion?:bool <- equal next-line, before-cursor
1227 break-unless no-motion?
1228 scroll?:bool <- greater-than cursor-row, 1
1229 break-if scroll?, +try-to-scroll
1230 return 0/don't-render
1231 }
1232 cursor-row <- add cursor-row, 1
1233 *editor <- put *editor, cursor-row:offset, cursor-row
1234 before-cursor <- copy next-line
1235 *editor <- put *editor, before-cursor:offset, before-cursor
1236 target-column:num <- copy cursor-column
1237 cursor-column <- copy left
1238 *editor <- put *editor, cursor-column:offset, cursor-column
1239 {
1240 done?:bool <- greater-or-equal cursor-column, target-column
1241 break-if done?
1242 curr:&:duplex-list:char <- next before-cursor
1243 break-unless curr
1244 currc:char <- get *curr, value:offset
1245 at-newline?:bool <- equal currc, 10/newline
1246 break-if at-newline?
1247
1248 before-cursor <- copy curr
1249 *editor <- put *editor, before-cursor:offset, before-cursor
1250 cursor-column <- add cursor-column, 1
1251 *editor <- put *editor, cursor-column:offset, cursor-column
1252 loop
1253 }
1254 return 0/don't-render
1255 }
1256 +try-to-scroll
1257 <scroll-down>
1258 go-render? <- copy 1/true
1259 ]
1260
1261 scenario editor-adjusts-column-at-next-line [
1262 local-scope
1263 assume-screen 10/width, 5/height
1264 s:text <- new [abc
1265 de]
1266 e:&:editor <- new-editor s, 0/left, 10/right
1267 editor-render screen, e
1268 $clear-trace
1269 assume-console [
1270 left-click 1, 3
1271 press down-arrow
1272 ]
1273 run [
1274 editor-event-loop screen, console, e
1275 3:num/raw <- get *e, cursor-row:offset
1276 4:num/raw <- get *e, cursor-column:offset
1277 ]
1278 memory-should-contain [
1279 3 <- 2
1280 4 <- 2
1281 ]
1282 check-trace-count-for-label 0, [print-character]
1283 assume-console [
1284 type [0]
1285 ]
1286 run [
1287 editor-event-loop screen, console, e
1288 ]
1289 screen-should-contain [
1290 . .
1291 .abc .
1292 .de0 .
1293 .╌╌╌╌╌╌╌╌╌╌.
1294 . .
1295 ]
1296 ]
1297
1298
1299
1300 scenario editor-moves-to-start-of-line-with-ctrl-a [
1301 local-scope
1302 assume-screen 10/width, 5/height
1303 s:text <- new [123
1304 456]
1305 e:&:editor <- new-editor s, 0/left, 10/right
1306 editor-render screen, e
1307 $clear-trace
1308
1309 assume-console [
1310 left-click 2, 3
1311 press ctrl-a
1312 ]
1313 run [
1314 editor-event-loop screen, console, e
1315 4:num/raw <- get *e, cursor-row:offset
1316 5:num/raw <- get *e, cursor-column:offset
1317 ]
1318
1319 memory-should-contain [
1320 4 <- 2
1321 5 <- 0
1322 ]
1323 check-trace-count-for-label 0, [print-character]
1324 ]
1325
1326 after <handle-special-character> [
1327 {
1328 move-to-start-of-line?:bool <- equal c, 1/ctrl-a
1329 break-unless move-to-start-of-line?
1330 <move-cursor-begin>
1331 move-to-start-of-line editor
1332 undo-coalesce-tag:num <- copy 0/never
1333 <move-cursor-end>
1334 return 0/don't-render
1335 }
1336 ]
1337
1338 after <handle-special-key> [
1339 {
1340 move-to-start-of-line?:bool <- equal k, 65521/home
1341 break-unless move-to-start-of-line?
1342 <move-cursor-begin>
1343 move-to-start-of-line editor
1344 undo-coalesce-tag:num <- copy 0/never
1345 <move-cursor-end>
1346 return 0/don't-render
1347 }
1348 ]
1349
1350 def move-to-start-of-line editor:&:editor -> editor:&:editor [
1351 local-scope
1352 load-ingredients
1353
1354 left:num <- get *editor, left:offset
1355 cursor-column:num <- copy left
1356 *editor <- put *editor, cursor-column:offset, cursor-column
1357
1358 before-cursor:&:duplex-list:char <- get *editor, before-cursor:offset
1359 init:&:duplex-list:char <- get *editor, data:offset
1360
1361 {
1362 at-start-of-text?:bool <- equal before-cursor, init
1363 break-if at-start-of-text?
1364 prev:char <- get *before-cursor, value:offset
1365 at-start-of-line?:bool <- equal prev, 10/newline
1366 break-if at-start-of-line?
1367 before-cursor <- prev before-cursor
1368 *editor <- put *editor, before-cursor:offset, before-cursor
1369 assert before-cursor, [move-to-start-of-line tried to move before start of text]
1370 loop
1371 }
1372 ]
1373
1374 scenario editor-moves-to-start-of-line-with-ctrl-a-2 [
1375 local-scope
1376 assume-screen 10/width, 5/height
1377 s:text <- new [123
1378 456]
1379 e:&:editor <- new-editor s, 0/left, 10/right
1380 editor-render screen, e
1381 $clear-trace
1382
1383 assume-console [
1384 left-click 1, 3
1385 press ctrl-a
1386 ]
1387 run [
1388 editor-event-loop screen, console, e
1389 4:num/raw <- get *e, cursor-row:offset
1390 5:num/raw <- get *e, cursor-column:offset
1391 ]
1392
1393 memory-should-contain [
1394 4 <- 1
1395 5 <- 0
1396 ]
1397 check-trace-count-for-label 0, [print-character]
1398 ]
1399
1400 scenario editor-moves-to-start-of-line-with-home [
1401 local-scope
1402 assume-screen 10/width, 5/height
1403 s:text <- new [123
1404 456]
1405 e:&:editor <- new-editor s, 0/left, 10/right
1406 $clear-trace
1407
1408 assume-console [
1409 left-click 2, 3
1410 press home
1411 ]
1412 run [
1413 editor-event-loop screen, console, e
1414 3:num/raw <- get *e, cursor-row:offset
1415 4:num/raw <- get *e, cursor-column:offset
1416 ]
1417
1418 memory-should-contain [
1419 3 <- 2
1420 4 <- 0
1421 ]
1422 check-trace-count-for-label 0, [print-character]
1423 ]
1424
1425 scenario editor-moves-to-start-of-line-with-home-2 [
1426 local-scope
1427 assume-screen 10/width, 5/height
1428 s:text <- new [123
1429 456]
1430 e:&:editor <- new-editor s, 0/left, 10/right
1431 editor-render screen, e
1432 $clear-trace
1433
1434 assume-console [
1435 left-click 1, 3
1436 press home
1437 ]
1438 run [
1439 editor-event-loop screen, console, e
1440 3:num/raw <- get *e, cursor-row:offset
1441 4:num/raw <- get *e, cursor-column:offset
1442 ]
1443
1444 memory-should-contain [
1445 3 <- 1
1446 4 <- 0
1447 ]
1448 check-trace-count-for-label 0, [print-character]
1449 ]
1450
1451
1452
1453 scenario editor-moves-to-end-of-line-with-ctrl-e [
1454 local-scope
1455 assume-screen 10/width, 5/height
1456 s:text <- new [123
1457 456]
1458 e:&:editor <- new-editor s, 0/left, 10/right
1459 editor-render screen, e
1460 $clear-trace
1461
1462 assume-console [
1463 left-click 1, 1
1464 press ctrl-e
1465 ]
1466 run [
1467 editor-event-loop screen, console, e
1468 4:num/raw <- get *e, cursor-row:offset
1469 5:num/raw <- get *e, cursor-column:offset
1470 ]
1471
1472 memory-should-contain [
1473 4 <- 1
1474 5 <- 3
1475 ]
1476 check-trace-count-for-label 0, [print-character]
1477
1478 assume-console [
1479 type [z]
1480 ]
1481 run [
1482 editor-event-loop screen, console, e
1483 4:num/raw <- get *e, cursor-row:offset
1484 5:num/raw <- get *e, cursor-column:offset
1485 ]
1486 memory-should-contain [
1487 4 <- 1
1488 5 <- 4
1489 ]
1490 screen-should-contain [
1491 . .
1492 .123z .
1493 .456 .
1494 .╌╌╌╌╌╌╌╌╌╌.
1495 . .
1496 ]
1497 check-trace-count-for-label 1, [print-character]
1498 ]
1499
1500 after <handle-special-character> [
1501 {
1502 move-to-end-of-line?:bool <- equal c, 5/ctrl-e
1503 break-unless move-to-end-of-line?
1504 <move-cursor-begin>
1505 move-to-end-of-line editor
1506 undo-coalesce-tag:num <- copy 0/never
1507 <move-cursor-end>
1508 return 0/don't-render
1509 }
1510 ]
1511
1512 after <handle-special-key> [
1513 {
1514 move-to-end-of-line?:bool <- equal k, 65520/end
1515 break-unless move-to-end-of-line?
1516 <move-cursor-begin>
1517 move-to-end-of-line editor
1518 undo-coalesce-tag:num <- copy 0/never
1519 <move-cursor-end>
1520 return 0/don't-render
1521 }
1522 ]
1523
1524 def move-to-end-of-line editor:&:editor -> editor:&:editor [
1525 local-scope
1526 load-ingredients
1527 before-cursor:&:duplex-list:char <- get *editor, before-cursor:offset
1528 cursor-column:num <- get *editor, cursor-column:offset
1529
1530 {
1531 next:&:duplex-list:char <- next before-cursor
1532 break-unless next
1533 nextc:char <- get *next, value:offset
1534 at-end-of-line?:bool <- equal nextc, 10/newline
1535 break-if at-end-of-line?
1536 before-cursor <- copy next
1537 *editor <- put *editor, before-cursor:offset, before-cursor
1538 cursor-column <- add cursor-column, 1
1539 *editor <- put *editor, cursor-column:offset, cursor-column
1540 loop
1541 }
1542 ]
1543
1544 scenario editor-moves-to-end-of-line-with-ctrl-e-2 [
1545 local-scope
1546 assume-screen 10/width, 5/height
1547 s:text <- new [123
1548 456]
1549 e:&:editor <- new-editor s, 0/left, 10/right
1550 editor-render screen, e
1551 $clear-trace
1552
1553 assume-console [
1554 left-click 2, 1
1555 press ctrl-e
1556 ]
1557 run [
1558 editor-event-loop screen, console, e
1559 4:num/raw <- get *e, cursor-row:offset
1560 5:num/raw <- get *e, cursor-column:offset
1561 ]
1562
1563 memory-should-contain [
1564 4 <- 2
1565 5 <- 3
1566 ]
1567 check-trace-count-for-label 0, [print-character]
1568 ]
1569
1570 scenario editor-moves-to-end-of-line-with-end [
1571 local-scope
1572 assume-screen 10/width, 5/height
1573 s:text <- new [123
1574 456]
1575 e:&:editor <- new-editor s, 0/left, 10/right
1576 editor-render screen, e
1577 $clear-trace
1578
1579 assume-console [
1580 left-click 1, 1
1581 press end
1582 ]
1583 run [
1584 editor-event-loop screen, console, e
1585 3:num/raw <- get *e, cursor-row:offset
1586 4:num/raw <- get *e, cursor-column:offset
1587 ]
1588
1589 memory-should-contain [
1590 3 <- 1
1591 4 <- 3
1592 ]
1593 check-trace-count-for-label 0, [print-character]
1594 ]
1595
1596 scenario editor-moves-to-end-of-line-with-end-2 [
1597 local-scope
1598 assume-screen 10/width, 5/height
1599 s:text <- new [123
1600 456]
1601 e:&:editor <- new-editor s, 0/left, 10/right
1602 editor-render screen, e
1603 $clear-trace
1604
1605 assume-console [
1606 left-click 2, 1
1607 press end
1608 ]
1609 run [
1610 editor-event-loop screen, console, e
1611 3:num/raw <- get *e, cursor-row:offset
1612 4:num/raw <- get *e, cursor-column:offset
1613 ]
1614
1615 memory-should-contain [
1616 3 <- 2
1617 4 <- 3
1618 ]
1619 check-trace-count-for-label 0, [print-character]
1620 ]
1621
1622
1623
1624 scenario editor-deletes-to-start-of-line-with-ctrl-u [
1625 local-scope
1626 assume-screen 10/width, 5/height
1627 s:text <- new [123
1628 456]
1629 e:&:editor <- new-editor s, 0/left, 10/right
1630
1631 assume-console [
1632 left-click 2, 2
1633 press ctrl-u
1634 ]
1635 run [
1636 editor-event-loop screen, console, e
1637 ]
1638
1639 screen-should-contain [
1640 . .
1641 .123 .
1642 .6 .
1643 .╌╌╌╌╌╌╌╌╌╌.
1644 . .
1645 ]
1646 ]
1647
1648 after <handle-special-character> [
1649 {
1650 delete-to-start-of-line?:bool <- equal c, 21/ctrl-u
1651 break-unless delete-to-start-of-line?
1652 <delete-to-start-of-line-begin>
1653 deleted-cells:&:duplex-list:char <- delete-to-start-of-line editor
1654 <delete-to-start-of-line-end>
1655 return 1/go-render
1656 }
1657 ]
1658
1659 def delete-to-start-of-line editor:&:editor -> result:&:duplex-list:char, editor:&:editor [
1660 local-scope
1661 load-ingredients
1662
1663 init:&:duplex-list:char <- get *editor, data:offset
1664 before-cursor:&:duplex-list:char <- get *editor, before-cursor:offset
1665 start:&:duplex-list:char <- copy before-cursor
1666 end:&:duplex-list:char <- next before-cursor
1667 {
1668 at-start-of-text?:bool <- equal start, init
1669 break-if at-start-of-text?
1670 curr:char <- get *start, value:offset
1671 at-start-of-line?:bool <- equal curr, 10/newline
1672 break-if at-start-of-line?
1673 start <- prev start
1674 assert start, [delete-to-start-of-line tried to move before start of text]
1675 loop
1676 }
1677
1678 result:&:duplex-list:char <- next start
1679 remove-between start, end
1680
1681 before-cursor <- copy start
1682 *editor <- put *editor, before-cursor:offset, before-cursor
1683 left:num <- get *editor, left:offset
1684 *editor <- put *editor, cursor-column:offset, left
1685 ]
1686
1687 scenario editor-deletes-to-start-of-line-with-ctrl-u-2 [
1688 local-scope
1689 assume-screen 10/width, 5/height
1690 s:text <- new [123
1691 456]
1692 e:&:editor <- new-editor s, 0/left, 10/right
1693
1694 assume-console [
1695 left-click 1, 2
1696 press ctrl-u
1697 ]
1698 run [
1699 editor-event-loop screen, console, e
1700 ]
1701
1702 screen-should-contain [
1703 . .
1704 .3 .
1705 .456 .
1706 .╌╌╌╌╌╌╌╌╌╌.
1707 . .
1708 ]
1709 ]
1710
1711 scenario editor-deletes-to-start-of-line-with-ctrl-u-3 [
1712 local-scope
1713 assume-screen 10/width, 5/height
1714 s:text <- new [123
1715 456]
1716 e:&:editor <- new-editor s, 0/left, 10/right
1717
1718 assume-console [
1719 left-click 1, 3
1720 press ctrl-u
1721 ]
1722 run [
1723 editor-event-loop screen, console, e
1724 ]
1725
1726 screen-should-contain [
1727 . .
1728 . .
1729 .456 .
1730 .╌╌╌╌╌╌╌╌╌╌.
1731 . .
1732 ]
1733 ]
1734
1735 scenario editor-deletes-to-start-of-final-line-with-ctrl-u [
1736 local-scope
1737 assume-screen 10/width, 5/height
1738 s:text <- new [123
1739 456]
1740 e:&:editor <- new-editor s, 0/left, 10/right
1741
1742 assume-console [
1743 left-click 2, 3
1744 press ctrl-u
1745 ]
1746 run [
1747 editor-event-loop screen, console, e
1748 ]
1749
1750 screen-should-contain [
1751 . .
1752 .123 .
1753 . .
1754 .╌╌╌╌╌╌╌╌╌╌.
1755 . .
1756 ]
1757 ]
1758
1759
1760
1761 scenario editor-deletes-to-end-of-line-with-ctrl-k [
1762 local-scope
1763 assume-screen 10/width, 5/height
1764 s:text <- new [123
1765 456]
1766 e:&:editor <- new-editor s, 0/left, 10/right
1767
1768 assume-console [
1769 left-click 1, 1
1770 press ctrl-k
1771 ]
1772 run [
1773 editor-event-loop screen, console, e
1774 ]
1775
1776 screen-should-contain [
1777 . .
1778 .1 .
1779 .456 .
1780 .╌╌╌╌╌╌╌╌╌╌.
1781 . .
1782 ]
1783 ]
1784
1785 after <handle-special-character> [
1786 {
1787 delete-to-end-of-line?:bool <- equal c, 11/ctrl-k
1788 break-unless delete-to-end-of-line?
1789 <delete-to-end-of-line-begin>
1790 deleted-cells:&:duplex-list:char <- delete-to-end-of-line editor
1791 <delete-to-end-of-line-end>
1792 return 1/go-render
1793 }
1794 ]
1795
1796 def delete-to-end-of-line editor:&:editor -> result:&:duplex-list:char, editor:&:editor [
1797 local-scope
1798 load-ingredients
1799
1800 start:&:duplex-list:char <- get *editor, before-cursor:offset
1801 end:&:duplex-list:char <- next start
1802 {
1803 at-end-of-text?:bool <- equal end, 0/null
1804 break-if at-end-of-text?
1805 curr:char <- get *end, value:offset
1806 at-end-of-line?:bool <- equal curr, 10/newline
1807 break-if at-end-of-line?
1808 end <- next end
1809 loop
1810 }
1811
1812 result <- next start
1813 remove-between start, end
1814 ]
1815
1816 scenario editor-deletes-to-end-of-line-with-ctrl-k-2 [
1817 local-scope
1818 assume-screen 10/width, 5/height
1819 s:text <- new [123
1820 456]
1821 e:&:editor <- new-editor s, 0/left, 10/right
1822
1823 assume-console [
1824 left-click 2, 1
1825 press ctrl-k
1826 ]
1827 run [
1828 editor-event-loop screen, console, e
1829 ]
1830
1831 screen-should-contain [
1832 . .
1833 .123 .
1834 .4 .
1835 .╌╌╌╌╌╌╌╌╌╌.
1836 . .
1837 ]
1838 ]
1839
1840 scenario editor-deletes-to-end-of-line-with-ctrl-k-3 [
1841 local-scope
1842 assume-screen 10/width, 5/height
1843 s:text <- new [123
1844 456]
1845 e:&:editor <- new-editor s, 0/left, 10/right
1846
1847 assume-console [
1848 left-click 1, 2
1849 press ctrl-k
1850 ]
1851 run [
1852 editor-event-loop screen, console, e
1853 ]
1854
1855 screen-should-contain [
1856 . .
1857 .12 .
1858 .456 .
1859 .╌╌╌╌╌╌╌╌╌╌.
1860 . .
1861 ]
1862 ]
1863
1864 scenario editor-deletes-to-end-of-line-with-ctrl-k-4 [
1865 local-scope
1866 assume-screen 10/width, 5/height
1867 s:text <- new [123
1868 456]
1869 e:&:editor <- new-editor s, 0/left, 10/right
1870
1871 assume-console [
1872 left-click 1, 3
1873 press ctrl-k
1874 ]
1875 run [
1876 editor-event-loop screen, console, e
1877 ]
1878
1879 screen-should-contain [
1880 . .
1881 .123 .
1882 .456 .
1883 .╌╌╌╌╌╌╌╌╌╌.
1884 . .
1885 ]
1886 ]
1887
1888 scenario editor-deletes-to-end-of-line-with-ctrl-k-5 [
1889 local-scope
1890 assume-screen 10/width, 5/height
1891 s:text <- new [123
1892 456]
1893 e:&:editor <- new-editor s, 0/left, 10/right
1894
1895 assume-console [
1896 left-click 2, 2
1897 press ctrl-k
1898 ]
1899 run [
1900 editor-event-loop screen, console, e
1901 ]
1902
1903 screen-should-contain [
1904 . .
1905 .123 .
1906 .45 .
1907 .╌╌╌╌╌╌╌╌╌╌.
1908 . .
1909 ]
1910 ]
1911
1912 scenario editor-deletes-to-end-of-line-with-ctrl-k-6 [
1913 local-scope
1914 assume-screen 10/width, 5/height
1915 s:text <- new [123
1916 456]
1917 e:&:editor <- new-editor s, 0/left, 10/right
1918
1919 assume-console [
1920 left-click 2, 3
1921 press ctrl-k
1922 ]
1923 run [
1924 editor-event-loop screen, console, e
1925 ]
1926
1927 screen-should-contain [
1928 . .
1929 .123 .
1930 .456 .
1931 .╌╌╌╌╌╌╌╌╌╌.
1932 . .
1933 ]
1934 ]
1935
1936
1937
1938 scenario editor-can-scroll-down-using-arrow-keys [
1939 local-scope
1940
1941 assume-screen 10/width, 4/height
1942
1943 s:text <- new [a
1944 b
1945 c
1946 d]
1947 e:&:editor <- new-editor s, 0/left, 10/right
1948 editor-render screen, e
1949 screen-should-contain [
1950 . .
1951 .a .
1952 .b .
1953 .c .
1954 ]
1955
1956 assume-console [
1957 left-click 3, 0
1958 press down-arrow
1959 ]
1960 run [
1961 editor-event-loop screen, console, e
1962 ]
1963
1964 screen-should-contain [
1965 . .
1966 .b .
1967 .c .
1968 .d .
1969 ]
1970 ]
1971
1972 after <scroll-down> [
1973 trace 10, [app], [scroll down]
1974 top-of-screen:&:duplex-list:char <- get *editor, top-of-screen:offset
1975 left:num <- get *editor, left:offset
1976 right:num <- get *editor, right:offset
1977 max:num <- subtract right, left
1978 old-top:&:duplex-list:char <- copy top-of-screen
1979 top-of-screen <- before-start-of-next-line top-of-screen, max
1980 *editor <- put *editor, top-of-screen:offset, top-of-screen
1981 no-movement?:bool <- equal old-top, top-of-screen
1982 return-if no-movement?, 0/don't-render
1983 ]
1984
1985
1986
1987
1988 def before-start-of-next-line original:&:duplex-list:char, max:num -> curr:&:duplex-list:char [
1989 local-scope
1990 load-ingredients
1991 count:num <- copy 0
1992 curr:&:duplex-list:char <- copy original
1993
1994 {
1995 c:char <- get *curr, value:offset
1996 at-newline?:bool <- equal c, 10/newline
1997 break-unless at-newline?
1998 curr <- next curr
1999 count <- add count, 1
2000 }
2001 {
2002 return-unless curr, original
2003 done?:bool <- greater-or-equal count, max
2004 break-if done?
2005 c:char <- get *curr, value:offset
2006 at-newline?:bool <- equal c, 10/newline
2007 break-if at-newline?
2008 curr <- next curr
2009 count <- add count, 1
2010 loop
2011 }
2012 return-unless curr, original
2013 return curr
2014 ]
2015
2016 scenario editor-scrolls-down-past-wrapped-line-using-arrow-keys [
2017 local-scope
2018
2019 assume-screen 10/width, 4/height
2020
2021
2022 s:text <- new [abcdef
2023 g
2024 h
2025 i]
2026 e:&:editor <- new-editor s, 0/left, 5/right
2027 editor-render screen, e
2028 screen-should-contain [
2029 . .
2030 .abcd↩ .
2031 .ef .
2032 .g .
2033 ]
2034
2035 assume-console [
2036 left-click 3, 0
2037 press down-arrow
2038 ]
2039 run [
2040 editor-event-loop screen, console, e
2041 ]
2042
2043 screen-should-contain [
2044 . .
2045 .ef .
2046 .g .
2047 .h .
2048 ]
2049 ]
2050
2051 scenario editor-scrolls-down-past-wrapped-line-using-arrow-keys-2 [
2052 local-scope
2053
2054 assume-screen 10/width, 4/height
2055
2056 s:text <- new [abcdefghij
2057 k
2058 l
2059 m]
2060 e:&:editor <- new-editor s, 0/left, 5/right
2061
2062 assume-console [
2063 left-click 3, 0
2064 press down-arrow
2065 ]
2066 run [
2067 editor-event-loop screen, console, e
2068 ]
2069
2070 screen-should-contain [
2071 . .
2072 .efgh↩ .
2073 .ij .
2074 .k .
2075 ]
2076
2077 assume-console [
2078 press down-arrow
2079 ]
2080 run [
2081 editor-event-loop screen, console, e
2082 ]
2083
2084 screen-should-contain [
2085 . .
2086 .ij .
2087 .k .
2088 .l .
2089 ]
2090 ]
2091
2092 scenario editor-scrolls-down-when-line-wraps [
2093 local-scope
2094
2095 assume-screen 5/width, 4/height
2096
2097 s:text <- new [a
2098 b
2099 cdef]
2100 e:&:editor <- new-editor s, 0/left, 5/right
2101
2102 assume-console [
2103 left-click 3, 4
2104 type [g]
2105 ]
2106 run [
2107 editor-event-loop screen, console, e
2108 3:num/raw <- get *e, cursor-row:offset
2109 4:num/raw <- get *e, cursor-column:offset
2110 ]
2111
2112 screen-should-contain [
2113 . .
2114 .b .
2115 .cdef↩.
2116 .g .
2117 ]
2118 memory-should-contain [
2119 3 <- 3
2120 4 <- 1
2121 ]
2122 ]
2123
2124 scenario editor-scrolls-down-on-newline [
2125 local-scope
2126 assume-screen 5/width, 4/height
2127
2128 s:text <- new [a
2129 b
2130 c]
2131 e:&:editor <- new-editor s, 0/left, 5/right
2132 assume-console [
2133 left-click 3, 4
2134 type [
2135 ]
2136 ]
2137 run [
2138 editor-event-loop screen, console, e
2139 3:num/raw <- get *e, cursor-row:offset
2140 4:num/raw <- get *e, cursor-column:offset
2141 ]
2142
2143 screen-should-contain [
2144 . .
2145 .b .
2146 .c .
2147 . .
2148 ]
2149 memory-should-contain [
2150 3 <- 3
2151 4 <- 0
2152 ]
2153 ]
2154
2155 scenario editor-scrolls-down-on-right-arrow [
2156 local-scope
2157
2158 assume-screen 5/width, 4/height
2159
2160 s:text <- new [a
2161 b
2162 cdefgh]
2163 e:&:editor <- new-editor s, 0/left, 5/right
2164
2165 assume-console [
2166 left-click 3, 3
2167 press right-arrow
2168 ]
2169 run [
2170 editor-event-loop screen, console, e
2171 3:num/raw <- get *e, cursor-row:offset
2172 4:num/raw <- get *e, cursor-column:offset
2173 ]
2174
2175 screen-should-contain [
2176 . .
2177 .b .
2178 .cdef↩.
2179 .gh .
2180 ]
2181 memory-should-contain [
2182 3 <- 3
2183 4 <- 0
2184 ]
2185 ]
2186
2187 scenario editor-scrolls-down-on-right-arrow-2 [
2188 local-scope
2189
2190 assume-screen 5/width, 4/height
2191
2192 s:text <- new [a
2193 b
2194 c
2195 d]
2196 e:&:editor <- new-editor s, 0/left, 5/right
2197
2198 assume-console [
2199 left-click 3, 3
2200 press right-arrow
2201 ]
2202 run [
2203 editor-event-loop screen, console, e
2204 3:num/raw <- get *e, cursor-row:offset
2205 4:num/raw <- get *e, cursor-column:offset
2206 ]
2207
2208 screen-should-contain [
2209 . .
2210 .b .
2211 .c .
2212 .d .
2213 ]
2214 memory-should-contain [
2215 3 <- 3
2216 4 <- 0
2217 ]
2218 ]
2219
2220 scenario editor-scrolls-at-end-on-down-arrow [
2221 local-scope
2222 assume-screen 10/width, 5/height
2223 s:text <- new [abc
2224 de]
2225 e:&:editor <- new-editor s, 0/left, 10/right
2226 editor-render screen, e
2227 $clear-trace
2228
2229 assume-console [
2230 left-click 2, 0
2231 press down-arrow
2232 ]
2233 run [
2234 editor-event-loop screen, console, e
2235 3:num/raw <- get *e, cursor-row:offset
2236 4:num/raw <- get *e, cursor-column:offset
2237 ]
2238
2239 memory-should-contain [
2240 3 <- 1
2241 4 <- 2
2242 ]
2243 assume-console [
2244 type [0]
2245 ]
2246 run [
2247 editor-event-loop screen, console, e
2248 ]
2249 screen-should-contain [
2250 . .
2251 .de0 .
2252 .╌╌╌╌╌╌╌╌╌╌.
2253 . .
2254 ]
2255
2256 $clear-trace
2257 assume-console [
2258 left-click 2, 0
2259 press down-arrow
2260 ]
2261 run [
2262 editor-event-loop screen, console, e
2263 3:num/raw <- get *e, cursor-row:offset
2264 4:num/raw <- get *e, cursor-column:offset
2265 ]
2266
2267 memory-should-contain [
2268 3 <- 1
2269 4 <- 3
2270 ]
2271 check-trace-count-for-label 0, [print-character]
2272 assume-console [
2273 type [1]
2274 ]
2275 run [
2276 editor-event-loop screen, console, e
2277 ]
2278 screen-should-contain [
2279 . .
2280 .de01 .
2281 .╌╌╌╌╌╌╌╌╌╌.
2282 . .
2283 ]
2284 ]
2285
2286 scenario editor-combines-page-and-line-scroll [
2287 local-scope
2288
2289 assume-screen 10/width, 4/height
2290
2291 s:text <- new [a
2292 b
2293 c
2294 d
2295 e
2296 f
2297 g]
2298 e:&:editor <- new-editor s, 0/left, 5/right
2299 editor-render screen, e
2300
2301 assume-console [
2302 press page-down
2303 left-click 3, 0
2304 press down-arrow
2305 ]
2306 run [
2307 editor-event-loop screen, console, e
2308 ]
2309
2310 screen-should-contain [
2311 . .
2312 .d .
2313 .e .
2314 .f .
2315 ]
2316 ]
2317
2318
2319
2320 scenario editor-can-scroll-up-using-arrow-keys [
2321 local-scope
2322
2323 assume-screen 10/width, 4/height
2324
2325 s:text <- new [a
2326 b
2327 c
2328 d]
2329 e:&:editor <- new-editor s, 0/left, 10/right
2330 editor-render screen, e
2331 screen-should-contain [
2332 . .
2333 .a .
2334 .b .
2335 .c .
2336 ]
2337
2338 assume-console [
2339 press page-down
2340 press up-arrow
2341 ]
2342 run [
2343 editor-event-loop screen, console, e
2344 ]
2345
2346 screen-should-contain [
2347 . .
2348 .b .
2349 .c .
2350 .d .
2351 ]
2352 ]
2353
2354 after <scroll-up> [
2355 trace 10, [app], [scroll up]
2356 top-of-screen:&:duplex-list:char <- get *editor, top-of-screen:offset
2357 old-top:&:duplex-list:char <- copy top-of-screen
2358 top-of-screen <- before-previous-line top-of-screen, editor
2359 *editor <- put *editor, top-of-screen:offset, top-of-screen
2360 no-movement?:bool <- equal old-top, top-of-screen
2361 return-if no-movement?, 0/don't-render
2362 ]
2363
2364
2365
2366
2367 def before-previous-line in:&:duplex-list:char, editor:&:editor -> out:&:duplex-list:char [
2368 local-scope
2369 load-ingredients
2370 curr:&:duplex-list:char <- copy in
2371 c:char <- get *curr, value:offset
2372
2373
2374
2375 left:num <- get *editor, left:offset
2376 right:num <- get *editor, right:offset
2377 max-line-length:num <- subtract right, left, -1/exclusive-right, 1/wrap-icon
2378 sentinel:&:duplex-list:char <- get *editor, data:offset
2379 len:num <- previous-line-length curr, sentinel
2380 {
2381 break-if len
2382
2383 prev:&:duplex-list:char <- prev curr
2384 return-unless prev, curr
2385 return prev
2386 }
2387 _, max:num <- divide-with-remainder len, max-line-length
2388
2389 {
2390 break-if max
2391 max <- copy max-line-length
2392 }
2393 max <- add max, 1
2394 count:num <- copy 0
2395
2396 {
2397 done?:bool <- greater-or-equal count, max
2398 break-if done?
2399 prev:&:duplex-list:char <- prev curr
2400 break-unless prev
2401 curr <- copy prev
2402 count <- add count, 1
2403 loop
2404 }
2405 return curr
2406 ]
2407
2408 scenario editor-scrolls-up-past-wrapped-line-using-arrow-keys [
2409 local-scope
2410
2411 assume-screen 10/width, 4/height
2412
2413
2414 s:text <- new [abcdef
2415 g
2416 h
2417 i]
2418 e:&:editor <- new-editor s, 0/left, 5/right
2419 editor-render screen, e
2420 screen-should-contain [
2421 . .
2422 .abcd↩ .
2423 .ef .
2424 .g .
2425 ]
2426
2427 assume-console [
2428 press page-down
2429 ]
2430 run [
2431 editor-event-loop screen, console, e
2432 ]
2433 screen-should-contain [
2434 . .
2435 .g .
2436 .h .
2437 .i .
2438 ]
2439
2440 assume-console [
2441 press up-arrow
2442 ]
2443 run [
2444 editor-event-loop screen, console, e
2445 ]
2446
2447 screen-should-contain [
2448 . .
2449 .ef .
2450 .g .
2451 .h .
2452 ]
2453 ]
2454
2455 scenario editor-scrolls-up-past-wrapped-line-using-arrow-keys-2 [
2456 local-scope
2457
2458 assume-screen 10/width, 5/height
2459
2460 s:text <- new [abcdefghij
2461 k
2462 l
2463 m]
2464 e:&:editor <- new-editor s, 0/left, 5/right
2465 editor-render screen, e
2466
2467 assume-console [
2468 press page-down
2469 ]
2470 run [
2471 editor-event-loop screen, console, e
2472 ]
2473 screen-should-contain [
2474 . .
2475 .k .
2476 .l .
2477 .m .
2478 .╌╌╌╌╌ .
2479 ]
2480
2481 assume-console [
2482 press up-arrow
2483 ]
2484 run [
2485 editor-event-loop screen, console, e
2486 ]
2487
2488 screen-should-contain [
2489 . .
2490 .ij .
2491 .k .
2492 .l .
2493 .m .
2494 ]
2495
2496 assume-console [
2497 press up-arrow
2498 ]
2499 run [
2500 editor-event-loop screen, console, e
2501 ]
2502
2503 screen-should-contain [
2504 . .
2505 .efgh↩ .
2506 .ij .
2507 .k .
2508 .l .
2509 ]
2510
2511 assume-console [
2512 press up-arrow
2513 ]
2514 run [
2515 editor-event-loop screen, console, e
2516 ]
2517
2518 screen-should-contain [
2519 . .
2520 .abcd↩ .
2521 .efgh↩ .
2522 .ij .
2523 .k .
2524 ]
2525 ]
2526
2527
2528
2529 scenario editor-scrolls-up-past-wrapped-line-using-arrow-keys-3 [
2530 local-scope
2531
2532 assume-screen 10/width, 4/height
2533
2534
2535 s:text <- new [abcdef
2536 g
2537 h
2538 i]
2539 e:&:editor <- new-editor s, 0/left, 6/right
2540 editor-render screen, e
2541 screen-should-contain [
2542 . .
2543 .abcde↩ .
2544 .f .
2545 .g .
2546 ]
2547
2548 assume-console [
2549 press page-down
2550 ]
2551 run [
2552 editor-event-loop screen, console, e
2553 ]
2554 screen-should-contain [
2555 . .
2556 .g .
2557 .h .
2558 .i .
2559 ]
2560
2561 assume-console [
2562 press up-arrow
2563 ]
2564 run [
2565 editor-event-loop screen, console, e
2566 ]
2567
2568 screen-should-contain [
2569 . .
2570 .f .
2571 .g .
2572 .h .
2573 ]
2574 ]
2575
2576
2577 scenario editor-scrolls-up-past-wrapped-line-using-arrow-keys-4 [
2578 local-scope
2579 assume-screen 10/width, 4/height
2580
2581 s:text <- new [a
2582 b
2583
2584 c
2585 d
2586 e]
2587 e:&:editor <- new-editor s, 0/left, 6/right
2588 editor-render screen, e
2589 assume-console [
2590 press page-down
2591 ]
2592 run [
2593 editor-event-loop screen, console, e
2594 ]
2595 screen-should-contain [
2596 . .
2597 . .
2598 .c .
2599 .d .
2600 ]
2601 assume-console [
2602 press page-down
2603 ]
2604 run [
2605 editor-event-loop screen, console, e
2606 ]
2607 screen-should-contain [
2608 . .
2609 .d .
2610 .e .
2611 .╌╌╌╌╌╌ .
2612 ]
2613 assume-console [
2614 press page-up
2615 ]
2616 run [
2617 editor-event-loop screen, console, e
2618 ]
2619 screen-should-contain [
2620 . .
2621 . .
2622 .c .
2623 .d .
2624 ]
2625 ]
2626
2627 scenario editor-scrolls-up-on-left-arrow [
2628 local-scope
2629
2630 assume-screen 5/width, 4/height
2631
2632 s:text <- new [a
2633 b
2634 c
2635 d
2636 e]
2637 e:&:editor <- new-editor s, 0/left, 5/right
2638 editor-render screen, e
2639
2640 assume-console [
2641 press page-down
2642 ]
2643 run [
2644 editor-event-loop screen, console, e
2645 ]
2646 screen-should-contain [
2647 . .
2648 .c .
2649 .d .
2650 .e .
2651 ]
2652
2653 assume-console [
2654 press left-arrow
2655 ]
2656 run [
2657 editor-event-loop screen, console, e
2658 3:num/raw <- get *e, cursor-row:offset
2659 4:num/raw <- get *e, cursor-column:offset
2660 ]
2661
2662 screen-should-contain [
2663 . .
2664 .b .
2665 .c .
2666 .d .
2667 ]
2668 memory-should-contain [
2669 3 <- 1
2670 4 <- 1
2671 ]
2672 ]
2673
2674 scenario editor-can-scroll-up-to-start-of-file [
2675 local-scope
2676
2677 assume-screen 10/width, 4/height
2678
2679 s:text <- new [a
2680 b
2681 c
2682 d]
2683 e:&:editor <- new-editor s, 0/left, 10/right
2684 editor-render screen, e
2685 screen-should-contain [
2686 . .
2687 .a .
2688 .b .
2689 .c .
2690 ]
2691
2692
2693 assume-console [
2694 press page-down
2695 press up-arrow
2696 press up-arrow
2697 ]
2698 run [
2699 editor-event-loop screen, console, e
2700 ]
2701
2702 screen-should-contain [
2703 . .
2704 .a .
2705 .b .
2706 .c .
2707 ]
2708
2709 assume-console [
2710 press up-arrow
2711 ]
2712 run [
2713 editor-event-loop screen, console, e
2714 ]
2715
2716 screen-should-contain [
2717 . .
2718 .a .
2719 .b .
2720 .c .
2721 ]
2722 ]
2723
2724
2725
2726 scenario editor-can-scroll [
2727 local-scope
2728 assume-screen 10/width, 4/height
2729 s:text <- new [a
2730 b
2731 c
2732 d]
2733 e:&:editor <- new-editor s, 0/left, 10/right
2734 editor-render screen, e
2735 screen-should-contain [
2736 . .
2737 .a .
2738 .b .
2739 .c .
2740 ]
2741
2742 assume-console [
2743 press page-down
2744 ]
2745 run [
2746 editor-event-loop screen, console, e
2747 ]
2748
2749 screen-should-contain [
2750 . .
2751 .c .
2752 .d .
2753 .╌╌╌╌╌╌╌╌╌╌.
2754 ]
2755 ]
2756
2757 after <handle-special-character> [
2758 {
2759 page-down?:bool <- equal c, 6/ctrl-f
2760 break-unless page-down?
2761 old-top:&:duplex-list:char <- get *editor, top-of-screen:offset
2762 <move-cursor-begin>
2763 page-down editor
2764 undo-coalesce-tag:num <- copy 0/never
2765 <move-cursor-end>
2766 top-of-screen:&:duplex-list:char <- get *editor, top-of-screen:offset
2767 movement?:bool <- not-equal top-of-screen, old-top
2768 return movement?/go-render
2769 }
2770 ]
2771
2772 after <handle-special-key> [
2773 {
2774 page-down?:bool <- equal k, 65518/page-down
2775 break-unless page-down?
2776 old-top:&:duplex-list:char <- get *editor, top-of-screen:offset
2777 <move-cursor-begin>
2778 page-down editor
2779 undo-coalesce-tag:num <- copy 0/never
2780 <move-cursor-end>
2781 top-of-screen:&:duplex-list:char <- get *editor, top-of-screen:offset
2782 movement?:bool <- not-equal top-of-screen, old-top
2783 return movement?/go-render
2784 }
2785 ]
2786
2787
2788
2789 def page-down editor:&:editor -> editor:&:editor [
2790 local-scope
2791 load-ingredients
2792
2793 bottom-of-screen:&:duplex-list:char <- get *editor, bottom-of-screen:offset
2794 return-unless bottom-of-screen
2795
2796 before-cursor:&:duplex-list:char <- get *editor, before-cursor:offset
2797 before-cursor:&:duplex-list:char <- prev bottom-of-screen
2798 *editor <- put *editor, before-cursor:offset, before-cursor
2799
2800 {
2801 last:char <- get *before-cursor, value:offset
2802 newline?:bool <- equal last, 10/newline
2803 break-unless newline?:bool
2804 before-cursor <- prev before-cursor
2805 *editor <- put *editor, before-cursor:offset, before-cursor
2806 }
2807
2808 move-to-start-of-line editor
2809 before-cursor <- get *editor, before-cursor:offset
2810 *editor <- put *editor, top-of-screen:offset, before-cursor
2811 ]
2812
2813 scenario editor-does-not-scroll-past-end [
2814 local-scope
2815 assume-screen 10/width, 4/height
2816 s:text <- new [a
2817 b]
2818 e:&:editor <- new-editor s, 0/left, 10/right
2819 editor-render screen, e
2820 screen-should-contain [
2821 . .
2822 .a .
2823 .b .
2824 .╌╌╌╌╌╌╌╌╌╌.
2825 ]
2826
2827 assume-console [
2828 press page-down
2829 ]
2830 run [
2831 editor-event-loop screen, console, e
2832 ]
2833
2834 screen-should-contain [
2835 . .
2836 .a .
2837 .b .
2838 .╌╌╌╌╌╌╌╌╌╌.
2839 ]
2840 ]
2841
2842 scenario editor-starts-next-page-at-start-of-wrapped-line [
2843 local-scope
2844
2845 assume-screen 10/width, 4/height
2846
2847 s:text <- new [a
2848 b
2849 cdefgh]
2850
2851 e:&:editor <- new-editor s, 0/left, 4/right
2852 editor-render screen, e
2853
2854 screen-should-contain [
2855 . .
2856 .a .
2857 .b .
2858 .cde↩ .
2859 ]
2860
2861 assume-console [
2862 press page-down
2863 ]
2864 run [
2865 editor-event-loop screen, console, e
2866 ]
2867
2868 screen-should-contain [
2869 . .
2870 .cde↩ .
2871 .fgh .
2872 .╌╌╌╌ .
2873 ]
2874 ]
2875
2876 scenario editor-starts-next-page-at-start-of-wrapped-line-2 [
2877 local-scope
2878
2879 assume-screen 10/width, 4/height
2880
2881
2882 s:text <- new [a
2883 bcdefgh]
2884 e:&:editor <- new-editor s, 0/left, 4/right
2885 editor-render screen, e
2886
2887 screen-should-contain [
2888 . .
2889 .a .
2890 .bcd↩ .
2891 .efg↩ .
2892 ]
2893
2894 assume-console [
2895 press page-down
2896 ]
2897 run [
2898 editor-event-loop screen, console, e
2899 ]
2900
2901 screen-should-contain [
2902 . .
2903 .bcd↩ .
2904 .efg↩ .
2905 .h .
2906 ]
2907 ]
2908
2909
2910
2911 scenario editor-can-scroll-up [
2912 local-scope
2913 assume-screen 10/width, 4/height
2914 s:text <- new [a
2915 b
2916 c
2917 d]
2918 e:&:editor <- new-editor s, 0/left, 10/right
2919 editor-render screen, e
2920 screen-should-contain [
2921 . .
2922 .a .
2923 .b .
2924 .c .
2925 ]
2926
2927 assume-console [
2928 press page-down
2929 ]
2930 run [
2931 editor-event-loop screen, console, e
2932 ]
2933
2934 screen-should-contain [
2935 . .
2936 .c .
2937 .d .
2938 .╌╌╌╌╌╌╌╌╌╌.
2939 ]
2940
2941 assume-console [
2942 press page-up
2943 ]
2944 run [
2945 editor-event-loop screen, console, e
2946 ]
2947
2948 screen-should-contain [
2949 . .
2950 .a .
2951 .b .
2952 .c .
2953 ]
2954 ]
2955
2956 after <handle-special-character> [
2957 {
2958 page-up?:bool <- equal c, 2/ctrl-b
2959 break-unless page-up?
2960 old-top:&:duplex-list:char <- get *editor, top-of-screen:offset
2961 <move-cursor-begin>
2962 editor <- page-up editor, screen-height
2963 undo-coalesce-tag:num <- copy 0/never
2964 <move-cursor-end>
2965 top-of-screen:&:duplex-list:char <- get *editor, top-of-screen:offset
2966 movement?:bool <- not-equal top-of-screen, old-top
2967 return movement?/go-render
2968 }
2969 ]
2970
2971 after <handle-special-key> [
2972 {
2973 page-up?:bool <- equal k, 65519/page-up
2974 break-unless page-up?
2975 old-top:&:duplex-list:char <- get *editor, top-of-screen:offset
2976 <move-cursor-begin>
2977 editor <- page-up editor, screen-height
2978 undo-coalesce-tag:num <- copy 0/never
2979 <move-cursor-end>
2980 top-of-screen:&:duplex-list:char <- get *editor, top-of-screen:offset
2981 movement?:bool <- not-equal top-of-screen, old-top
2982
2983 return movement?/go-render
2984 }
2985 ]
2986
2987 def page-up editor:&:editor, screen-height:num -> editor:&:editor [
2988 local-scope
2989 load-ingredients
2990 max:num <- subtract screen-height, 1/menu-bar, 1/overlapping-line
2991 count:num <- copy 0
2992 top-of-screen:&:duplex-list:char <- get *editor, top-of-screen:offset
2993 {
2994 done?:bool <- greater-or-equal count, max
2995 break-if done?
2996 prev:&:duplex-list:char <- before-previous-line top-of-screen, editor
2997 break-unless prev
2998 top-of-screen <- copy prev
2999 *editor <- put *editor, top-of-screen:offset, top-of-screen
3000 count <- add count, 1
3001 loop
3002 }
3003 ]
3004
3005 scenario editor-can-scroll-up-multiple-pages [
3006 local-scope
3007
3008 assume-screen 10/width, 4/height
3009
3010 s:text <- new [a
3011 b
3012 c
3013 d
3014 e
3015 f
3016 g
3017 h]
3018 e:&:editor <- new-editor s, 0/left, 10/right
3019 editor-render screen, e
3020 screen-should-contain [
3021 . .
3022 .a .
3023 .b .
3024 .c .
3025 ]
3026
3027 assume-console [
3028 press page-down
3029 press page-down
3030 ]
3031 run [
3032 editor-event-loop screen, console, e
3033 ]
3034
3035 screen-should-contain [
3036 . .
3037 .e .
3038 .f .
3039 .g .
3040 ]
3041
3042 assume-console [
3043 press page-up
3044 ]
3045 run [
3046 editor-event-loop screen, console, e
3047 ]
3048
3049 screen-should-contain [
3050 . .
3051 .c .
3052 .d .
3053 .e .
3054 ]
3055
3056 assume-console [
3057 press page-up
3058 ]
3059 run [
3060 editor-event-loop screen, console, e
3061 ]
3062
3063 screen-should-contain [
3064 . .
3065 .a .
3066 .b .
3067 .c .
3068 ]
3069 ]
3070
3071 scenario editor-can-scroll-up-wrapped-lines [
3072 local-scope
3073
3074 assume-screen 10/width, 6/height
3075
3076 s:text <- new [a
3077 b
3078 cdefgh
3079 i
3080 j
3081 k
3082 l
3083 m
3084 n
3085 o]
3086
3087 e:&:editor <- new-editor s, 0/left, 4/right
3088 editor-render screen, e
3089
3090 screen-should-contain [
3091 . .
3092 .a .
3093 .b .
3094 .cde↩ .
3095 .fgh .
3096 .i .
3097 ]
3098
3099 assume-console [
3100 press page-down
3101 left-click 5, 0
3102 press down-arrow
3103 ]
3104 run [
3105 editor-event-loop screen, console, e
3106 ]
3107
3108 screen-should-contain [
3109 . .
3110 .j .
3111 .k .
3112 .l .
3113 .m .
3114 .n .
3115 ]
3116
3117 assume-console [
3118 press page-up
3119 ]
3120 run [
3121 editor-event-loop screen, console, e
3122 ]
3123
3124 screen-should-contain [
3125 . .
3126 .b .
3127 .cde↩ .
3128 .fgh .
3129 .i .
3130 .j .
3131 ]
3132 ]
3133
3134 scenario editor-can-scroll-up-wrapped-lines-2 [
3135 local-scope
3136
3137 assume-screen 10/width, 4/height
3138
3139
3140 s:text <- new [a
3141 bcdefgh]
3142 e:&:editor <- new-editor s, 0/left, 4/right
3143 editor-render screen, e
3144
3145 screen-should-contain [
3146 . .
3147 .a .
3148 .bcd↩ .
3149 .efg↩ .
3150 ]
3151
3152 assume-console [
3153 press page-down
3154 ]
3155 run [
3156 editor-event-loop screen, console, e
3157 ]
3158
3159 screen-should-contain [
3160 . .
3161 .bcd↩ .
3162 .efg↩ .
3163 .h .
3164 ]
3165
3166 assume-console [
3167 press page-up
3168 ]
3169 run [
3170 editor-event-loop screen, console, e
3171 ]
3172
3173 screen-should-contain [
3174 . .
3175 .a .
3176 .bcd↩ .
3177 .efg↩ .
3178 ]
3179 ]
3180
3181 scenario editor-can-scroll-up-past-nonempty-lines [
3182 local-scope
3183 assume-screen 10/width, 4/height
3184
3185 s:text <- new [axx
3186 bxx
3187 cxx
3188 dxx
3189 exx
3190 fxx
3191 gxx
3192 hxx
3193 ]
3194 e:&:editor <- new-editor s, 0/left, 4/right
3195 editor-render screen, e
3196 screen-should-contain [
3197 . .
3198 .axx .
3199 .bxx .
3200 .cxx .
3201 ]
3202 assume-console [
3203 press page-down
3204 ]
3205 run [
3206 editor-event-loop screen, console, e
3207 ]
3208 screen-should-contain [
3209 . .
3210 .cxx .
3211 .dxx .
3212 .exx .
3213 ]
3214 assume-console [
3215 press page-down
3216 ]
3217 run [
3218 editor-event-loop screen, console, e
3219 ]
3220 screen-should-contain [
3221 . .
3222 .exx .
3223 .fxx .
3224 .gxx .
3225 ]
3226
3227 assume-console [
3228 press page-up
3229 ]
3230 run [
3231 editor-event-loop screen, console, e
3232 ]
3233 screen-should-contain [
3234 . .
3235 .cxx .
3236 .dxx .
3237 .exx .
3238 ]
3239 ]
3240
3241 scenario editor-can-scroll-up-past-empty-lines [
3242 local-scope
3243 assume-screen 10/width, 4/height
3244
3245 s:text <- new [axy
3246 bxy
3247 cxy
3248
3249 dxy
3250 exy
3251 fxy
3252 gxy
3253 ]
3254 e:&:editor <- new-editor s, 0/left, 4/right
3255 editor-render screen, e
3256 screen-should-contain [
3257 . .
3258 .axy .
3259 .bxy .
3260 .cxy .
3261 ]
3262 assume-console [
3263 press page-down
3264 ]
3265 run [
3266 editor-event-loop screen, console, e
3267 ]
3268 screen-should-contain [
3269 . .
3270 .cxy .
3271 . .
3272 .dxy .
3273 ]
3274 assume-console [
3275 press page-down
3276 ]
3277 run [
3278 editor-event-loop screen, console, e
3279 ]
3280 screen-should-contain [
3281 . .
3282 .dxy .
3283 .exy .
3284 .fxy .
3285 ]
3286
3287 assume-console [
3288 press page-up
3289 ]
3290 run [
3291 editor-event-loop screen, console, e
3292 ]
3293 screen-should-contain [
3294 . .
3295 .cxy .
3296 . .
3297 .dxy .
3298 ]
3299 ]