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 scenario editor-adjusts-column-at-previous-line [
1064 local-scope
1065 assume-screen 10/width, 5/height
1066 s:text <- new [ab
1067 def]
1068 e:&:editor <- new-editor s, 0/left, 10/right
1069 editor-render screen, e
1070 $clear-trace
1071 assume-console [
1072 left-click 2, 3
1073 press up-arrow
1074 ]
1075 run [
1076 editor-event-loop screen, console, e
1077 3:num/raw <- get *e, cursor-row:offset
1078 4:num/raw <- get *e, cursor-column:offset
1079 ]
1080 memory-should-contain [
1081 3 <- 1
1082 4 <- 2
1083 ]
1084 check-trace-count-for-label 0, [print-character]
1085 assume-console [
1086 type [0]
1087 ]
1088 run [
1089 editor-event-loop screen, console, e
1090 ]
1091 screen-should-contain [
1092 . .
1093 .ab0 .
1094 .def .
1095 .╌╌╌╌╌╌╌╌╌╌.
1096 . .
1097 ]
1098 ]
1099
1100 scenario editor-adjusts-column-at-empty-line [
1101 local-scope
1102 assume-screen 10/width, 5/height
1103 s:text <- new [
1104 def]
1105 e:&:editor <- new-editor s, 0/left, 10/right
1106 editor-render screen, e
1107 $clear-trace
1108 assume-console [
1109 left-click 2, 3
1110 press up-arrow
1111 ]
1112 run [
1113 editor-event-loop screen, console, e
1114 3:num/raw <- get *e, cursor-row:offset
1115 4:num/raw <- get *e, cursor-column:offset
1116 ]
1117 memory-should-contain [
1118 3 <- 1
1119 4 <- 0
1120 ]
1121 check-trace-count-for-label 0, [print-character]
1122 assume-console [
1123 type [0]
1124 ]
1125 run [
1126 editor-event-loop screen, console, e
1127 ]
1128 screen-should-contain [
1129 . .
1130 .0 .
1131 .def .
1132 .╌╌╌╌╌╌╌╌╌╌.
1133 . .
1134 ]
1135 ]
1136
1137 scenario editor-moves-to-previous-line-from-zero-margin [
1138 local-scope
1139 assume-screen 10/width, 5/height
1140
1141 s:text <- new [abc
1142 def
1143 ghi]
1144 e:&:editor <- new-editor s, 0/left, 10/right
1145 editor-render screen, e
1146 $clear-trace
1147
1148 assume-console [
1149 left-click 3, 0
1150 press up-arrow
1151 ]
1152 run [
1153 editor-event-loop screen, console, e
1154 3:num/raw <- get *e, cursor-row:offset
1155 4:num/raw <- get *e, cursor-column:offset
1156 ]
1157 memory-should-contain [
1158 3 <- 2
1159 4 <- 0
1160 ]
1161 check-trace-count-for-label 0, [print-character]
1162 assume-console [
1163 type [0]
1164 ]
1165 run [
1166 editor-event-loop screen, console, e
1167 ]
1168 screen-should-contain [
1169 . .
1170 .abc .
1171 .0def .
1172 .ghi .
1173 .╌╌╌╌╌╌╌╌╌╌.
1174 ]
1175 ]
1176
1177 scenario editor-moves-to-previous-line-from-left-margin [
1178 local-scope
1179 assume-screen 10/width, 5/height
1180
1181 s:text <- new [abc
1182 def
1183 ghi]
1184 e:&:editor <- new-editor s, 1/left, 10/right
1185 editor-render screen, e
1186 $clear-trace
1187
1188 assume-console [
1189 left-click 3, 1
1190 press up-arrow
1191 ]
1192 run [
1193 editor-event-loop screen, console, e
1194 3:num/raw <- get *e, cursor-row:offset
1195 4:num/raw <- get *e, cursor-column:offset
1196 ]
1197 memory-should-contain [
1198 3 <- 2
1199 4 <- 1
1200 ]
1201 check-trace-count-for-label 0, [print-character]
1202 assume-console [
1203 type [0]
1204 ]
1205 run [
1206 editor-event-loop screen, console, e
1207 ]
1208 screen-should-contain [
1209 . .
1210 . abc .
1211 . 0def .
1212 . ghi .
1213 . ╌╌╌╌╌╌╌╌╌.
1214 ]
1215 ]
1216
1217 scenario editor-moves-to-top-line-in-presence-of-wrapped-line [
1218 local-scope
1219 assume-screen 10/width, 5/height
1220 e:&:editor <- new-editor [abcde], 0/left, 5/right
1221 editor-render screen, e
1222 screen-should-contain [
1223 . .
1224 .abcd↩ .
1225 .e .
1226 .╌╌╌╌╌ .
1227 ]
1228 $clear-trace
1229 assume-console [
1230 left-click 2, 0
1231 press up-arrow
1232 ]
1233 run [
1234 editor-event-loop screen, console, e
1235 3:num/raw <- get *e, cursor-row:offset
1236 4:num/raw <- get *e, cursor-column:offset
1237 ]
1238 memory-should-contain [
1239 3 <- 1
1240 4 <- 0
1241 ]
1242 check-trace-count-for-label 0, [print-character]
1243 assume-console [
1244 type [0]
1245 ]
1246 run [
1247 editor-event-loop screen, console, e
1248 ]
1249 screen-should-contain [
1250 . .
1251 .0abc↩ .
1252 .de .
1253 .╌╌╌╌╌ .
1254 ]
1255 ]
1256
1257 scenario editor-moves-to-top-line-in-presence-of-wrapped-line-2 [
1258 local-scope
1259 assume-screen 10/width, 5/height
1260 s:text <- new [abc
1261 defgh]
1262 e:&:editor <- new-editor s, 0/left, 5/right
1263 editor-render screen, e
1264 screen-should-contain [
1265 . .
1266 .abc .
1267 .defg↩ .
1268 .h .
1269 .╌╌╌╌╌ .
1270 ]
1271 $clear-trace
1272 assume-console [
1273 left-click 3, 0
1274 press up-arrow
1275 press up-arrow
1276 ]
1277 run [
1278 editor-event-loop screen, console, e
1279 3:num/raw <- get *e, cursor-row:offset
1280 4:num/raw <- get *e, cursor-column:offset
1281 ]
1282 memory-should-contain [
1283 3 <- 1
1284 4 <- 0
1285 ]
1286 check-trace-count-for-label 0, [print-character]
1287 assume-console [
1288 type [0]
1289 ]
1290 run [
1291 editor-event-loop screen, console, e
1292 ]
1293 screen-should-contain [
1294 . .
1295 .0abc .
1296 .defg↩ .
1297 .h .
1298 .╌╌╌╌╌ .
1299 ]
1300 ]
1301
1302
1303
1304 scenario editor-moves-to-next-line-with-down-arrow [
1305 local-scope
1306 assume-screen 10/width, 5/height
1307 s:text <- new [abc
1308 def]
1309 e:&:editor <- new-editor s, 0/left, 10/right
1310 editor-render screen, e
1311 $clear-trace
1312
1313 assume-console [
1314 press down-arrow
1315 ]
1316 run [
1317 editor-event-loop screen, console, e
1318 3:num/raw <- get *e, cursor-row:offset
1319 4:num/raw <- get *e, cursor-column:offset
1320 ]
1321
1322 memory-should-contain [
1323 3 <- 2
1324 4 <- 0
1325 ]
1326 check-trace-count-for-label 0, [print-character]
1327 assume-console [
1328 type [0]
1329 ]
1330 run [
1331 editor-event-loop screen, console, e
1332 ]
1333 screen-should-contain [
1334 . .
1335 .abc .
1336 .0def .
1337 .╌╌╌╌╌╌╌╌╌╌.
1338 . .
1339 ]
1340 ]
1341
1342 after <handle-special-key> [
1343 {
1344 move-to-next-line?:bool <- equal k, 65516/down-arrow
1345 break-unless move-to-next-line?
1346 <begin-move-cursor>
1347 go-render? <- move-to-next-line editor, screen-height
1348 undo-coalesce-tag:num <- copy 4/down-arrow
1349 <end-move-cursor>
1350 return
1351 }
1352 ]
1353
1354 def move-to-next-line editor:&:editor, screen-height:num -> go-render?:bool, editor:&:editor [
1355 local-scope
1356 load-inputs
1357 cursor-row:num <- get *editor, cursor-row:offset
1358 cursor-column:num <- get *editor, cursor-column:offset
1359 before-cursor:&:duplex-list:char <- get *editor, before-cursor:offset
1360 left:num <- get *editor, left:offset
1361 right:num <- get *editor, right:offset
1362 last-line:num <- subtract screen-height, 1
1363 bottom:num <- get *editor, bottom:offset
1364 at-bottom-of-screen?:bool <- greater-or-equal bottom, last-line
1365 {
1366 break-if before-cursor
1367 {
1368 break-if at-bottom-of-screen?
1369 return 0/don't-render
1370 }
1371 {
1372 break-unless at-bottom-of-screen?
1373 jump +try-to-scroll
1374 }
1375 }
1376 next:&:duplex-list:char <- next before-cursor
1377 {
1378 break-if next
1379 {
1380 break-if at-bottom-of-screen?
1381 return 0/don't-render
1382 }
1383 {
1384 break-unless at-bottom-of-screen?
1385 jump +try-to-scroll
1386 }
1387 }
1388 already-at-bottom?:bool <- greater-or-equal cursor-row, last-line
1389 {
1390
1391 break-if already-at-bottom?
1392 target-column:num <- copy cursor-column
1393
1394 {
1395 next:&:duplex-list:char <- next before-cursor
1396 break-unless next
1397 done?:bool <- greater-or-equal cursor-column, right
1398 break-if done?
1399 cursor-column <- add cursor-column, 1
1400 before-cursor <- copy next
1401 c:char <- get *next, value:offset
1402 at-newline?:bool <- equal c, 10/newline
1403 break-if at-newline?
1404 loop
1405 }
1406 {
1407 break-if next
1408 {
1409 break-if at-bottom-of-screen?
1410 return 0/don't-render
1411 }
1412 {
1413 break-unless at-bottom-of-screen?
1414 jump +try-to-scroll
1415 }
1416 }
1417 cursor-row <- add cursor-row, 1
1418 cursor-column <- copy left
1419 {
1420 next:&:duplex-list:char <- next before-cursor
1421 break-unless next
1422 c:char <- get *next, value:offset
1423 at-newline?:bool <- equal c, 10/newline
1424 break-if at-newline?
1425 done?:bool <- greater-or-equal cursor-column, target-column
1426 break-if done?
1427 cursor-column <- add cursor-column, 1
1428 before-cursor <- copy next
1429 loop
1430 }
1431 *editor <- put *editor, before-cursor:offset, before-cursor
1432 *editor <- put *editor, cursor-column:offset, cursor-column
1433 *editor <- put *editor, cursor-row:offset, cursor-row
1434 return 0/don't-render
1435 }
1436 +try-to-scroll
1437 <scroll-down>
1438 go-render? <- copy 1/true
1439 ]
1440
1441 scenario editor-adjusts-column-at-next-line [
1442 local-scope
1443 assume-screen 10/width, 5/height
1444
1445 s:text <- new [abcde
1446 fg
1447 hi]
1448 e:&:editor <- new-editor s, 0/left, 10/right
1449 editor-render screen, e
1450 $clear-trace
1451
1452 assume-console [
1453 left-click 1, 8
1454 press down-arrow
1455 ]
1456 run [
1457 editor-event-loop screen, console, e
1458 3:num/raw <- get *e, cursor-row:offset
1459 4:num/raw <- get *e, cursor-column:offset
1460 ]
1461
1462 memory-should-contain [
1463 3 <- 2
1464 4 <- 2
1465 ]
1466 check-trace-count-for-label 0, [print-character]
1467 assume-console [
1468 type [0]
1469 ]
1470 run [
1471 editor-event-loop screen, console, e
1472 ]
1473 screen-should-contain [
1474 . .
1475 .abcde .
1476 .fg0 .
1477 .hi .
1478 .╌╌╌╌╌╌╌╌╌╌.
1479 ]
1480 ]
1481
1482 scenario editor-moves-down-within-wrapped-line [
1483 local-scope
1484 assume-screen 10/width, 5/height
1485 e:&:editor <- new-editor [abcdefghijklmno], 0/left, 10/right
1486 editor-render screen, e
1487 screen-should-contain [
1488 . .
1489 .abcdefghi↩.
1490 .jklmno .
1491 .╌╌╌╌╌╌╌╌╌╌.
1492 . .
1493 ]
1494
1495 assume-console [
1496 left-click 1, 8
1497 press down-arrow
1498 ]
1499 run [
1500 editor-event-loop screen, console, e
1501 3:num/raw <- get *e, cursor-row:offset
1502 4:num/raw <- get *e, cursor-column:offset
1503 ]
1504
1505 memory-should-contain [
1506 3 <- 2
1507 4 <- 6
1508 ]
1509 ]
1510
1511
1512
1513 scenario editor-moves-to-start-of-line-with-ctrl-a [
1514 local-scope
1515 assume-screen 10/width, 5/height
1516 s:text <- new [123
1517 456]
1518 e:&:editor <- new-editor s, 0/left, 10/right
1519 editor-render screen, e
1520 $clear-trace
1521
1522 assume-console [
1523 left-click 2, 3
1524 press ctrl-a
1525 ]
1526 run [
1527 editor-event-loop screen, console, e
1528 4:num/raw <- get *e, cursor-row:offset
1529 5:num/raw <- get *e, cursor-column:offset
1530 ]
1531
1532 memory-should-contain [
1533 4 <- 2
1534 5 <- 0
1535 ]
1536 check-trace-count-for-label 0, [print-character]
1537 ]
1538
1539 after <handle-special-character> [
1540 {
1541 move-to-start-of-line?:bool <- equal c, 1/ctrl-a
1542 break-unless move-to-start-of-line?
1543 <begin-move-cursor>
1544 move-to-start-of-screen-line editor
1545 undo-coalesce-tag:num <- copy 0/never
1546 <end-move-cursor>
1547 return 0/don't-render
1548 }
1549 ]
1550
1551 after <handle-special-key> [
1552 {
1553 move-to-start-of-line?:bool <- equal k, 65521/home
1554 break-unless move-to-start-of-line?
1555 <begin-move-cursor>
1556 move-to-start-of-screen-line editor
1557 undo-coalesce-tag:num <- copy 0/never
1558 <end-move-cursor>
1559 return 0/don't-render
1560 }
1561 ]
1562
1563
1564
1565 def move-to-start-of-screen-line editor:&:editor -> editor:&:editor [
1566 local-scope
1567 load-inputs
1568
1569 left:num <- get *editor, left:offset
1570 col:num <- get *editor, cursor-column:offset
1571
1572 curr:&:duplex-list:char <- get *editor, before-cursor:offset
1573
1574 {
1575 done?:bool <- equal col, left
1576 break-if done?
1577 assert curr, [move-to-start-of-line tried to move before start of text]
1578 curr <- prev curr
1579 col <- subtract col, 1
1580 loop
1581 }
1582 *editor <- put *editor, cursor-column:offset, col
1583 *editor <- put *editor, before-cursor:offset, curr
1584 ]
1585
1586 scenario editor-moves-to-start-of-line-with-ctrl-a-2 [
1587 local-scope
1588 assume-screen 10/width, 5/height
1589 s:text <- new [123
1590 456]
1591 e:&:editor <- new-editor s, 0/left, 10/right
1592 editor-render screen, e
1593 $clear-trace
1594
1595 assume-console [
1596 left-click 1, 3
1597 press ctrl-a
1598 ]
1599 run [
1600 editor-event-loop screen, console, e
1601 4:num/raw <- get *e, cursor-row:offset
1602 5:num/raw <- get *e, cursor-column:offset
1603 ]
1604
1605 memory-should-contain [
1606 4 <- 1
1607 5 <- 0
1608 ]
1609 check-trace-count-for-label 0, [print-character]
1610 ]
1611
1612 scenario editor-moves-to-start-of-line-with-home [
1613 local-scope
1614 assume-screen 10/width, 5/height
1615 s:text <- new [123
1616 456]
1617 e:&:editor <- new-editor s, 0/left, 10/right
1618 $clear-trace
1619
1620 assume-console [
1621 left-click 2, 3
1622 press home
1623 ]
1624 run [
1625 editor-event-loop screen, console, e
1626 3:num/raw <- get *e, cursor-row:offset
1627 4:num/raw <- get *e, cursor-column:offset
1628 ]
1629
1630 memory-should-contain [
1631 3 <- 2
1632 4 <- 0
1633 ]
1634 check-trace-count-for-label 0, [print-character]
1635 ]
1636
1637 scenario editor-moves-to-start-of-line-with-home-2 [
1638 local-scope
1639 assume-screen 10/width, 5/height
1640 s:text <- new [123
1641 456]
1642 e:&:editor <- new-editor s, 0/left, 10/right
1643 editor-render screen, e
1644 $clear-trace
1645
1646 assume-console [
1647 left-click 1, 3
1648 press home
1649 ]
1650 run [
1651 editor-event-loop screen, console, e
1652 3:num/raw <- get *e, cursor-row:offset
1653 4:num/raw <- get *e, cursor-column:offset
1654 ]
1655
1656 memory-should-contain [
1657 3 <- 1
1658 4 <- 0
1659 ]
1660 check-trace-count-for-label 0, [print-character]
1661 ]
1662
1663 scenario editor-moves-to-start-of-screen-line-with-ctrl-a [
1664 local-scope
1665 assume-screen 10/width, 5/height
1666 e:&:editor <- new-editor [123456], 0/left, 5/right
1667 editor-render screen, e
1668 screen-should-contain [
1669 . .
1670 .1234↩ .
1671 .56 .
1672 .╌╌╌╌╌ .
1673 . .
1674 ]
1675 $clear-trace
1676
1677 assume-console [
1678 left-click 2, 1
1679 press ctrl-a
1680 press up-arrow
1681 ]
1682 run [
1683 editor-event-loop screen, console, e
1684 4:num/raw <- get *e, cursor-row:offset
1685 5:num/raw <- get *e, cursor-column:offset
1686 ]
1687
1688 memory-should-contain [
1689 4 <- 1
1690 5 <- 0
1691 ]
1692 check-trace-count-for-label 0, [print-character]
1693
1694 assume-console [
1695 type [a]
1696 ]
1697 run [
1698 editor-event-loop screen, console, e
1699 4:num/raw <- get *e, cursor-row:offset
1700 5:num/raw <- get *e, cursor-column:offset
1701 ]
1702 screen-should-contain [
1703 . .
1704 .a123↩ .
1705 .456 .
1706 .╌╌╌╌╌ .
1707 . .
1708 ]
1709 memory-should-contain [
1710 4 <- 1
1711 5 <- 1
1712 ]
1713 ]
1714
1715
1716
1717 scenario editor-moves-to-end-of-line-with-ctrl-e [
1718 local-scope
1719 assume-screen 10/width, 5/height
1720 s:text <- new [123
1721 456]
1722 e:&:editor <- new-editor s, 0/left, 10/right
1723 editor-render screen, e
1724 $clear-trace
1725
1726 assume-console [
1727 left-click 1, 1
1728 press ctrl-e
1729 ]
1730 run [
1731 editor-event-loop screen, console, e
1732 4:num/raw <- get *e, cursor-row:offset
1733 5:num/raw <- get *e, cursor-column:offset
1734 ]
1735
1736 memory-should-contain [
1737 4 <- 1
1738 5 <- 3
1739 ]
1740 check-trace-count-for-label 0, [print-character]
1741
1742 assume-console [
1743 type [z]
1744 ]
1745 run [
1746 editor-event-loop screen, console, e
1747 4:num/raw <- get *e, cursor-row:offset
1748 5:num/raw <- get *e, cursor-column:offset
1749 ]
1750 memory-should-contain [
1751 4 <- 1
1752 5 <- 4
1753 ]
1754 screen-should-contain [
1755 . .
1756 .123z .
1757 .456 .
1758 .╌╌╌╌╌╌╌╌╌╌.
1759 . .
1760 ]
1761 check-trace-count-for-label 1, [print-character]
1762 ]
1763
1764 after <handle-special-character> [
1765 {
1766 move-to-end-of-line?:bool <- equal c, 5/ctrl-e
1767 break-unless move-to-end-of-line?
1768 <begin-move-cursor>
1769 move-to-end-of-line editor
1770 undo-coalesce-tag:num <- copy 0/never
1771 <end-move-cursor>
1772 return 0/don't-render
1773 }
1774 ]
1775
1776 after <handle-special-key> [
1777 {
1778 move-to-end-of-line?:bool <- equal k, 65520/end
1779 break-unless move-to-end-of-line?
1780 <begin-move-cursor>
1781 move-to-end-of-line editor
1782 undo-coalesce-tag:num <- copy 0/never
1783 <end-move-cursor>
1784 return 0/don't-render
1785 }
1786 ]
1787
1788 def move-to-end-of-line editor:&:editor -> editor:&:editor [
1789 local-scope
1790 load-inputs
1791 before-cursor:&:duplex-list:char <- get *editor, before-cursor:offset
1792 cursor-column:num <- get *editor, cursor-column:offset
1793 right:num <- get *editor, right:offset
1794
1795 {
1796 next:&:duplex-list:char <- next before-cursor
1797 break-unless next
1798 nextc:char <- get *next, value:offset
1799 at-end-of-line?:bool <- equal nextc, 10/newline
1800 break-if at-end-of-line?
1801 cursor-column <- add cursor-column, 1
1802 at-right?:bool <- equal cursor-column, right
1803 break-if at-right?
1804 *editor <- put *editor, cursor-column:offset, cursor-column
1805 before-cursor <- copy next
1806 *editor <- put *editor, before-cursor:offset, before-cursor
1807 loop
1808 }
1809 ]
1810
1811 scenario editor-moves-to-end-of-line-with-ctrl-e-2 [
1812 local-scope
1813 assume-screen 10/width, 5/height
1814 s:text <- new [123
1815 456]
1816 e:&:editor <- new-editor s, 0/left, 10/right
1817 editor-render screen, e
1818 $clear-trace
1819
1820 assume-console [
1821 left-click 2, 1
1822 press ctrl-e
1823 ]
1824 run [
1825 editor-event-loop screen, console, e
1826 4:num/raw <- get *e, cursor-row:offset
1827 5:num/raw <- get *e, cursor-column:offset
1828 ]
1829
1830 memory-should-contain [
1831 4 <- 2
1832 5 <- 3
1833 ]
1834 check-trace-count-for-label 0, [print-character]
1835 ]
1836
1837 scenario editor-moves-to-end-of-line-with-end [
1838 local-scope
1839 assume-screen 10/width, 5/height
1840 s:text <- new [123
1841 456]
1842 e:&:editor <- new-editor s, 0/left, 10/right
1843 editor-render screen, e
1844 $clear-trace
1845
1846 assume-console [
1847 left-click 1, 1
1848 press end
1849 ]
1850 run [
1851 editor-event-loop screen, console, e
1852 3:num/raw <- get *e, cursor-row:offset
1853 4:num/raw <- get *e, cursor-column:offset
1854 ]
1855
1856 memory-should-contain [
1857 3 <- 1
1858 4 <- 3
1859 ]
1860 check-trace-count-for-label 0, [print-character]
1861 ]
1862
1863 scenario editor-moves-to-end-of-line-with-end-2 [
1864 local-scope
1865 assume-screen 10/width, 5/height
1866 s:text <- new [123
1867 456]
1868 e:&:editor <- new-editor s, 0/left, 10/right
1869 editor-render screen, e
1870 $clear-trace
1871
1872 assume-console [
1873 left-click 2, 1
1874 press end
1875 ]
1876 run [
1877 editor-event-loop screen, console, e
1878 3:num/raw <- get *e, cursor-row:offset
1879 4:num/raw <- get *e, cursor-column:offset
1880 ]
1881
1882 memory-should-contain [
1883 3 <- 2
1884 4 <- 3
1885 ]
1886 check-trace-count-for-label 0, [print-character]
1887 ]
1888
1889 scenario editor-moves-to-end-of-wrapped-line [
1890 local-scope
1891 assume-screen 10/width, 5/height
1892 s:text <- new [123456
1893 789]
1894 e:&:editor <- new-editor s, 0/left, 5/right
1895 editor-render screen, e
1896 $clear-trace
1897
1898 assume-console [
1899 left-click 1, 1
1900 press end
1901 ]
1902 run [
1903 editor-event-loop screen, console, e
1904 10:num/raw <- get *e, cursor-row:offset
1905 11:num/raw <- get *e, cursor-column:offset
1906 ]
1907
1908 memory-should-contain [
1909 10 <- 1
1910 11 <- 3
1911 ]
1912
1913 check-trace-count-for-label 0, [print-character]
1914
1915 assume-console [
1916 type [a]
1917 ]
1918 run [
1919 editor-event-loop screen, console, e
1920 ]
1921 screen-should-contain [
1922 . .
1923 .123a↩ .
1924 .456 .
1925 .789 .
1926 .╌╌╌╌╌ .
1927 ]
1928 ]
1929
1930
1931
1932 scenario editor-deletes-to-start-of-line-with-ctrl-u [
1933 local-scope
1934 assume-screen 10/width, 5/height
1935 s:text <- new [123
1936 456]
1937 e:&:editor <- new-editor s, 0/left, 10/right
1938 editor-render screen, e
1939 $clear-trace
1940
1941 assume-console [
1942 left-click 2, 2
1943 press ctrl-u
1944 ]
1945 run [
1946 editor-event-loop screen, console, e
1947 ]
1948
1949 screen-should-contain [
1950 . .
1951 .123 .
1952 .6 .
1953 .╌╌╌╌╌╌╌╌╌╌.
1954 . .
1955 ]
1956 check-trace-count-for-label 10, [print-character]
1957 ]
1958
1959 after <handle-special-character> [
1960 {
1961 delete-to-start-of-line?:bool <- equal c, 21/ctrl-u
1962 break-unless delete-to-start-of-line?
1963 <begin-delete-to-start-of-line>
1964 deleted-cells:&:duplex-list:char <- delete-to-start-of-line editor
1965 <end-delete-to-start-of-line>
1966 go-render?:bool <- minimal-render-for-ctrl-u screen, editor, deleted-cells
1967 return
1968 }
1969 ]
1970
1971 def minimal-render-for-ctrl-u screen:&:screen, editor:&:editor, deleted-cells:&:duplex-list:char -> go-render?:bool, screen:&:screen [
1972 local-scope
1973 load-inputs
1974 curr-column:num <- get *editor, cursor-column:offset
1975
1976 buf:&:buffer:char <- new-buffer 30
1977 curr:&:duplex-list:char <- get *editor, before-cursor:offset
1978 i:num <- copy curr-column
1979 right:num <- get *editor, right:offset
1980 {
1981
1982 wrap?:bool <- greater-or-equal i, right
1983 return-if wrap?, 1/go-render
1984 curr <- next curr
1985 break-unless curr
1986 c:char <- get *curr, value:offset
1987 b:bool <- equal c, 10
1988 break-if b
1989 buf <- append buf, c
1990 i <- add i, 1
1991 loop
1992 }
1993
1994 num-deleted-cells:num <- length deleted-cells
1995 old-row-len:num <- add i, num-deleted-cells
1996 left:num <- get *editor, left:offset
1997 end:num <- subtract right, left
1998 wrap?:bool <- greater-or-equal old-row-len, end
1999 return-if wrap?, 1/go-render
2000 curr-line:text <- buffer-to-array buf
2001 curr-row:num <- get *editor, cursor-row:offset
2002 render-code screen, curr-line, curr-column, right, curr-row
2003 return 0/dont-render
2004 ]
2005
2006 def delete-to-start-of-line editor:&:editor -> result:&:duplex-list:char, editor:&:editor [
2007 local-scope
2008 load-inputs
2009
2010 init:&:duplex-list:char <- get *editor, data:offset
2011 top-of-screen:&:duplex-list:char <- get *editor, top-of-screen:offset
2012 update-top-of-screen?:bool <- copy 0/false
2013 before-cursor:&:duplex-list:char <- get *editor, before-cursor:offset
2014 start:&:duplex-list:char <- copy before-cursor
2015 end:&:duplex-list:char <- next before-cursor
2016 {
2017 at-start-of-text?:bool <- equal start, init
2018 break-if at-start-of-text?
2019 curr:char <- get *start, value:offset
2020 at-start-of-line?:bool <- equal curr, 10/newline
2021 break-if at-start-of-line?
2022
2023 at-top-of-screen?:bool <- equal start, top-of-screen
2024 update-top-of-screen?:bool <- or update-top-of-screen?, at-top-of-screen?
2025 start <- prev start
2026 assert start, [delete-to-start-of-line tried to move before start of text]
2027 loop
2028 }
2029
2030 result:&:duplex-list:char <- next start
2031 remove-between start, end
2032
2033 {
2034 break-unless update-top-of-screen?
2035 put *editor, top-of-screen:offset, start
2036 }
2037
2038 before-cursor <- copy start
2039 *editor <- put *editor, before-cursor:offset, before-cursor
2040 left:num <- get *editor, left:offset
2041 *editor <- put *editor, cursor-column:offset, left
2042
2043 right:num <- get *editor, right:offset
2044 width:num <- subtract right, left
2045 num-deleted:num <- length result
2046 cursor-row-adjustment:num <- divide-with-remainder num-deleted, width
2047 return-unless cursor-row-adjustment
2048 cursor-row:num <- get *editor, cursor-row:offset
2049 cursor-row-in-editor:num <- subtract cursor-row, 1
2050 at-top?:bool <- lesser-or-equal cursor-row-in-editor, cursor-row-adjustment
2051 {
2052 break-unless at-top?
2053 cursor-row <- copy 1
2054 }
2055 {
2056 break-if at-top?
2057 cursor-row <- subtract cursor-row, cursor-row-adjustment
2058 }
2059 put *editor, cursor-row:offset, cursor-row
2060 ]
2061
2062 def render-code screen:&:screen, s:text, left:num, right:num, row:num -> row:num, screen:&:screen [
2063 local-scope
2064 load-inputs
2065 return-unless s
2066 color:num <- copy 7/white
2067 column:num <- copy left
2068 screen <- move-cursor screen, row, column
2069 screen-height:num <- screen-height screen
2070 i:num <- copy 0
2071 len:num <- length *s
2072 {
2073 +next-character
2074 done?:bool <- greater-or-equal i, len
2075 break-if done?
2076 done? <- greater-or-equal row, screen-height
2077 break-if done?
2078 c:char <- index *s, i
2079 <character-c-received>
2080 {
2081
2082 newline?:bool <- equal c, 10/newline
2083 break-unless newline?
2084
2085 {
2086 done?:bool <- greater-than column, right
2087 break-if done?
2088 space:char <- copy 32/space
2089 print screen, space
2090 column <- add column, 1
2091 loop
2092 }
2093 row <- add row, 1
2094 column <- copy left
2095 screen <- move-cursor screen, row, column
2096 i <- add i, 1
2097 loop +next-character
2098 }
2099 {
2100
2101 at-right?:bool <- equal column, right
2102 break-unless at-right?
2103
2104 wrap-icon:char <- copy 8617/loop-back-to-left
2105 print screen, wrap-icon, 245/grey
2106 column <- copy left
2107 row <- add row, 1
2108 screen <- move-cursor screen, row, column
2109
2110 loop +next-character
2111 }
2112 i <- add i, 1
2113 print screen, c, color
2114 column <- add column, 1
2115 loop
2116 }
2117 was-at-left?:bool <- equal column, left
2118 clear-line-until screen, right
2119 {
2120 break-if was-at-left?
2121 row <- add row, 1
2122 }
2123 move-cursor screen, row, left
2124 ]
2125
2126 scenario editor-deletes-to-start-of-line-with-ctrl-u-2 [
2127 local-scope
2128 assume-screen 10/width, 5/height
2129 s:text <- new [123
2130 456]
2131 e:&:editor <- new-editor s, 0/left, 10/right
2132 editor-render screen, e
2133 $clear-trace
2134
2135 assume-console [
2136 left-click 1, 2
2137 press ctrl-u
2138 ]
2139 run [
2140 editor-event-loop screen, console, e
2141 ]
2142
2143 screen-should-contain [
2144 . .
2145 .3 .
2146 .456 .
2147 .╌╌╌╌╌╌╌╌╌╌.
2148 . .
2149 ]
2150 check-trace-count-for-label 10, [print-character]
2151 ]
2152
2153 scenario editor-deletes-to-start-of-line-with-ctrl-u-3 [
2154 local-scope
2155 assume-screen 10/width, 5/height
2156 s:text <- new [123
2157 456]
2158 e:&:editor <- new-editor s, 0/left, 10/right
2159 editor-render screen, e
2160 $clear-trace
2161
2162 assume-console [
2163 left-click 1, 3
2164 press ctrl-u
2165 ]
2166 run [
2167 editor-event-loop screen, console, e
2168 ]
2169
2170 screen-should-contain [
2171 . .
2172 . .
2173 .456 .
2174 .╌╌╌╌╌╌╌╌╌╌.
2175 . .
2176 ]
2177 check-trace-count-for-label 10, [print-character]
2178 ]
2179
2180 scenario editor-deletes-to-start-of-final-line-with-ctrl-u [
2181 local-scope
2182 assume-screen 10/width, 5/height
2183 s:text <- new [123
2184 456]
2185 e:&:editor <- new-editor s, 0/left, 10/right
2186 editor-render screen, e
2187 $clear-trace
2188
2189 assume-console [
2190 left-click 2, 3
2191 press ctrl-u
2192 ]
2193 run [
2194 editor-event-loop screen, console, e
2195 ]
2196
2197 screen-should-contain [
2198 . .
2199 .123 .
2200 . .
2201 .╌╌╌╌╌╌╌╌╌╌.
2202 . .
2203 ]
2204 check-trace-count-for-label 10, [print-character]
2205 ]
2206
2207 scenario editor-deletes-to-start-of-wrapped-line-with-ctrl-u [
2208 local-scope
2209 assume-screen 10/width, 10/height
2210
2211 s:text <- new [123456
2212 789]
2213 e:&:editor <- new-editor s, 0/left, 5/right
2214 editor-render screen, e
2215 screen-should-contain [
2216 . .
2217 .1234↩ .
2218 .56 .
2219 .789 .
2220 .╌╌╌╌╌ .
2221 . .
2222 ]
2223 $clear-trace
2224
2225 assume-console [
2226 left-click 1, 3
2227 press ctrl-u
2228 ]
2229 run [
2230 editor-event-loop screen, console, e
2231 ]
2232
2233 screen-should-contain [
2234 . .
2235 .456 .
2236 .789 .
2237 .╌╌╌╌╌ .
2238 . .
2239 ]
2240 check-trace-count-for-label 45, [print-character]
2241 ]
2242
2243
2244 scenario editor-deletes-to-start-of-wrapped-line-with-ctrl-u-2 [
2245 local-scope
2246 assume-screen 10/width, 10/height
2247
2248 s:text <- new [1
2249 2
2250 345678
2251 9]
2252 e:&:editor <- new-editor s, 0/left, 5/right
2253 editor-render screen, e
2254 screen-should-contain [
2255 . .
2256 .1 .
2257 .2 .
2258 .3456↩ .
2259 .78 .
2260 .9 .
2261 .╌╌╌╌╌ .
2262 . .
2263 ]
2264
2265 assume-console [
2266 left-click 4, 1
2267 press ctrl-u
2268 ]
2269 run [
2270 editor-event-loop screen, console, e
2271 10:num/raw <- get *e, cursor-row:offset
2272 11:num/raw <- get *e, cursor-column:offset
2273 ]
2274 screen-should-contain [
2275 . .
2276 .1 .
2277 .2 .
2278 .8 .
2279 .9 .
2280 .╌╌╌╌╌ .
2281 . .
2282 ]
2283
2284 memory-should-contain [
2285 10 <- 3
2286 11 <- 0
2287 ]
2288 ]
2289
2290
2291 scenario editor-deletes-to-start-of-wrapped-line-with-ctrl-u-3 [
2292 local-scope
2293 assume-screen 10/width, 10/height
2294
2295 s:text <- new [1
2296 2
2297 3456789abcd
2298 e]
2299 e:&:editor <- new-editor s, 0/left, 5/right
2300 editor-render screen, e
2301 assume-console [
2302 left-click 4, 1
2303 ]
2304 editor-event-loop screen, console, e
2305 screen-should-contain [
2306 . .
2307 .1 .
2308 .2 .
2309 .3456↩ .
2310 .789a↩ .
2311 .bcd .
2312 .e .
2313 .╌╌╌╌╌ .
2314 . .
2315 ]
2316 assume-console [
2317 left-click 5, 1
2318 press ctrl-u
2319 ]
2320 run [
2321 editor-event-loop screen, console, e
2322 10:num/raw <- get *e, cursor-row:offset
2323 11:num/raw <- get *e, cursor-column:offset
2324 ]
2325 screen-should-contain [
2326 . .
2327 .1 .
2328 .2 .
2329 .cd .
2330 .e .
2331 .╌╌╌╌╌ .
2332 . .
2333 ]
2334
2335 memory-should-contain [
2336 10 <- 3
2337 11 <- 0
2338 ]
2339 ]
2340
2341
2342 scenario editor-deletes-to-start-of-wrapped-line-with-ctrl-u-4 [
2343 local-scope
2344 assume-screen 10/width, 10/height
2345
2346 s:text <- new [1234567
2347 89]
2348 e:&:editor <- new-editor s, 0/left, 5/right
2349 editor-render screen, e
2350 screen-should-contain [
2351 . .
2352 .1234↩ .
2353 .567 .
2354 .89 .
2355 .╌╌╌╌╌ .
2356 . .
2357 ]
2358
2359 assume-console [
2360 left-click 2, 1
2361 press ctrl-u
2362 ]
2363 run [
2364 editor-event-loop screen, console, e
2365 10:num/raw <- get *e, cursor-row:offset
2366 11:num/raw <- get *e, cursor-column:offset
2367 ]
2368 screen-should-contain [
2369 . .
2370 .67 .
2371 .89 .
2372 .╌╌╌╌╌ .
2373 . .
2374 ]
2375
2376 memory-should-contain [
2377 10 <- 1
2378 11 <- 0
2379 ]
2380 ]
2381
2382
2383 scenario editor-deletes-to-start-of-wrapped-line-with-ctrl-u-5 [
2384 local-scope
2385 assume-screen 10/width, 10/height
2386
2387 s:text <- new [1
2388 2
2389 345678
2390 9]
2391 e:&:editor <- new-editor s, 0/left, 5/right
2392 editor-render screen, e
2393
2394 assume-console [
2395 left-click 4, 1
2396 press ctrl-t
2397 ]
2398 editor-event-loop screen, console, e
2399 screen-should-contain [
2400 . .
2401 .78 .
2402 .9 .
2403 .╌╌╌╌╌ .
2404 . .
2405 ]
2406 assume-console [
2407 left-click 1, 1
2408 press ctrl-u
2409 ]
2410 run [
2411 editor-event-loop screen, console, e
2412 10:num/raw <- get *e, cursor-row:offset
2413 11:num/raw <- get *e, cursor-column:offset
2414 ]
2415
2416 screen-should-contain [
2417 . .
2418 .8 .
2419 .9 .
2420 .╌╌╌╌╌ .
2421 . .
2422 ]
2423 memory-should-contain [
2424 10 <- 1
2425 11 <- 0
2426 ]
2427
2428 assume-console [
2429 press up-arrow
2430 ]
2431 run [
2432 editor-event-loop screen, console, e
2433 ]
2434 screen-should-contain [
2435 . .
2436 .2 .
2437 .8 .
2438 .9 .
2439 .╌╌╌╌╌ .
2440 . .
2441 ]
2442 ]
2443
2444
2445 scenario editor-deletes-to-start-of-wrapped-line-with-ctrl-u-6 [
2446 local-scope
2447 assume-screen 10/width, 10/height
2448
2449 s:text <- new [1
2450 2
2451 3456789abcd
2452 e]
2453 e:&:editor <- new-editor s, 0/left, 5/right
2454 editor-render screen, e
2455
2456 assume-console [
2457 left-click 4, 1
2458 press ctrl-t
2459 press ctrl-s
2460 ]
2461 editor-event-loop screen, console, e
2462 screen-should-contain [
2463 . .
2464 .bcd .
2465 .e .
2466 .╌╌╌╌╌ .
2467 . .
2468 ]
2469 assume-console [
2470 left-click 1, 1
2471 press ctrl-u
2472 ]
2473 run [
2474 editor-event-loop screen, console, e
2475 10:num/raw <- get *e, cursor-row:offset
2476 11:num/raw <- get *e, cursor-column:offset
2477 ]
2478
2479 screen-should-contain [
2480 . .
2481 .cd .
2482 .e .
2483 .╌╌╌╌╌ .
2484 . .
2485 ]
2486 memory-should-contain [
2487 10 <- 1
2488 11 <- 0
2489 ]
2490
2491 assume-console [
2492 press up-arrow
2493 ]
2494 run [
2495 editor-event-loop screen, console, e
2496 ]
2497 screen-should-contain [
2498 . .
2499 .2 .
2500 .cd .
2501 .e .
2502 .╌╌╌╌╌ .
2503 . .
2504 ]
2505 ]
2506
2507
2508
2509 scenario editor-deletes-to-end-of-line-with-ctrl-k [
2510 local-scope
2511 assume-screen 10/width, 5/height
2512 s:text <- new [123
2513 456]
2514 e:&:editor <- new-editor s, 0/left, 10/right
2515 editor-render screen, e
2516 $clear-trace
2517
2518 assume-console [
2519 left-click 1, 1
2520 press ctrl-k
2521 ]
2522 run [
2523 editor-event-loop screen, console, e
2524 ]
2525
2526 screen-should-contain [
2527 . .
2528 .1 .
2529 .456 .
2530 .╌╌╌╌╌╌╌╌╌╌.
2531 . .
2532 ]
2533 check-trace-count-for-label 9, [print-character]
2534 ]
2535
2536 after <handle-special-character> [
2537 {
2538 delete-to-end-of-line?:bool <- equal c, 11/ctrl-k
2539 break-unless delete-to-end-of-line?
2540 <begin-delete-to-end-of-line>
2541 deleted-cells:&:duplex-list:char <- delete-to-end-of-line editor
2542 <end-delete-to-end-of-line>
2543
2544 go-render?:bool <- minimal-render-for-ctrl-k screen, editor, deleted-cells
2545 return
2546 }
2547 ]
2548
2549 def minimal-render-for-ctrl-k screen:&:screen, editor:&:editor, deleted-cells:&:duplex-list:char -> go-render?:bool, screen:&:screen [
2550 local-scope
2551 load-inputs
2552
2553 return-unless deleted-cells, 0/dont-render
2554
2555 curr-column:num <- get *editor, cursor-column:offset
2556 num-deleted-cells:num <- length deleted-cells
2557 old-row-len:num <- add curr-column, num-deleted-cells
2558 left:num <- get *editor, left:offset
2559 right:num <- get *editor, right:offset
2560 end:num <- subtract right, left
2561 wrap?:bool <- greater-or-equal old-row-len, end
2562 return-if wrap?, 1/go-render
2563 clear-line-until screen, right
2564 return 0/dont-render
2565 ]
2566
2567 def delete-to-end-of-line editor:&:editor -> result:&:duplex-list:char, editor:&:editor [
2568 local-scope
2569 load-inputs
2570
2571 start:&:duplex-list:char <- get *editor, before-cursor:offset
2572 end:&:duplex-list:char <- next start
2573 {
2574 at-end-of-text?:bool <- equal end, 0/null
2575 break-if at-end-of-text?
2576 curr:char <- get *end, value:offset
2577 at-end-of-line?:bool <- equal curr, 10/newline
2578 break-if at-end-of-line?
2579 end <- next end
2580 loop
2581 }
2582
2583 result <- next start
2584 remove-between start, end
2585 ]
2586
2587 scenario editor-deletes-to-end-of-line-with-ctrl-k-2 [
2588 local-scope
2589 assume-screen 10/width, 5/height
2590 s:text <- new [123
2591 456]
2592 e:&:editor <- new-editor s, 0/left, 10/right
2593 editor-render screen, e
2594 $clear-trace
2595
2596 assume-console [
2597 left-click 2, 1
2598 press ctrl-k
2599 ]
2600 run [
2601 editor-event-loop screen, console, e
2602 ]
2603
2604 screen-should-contain [
2605 . .
2606 .123 .
2607 .4 .
2608 .╌╌╌╌╌╌╌╌╌╌.
2609 . .
2610 ]
2611 check-trace-count-for-label 9, [print-character]
2612 ]
2613
2614 scenario editor-deletes-to-end-of-line-with-ctrl-k-3 [
2615 local-scope
2616 assume-screen 10/width, 5/height
2617 s:text <- new [123
2618 456]
2619 e:&:editor <- new-editor s, 0/left, 10/right
2620 editor-render screen, e
2621 $clear-trace
2622
2623 assume-console [
2624 left-click 1, 2
2625 press ctrl-k
2626 ]
2627 run [
2628 editor-event-loop screen, console, e
2629 ]
2630
2631 screen-should-contain [
2632 . .
2633 .12 .
2634 .456 .
2635 .╌╌╌╌╌╌╌╌╌╌.
2636 . .
2637 ]
2638 check-trace-count-for-label 8, [print-character]
2639 ]
2640
2641 scenario editor-deletes-to-end-of-line-with-ctrl-k-4 [
2642 local-scope
2643 assume-screen 10/width, 5/height
2644 s:text <- new [123
2645 456]
2646 e:&:editor <- new-editor s, 0/left, 10/right
2647 editor-render screen, e
2648 $clear-trace
2649
2650 assume-console [
2651 left-click 1, 3
2652 press ctrl-k
2653 ]
2654 run [
2655 editor-event-loop screen, console, e
2656 ]
2657
2658 screen-should-contain [
2659 . .
2660 .123 .
2661 .456 .
2662 .╌╌╌╌╌╌╌╌╌╌.
2663 . .
2664 ]
2665 check-trace-count-for-label 7, [print-character]
2666 ]
2667
2668 scenario editor-deletes-to-end-of-line-with-ctrl-k-5 [
2669 local-scope
2670 assume-screen 10/width, 5/height
2671 s:text <- new [123
2672 456]
2673 e:&:editor <- new-editor s, 0/left, 10/right
2674 editor-render screen, e
2675 $clear-trace
2676
2677 assume-console [
2678 left-click 2, 2
2679 press ctrl-k
2680 ]
2681 run [
2682 editor-event-loop screen, console, e
2683 ]
2684
2685 screen-should-contain [
2686 . .
2687 .123 .
2688 .45 .
2689 .╌╌╌╌╌╌╌╌╌╌.
2690 . .
2691 ]
2692 check-trace-count-for-label 8, [print-character]
2693 ]
2694
2695 scenario editor-deletes-to-end-of-line-with-ctrl-k-6 [
2696 local-scope
2697 assume-screen 10/width, 5/height
2698 s:text <- new [123
2699 456]
2700 e:&:editor <- new-editor s, 0/left, 10/right
2701 editor-render screen, e
2702 $clear-trace
2703
2704 assume-console [
2705 left-click 2, 3
2706 press ctrl-k
2707 ]
2708 run [
2709 editor-event-loop screen, console, e
2710 ]
2711
2712 screen-should-contain [
2713 . .
2714 .123 .
2715 .456 .
2716 .╌╌╌╌╌╌╌╌╌╌.
2717 . .
2718 ]
2719
2720 check-trace-count-for-label 0, [print-character]
2721 ]
2722
2723 scenario editor-deletes-to-end-of-wrapped-line-with-ctrl-k [
2724 local-scope
2725 assume-screen 10/width, 5/height
2726
2727 s:text <- new [1234
2728 567]
2729 e:&:editor <- new-editor s, 0/left, 4/right
2730 editor-render screen, e
2731 $clear-trace
2732
2733 assume-console [
2734 press ctrl-k
2735 ]
2736 run [
2737 editor-event-loop screen, console, e
2738 ]
2739
2740 screen-should-contain [
2741 . .
2742 . .
2743 .567 .
2744 .╌╌╌╌ .
2745 . .
2746 ]
2747
2748 check-trace-count-for-label 16, [print-character]
2749 ]
2750
2751
2752
2753 scenario editor-can-scroll-down-using-arrow-keys [
2754 local-scope
2755
2756 assume-screen 10/width, 4/height
2757
2758 s:text <- new [a
2759 b
2760 c
2761 d]
2762 e:&:editor <- new-editor s, 0/left, 10/right
2763 editor-render screen, e
2764 screen-should-contain [
2765 . .
2766 .a .
2767 .b .
2768 .c .
2769 ]
2770
2771 assume-console [
2772 left-click 3, 0
2773 press down-arrow
2774 ]
2775 run [
2776 editor-event-loop screen, console, e
2777 ]
2778
2779 screen-should-contain [
2780 . .
2781 .b .
2782 .c .
2783 .d .
2784 ]
2785 ]
2786
2787 after <scroll-down> [
2788 trace 10, [app], [scroll down]
2789 top-of-screen:&:duplex-list:char <- get *editor, top-of-screen:offset
2790 left:num <- get *editor, left:offset
2791 right:num <- get *editor, right:offset
2792 max:num <- subtract right, left
2793 old-top:&:duplex-list:char <- copy top-of-screen
2794 top-of-screen <- before-start-of-next-line top-of-screen, max
2795 *editor <- put *editor, top-of-screen:offset, top-of-screen
2796 no-movement?:bool <- equal old-top, top-of-screen
2797 return-if no-movement?, 0/don't-render
2798 ]
2799
2800
2801
2802
2803
2804 def before-start-of-next-line original:&:duplex-list:char, max:num -> curr:&:duplex-list:char [
2805 local-scope
2806 load-inputs
2807 count:num <- copy 0
2808 curr:&:duplex-list:char <- copy original
2809
2810 {
2811 c:char <- get *curr, value:offset
2812 at-newline?:bool <- equal c, 10/newline
2813 break-unless at-newline?
2814 curr <- next curr
2815 count <- add count, 1
2816 }
2817 {
2818 return-unless curr, original
2819 done?:bool <- greater-or-equal count, max
2820 break-if done?
2821 c:char <- get *curr, value:offset
2822 at-newline?:bool <- equal c, 10/newline
2823 break-if at-newline?
2824 curr <- next curr
2825 count <- add count, 1
2826 loop
2827 }
2828 return-unless curr, original
2829 return curr
2830 ]
2831
2832 scenario editor-scrolls-down-past-wrapped-line-using-arrow-keys [
2833 local-scope
2834
2835 assume-screen 10/width, 4/height
2836
2837
2838 s:text <- new [abcdef
2839 g
2840 h
2841 i]
2842 e:&:editor <- new-editor s, 0/left, 5/right
2843 editor-render screen, e
2844 screen-should-contain [
2845 . .
2846 .abcd↩ .
2847 .ef .
2848 .g .
2849 ]
2850
2851 assume-console [
2852 left-click 3, 0
2853 press down-arrow
2854 ]
2855 run [
2856 editor-event-loop screen, console, e
2857 ]
2858
2859 screen-should-contain [
2860 . .
2861 .ef .
2862 .g .
2863 .h .
2864 ]
2865 ]
2866
2867 scenario editor-scrolls-down-past-wrapped-line-using-arrow-keys-2 [
2868 local-scope
2869
2870 assume-screen 10/width, 4/height
2871
2872 s:text <- new [abcdefghij
2873 k
2874 l
2875 m]
2876 e:&:editor <- new-editor s, 0/left, 5/right
2877
2878 assume-console [
2879 left-click 3, 0
2880 press down-arrow
2881 ]
2882 run [
2883 editor-event-loop screen, console, e
2884 ]
2885
2886 screen-should-contain [
2887 . .
2888 .efgh↩ .
2889 .ij .
2890 .k .
2891 ]
2892
2893 assume-console [
2894 press down-arrow
2895 ]
2896 run [
2897 editor-event-loop screen, console, e
2898 ]
2899
2900 screen-should-contain [
2901 . .
2902 .ij .
2903 .k .
2904 .l .
2905 ]
2906 ]
2907
2908 scenario editor-scrolls-down-when-line-wraps [
2909 local-scope
2910
2911 assume-screen 5/width, 4/height
2912
2913 s:text <- new [a
2914 b
2915 cdef]
2916 e:&:editor <- new-editor s, 0/left, 5/right
2917
2918 assume-console [
2919 left-click 3, 4
2920 type [g]
2921 ]
2922 run [
2923 editor-event-loop screen, console, e
2924 3:num/raw <- get *e, cursor-row:offset
2925 4:num/raw <- get *e, cursor-column:offset
2926 ]
2927
2928 screen-should-contain [
2929 . .
2930 .b .
2931 .cdef↩.
2932 .g .
2933 ]
2934 memory-should-contain [
2935 3 <- 3
2936 4 <- 1
2937 ]
2938 ]
2939
2940 scenario editor-stops-scrolling-once-bottom-is-visible [
2941 local-scope
2942
2943 assume-screen 10/width, 4/height
2944
2945 s:text <- new [a
2946 b]
2947 e:&:editor <- new-editor s, 0/left, 10/right
2948 editor-render screen, e
2949 screen-should-contain [
2950 . .
2951 .a .
2952 .b .
2953 .╌╌╌╌╌╌╌╌╌╌.
2954 ]
2955
2956 assume-console [
2957 left-click 3, 0
2958 press down-arrow
2959 ]
2960 run [
2961 editor-event-loop screen, console, e
2962 ]
2963
2964 screen-should-contain [
2965 . .
2966 .a .
2967 .b .
2968 .╌╌╌╌╌╌╌╌╌╌.
2969 ]
2970 ]
2971
2972 scenario editor-scrolls-down-on-newline [
2973 local-scope
2974 assume-screen 5/width, 4/height
2975
2976 s:text <- new [a
2977 b
2978 c]
2979 e:&:editor <- new-editor s, 0/left, 5/right
2980 assume-console [
2981 left-click 3, 4
2982 type [
2983 ]
2984 ]
2985 run [
2986 editor-event-loop screen, console, e
2987 3:num/raw <- get *e, cursor-row:offset
2988 4:num/raw <- get *e, cursor-column:offset
2989 ]
2990
2991 screen-should-contain [
2992 . .
2993 .b .
2994 .c .
2995 . .
2996 ]
2997 memory-should-contain [
2998 3 <- 3
2999 4 <- 0
3000 ]
3001 ]
3002
3003 scenario editor-scrolls-down-on-right-arrow [
3004 local-scope
3005
3006 assume-screen 5/width, 4/height
3007
3008 s:text <- new [a
3009 b
3010 cdefgh]
3011 e:&:editor <- new-editor s, 0/left, 5/right
3012
3013 assume-console [
3014 left-click 3, 3
3015 press right-arrow
3016 ]
3017 run [
3018 editor-event-loop screen, console, e
3019 3:num/raw <- get *e, cursor-row:offset
3020 4:num/raw <- get *e, cursor-column:offset
3021 ]
3022
3023 screen-should-contain [
3024 . .
3025 .b .
3026 .cdef↩.
3027 .gh .
3028 ]
3029 memory-should-contain [
3030 3 <- 3
3031 4 <- 0
3032 ]
3033 ]
3034
3035 scenario editor-scrolls-down-on-right-arrow-2 [
3036 local-scope
3037
3038 assume-screen 5/width, 4/height
3039
3040 s:text <- new [a
3041 b
3042 c
3043 d]
3044 e:&:editor <- new-editor s, 0/left, 5/right
3045
3046 assume-console [
3047 left-click 3, 3
3048 press right-arrow
3049 ]
3050 run [
3051 editor-event-loop screen, console, e
3052 3:num/raw <- get *e, cursor-row:offset
3053 4:num/raw <- get *e, cursor-column:offset
3054 ]
3055
3056 screen-should-contain [
3057 . .
3058 .b .
3059 .c .
3060 .d .
3061 ]
3062 memory-should-contain [
3063 3 <- 3
3064 4 <- 0
3065 ]
3066 ]
3067
3068 scenario editor-scrolls-at-end-on-down-arrow [
3069 local-scope
3070 assume-screen 10/width, 5/height
3071 s:text <- new [abc
3072 de]
3073 e:&:editor <- new-editor s, 0/left, 10/right
3074 editor-render screen, e
3075 $clear-trace
3076
3077 assume-console [
3078 left-click 2, 0
3079 press down-arrow
3080 ]
3081 run [
3082 editor-event-loop screen, console, e
3083 3:num/raw <- get *e, cursor-row:offset
3084 4:num/raw <- get *e, cursor-column:offset
3085 ]
3086
3087 memory-should-contain [
3088 3 <- 2
3089 4 <- 0
3090 ]
3091 ]
3092
3093 scenario editor-combines-page-and-line-scroll [
3094 local-scope
3095
3096 assume-screen 10/width, 4/height
3097
3098 s:text <- new [a
3099 b
3100 c
3101 d
3102 e
3103 f
3104 g]
3105 e:&:editor <- new-editor s, 0/left, 5/right
3106 editor-render screen, e
3107
3108 assume-console [
3109 press page-down
3110 left-click 3, 0
3111 press down-arrow
3112 ]
3113 run [
3114 editor-event-loop screen, console, e
3115 ]
3116
3117 screen-should-contain [
3118 . .
3119 .d .
3120 .e .
3121 .f .
3122 ]
3123 ]
3124
3125
3126
3127 scenario editor-can-scroll-up-using-arrow-keys [
3128 local-scope
3129
3130 assume-screen 10/width, 4/height
3131
3132 s:text <- new [a
3133 b
3134 c
3135 d]
3136 e:&:editor <- new-editor s, 0/left, 10/right
3137 editor-render screen, e
3138 screen-should-contain [
3139 . .
3140 .a .
3141 .b .
3142 .c .
3143 ]
3144
3145 assume-console [
3146 press page-down
3147 press up-arrow
3148 ]
3149 run [
3150 editor-event-loop screen, console, e
3151 ]
3152
3153 screen-should-contain [
3154 . .
3155 .b .
3156 .c .
3157 .d .
3158 ]
3159 ]
3160
3161 after <scroll-up> [
3162 trace 10, [app], [scroll up]
3163 top-of-screen:&:duplex-list:char <- get *editor, top-of-screen:offset
3164 old-top:&:duplex-list:char <- copy top-of-screen
3165 top-of-screen <- before-previous-screen-line top-of-screen, editor
3166 *editor <- put *editor, top-of-screen:offset, top-of-screen
3167 no-movement?:bool <- equal old-top, top-of-screen
3168 return-if no-movement?, 0/don't-render
3169 ]
3170
3171
3172
3173
3174
3175 def before-previous-screen-line in:&:duplex-list:char, editor:&:editor -> out:&:duplex-list:char [
3176 local-scope
3177 load-inputs
3178 curr:&:duplex-list:char <- copy in
3179 c:char <- get *curr, value:offset
3180
3181
3182
3183 left:num <- get *editor, left:offset
3184 right:num <- get *editor, right:offset
3185 max-line-length:num <- subtract right, left, -1/exclusive-right, 1/wrap-icon
3186 sentinel:&:duplex-list:char <- get *editor, data:offset
3187 len:num <- previous-line-length curr, sentinel
3188 {
3189 break-if len
3190
3191 prev:&:duplex-list:char <- prev curr
3192 return-unless prev, curr
3193 return prev
3194 }
3195 _, max:num <- divide-with-remainder len, max-line-length
3196
3197 {
3198 break-if max
3199 max <- copy max-line-length
3200 }
3201 max <- add max, 1
3202 count:num <- copy 0
3203
3204 {
3205 done?:bool <- greater-or-equal count, max
3206 break-if done?
3207 prev:&:duplex-list:char <- prev curr
3208 break-unless prev
3209 curr <- copy prev
3210 count <- add count, 1
3211 loop
3212 }
3213 return curr
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 ]