https://github.com/akkartik/mu1/blob/master/edit/003-shortcuts.mu
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, false/no-more-render, null/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?, true/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?, true/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?, true/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 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 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 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, false/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?, true/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?, true/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 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?, false/don't-render
472 <scroll-down>
473 cursor-row <- subtract cursor-row, 1
474 *editor <- put *editor, cursor-row:offset, cursor-row
475 return true/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?, false/no-more-render
495 <scroll-down>
496 cursor-row <- subtract cursor-row, 1
497 *editor <- put *editor, cursor-row:offset, cursor-row
498 return true/go-render
499 }
500
501 cursor-column <- add cursor-column, 1
502 *editor <- put *editor, cursor-column:offset, cursor-column
503 go-render? <- copy 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, false/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 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 true/go-render
1060 }
1061 ]
1062
1063
1064
1065
1066
1067 def before-previous-screen-line in:&:duplex-list:char, editor:&:editor -> out:&:duplex-list:char [
1068 local-scope
1069 load-inputs
1070 curr:&:duplex-list:char <- copy in
1071 c:char <- get *curr, value:offset
1072
1073
1074
1075 left:num <- get *editor, left:offset
1076 right:num <- get *editor, right:offset
1077 max-line-length:num <- subtract right, left, -1/exclusive-right, 1/wrap-icon
1078 sentinel:&:duplex-list:char <- get *editor, data:offset
1079 len:num <- previous-line-length curr, sentinel
1080 {
1081 break-if len
1082
1083 prev:&:duplex-list:char <- prev curr
1084 return-unless prev, curr
1085 return prev
1086 }
1087 _, max:num <- divide-with-remainder len, max-line-length
1088
1089 {
1090 break-if max
1091 max <- copy max-line-length
1092 }
1093 max <- add max, 1
1094 count:num <- copy 0
1095
1096 {
1097 done?:bool <- greater-or-equal count, max
1098 break-if done?
1099 prev:&:duplex-list:char <- prev curr
1100 break-unless prev
1101 curr <- copy prev
1102 count <- add count, 1
1103 loop
1104 }
1105 return curr
1106 ]
1107
1108 scenario editor-adjusts-column-at-previous-line [
1109 local-scope
1110 assume-screen 10/width, 5/height
1111 s:text <- new [ab
1112 def]
1113 e:&:editor <- new-editor s, 0/left, 10/right
1114 editor-render screen, e
1115 $clear-trace
1116 assume-console [
1117 left-click 2, 3
1118 press up-arrow
1119 ]
1120 run [
1121 editor-event-loop screen, console, e
1122 3:num/raw <- get *e, cursor-row:offset
1123 4:num/raw <- get *e, cursor-column:offset
1124 ]
1125 memory-should-contain [
1126 3 <- 1
1127 4 <- 2
1128 ]
1129 check-trace-count-for-label 0, [print-character]
1130 assume-console [
1131 type [0]
1132 ]
1133 run [
1134 editor-event-loop screen, console, e
1135 ]
1136 screen-should-contain [
1137 . .
1138 .ab0 .
1139 .def .
1140 .╌╌╌╌╌╌╌╌╌╌.
1141 . .
1142 ]
1143 ]
1144
1145 scenario editor-adjusts-column-at-empty-line [
1146 local-scope
1147 assume-screen 10/width, 5/height
1148 s:text <- new [
1149 def]
1150 e:&:editor <- new-editor s, 0/left, 10/right
1151 editor-render screen, e
1152 $clear-trace
1153 assume-console [
1154 left-click 2, 3
1155 press up-arrow
1156 ]
1157 run [
1158 editor-event-loop screen, console, e
1159 3:num/raw <- get *e, cursor-row:offset
1160 4:num/raw <- get *e, cursor-column:offset
1161 ]
1162 memory-should-contain [
1163 3 <- 1
1164 4 <- 0
1165 ]
1166 check-trace-count-for-label 0, [print-character]
1167 assume-console [
1168 type [0]
1169 ]
1170 run [
1171 editor-event-loop screen, console, e
1172 ]
1173 screen-should-contain [
1174 . .
1175 .0 .
1176 .def .
1177 .╌╌╌╌╌╌╌╌╌╌.
1178 . .
1179 ]
1180 ]
1181
1182 scenario editor-moves-to-previous-line-from-zero-margin [
1183 local-scope
1184 assume-screen 10/width, 5/height
1185
1186 s:text <- new [abc
1187 def
1188 ghi]
1189 e:&:editor <- new-editor s, 0/left, 10/right
1190 editor-render screen, e
1191 $clear-trace
1192
1193 assume-console [
1194 left-click 3, 0
1195 press up-arrow
1196 ]
1197 run [
1198 editor-event-loop screen, console, e
1199 3:num/raw <- get *e, cursor-row:offset
1200 4:num/raw <- get *e, cursor-column:offset
1201 ]
1202 memory-should-contain [
1203 3 <- 2
1204 4 <- 0
1205 ]
1206 check-trace-count-for-label 0, [print-character]
1207 assume-console [
1208 type [0]
1209 ]
1210 run [
1211 editor-event-loop screen, console, e
1212 ]
1213 screen-should-contain [
1214 . .
1215 .abc .
1216 .0def .
1217 .ghi .
1218 .╌╌╌╌╌╌╌╌╌╌.
1219 ]
1220 ]
1221
1222 scenario editor-moves-to-previous-line-from-left-margin [
1223 local-scope
1224 assume-screen 10/width, 5/height
1225
1226 s:text <- new [abc
1227 def
1228 ghi]
1229 e:&:editor <- new-editor s, 1/left, 10/right
1230 editor-render screen, e
1231 $clear-trace
1232
1233 assume-console [
1234 left-click 3, 1
1235 press up-arrow
1236 ]
1237 run [
1238 editor-event-loop screen, console, e
1239 3:num/raw <- get *e, cursor-row:offset
1240 4:num/raw <- get *e, cursor-column:offset
1241 ]
1242 memory-should-contain [
1243 3 <- 2
1244 4 <- 1
1245 ]
1246 check-trace-count-for-label 0, [print-character]
1247 assume-console [
1248 type [0]
1249 ]
1250 run [
1251 editor-event-loop screen, console, e
1252 ]
1253 screen-should-contain [
1254 . .
1255 . abc .
1256 . 0def .
1257 . ghi .
1258 . ╌╌╌╌╌╌╌╌╌.
1259 ]
1260 ]
1261
1262 scenario editor-moves-to-top-line-in-presence-of-wrapped-line [
1263 local-scope
1264 assume-screen 10/width, 5/height
1265 e:&:editor <- new-editor [abcde], 0/left, 5/right
1266 editor-render screen, e
1267 screen-should-contain [
1268 . .
1269 .abcd↩ .
1270 .e .
1271 .╌╌╌╌╌ .
1272 ]
1273 $clear-trace
1274 assume-console [
1275 left-click 2, 0
1276 press up-arrow
1277 ]
1278 run [
1279 editor-event-loop screen, console, e
1280 3:num/raw <- get *e, cursor-row:offset
1281 4:num/raw <- get *e, cursor-column:offset
1282 ]
1283 memory-should-contain [
1284 3 <- 1
1285 4 <- 0
1286 ]
1287 check-trace-count-for-label 0, [print-character]
1288 assume-console [
1289 type [0]
1290 ]
1291 run [
1292 editor-event-loop screen, console, e
1293 ]
1294 screen-should-contain [
1295 . .
1296 .0abc↩ .
1297 .de .
1298 .╌╌╌╌╌ .
1299 ]
1300 ]
1301
1302 scenario editor-moves-to-top-line-in-presence-of-wrapped-line-2 [
1303 local-scope
1304 assume-screen 10/width, 5/height
1305 s:text <- new [abc
1306 defgh]
1307 e:&:editor <- new-editor s, 0/left, 5/right
1308 editor-render screen, e
1309 screen-should-contain [
1310 . .
1311 .abc .
1312 .defg↩ .
1313 .h .
1314 .╌╌╌╌╌ .
1315 ]
1316 $clear-trace
1317 assume-console [
1318 left-click 3, 0
1319 press up-arrow
1320 press up-arrow
1321 ]
1322 run [
1323 editor-event-loop screen, console, e
1324 3:num/raw <- get *e, cursor-row:offset
1325 4:num/raw <- get *e, cursor-column:offset
1326 ]
1327 memory-should-contain [
1328 3 <- 1
1329 4 <- 0
1330 ]
1331 check-trace-count-for-label 0, [print-character]
1332 assume-console [
1333 type [0]
1334 ]
1335 run [
1336 editor-event-loop screen, console, e
1337 ]
1338 screen-should-contain [
1339 . .
1340 .0abc .
1341 .defg↩ .
1342 .h .
1343 .╌╌╌╌╌ .
1344 ]
1345 ]
1346
1347
1348
1349 scenario editor-moves-to-next-line-with-down-arrow [
1350 local-scope
1351 assume-screen 10/width, 5/height
1352 s:text <- new [abc
1353 def]
1354 e:&:editor <- new-editor s, 0/left, 10/right
1355 editor-render screen, e
1356 $clear-trace
1357
1358 assume-console [
1359 press down-arrow
1360 ]
1361 run [
1362 editor-event-loop screen, console, e
1363 3:num/raw <- get *e, cursor-row:offset
1364 4:num/raw <- get *e, cursor-column:offset
1365 ]
1366
1367 memory-should-contain [
1368 3 <- 2
1369 4 <- 0
1370 ]
1371 check-trace-count-for-label 0, [print-character]
1372 assume-console [
1373 type [0]
1374 ]
1375 run [
1376 editor-event-loop screen, console, e
1377 ]
1378 screen-should-contain [
1379 . .
1380 .abc .
1381 .0def .
1382 .╌╌╌╌╌╌╌╌╌╌.
1383 . .
1384 ]
1385 ]
1386
1387 after <handle-special-key> [
1388 {
1389 move-to-next-line?:bool <- equal k, 65516/down-arrow
1390 break-unless move-to-next-line?
1391 <begin-move-cursor>
1392 go-render? <- move-to-next-line editor, screen-height
1393 undo-coalesce-tag:num <- copy 4/down-arrow
1394 <end-move-cursor>
1395 return
1396 }
1397 ]
1398
1399 def move-to-next-line editor:&:editor, screen-height:num -> go-render?:bool, editor:&:editor [
1400 local-scope
1401 load-inputs
1402 cursor-row:num <- get *editor, cursor-row:offset
1403 cursor-column:num <- get *editor, cursor-column:offset
1404 before-cursor:&:duplex-list:char <- get *editor, before-cursor:offset
1405 left:num <- get *editor, left:offset
1406 right:num <- get *editor, right:offset
1407 last-line:num <- subtract screen-height, 1
1408 bottom:num <- get *editor, bottom:offset
1409 at-bottom-of-screen?:bool <- greater-or-equal bottom, last-line
1410 {
1411 break-if before-cursor
1412 {
1413 break-if at-bottom-of-screen?
1414 return false/don't-render
1415 }
1416 {
1417 break-unless at-bottom-of-screen?
1418 jump +try-to-scroll
1419 }
1420 }
1421 next:&:duplex-list:char <- next before-cursor
1422 {
1423 break-if next
1424 {
1425 break-if at-bottom-of-screen?
1426 return false/don't-render
1427 }
1428 {
1429 break-unless at-bottom-of-screen?
1430 jump +try-to-scroll
1431 }
1432 }
1433 already-at-bottom?:bool <- greater-or-equal cursor-row, last-line
1434 {
1435
1436 break-if already-at-bottom?
1437 target-column:num <- copy cursor-column
1438
1439 {
1440 next:&:duplex-list:char <- next before-cursor
1441 break-unless next
1442 done?:bool <- greater-or-equal cursor-column, right
1443 break-if done?
1444 cursor-column <- add cursor-column, 1
1445 before-cursor <- copy next
1446 c:char <- get *next, value:offset
1447 at-newline?:bool <- equal c, 10/newline
1448 break-if at-newline?
1449 loop
1450 }
1451 {
1452 break-if next
1453 {
1454 break-if at-bottom-of-screen?
1455 return false/don't-render
1456 }
1457 {
1458 break-unless at-bottom-of-screen?
1459 jump +try-to-scroll
1460 }
1461 }
1462 cursor-row <- add cursor-row, 1
1463 cursor-column <- copy left
1464 {
1465 next:&:duplex-list:char <- next before-cursor
1466 break-unless next
1467 c:char <- get *next, value:offset
1468 at-newline?:bool <- equal c, 10/newline
1469 break-if at-newline?
1470 done?:bool <- greater-or-equal cursor-column, target-column
1471 break-if done?
1472 cursor-column <- add cursor-column, 1
1473 before-cursor <- copy next
1474 loop
1475 }
1476 *editor <- put *editor, before-cursor:offset, before-cursor
1477 *editor <- put *editor, cursor-column:offset, cursor-column
1478 *editor <- put *editor, cursor-row:offset, cursor-row
1479 return false/don't-render
1480 }
1481 +try-to-scroll
1482 <scroll-down>
1483 go-render? <- copy true
1484 ]
1485
1486 scenario editor-adjusts-column-at-next-line [
1487 local-scope
1488 assume-screen 10/width, 5/height
1489
1490 s:text <- new [abcde
1491 fg
1492 hi]
1493 e:&:editor <- new-editor s, 0/left, 10/right
1494 editor-render screen, e
1495 $clear-trace
1496
1497 assume-console [
1498 left-click 1, 8
1499 press down-arrow
1500 ]
1501 run [
1502 editor-event-loop screen, console, e
1503 3:num/raw <- get *e, cursor-row:offset
1504 4:num/raw <- get *e, cursor-column:offset
1505 ]
1506
1507 memory-should-contain [
1508 3 <- 2
1509 4 <- 2
1510 ]
1511 check-trace-count-for-label 0, [print-character]
1512 assume-console [
1513 type [0]
1514 ]
1515 run [
1516 editor-event-loop screen, console, e
1517 ]
1518 screen-should-contain [
1519 . .
1520 .abcde .
1521 .fg0 .
1522 .hi .
1523 .╌╌╌╌╌╌╌╌╌╌.
1524 ]
1525 ]
1526
1527 scenario editor-moves-down-within-wrapped-line [
1528 local-scope
1529 assume-screen 10/width, 5/height
1530 e:&:editor <- new-editor [abcdefghijklmno], 0/left, 10/right
1531 editor-render screen, e
1532 screen-should-contain [
1533 . .
1534 .abcdefghi↩.
1535 .jklmno .
1536 .╌╌╌╌╌╌╌╌╌╌.
1537 . .
1538 ]
1539
1540 assume-console [
1541 left-click 1, 8
1542 press down-arrow
1543 ]
1544 run [
1545 editor-event-loop screen, console, e
1546 3:num/raw <- get *e, cursor-row:offset
1547 4:num/raw <- get *e, cursor-column:offset
1548 ]
1549
1550 memory-should-contain [
1551 3 <- 2
1552 4 <- 6
1553 ]
1554 ]
1555
1556
1557
1558 scenario editor-moves-to-start-of-line-with-ctrl-a [
1559 local-scope
1560 assume-screen 10/width, 5/height
1561 s:text <- new [123
1562 456]
1563 e:&:editor <- new-editor s, 0/left, 10/right
1564 editor-render screen, e
1565 $clear-trace
1566
1567 assume-console [
1568 left-click 2, 3
1569 press ctrl-a
1570 ]
1571 run [
1572 editor-event-loop screen, console, e
1573 4:num/raw <- get *e, cursor-row:offset
1574 5:num/raw <- get *e, cursor-column:offset
1575 ]
1576
1577 memory-should-contain [
1578 4 <- 2
1579 5 <- 0
1580 ]
1581 check-trace-count-for-label 0, [print-character]
1582 ]
1583
1584 after <handle-special-character> [
1585 {
1586 move-to-start-of-line?:bool <- equal c, 1/ctrl-a
1587 break-unless move-to-start-of-line?
1588 <begin-move-cursor>
1589 move-to-start-of-screen-line editor
1590 undo-coalesce-tag:num <- copy 0/never
1591 <end-move-cursor>
1592 return false/don't-render
1593 }
1594 ]
1595
1596 after <handle-special-key> [
1597 {
1598 move-to-start-of-line?:bool <- equal k, 65521/home
1599 break-unless move-to-start-of-line?
1600 <begin-move-cursor>
1601 move-to-start-of-screen-line editor
1602 undo-coalesce-tag:num <- copy 0/never
1603 <end-move-cursor>
1604 return false/don't-render
1605 }
1606 ]
1607
1608
1609
1610 def move-to-start-of-screen-line editor:&:editor -> editor:&:editor [
1611 local-scope
1612 load-inputs
1613
1614 left:num <- get *editor, left:offset
1615 col:num <- get *editor, cursor-column:offset
1616
1617 curr:&:duplex-list:char <- get *editor, before-cursor:offset
1618
1619 {
1620 done?:bool <- equal col, left
1621 break-if done?
1622 assert curr, [move-to-start-of-line tried to move before start of text]
1623 curr <- prev curr
1624 col <- subtract col, 1
1625 loop
1626 }
1627 *editor <- put *editor, cursor-column:offset, col
1628 *editor <- put *editor, before-cursor:offset, curr
1629 ]
1630
1631 scenario editor-moves-to-start-of-line-with-ctrl-a-2 [
1632 local-scope
1633 assume-screen 10/width, 5/height
1634 s:text <- new [123
1635 456]
1636 e:&:editor <- new-editor s, 0/left, 10/right
1637 editor-render screen, e
1638 $clear-trace
1639
1640 assume-console [
1641 left-click 1, 3
1642 press ctrl-a
1643 ]
1644 run [
1645 editor-event-loop screen, console, e
1646 4:num/raw <- get *e, cursor-row:offset
1647 5:num/raw <- get *e, cursor-column:offset
1648 ]
1649
1650 memory-should-contain [
1651 4 <- 1
1652 5 <- 0
1653 ]
1654 check-trace-count-for-label 0, [print-character]
1655 ]
1656
1657 scenario editor-moves-to-start-of-line-with-home [
1658 local-scope
1659 assume-screen 10/width, 5/height
1660 s:text <- new [123
1661 456]
1662 e:&:editor <- new-editor s, 0/left, 10/right
1663 $clear-trace
1664
1665 assume-console [
1666 left-click 2, 3
1667 press home
1668 ]
1669 run [
1670 editor-event-loop screen, console, e
1671 3:num/raw <- get *e, cursor-row:offset
1672 4:num/raw <- get *e, cursor-column:offset
1673 ]
1674
1675 memory-should-contain [
1676 3 <- 2
1677 4 <- 0
1678 ]
1679 check-trace-count-for-label 0, [print-character]
1680 ]
1681
1682 scenario editor-moves-to-start-of-line-with-home-2 [
1683 local-scope
1684 assume-screen 10/width, 5/height
1685 s:text <- new [123
1686 456]
1687 e:&:editor <- new-editor s, 0/left, 10/right
1688 editor-render screen, e
1689 $clear-trace
1690
1691 assume-console [
1692 left-click 1, 3
1693 press home
1694 ]
1695 run [
1696 editor-event-loop screen, console, e
1697 3:num/raw <- get *e, cursor-row:offset
1698 4:num/raw <- get *e, cursor-column:offset
1699 ]
1700
1701 memory-should-contain [
1702 3 <- 1
1703 4 <- 0
1704 ]
1705 check-trace-count-for-label 0, [print-character]
1706 ]
1707
1708 scenario editor-moves-to-start-of-screen-line-with-ctrl-a [
1709 local-scope
1710 assume-screen 10/width, 5/height
1711 e:&:editor <- new-editor [123456], 0/left, 5/right
1712 editor-render screen, e
1713 screen-should-contain [
1714 . .
1715 .1234↩ .
1716 .56 .
1717 .╌╌╌╌╌ .
1718 . .
1719 ]
1720 $clear-trace
1721
1722 assume-console [
1723 left-click 2, 1
1724 press ctrl-a
1725 press up-arrow
1726 ]
1727 run [
1728 editor-event-loop screen, console, e
1729 4:num/raw <- get *e, cursor-row:offset
1730 5:num/raw <- get *e, cursor-column:offset
1731 ]
1732
1733 memory-should-contain [
1734 4 <- 1
1735 5 <- 0
1736 ]
1737 check-trace-count-for-label 0, [print-character]
1738
1739 assume-console [
1740 type [a]
1741 ]
1742 run [
1743 editor-event-loop screen, console, e
1744 4:num/raw <- get *e, cursor-row:offset
1745 5:num/raw <- get *e, cursor-column:offset
1746 ]
1747 screen-should-contain [
1748 . .
1749 .a123↩ .
1750 .456 .
1751 .╌╌╌╌╌ .
1752 . .
1753 ]
1754 memory-should-contain [
1755 4 <- 1
1756 5 <- 1
1757 ]
1758 ]
1759
1760
1761
1762 scenario editor-moves-to-end-of-line-with-ctrl-e [
1763 local-scope
1764 assume-screen 10/width, 5/height
1765 s:text <- new [123
1766 456]
1767 e:&:editor <- new-editor s, 0/left, 10/right
1768 editor-render screen, e
1769 $clear-trace
1770
1771 assume-console [
1772 left-click 1, 1
1773 press ctrl-e
1774 ]
1775 run [
1776 editor-event-loop screen, console, e
1777 4:num/raw <- get *e, cursor-row:offset
1778 5:num/raw <- get *e, cursor-column:offset
1779 ]
1780
1781 memory-should-contain [
1782 4 <- 1
1783 5 <- 3
1784 ]
1785 check-trace-count-for-label 0, [print-character]
1786
1787 assume-console [
1788 type [z]
1789 ]
1790 run [
1791 editor-event-loop screen, console, e
1792 4:num/raw <- get *e, cursor-row:offset
1793 5:num/raw <- get *e, cursor-column:offset
1794 ]
1795 memory-should-contain [
1796 4 <- 1
1797 5 <- 4
1798 ]
1799 screen-should-contain [
1800 . .
1801 .123z .
1802 .456 .
1803 .╌╌╌╌╌╌╌╌╌╌.
1804 . .
1805 ]
1806 check-trace-count-for-label 1, [print-character]
1807 ]
1808
1809 after <handle-special-character> [
1810 {
1811 move-to-end-of-line?:bool <- equal c, 5/ctrl-e
1812 break-unless move-to-end-of-line?
1813 <begin-move-cursor>
1814 move-to-end-of-line editor
1815 undo-coalesce-tag:num <- copy 0/never
1816 <end-move-cursor>
1817 return false/don't-render
1818 }
1819 ]
1820
1821 after <handle-special-key> [
1822 {
1823 move-to-end-of-line?:bool <- equal k, 65520/end
1824 break-unless move-to-end-of-line?
1825 <begin-move-cursor>
1826 move-to-end-of-line editor
1827 undo-coalesce-tag:num <- copy 0/never
1828 <end-move-cursor>
1829 return false/don't-render
1830 }
1831 ]
1832
1833 def move-to-end-of-line editor:&:editor -> editor:&:editor [
1834 local-scope
1835 load-inputs
1836 before-cursor:&:duplex-list:char <- get *editor, before-cursor:offset
1837 cursor-column:num <- get *editor, cursor-column:offset
1838 right:num <- get *editor, right:offset
1839
1840 {
1841 next:&:duplex-list:char <- next before-cursor
1842 break-unless next
1843 nextc:char <- get *next, value:offset
1844 at-end-of-line?:bool <- equal nextc, 10/newline
1845 break-if at-end-of-line?
1846 cursor-column <- add cursor-column, 1
1847 at-right?:bool <- equal cursor-column, right
1848 break-if at-right?
1849 *editor <- put *editor, cursor-column:offset, cursor-column
1850 before-cursor <- copy next
1851 *editor <- put *editor, before-cursor:offset, before-cursor
1852 loop
1853 }
1854 ]
1855
1856 scenario editor-moves-to-end-of-line-with-ctrl-e-2 [
1857 local-scope
1858 assume-screen 10/width, 5/height
1859 s:text <- new [123
1860 456]
1861 e:&:editor <- new-editor s, 0/left, 10/right
1862 editor-render screen, e
1863 $clear-trace
1864
1865 assume-console [
1866 left-click 2, 1
1867 press ctrl-e
1868 ]
1869 run [
1870 editor-event-loop screen, console, e
1871 4:num/raw <- get *e, cursor-row:offset
1872 5:num/raw <- get *e, cursor-column:offset
1873 ]
1874
1875 memory-should-contain [
1876 4 <- 2
1877 5 <- 3
1878 ]
1879 check-trace-count-for-label 0, [print-character]
1880 ]
1881
1882 scenario editor-moves-to-end-of-line-with-end [
1883 local-scope
1884 assume-screen 10/width, 5/height
1885 s:text <- new [123
1886 456]
1887 e:&:editor <- new-editor s, 0/left, 10/right
1888 editor-render screen, e
1889 $clear-trace
1890
1891 assume-console [
1892 left-click 1, 1
1893 press end
1894 ]
1895 run [
1896 editor-event-loop screen, console, e
1897 3:num/raw <- get *e, cursor-row:offset
1898 4:num/raw <- get *e, cursor-column:offset
1899 ]
1900
1901 memory-should-contain [
1902 3 <- 1
1903 4 <- 3
1904 ]
1905 check-trace-count-for-label 0, [print-character]
1906 ]
1907
1908 scenario editor-moves-to-end-of-line-with-end-2 [
1909 local-scope
1910 assume-screen 10/width, 5/height
1911 s:text <- new [123
1912 456]
1913 e:&:editor <- new-editor s, 0/left, 10/right
1914 editor-render screen, e
1915 $clear-trace
1916
1917 assume-console [
1918 left-click 2, 1
1919 press end
1920 ]
1921 run [
1922 editor-event-loop screen, console, e
1923 3:num/raw <- get *e, cursor-row:offset
1924 4:num/raw <- get *e, cursor-column:offset
1925 ]
1926
1927 memory-should-contain [
1928 3 <- 2
1929 4 <- 3
1930 ]
1931 check-trace-count-for-label 0, [print-character]
1932 ]
1933
1934 scenario editor-moves-to-end-of-wrapped-line [
1935 local-scope
1936 assume-screen 10/width, 5/height
1937 s:text <- new [123456
1938 789]
1939 e:&:editor <- new-editor s, 0/left, 5/right
1940 editor-render screen, e
1941 $clear-trace
1942
1943 assume-console [
1944 left-click 1, 1
1945 press end
1946 ]
1947 run [
1948 editor-event-loop screen, console, e
1949 10:num/raw <- get *e, cursor-row:offset
1950 11:num/raw <- get *e, cursor-column:offset
1951 ]
1952
1953 memory-should-contain [
1954 10 <- 1
1955 11 <- 3
1956 ]
1957
1958 check-trace-count-for-label 0, [print-character]
1959
1960 assume-console [
1961 type [a]
1962 ]
1963 run [
1964 editor-event-loop screen, console, e
1965 ]
1966 screen-should-contain [
1967 . .
1968 .123a↩ .
1969 .456 .
1970 .789 .
1971 .╌╌╌╌╌ .
1972 ]
1973 ]
1974
1975
1976
1977 scenario editor-deletes-to-start-of-line-with-ctrl-u [
1978 local-scope
1979 assume-screen 10/width, 5/height
1980 s:text <- new [123
1981 456]
1982 e:&:editor <- new-editor s, 0/left, 10/right
1983 editor-render screen, e
1984 $clear-trace
1985
1986 assume-console [
1987 left-click 2, 2
1988 press ctrl-u
1989 ]
1990 run [
1991 editor-event-loop screen, console, e
1992 ]
1993
1994 screen-should-contain [
1995 . .
1996 .123 .
1997 .6 .
1998 .╌╌╌╌╌╌╌╌╌╌.
1999 . .
2000 ]
2001 check-trace-count-for-label 10, [print-character]
2002 ]
2003
2004 after <handle-special-character> [
2005 {
2006 delete-to-start-of-line?:bool <- equal c, 21/ctrl-u
2007 break-unless delete-to-start-of-line?
2008 <begin-delete-to-start-of-line>
2009 deleted-cells:&:duplex-list:char <- delete-to-start-of-line editor
2010 <end-delete-to-start-of-line>
2011 go-render?:bool <- minimal-render-for-ctrl-u screen, editor, deleted-cells
2012 return
2013 }
2014 ]
2015
2016 def minimal-render-for-ctrl-u screen:&:screen, editor:&:editor, deleted-cells:&:duplex-list:char -> go-render?:bool, screen:&:screen [
2017 local-scope
2018 load-inputs
2019 curr-column:num <- get *editor, cursor-column:offset
2020
2021 buf:&:buffer:char <- new-buffer 30
2022 curr:&:duplex-list:char <- get *editor, before-cursor:offset
2023 i:num <- copy curr-column
2024 right:num <- get *editor, right:offset
2025 {
2026
2027 wrap?:bool <- greater-or-equal i, right
2028 return-if wrap?, true/go-render
2029 curr <- next curr
2030 break-unless curr
2031 c:char <- get *curr, value:offset
2032 b:bool <- equal c, 10
2033 break-if b
2034 buf <- append buf, c
2035 i <- add i, 1
2036 loop
2037 }
2038
2039 num-deleted-cells:num <- length deleted-cells
2040 old-row-len:num <- add i, num-deleted-cells
2041 left:num <- get *editor, left:offset
2042 end:num <- subtract right, left
2043 wrap?:bool <- greater-or-equal old-row-len, end
2044 return-if wrap?, true/go-render
2045 curr-line:text <- buffer-to-array buf
2046 curr-row:num <- get *editor, cursor-row:offset
2047 render-code screen, curr-line, curr-column, right, curr-row
2048 return false/dont-render
2049 ]
2050
2051 def delete-to-start-of-line editor:&:editor -> result:&:duplex-list:char, editor:&:editor [
2052 local-scope
2053 load-inputs
2054
2055 init:&:duplex-list:char <- get *editor, data:offset
2056 top-of-screen:&:duplex-list:char <- get *editor, top-of-screen:offset
2057 update-top-of-screen?:bool <- copy false
2058 before-cursor:&:duplex-list:char <- get *editor, before-cursor:offset
2059 start:&:duplex-list:char <- copy before-cursor
2060 end:&:duplex-list:char <- next before-cursor
2061 {
2062 at-start-of-text?:bool <- equal start, init
2063 break-if at-start-of-text?
2064 curr:char <- get *start, value:offset
2065 at-start-of-line?:bool <- equal curr, 10/newline
2066 break-if at-start-of-line?
2067
2068 at-top-of-screen?:bool <- equal start, top-of-screen
2069 update-top-of-screen?:bool <- or update-top-of-screen?, at-top-of-screen?
2070 start <- prev start
2071 assert start, [delete-to-start-of-line tried to move before start of text]
2072 loop
2073 }
2074
2075 result:&:duplex-list:char <- next start
2076 remove-between start, end
2077
2078 {
2079 break-unless update-top-of-screen?
2080 put *editor, top-of-screen:offset, start
2081 }
2082
2083 before-cursor <- copy start
2084 *editor <- put *editor, before-cursor:offset, before-cursor
2085 left:num <- get *editor, left:offset
2086 *editor <- put *editor, cursor-column:offset, left
2087
2088 right:num <- get *editor, right:offset
2089 width:num <- subtract right, left
2090 num-deleted:num <- length result
2091 cursor-row-adjustment:num <- divide-with-remainder num-deleted, width
2092 return-unless cursor-row-adjustment
2093 cursor-row:num <- get *editor, cursor-row:offset
2094 cursor-row-in-editor:num <- subtract cursor-row, 1
2095 at-top?:bool <- lesser-or-equal cursor-row-in-editor, cursor-row-adjustment
2096 {
2097 break-unless at-top?
2098 cursor-row <- copy 1
2099 }
2100 {
2101 break-if at-top?
2102 cursor-row <- subtract cursor-row, cursor-row-adjustment
2103 }
2104 put *editor, cursor-row:offset, cursor-row
2105 ]
2106
2107 def render-code screen:&:screen, s:text, left:num, right:num, row:num -> row:num, screen:&:screen [
2108 local-scope
2109 load-inputs
2110 return-unless s
2111 color:num <- copy 7/white
2112 column:num <- copy left
2113 screen <- move-cursor screen, row, column
2114 screen-height:num <- screen-height screen
2115 i:num <- copy 0
2116 len:num <- length *s
2117 {
2118 +next-character
2119 done?:bool <- greater-or-equal i, len
2120 break-if done?
2121 done? <- greater-or-equal row, screen-height
2122 break-if done?
2123 c:char <- index *s, i
2124 <character-c-received>
2125 {
2126
2127 newline?:bool <- equal c, 10/newline
2128 break-unless newline?
2129
2130 {
2131 done?:bool <- greater-than column, right
2132 break-if done?
2133 space:char <- copy 32/space
2134 print screen, space
2135 column <- add column, 1
2136 loop
2137 }
2138 row <- add row, 1
2139 column <- copy left
2140 screen <- move-cursor screen, row, column
2141 i <- add i, 1
2142 loop +next-character
2143 }
2144 {
2145
2146 at-right?:bool <- equal column, right
2147 break-unless at-right?
2148
2149 wrap-icon:char <- copy 8617/loop-back-to-left
2150 print screen, wrap-icon, 245/grey
2151 column <- copy left
2152 row <- add row, 1
2153 screen <- move-cursor screen, row, column
2154
2155 loop +next-character
2156 }
2157 i <- add i, 1
2158 print screen, c, color
2159 column <- add column, 1
2160 loop
2161 }
2162 was-at-left?:bool <- equal column, left
2163 clear-line-until screen, right
2164 {
2165 break-if was-at-left?
2166 row <- add row, 1
2167 }
2168 move-cursor screen, row, left
2169 ]
2170
2171 scenario editor-deletes-to-start-of-line-with-ctrl-u-2 [
2172 local-scope
2173 assume-screen 10/width, 5/height
2174 s:text <- new [123
2175 456]
2176 e:&:editor <- new-editor s, 0/left, 10/right
2177 editor-render screen, e
2178 $clear-trace
2179
2180 assume-console [
2181 left-click 1, 2
2182 press ctrl-u
2183 ]
2184 run [
2185 editor-event-loop screen, console, e
2186 ]
2187
2188 screen-should-contain [
2189 . .
2190 .3 .
2191 .456 .
2192 .╌╌╌╌╌╌╌╌╌╌.
2193 . .
2194 ]
2195 check-trace-count-for-label 10, [print-character]
2196 ]
2197
2198 scenario editor-deletes-to-start-of-line-with-ctrl-u-3 [
2199 local-scope
2200 assume-screen 10/width, 5/height
2201 s:text <- new [123
2202 456]
2203 e:&:editor <- new-editor s, 0/left, 10/right
2204 editor-render screen, e
2205 $clear-trace
2206
2207 assume-console [
2208 left-click 1, 3
2209 press ctrl-u
2210 ]
2211 run [
2212 editor-event-loop screen, console, e
2213 ]
2214
2215 screen-should-contain [
2216 . .
2217 . .
2218 .456 .
2219 .╌╌╌╌╌╌╌╌╌╌.
2220 . .
2221 ]
2222 check-trace-count-for-label 10, [print-character]
2223 ]
2224
2225 scenario editor-deletes-to-start-of-final-line-with-ctrl-u [
2226 local-scope
2227 assume-screen 10/width, 5/height
2228 s:text <- new [123
2229 456]
2230 e:&:editor <- new-editor s, 0/left, 10/right
2231 editor-render screen, e
2232 $clear-trace
2233
2234 assume-console [
2235 left-click 2, 3
2236 press ctrl-u
2237 ]
2238 run [
2239 editor-event-loop screen, console, e
2240 ]
2241
2242 screen-should-contain [
2243 . .
2244 .123 .
2245 . .
2246 .╌╌╌╌╌╌╌╌╌╌.
2247 . .
2248 ]
2249 check-trace-count-for-label 10, [print-character]
2250 ]
2251
2252 scenario editor-deletes-to-start-of-wrapped-line-with-ctrl-u [
2253 local-scope
2254 assume-screen 10/width, 10/height
2255
2256 s:text <- new [123456
2257 789]
2258 e:&:editor <- new-editor s, 0/left, 5/right
2259 editor-render screen, e
2260 screen-should-contain [
2261 . .
2262 .1234↩ .
2263 .56 .
2264 .789 .
2265 .╌╌╌╌╌ .
2266 . .
2267 ]
2268 $clear-trace
2269
2270 assume-console [
2271 left-click 1, 3
2272 press ctrl-u
2273 ]
2274 run [
2275 editor-event-loop screen, console, e
2276 ]
2277
2278 screen-should-contain [
2279 . .
2280 .456 .
2281 .789 .
2282 .╌╌╌╌╌ .
2283 . .
2284 ]
2285 check-trace-count-for-label 45, [print-character]
2286 ]
2287
2288
2289 scenario editor-deletes-to-start-of-wrapped-line-with-ctrl-u-2 [
2290 local-scope
2291 assume-screen 10/width, 10/height
2292
2293 s:text <- new [1
2294 2
2295 345678
2296 9]
2297 e:&:editor <- new-editor s, 0/left, 5/right
2298 editor-render screen, e
2299 screen-should-contain [
2300 . .
2301 .1 .
2302 .2 .
2303 .3456↩ .
2304 .78 .
2305 .9 .
2306 .╌╌╌╌╌ .
2307 . .
2308 ]
2309
2310 assume-console [
2311 left-click 4, 1
2312 press ctrl-u
2313 ]
2314 run [
2315 editor-event-loop screen, console, e
2316 10:num/raw <- get *e, cursor-row:offset
2317 11:num/raw <- get *e, cursor-column:offset
2318 ]
2319 screen-should-contain [
2320 . .
2321 .1 .
2322 .2 .
2323 .8 .
2324 .9 .
2325 .╌╌╌╌╌ .
2326 . .
2327 ]
2328
2329 memory-should-contain [
2330 10 <- 3
2331 11 <- 0
2332 ]
2333 ]
2334
2335
2336 scenario editor-deletes-to-start-of-wrapped-line-with-ctrl-u-3 [
2337 local-scope
2338 assume-screen 10/width, 10/height
2339
2340 s:text <- new [1
2341 2
2342 3456789abcd
2343 e]
2344 e:&:editor <- new-editor s, 0/left, 5/right
2345 editor-render screen, e
2346 assume-console [
2347 left-click 4, 1
2348 ]
2349 editor-event-loop screen, console, e
2350 screen-should-contain [
2351 . .
2352 .1 .
2353 .2 .
2354 .3456↩ .
2355 .789a↩ .
2356 .bcd .
2357 .e .
2358 .╌╌╌╌╌ .
2359 . .
2360 ]
2361 assume-console [
2362 left-click 5, 1
2363 press ctrl-u
2364 ]
2365 run [
2366 editor-event-loop screen, console, e
2367 10:num/raw <- get *e, cursor-row:offset
2368 11:num/raw <- get *e, cursor-column:offset
2369 ]
2370 screen-should-contain [
2371 . .
2372 .1 .
2373 .2 .
2374 .cd .
2375 .e .
2376 .╌╌╌╌╌ .
2377 . .
2378 ]
2379
2380 memory-should-contain [
2381 10 <- 3
2382 11 <- 0
2383 ]
2384 ]
2385
2386
2387 scenario editor-deletes-to-start-of-wrapped-line-with-ctrl-u-4 [
2388 local-scope
2389 assume-screen 10/width, 10/height
2390
2391 s:text <- new [1234567
2392 89]
2393 e:&:editor <- new-editor s, 0/left, 5/right
2394 editor-render screen, e
2395 screen-should-contain [
2396 . .
2397 .1234↩ .
2398 .567 .
2399 .89 .
2400 .╌╌╌╌╌ .
2401 . .
2402 ]
2403
2404 assume-console [
2405 left-click 2, 1
2406 press ctrl-u
2407 ]
2408 run [
2409 editor-event-loop screen, console, e
2410 10:num/raw <- get *e, cursor-row:offset
2411 11:num/raw <- get *e, cursor-column:offset
2412 ]
2413 screen-should-contain [
2414 . .
2415 .67 .
2416 .89 .
2417 .╌╌╌╌╌ .
2418 . .
2419 ]
2420
2421 memory-should-contain [
2422 10 <- 1
2423 11 <- 0
2424 ]
2425 ]
2426
2427
2428 scenario editor-deletes-to-start-of-wrapped-line-with-ctrl-u-5 [
2429 local-scope
2430 assume-screen 10/width, 10/height
2431
2432 s:text <- new [1
2433 2
2434 345678
2435 9]
2436 e:&:editor <- new-editor s, 0/left, 5/right
2437 editor-render screen, e
2438
2439 assume-console [
2440 left-click 4, 1
2441 press ctrl-t
2442 ]
2443 editor-event-loop screen, console, e
2444 screen-should-contain [
2445 . .
2446 .78 .
2447 .9 .
2448 .╌╌╌╌╌ .
2449 . .
2450 ]
2451 assume-console [
2452 left-click 1, 1
2453 press ctrl-u
2454 ]
2455 run [
2456 editor-event-loop screen, console, e
2457 10:num/raw <- get *e, cursor-row:offset
2458 11:num/raw <- get *e, cursor-column:offset
2459 ]
2460
2461 screen-should-contain [
2462 . .
2463 .8 .
2464 .9 .
2465 .╌╌╌╌╌ .
2466 . .
2467 ]
2468 memory-should-contain [
2469 10 <- 1
2470 11 <- 0
2471 ]
2472
2473 assume-console [
2474 press up-arrow
2475 ]
2476 run [
2477 editor-event-loop screen, console, e
2478 ]
2479 screen-should-contain [
2480 . .
2481 .2 .
2482 .8 .
2483 .9 .
2484 .╌╌╌╌╌ .
2485 . .
2486 ]
2487 ]
2488
2489
2490 scenario editor-deletes-to-start-of-wrapped-line-with-ctrl-u-6 [
2491 local-scope
2492 assume-screen 10/width, 10/height
2493
2494 s:text <- new [1
2495 2
2496 3456789abcd
2497 e]
2498 e:&:editor <- new-editor s, 0/left, 5/right
2499 editor-render screen, e
2500
2501 assume-console [
2502 left-click 4, 1
2503 press ctrl-t
2504 press ctrl-s
2505 ]
2506 editor-event-loop screen, console, e
2507 screen-should-contain [
2508 . .
2509 .bcd .
2510 .e .
2511 .╌╌╌╌╌ .
2512 . .
2513 ]
2514 assume-console [
2515 left-click 1, 1
2516 press ctrl-u
2517 ]
2518 run [
2519 editor-event-loop screen, console, e
2520 10:num/raw <- get *e, cursor-row:offset
2521 11:num/raw <- get *e, cursor-column:offset
2522 ]
2523
2524 screen-should-contain [
2525 . .
2526 .cd .
2527 .e .
2528 .╌╌╌╌╌ .
2529 . .
2530 ]
2531 memory-should-contain [
2532 10 <- 1
2533 11 <- 0
2534 ]
2535
2536 assume-console [
2537 press up-arrow
2538 ]
2539 run [
2540 editor-event-loop screen, console, e
2541 ]
2542 screen-should-contain [
2543 . .
2544 .2 .
2545 .cd .
2546 .e .
2547 .╌╌╌╌╌ .
2548 . .
2549 ]
2550 ]
2551
2552
2553
2554 scenario editor-deletes-to-end-of-line-with-ctrl-k [
2555 local-scope
2556 assume-screen 10/width, 5/height
2557 s:text <- new [123
2558 456]
2559 e:&:editor <- new-editor s, 0/left, 10/right
2560 editor-render screen, e
2561 $clear-trace
2562
2563 assume-console [
2564 left-click 1, 1
2565 press ctrl-k
2566 ]
2567 run [
2568 editor-event-loop screen, console, e
2569 ]
2570
2571 screen-should-contain [
2572 . .
2573 .1 .
2574 .456 .
2575 .╌╌╌╌╌╌╌╌╌╌.
2576 . .
2577 ]
2578 check-trace-count-for-label 9, [print-character]
2579 ]
2580
2581 after <handle-special-character> [
2582 {
2583 delete-to-end-of-line?:bool <- equal c, 11/ctrl-k
2584 break-unless delete-to-end-of-line?
2585 <begin-delete-to-end-of-line>
2586 deleted-cells:&:duplex-list:char <- delete-to-end-of-line editor
2587 <end-delete-to-end-of-line>
2588
2589 go-render?:bool <- minimal-render-for-ctrl-k screen, editor, deleted-cells
2590 return
2591 }
2592 ]
2593
2594 def minimal-render-for-ctrl-k screen:&:screen, editor:&:editor, deleted-cells:&:duplex-list:char -> go-render?:bool, screen:&:screen [
2595 local-scope
2596 load-inputs
2597
2598 return-unless deleted-cells, false/dont-render
2599
2600 curr-column:num <- get *editor, cursor-column:offset
2601 num-deleted-cells:num <- length deleted-cells
2602 old-row-len:num <- add curr-column, num-deleted-cells
2603 left:num <- get *editor, left:offset
2604 right:num <- get *editor, right:offset
2605 end:num <- subtract right, left
2606 wrap?:bool <- greater-or-equal old-row-len, end
2607 return-if wrap?, true/go-render
2608 clear-line-until screen, right
2609 return false/dont-render
2610 ]
2611
2612 def delete-to-end-of-line editor:&:editor -> result:&:duplex-list:char, editor:&:editor [
2613 local-scope
2614 load-inputs
2615
2616 start:&:duplex-list:char <- get *editor, before-cursor:offset
2617 end:&:duplex-list:char <- next start
2618 {
2619 at-end-of-text?:bool <- equal end, null
2620 break-if at-end-of-text?
2621 curr:char <- get *end, value:offset
2622 at-end-of-line?:bool <- equal curr, 10/newline
2623 break-if at-end-of-line?
2624 end <- next end
2625 loop
2626 }
2627
2628 result <- next start
2629 remove-between start, end
2630 ]
2631
2632 scenario editor-deletes-to-end-of-line-with-ctrl-k-2 [
2633 local-scope
2634 assume-screen 10/width, 5/height
2635 s:text <- new [123
2636 456]
2637 e:&:editor <- new-editor s, 0/left, 10/right
2638 editor-render screen, e
2639 $clear-trace
2640
2641 assume-console [
2642 left-click 2, 1
2643 press ctrl-k
2644 ]
2645 run [
2646 editor-event-loop screen, console, e
2647 ]
2648
2649 screen-should-contain [
2650 . .
2651 .123 .
2652 .4 .
2653 .╌╌╌╌╌╌╌╌╌╌.
2654 . .
2655 ]
2656 check-trace-count-for-label 9, [print-character]
2657 ]
2658
2659 scenario editor-deletes-to-end-of-line-with-ctrl-k-3 [
2660 local-scope
2661 assume-screen 10/width, 5/height
2662 s:text <- new [123
2663 456]
2664 e:&:editor <- new-editor s, 0/left, 10/right
2665 editor-render screen, e
2666 $clear-trace
2667
2668 assume-console [
2669 left-click 1, 2
2670 press ctrl-k
2671 ]
2672 run [
2673 editor-event-loop screen, console, e
2674 ]
2675
2676 screen-should-contain [
2677 . .
2678 .12 .
2679 .456 .
2680 .╌╌╌╌╌╌╌╌╌╌.
2681 . .
2682 ]
2683 check-trace-count-for-label 8, [print-character]
2684 ]
2685
2686 scenario editor-deletes-to-end-of-line-with-ctrl-k-4 [
2687 local-scope
2688 assume-screen 10/width, 5/height
2689 s:text <- new [123
2690 456]
2691 e:&:editor <- new-editor s, 0/left, 10/right
2692 editor-render screen, e
2693 $clear-trace
2694
2695 assume-console [
2696 left-click 1, 3
2697 press ctrl-k
2698 ]
2699 run [
2700 editor-event-loop screen, console, e
2701 ]
2702
2703 screen-should-contain [
2704 . .
2705 .123 .
2706 .456 .
2707 .╌╌╌╌╌╌╌╌╌╌.
2708 . .
2709 ]
2710 check-trace-count-for-label 7, [print-character]
2711 ]
2712
2713 scenario editor-deletes-to-end-of-line-with-ctrl-k-5 [
2714 local-scope
2715 assume-screen 10/width, 5/height
2716 s:text <- new [123
2717 456]
2718 e:&:editor <- new-editor s, 0/left, 10/right
2719 editor-render screen, e
2720 $clear-trace
2721
2722 assume-console [
2723 left-click 2, 2
2724 press ctrl-k
2725 ]
2726 run [
2727 editor-event-loop screen, console, e
2728 ]
2729
2730 screen-should-contain [
2731 . .
2732 .123 .
2733 .45 .
2734 .╌╌╌╌╌╌╌╌╌╌.
2735 . .
2736 ]
2737 check-trace-count-for-label 8, [print-character]
2738 ]
2739
2740 scenario editor-deletes-to-end-of-line-with-ctrl-k-6 [
2741 local-scope
2742 assume-screen 10/width, 5/height
2743 s:text <- new [123
2744 456]
2745 e:&:editor <- new-editor s, 0/left, 10/right
2746 editor-render screen, e
2747 $clear-trace
2748
2749 assume-console [
2750 left-click 2, 3
2751 press ctrl-k
2752 ]
2753 run [
2754 editor-event-loop screen, console, e
2755 ]
2756
2757 screen-should-contain [
2758 . .
2759 .123 .
2760 .456 .
2761 .╌╌╌╌╌╌╌╌╌╌.
2762 . .
2763 ]
2764
2765 check-trace-count-for-label 0, [print-character]
2766 ]
2767
2768 scenario editor-deletes-to-end-of-wrapped-line-with-ctrl-k [
2769 local-scope
2770 assume-screen 10/width, 5/height
2771
2772 s:text <- new [1234
2773 567]
2774 e:&:editor <- new-editor s, 0/left, 4/right
2775 editor-render screen, e
2776 $clear-trace
2777
2778 assume-console [
2779 press ctrl-k
2780 ]
2781 run [
2782 editor-event-loop screen, console, e
2783 ]
2784
2785 screen-should-contain [
2786 . .
2787 . .
2788 .567 .
2789 .╌╌╌╌ .
2790 . .
2791 ]
2792
2793 check-trace-count-for-label 16, [print-character]
2794 ]
2795
2796
2797
2798 scenario editor-can-scroll-down-using-arrow-keys [
2799 local-scope
2800
2801 assume-screen 10/width, 4/height
2802
2803 s:text <- new [a
2804 b
2805 c
2806 d]
2807 e:&:editor <- new-editor s, 0/left, 10/right
2808 editor-render screen, e
2809 screen-should-contain [
2810 . .
2811 .a .
2812 .b .
2813 .c .
2814 ]
2815
2816 assume-console [
2817 left-click 3, 0
2818 press down-arrow
2819 ]
2820 run [
2821 editor-event-loop screen, console, e
2822 ]
2823
2824 screen-should-contain [
2825 . .
2826 .b .
2827 .c .
2828 .d .
2829 ]
2830 ]
2831
2832 after <scroll-down> [
2833 trace 10, [app], [scroll down]
2834 top-of-screen:&:duplex-list:char <- get *editor, top-of-screen:offset
2835 left:num <- get *editor, left:offset
2836 right:num <- get *editor, right:offset
2837 max:num <- subtract right, left
2838 old-top:&:duplex-list:char <- copy top-of-screen
2839 top-of-screen <- before-start-of-next-line top-of-screen, max
2840 *editor <- put *editor, top-of-screen:offset, top-of-screen
2841 no-movement?:bool <- equal old-top, top-of-screen
2842 return-if no-movement?, false/don't-render
2843 ]
2844
2845 after <scroll-down2> [
2846 trace 10, [app], [scroll down]
2847 top-of-screen:&:duplex-list:char <- get *editor, top-of-screen:offset
2848 left:num <- get *editor, left:offset
2849 right:num <- get *editor, right:offset
2850 max:num <- subtract right, left
2851 old-top:&:duplex-list:char <- copy top-of-screen
2852 top-of-screen <- before-start-of-next-line top-of-screen, max
2853 *editor <- put *editor, top-of-screen:offset, top-of-screen
2854 no-movement?:bool <- equal old-top, top-of-screen
2855 return-if no-movement?
2856 ]
2857
2858
2859
2860
2861
2862 def before-start-of-next-line original:&:duplex-list:char, max:num -> curr:&:duplex-list:char [
2863 local-scope
2864 load-inputs
2865 count:num <- copy 0
2866 curr:&:duplex-list:char <- copy original
2867
2868 {
2869 c:char <- get *curr, value:offset
2870 at-newline?:bool <- equal c, 10/newline
2871 break-unless at-newline?
2872 curr <- next curr
2873 count <- add count, 1
2874 }
2875 {
2876 return-unless curr, original
2877 done?:bool <- greater-or-equal count, max
2878 break-if done?
2879 c:char <- get *curr, value:offset
2880 at-newline?:bool <- equal c, 10/newline
2881 break-if at-newline?
2882 curr <- next curr
2883 count <- add count, 1
2884 loop
2885 }
2886 return-unless curr, original
2887 return curr
2888 ]
2889
2890 scenario editor-scrolls-down-past-wrapped-line-using-arrow-keys [
2891 local-scope
2892
2893 assume-screen 10/width, 4/height
2894
2895
2896 s:text <- new [abcdef
2897 g
2898 h
2899 i]
2900 e:&:editor <- new-editor s, 0/left, 5/right
2901 editor-render screen, e
2902 screen-should-contain [
2903 . .
2904 .abcd↩ .
2905 .ef .
2906 .g .
2907 ]
2908
2909 assume-console [
2910 left-click 3, 0
2911 press down-arrow
2912 ]
2913 run [
2914 editor-event-loop screen, console, e
2915 ]
2916
2917 screen-should-contain [
2918 . .
2919 .ef .
2920 .g .
2921 .h .
2922 ]
2923 ]
2924
2925 scenario editor-scrolls-down-past-wrapped-line-using-arrow-keys-2 [
2926 local-scope
2927
2928 assume-screen 10/width, 4/height
2929
2930 s:text <- new [abcdefghij
2931 k
2932 l
2933 m]
2934 e:&:editor <- new-editor s, 0/left, 5/right
2935
2936 assume-console [
2937 left-click 3, 0
2938 press down-arrow
2939 ]
2940 run [
2941 editor-event-loop screen, console, e
2942 ]
2943
2944 screen-should-contain [
2945 . .
2946 .efgh↩ .
2947 .ij .
2948 .k .
2949 ]
2950
2951 assume-console [
2952 press down-arrow
2953 ]
2954 run [
2955 editor-event-loop screen, console, e
2956 ]
2957
2958 screen-should-contain [
2959 . .
2960 .ij .
2961 .k .
2962 .l .
2963 ]
2964 ]
2965
2966 scenario editor-scrolls-down-when-line-wraps [
2967 local-scope
2968
2969 assume-screen 5/width, 4/height
2970
2971 s:text <- new [a
2972 b
2973 cdef]
2974 e:&:editor <- new-editor s, 0/left, 5/right
2975
2976 assume-console [
2977 left-click 3, 4
2978 type [g]
2979 ]
2980 run [
2981 editor-event-loop screen, console, e
2982 3:num/raw <- get *e, cursor-row:offset
2983 4:num/raw <- get *e, cursor-column:offset
2984 ]
2985
2986 screen-should-contain [
2987 . .
2988 .b .
2989 .cdef↩.
2990 .g .
2991 ]
2992 memory-should-contain [
2993 3 <- 3
2994 4 <- 1
2995 ]
2996 ]
2997
2998 scenario editor-stops-scrolling-once-bottom-is-visible [
2999 local-scope
3000
3001 assume-screen 10/width, 4/height
3002
3003 s:text <- new [a
3004 b]
3005 e:&:editor <- new-editor s, 0/left, 10/right
3006 editor-render screen, e
3007 screen-should-contain [
3008 . .
3009 .a .
3010 .b .
3011 .╌╌╌╌╌╌╌╌╌╌.
3012 ]
3013
3014 assume-console [
3015 left-click 3, 0
3016 press down-arrow
3017 ]
3018 run [
3019 editor-event-loop screen, console, e
3020 ]
3021
3022 screen-should-contain [
3023 . .
3024 .a .
3025 .b .
3026 .╌╌╌╌╌╌╌╌╌╌.
3027 ]
3028 ]
3029
3030 scenario editor-scrolls-down-on-newline [
3031 local-scope
3032 assume-screen 5/width, 4/height
3033
3034 s:text <- new [a
3035 b
3036 c]
3037 e:&:editor <- new-editor s, 0/left, 5/right
3038 assume-console [
3039 left-click 3, 4
3040 type [
3041 ]
3042 ]
3043 run [
3044 editor-event-loop screen, console, e
3045 3:num/raw <- get *e, cursor-row:offset
3046 4:num/raw <- get *e, cursor-column:offset
3047 ]
3048
3049 screen-should-contain [
3050 . .
3051 .b .
3052 .c .
3053 . .
3054 ]
3055 memory-should-contain [
3056 3 <- 3
3057 4 <- 0
3058 ]
3059 ]
3060
3061 scenario editor-scrolls-down-on-right-arrow [
3062 local-scope
3063
3064 assume-screen 5/width, 4/height
3065
3066 s:text <- new [a
3067 b
3068 cdefgh]
3069 e:&:editor <- new-editor s, 0/left, 5/right
3070
3071 assume-console [
3072 left-click 3, 3
3073 press right-arrow
3074 ]
3075 run [
3076 editor-event-loop screen, console, e
3077 3:num/raw <- get *e, cursor-row:offset
3078 4:num/raw <- get *e, cursor-column:offset
3079 ]
3080
3081 screen-should-contain [
3082 . .
3083 .b .
3084 .cdef↩.
3085 .gh .
3086 ]
3087 memory-should-contain [
3088 3 <- 3
3089 4 <- 0
3090 ]
3091 ]
3092
3093 scenario editor-scrolls-down-on-right-arrow-2 [
3094 local-scope
3095
3096 assume-screen 5/width, 4/height
3097
3098 s:text <- new [a
3099 b
3100 c
3101 d]
3102 e:&:editor <- new-editor s, 0/left, 5/right
3103
3104 assume-console [
3105 left-click 3, 3
3106 press right-arrow
3107 ]
3108 run [
3109 editor-event-loop screen, console, e
3110 3:num/raw <- get *e, cursor-row:offset
3111 4:num/raw <- get *e, cursor-column:offset
3112 ]
3113
3114 screen-should-contain [
3115 . .
3116 .b .
3117 .c .
3118 .d .
3119 ]
3120 memory-should-contain [
3121 3 <- 3
3122 4 <- 0
3123 ]
3124 ]
3125
3126 scenario editor-scrolls-at-end-on-down-arrow [
3127 local-scope
3128 assume-screen 10/width, 5/height
3129 s:text <- new [abc
3130 de]
3131 e:&:editor <- new-editor s, 0/left, 10/right
3132 editor-render screen, e
3133 $clear-trace
3134
3135 assume-console [
3136 left-click 2, 0
3137 press down-arrow
3138 ]
3139 run [
3140 editor-event-loop screen, console, e
3141 3:num/raw <- get *e, cursor-row:offset
3142 4:num/raw <- get *e, cursor-column:offset
3143 ]
3144
3145 memory-should-contain [
3146 3 <- 2
3147 4 <- 0
3148 ]
3149 ]
3150
3151 scenario editor-combines-page-and-line-scroll [
3152 local-scope
3153
3154 assume-screen 10/width, 4/height
3155
3156 s:text <- new [a
3157 b
3158 c
3159 d
3160 e
3161 f
3162 g]
3163 e:&:editor <- new-editor s, 0/left, 5/right
3164 editor-render screen, e
3165
3166 assume-console [
3167 press page-down
3168 left-click 3, 0
3169 press down-arrow
3170 ]
3171 run [
3172 editor-event-loop screen, console, e
3173 ]
3174
3175 screen-should-contain [
3176 . .
3177 .d .
3178 .e .
3179 .f .
3180 ]
3181 ]
3182
3183
3184
3185 scenario editor-can-scroll-up-using-arrow-keys [
3186 local-scope
3187
3188 assume-screen 10/width, 4/height
3189
3190 s:text <- new [a
3191 b
3192 c
3193 d]
3194 e:&:editor <- new-editor s, 0/left, 10/right
3195 editor-render screen, e
3196 screen-should-contain [
3197 . .
3198 .a .
3199 .b .
3200 .c .
3201 ]
3202
3203 assume-console [
3204 press page-down
3205 press up-arrow
3206 ]
3207 run [
3208 editor-event-loop screen, console, e
3209 ]
3210
3211 screen-should-contain [
3212 . .
3213 .b .
3214 .c .
3215 .d .
3216 ]
3217 ]
3218
3219 after <scroll-up> [
3220 trace 10, [app], [scroll up]
3221 top-of-screen:&:duplex-list:char <- get *editor, top-of-screen:offset
3222 old-top:&:duplex-list:char <- copy top-of-screen
3223 top-of-screen <- before-previous-screen-line top-of-screen, editor
3224 *editor <- put *editor, top-of-screen:offset, top-of-screen
3225 no-movement?:bool <- equal old-top, top-of-screen
3226 return-if no-movement?, false/don't-render
3227 ]
3228
3229 scenario editor-scrolls-up-past-wrapped-line-using-arrow-keys [
3230 local-scope
3231
3232 assume-screen 10/width, 4/height
3233
3234
3235 s:text <- new [abcdef
3236 g
3237 h
3238 i]
3239 e:&:editor <- new-editor s, 0/left, 5/right
3240 editor-render screen, e
3241 screen-should-contain [
3242 . .
3243 .abcd↩ .
3244 .ef .
3245 .g .
3246 ]
3247
3248 assume-console [
3249 press page-down
3250 ]
3251 run [
3252 editor-event-loop screen, console, e
3253 ]
3254 screen-should-contain [
3255 . .
3256 .g .
3257 .h .
3258 .i .
3259 ]
3260
3261 assume-console [
3262 press up-arrow
3263 ]
3264 run [
3265 editor-event-loop screen, console, e
3266 ]
3267
3268 screen-should-contain [
3269 . .
3270 .ef .
3271 .g .
3272 .h .
3273 ]
3274 ]
3275
3276 scenario editor-scrolls-up-past-wrapped-line-using-arrow-keys-2 [
3277 local-scope
3278
3279 assume-screen 10/width, 5/height
3280
3281 s:text <- new [abcdefghij
3282 k
3283 l
3284 m]
3285 e:&:editor <- new-editor s, 0/left, 5/right
3286 editor-render screen, e
3287
3288 assume-console [
3289 press page-down
3290 ]
3291 run [
3292 editor-event-loop screen, console, e
3293 ]
3294 screen-should-contain [
3295 . .
3296 .k .
3297 .l .
3298 .m .
3299 .╌╌╌╌╌ .
3300 ]
3301
3302 assume-console [
3303 press up-arrow
3304 ]
3305 run [
3306 editor-event-loop screen, console, e
3307 ]
3308
3309 screen-should-contain [
3310 . .
3311 .ij .
3312 .k .
3313 .l .
3314 .m .
3315 ]
3316
3317 assume-console [
3318 press up-arrow
3319 ]
3320 run [
3321 editor-event-loop screen, console, e
3322 ]
3323
3324 screen-should-contain [
3325 . .
3326 .efgh↩ .
3327 .ij .
3328 .k .
3329 .l .
3330 ]
3331
3332 assume-console [
3333 press up-arrow
3334 ]
3335 run [
3336 editor-event-loop screen, console, e
3337 ]
3338
3339 screen-should-contain [
3340 . .
3341 .abcd↩ .
3342 .efgh↩ .
3343 .ij .
3344 .k .
3345 ]
3346 ]
3347
3348
3349
3350 scenario editor-scrolls-up-past-wrapped-line-using-arrow-keys-3 [
3351 local-scope
3352
3353 assume-screen 10/width, 4/height
3354
3355
3356 s:text <- new [abcdef
3357 g
3358 h
3359 i]
3360 e:&:editor <- new-editor s, 0/left, 6/right
3361 editor-render screen, e
3362 screen-should-contain [
3363 . .
3364 .abcde↩ .
3365 .f .
3366 .g .
3367 ]
3368
3369 assume-console [
3370 press page-down
3371 ]
3372 run [
3373 editor-event-loop screen, console, e
3374 ]
3375 screen-should-contain [
3376 . .
3377 .g .
3378 .h .
3379 .i .
3380 ]
3381
3382 assume-console [
3383 press up-arrow
3384 ]
3385 run [
3386 editor-event-loop screen, console, e
3387 ]
3388
3389 screen-should-contain [
3390 . .
3391 .f .
3392 .g .
3393 .h .
3394 ]
3395 ]
3396
3397
3398 scenario editor-scrolls-up-past-wrapped-line-using-arrow-keys-4 [
3399 local-scope
3400 assume-screen 10/width, 4/height
3401
3402 s:text <- new [a
3403 b
3404
3405 c
3406 d
3407 e]
3408 e:&:editor <- new-editor s, 0/left, 6/right
3409 editor-render screen, e
3410 assume-console [
3411 press page-down
3412 ]
3413 run [
3414 editor-event-loop screen, console, e
3415 ]
3416 screen-should-contain [
3417 . .
3418 . .
3419 .c .
3420 .d .
3421 ]
3422 assume-console [
3423 press page-down
3424 ]
3425 run [
3426 editor-event-loop screen, console, e
3427 ]
3428 screen-should-contain [
3429 . .
3430 .d .
3431 .e .
3432 .╌╌╌╌╌╌ .
3433 ]
3434 assume-console [
3435 press page-up
3436 ]
3437 run [
3438 editor-event-loop screen, console, e
3439 ]
3440 screen-should-contain [
3441 . .
3442 . .
3443 .c .
3444 .d .
3445 ]
3446 ]
3447
3448 scenario editor-scrolls-up-on-left-arrow [
3449 local-scope
3450
3451 assume-screen 5/width, 4/height
3452
3453 s:text <- new [a
3454 b
3455 c
3456 d
3457 e]
3458 e:&:editor <- new-editor s, 0/left, 5/right
3459 editor-render screen, e
3460
3461 assume-console [
3462 press page-down
3463 ]
3464 run [
3465 editor-event-loop screen, console, e
3466 ]
3467 screen-should-contain [
3468 . .
3469 .c .
3470 .d .
3471 .e .
3472 ]
3473
3474 assume-console [
3475 press left-arrow
3476 ]
3477 run [
3478 editor-event-loop screen, console, e
3479 3:num/raw <- get *e, cursor-row:offset
3480 4:num/raw <- get *e, cursor-column:offset
3481 ]
3482
3483 screen-should-contain [
3484 . .
3485 .b .
3486 .c .
3487 .d .
3488 ]
3489 memory-should-contain [
3490 3 <- 1
3491 4 <- 1
3492 ]
3493 ]
3494
3495 scenario editor-can-scroll-up-to-start-of-file [
3496 local-scope
3497
3498 assume-screen 10/width, 4/height
3499
3500 s:text <- new [a
3501 b
3502 c
3503 d]
3504 e:&:editor <- new-editor s, 0/left, 10/right
3505 editor-render screen, e
3506 screen-should-contain [
3507 . .
3508 .a .
3509 .b .
3510 .c .
3511 ]
3512
3513
3514 assume-console [
3515 press page-down
3516 press up-arrow
3517 press up-arrow
3518 ]
3519 run [
3520 editor-event-loop screen, console, e
3521 ]
3522
3523 screen-should-contain [
3524 . .
3525 .a .
3526 .b .
3527 .c .
3528 ]
3529
3530 assume-console [
3531 press up-arrow
3532 ]
3533 run [
3534 editor-event-loop screen, console, e
3535 ]
3536
3537 screen-should-contain [
3538 . .
3539 .a .
3540 .b .
3541 .c .
3542 ]
3543 ]
3544
3545
3546
3547 scenario editor-can-scroll [
3548 local-scope
3549 assume-screen 10/width, 4/height
3550 s:text <- new [a
3551 b
3552 c
3553 d]
3554 e:&:editor <- new-editor s, 0/left, 10/right
3555 editor-render screen, e
3556 screen-should-contain [
3557 . .
3558 .a .
3559 .b .
3560 .c .
3561 ]
3562
3563 assume-console [
3564 press page-down
3565 ]
3566 run [
3567 editor-event-loop screen, console, e
3568 ]
3569
3570 screen-should-contain [
3571 . .
3572 .c .
3573 .d .
3574 .╌╌╌╌╌╌╌╌╌╌.
3575 ]
3576 ]
3577
3578 after <handle-special-character> [
3579 {
3580 page-down?:bool <- equal c, 6/ctrl-f
3581 break-unless page-down?
3582 old-top:&:duplex-list:char <- get *editor, top-of-screen:offset
3583 <begin-move-cursor>
3584 page-down editor
3585 undo-coalesce-tag:num <- copy 0/never
3586 <end-move-cursor>
3587 top-of-screen:&:duplex-list:char <- get *editor, top-of-screen:offset
3588 movement?:bool <- not-equal top-of-screen, old-top
3589 return movement?/go-render
3590 }
3591 ]
3592
3593 after <handle-special-key> [
3594 {
3595 page-down?:bool <- equal k, 65518/page-down
3596 break-unless page-down?
3597 old-top:&:duplex-list:char <- get *editor, top-of-screen:offset
3598 <begin-move-cursor>
3599 page-down editor
3600 undo-coalesce-tag:num <- copy 0/never
3601 <end-move-cursor>
3602 top-of-screen:&:duplex-list:char <- get *editor, top-of-screen:offset
3603 movement?:bool <- not-equal top-of-screen, old-top
3604 return movement?/go-render
3605 }
3606 ]
3607
3608
3609
3610 def page-down editor:&:editor -> editor:&:editor [
3611 local-scope
3612 load-inputs
3613
3614 bottom-of-screen:&:duplex-list:char <- get *editor, bottom-of-screen:offset
3615 return-unless bottom-of-screen
3616
3617 before-cursor:&:duplex-list:char <- get *editor, before-cursor:offset
3618 before-cursor:&:duplex-list:char <- prev bottom-of-screen
3619 *editor <- put *editor, before-cursor:offset, before-cursor
3620
3621 {
3622 last:char <- get *before-cursor, value:offset
3623 newline?:bool <- equal last, 10/newline
3624 break-unless newline?:bool
3625 before-cursor <- prev before-cursor
3626 *editor <- put *editor, before-cursor:offset, before-cursor
3627 }
3628
3629 move-to-start-of-line editor
3630 before-cursor <- get *editor, before-cursor:offset
3631 *editor <- put *editor, top-of-screen:offset, before-cursor
3632 ]
3633
3634
3635 def move-to-start-of-line editor:&:editor -> editor:&:editor [
3636 local-scope
3637 load-inputs
3638
3639 left:num <- get *editor, left:offset
3640 cursor-column:num <- copy left
3641 *editor <- put *editor, cursor-column:offset, cursor-column
3642
3643 before-cursor:&:duplex-list:char <- get *editor, before-cursor:offset
3644 init:&:duplex-list:char <- get *editor, data:offset
3645
3646 {
3647 at-start-of-text?:bool <- equal before-cursor, init
3648 break-if at-start-of-text?
3649 prev:char <- get *before-cursor, value:offset
3650 at-start-of-line?:bool <- equal prev, 10/newline
3651 break-if at-start-of-line?
3652 before-cursor <- prev before-cursor
3653 *editor <- put *editor, before-cursor:offset, before-cursor
3654 assert before-cursor, [move-to-start-of-line tried to move before start of text]
3655 loop
3656 }
3657 ]
3658
3659 scenario editor-does-not-scroll-past-end [
3660 local-scope
3661 assume-screen 10/width, 4/height
3662 s:text <- new [a
3663 b]
3664 e:&:editor <- new-editor s, 0/left, 10/right
3665 editor-render screen, e
3666 screen-should-contain [
3667 . .
3668 .a .
3669 .b .
3670 .╌╌╌╌╌╌╌╌╌╌.
3671 ]
3672
3673 assume-console [
3674 press page-down
3675 ]
3676 run [
3677 editor-event-loop screen, console, e
3678 ]
3679
3680 screen-should-contain [
3681 . .
3682 .a .
3683 .b .
3684 .╌╌╌╌╌╌╌╌╌╌.
3685 ]
3686 ]
3687
3688 scenario editor-starts-next-page-at-start-of-wrapped-line [
3689 local-scope
3690
3691 assume-screen 10/width, 4/height
3692
3693 s:text <- new [a
3694 b
3695 cdefgh]
3696
3697 e:&:editor <- new-editor s, 0/left, 4/right
3698 editor-render screen, e
3699
3700 screen-should-contain [
3701 . .
3702 .a .
3703 .b .
3704 .cde↩ .
3705 ]
3706
3707 assume-console [
3708 press page-down
3709 ]
3710 run [
3711 editor-event-loop screen, console, e
3712 ]
3713
3714 screen-should-contain [
3715 . .
3716 .cde↩ .
3717 .fgh .
3718 .╌╌╌╌ .
3719 ]
3720 ]
3721
3722 scenario editor-starts-next-page-at-start-of-wrapped-line-2 [
3723 local-scope
3724
3725 assume-screen 10/width, 4/height
3726
3727
3728 s:text <- new [a
3729 bcdefgh]
3730 e:&:editor <- new-editor s, 0/left, 4/right
3731 editor-render screen, e
3732
3733 screen-should-contain [
3734 . .
3735 .a .
3736 .bcd↩ .
3737 .efg↩ .
3738 ]
3739
3740 assume-console [
3741 press page-down
3742 ]
3743 run [
3744 editor-event-loop screen, console, e
3745 ]
3746
3747 screen-should-contain [
3748 . .
3749 .bcd↩ .
3750 .efg↩ .
3751 .h .
3752 ]
3753 ]
3754
3755
3756
3757 scenario editor-can-scroll-up [
3758 local-scope
3759 assume-screen 10/width, 4/height
3760 s:text <- new [a
3761 b
3762 c
3763 d]
3764 e:&:editor <- new-editor s, 0/left, 10/right
3765 editor-render screen, e
3766 screen-should-contain [
3767 . .
3768 .a .
3769 .b .
3770 .c .
3771 ]
3772
3773 assume-console [
3774 press page-down
3775 ]
3776 run [
3777 editor-event-loop screen, console, e
3778 ]
3779
3780 screen-should-contain [
3781 . .
3782 .c .
3783 .d .
3784 .╌╌╌╌╌╌╌╌╌╌.
3785 ]
3786
3787 assume-console [
3788 press page-up
3789 ]
3790 run [
3791 editor-event-loop screen, console, e
3792 ]
3793
3794 screen-should-contain [
3795 . .
3796 .a .
3797 .b .
3798 .c .
3799 ]
3800 ]
3801
3802 after <handle-special-character> [
3803 {
3804 page-up?:bool <- equal c, 2/ctrl-b
3805 break-unless page-up?
3806 old-top:&:duplex-list:char <- get *editor, top-of-screen:offset
3807 <begin-move-cursor>
3808 editor <- page-up editor, screen-height
3809 undo-coalesce-tag:num <- copy 0/never
3810 <end-move-cursor>
3811 top-of-screen:&:duplex-list:char <- get *editor, top-of-screen:offset
3812 movement?:bool <- not-equal top-of-screen, old-top
3813 return movement?/go-render
3814 }
3815 ]
3816
3817 after <handle-special-key> [
3818 {
3819 page-up?:bool <- equal k, 65519/page-up
3820 break-unless page-up?
3821 old-top:&:duplex-list:char <- get *editor, top-of-screen:offset
3822 <begin-move-cursor>
3823 editor <- page-up editor, screen-height
3824 undo-coalesce-tag:num <- copy 0/never
3825 <end-move-cursor>
3826 top-of-screen:&:duplex-list:char <- get *editor, top-of-screen:offset
3827 movement?:bool <- not-equal top-of-screen, old-top
3828
3829 return movement?/go-render
3830 }
3831 ]
3832
3833 def page-up editor:&:editor, screen-height:num -> editor:&:editor [
3834 local-scope
3835 load-inputs
3836 max:num <- subtract screen-height, 1/menu-bar, 1/overlapping-line
3837 count:num <- copy 0
3838 top-of-screen:&:duplex-list:char <- get *editor, top-of-screen:offset
3839 {
3840 done?:bool <- greater-or-equal count, max
3841 break-if done?
3842 prev:&:duplex-list:char <- before-previous-screen-line top-of-screen, editor
3843 break-unless prev
3844 top-of-screen <- copy prev
3845 *editor <- put *editor, top-of-screen:offset, top-of-screen
3846 count <- add count, 1
3847 loop
3848 }
3849 ]
3850
3851 scenario editor-can-scroll-up-multiple-pages [
3852 local-scope
3853
3854 assume-screen 10/width, 4/height
3855
3856 s:text <- new [a
3857 b
3858 c
3859 d
3860 e
3861 f
3862 g
3863 h]
3864 e:&:editor <- new-editor s, 0/left, 10/right
3865 editor-render screen, e
3866 screen-should-contain [
3867 . .
3868 .a .
3869 .b .
3870 .c .
3871 ]
3872
3873 assume-console [
3874 press page-down
3875 press page-down
3876 ]
3877 run [
3878 editor-event-loop screen, console, e
3879 ]
3880
3881 screen-should-contain [
3882 . .
3883 .e .
3884 .f .
3885 .g .
3886 ]
3887
3888 assume-console [
3889 press page-up
3890 ]
3891 run [
3892 editor-event-loop screen, console, e
3893 ]
3894
3895 screen-should-contain [
3896 . .
3897 .c .
3898 .d .
3899 .e .
3900 ]
3901
3902 assume-console [
3903 press page-up
3904 ]
3905 run [
3906 editor-event-loop screen, console, e
3907 ]
3908
3909 screen-should-contain [
3910 . .
3911 .a .
3912 .b .
3913 .c .
3914 ]
3915 ]
3916
3917 scenario editor-can-scroll-up-wrapped-lines [
3918 local-scope
3919
3920 assume-screen 10/width, 6/height
3921
3922 s:text <- new [a
3923 b
3924 cdefgh
3925 i
3926 j
3927 k
3928 l
3929 m
3930 n
3931 o]
3932
3933 e:&:editor <- new-editor s, 0/left, 4/right
3934 editor-render screen, e
3935
3936 screen-should-contain [
3937 . .
3938 .a .
3939 .b .
3940 .cde↩ .
3941 .fgh .
3942 .i .
3943 ]
3944
3945 assume-console [
3946 press page-down
3947 left-click 5, 0
3948 press down-arrow
3949 ]
3950 run [
3951 editor-event-loop screen, console, e
3952 ]
3953
3954 screen-should-contain [
3955 . .
3956 .j .
3957 .k .
3958 .l .
3959 .m .
3960 .n .
3961 ]
3962
3963 assume-console [
3964 press page-up
3965 ]
3966 run [
3967 editor-event-loop screen, console, e
3968 ]
3969
3970 screen-should-contain [
3971 . .
3972 .b .
3973 .cde↩ .
3974 .fgh .
3975 .i .
3976 .j .
3977 ]
3978 ]
3979
3980 scenario editor-can-scroll-up-wrapped-lines-2 [
3981 local-scope
3982
3983 assume-screen 10/width, 4/height
3984
3985
3986 s:text <- new [a
3987 bcdefgh]
3988 e:&:editor <- new-editor s, 0/left, 4/right
3989 editor-render screen, e
3990
3991 screen-should-contain [
3992 . .
3993 .a .
3994 .bcd↩ .
3995 .efg↩ .
3996 ]
3997
3998 assume-console [
3999 press page-down
4000 ]
4001 run [
4002 editor-event-loop screen, console, e
4003 ]
4004
4005 screen-should-contain [
4006 . .
4007 .bcd↩ .
4008 .efg↩ .
4009 .h .
4010 ]
4011
4012 assume-console [
4013 press page-up
4014 ]
4015 run [
4016 editor-event-loop screen, console, e
4017 ]
4018
4019 screen-should-contain [
4020 . .
4021 .a .
4022 .bcd↩ .
4023 .efg↩ .
4024 ]
4025 ]
4026
4027 scenario editor-can-scroll-up-past-nonempty-lines [
4028 local-scope
4029 assume-screen 10/width, 4/height
4030
4031 s:text <- new [axx
4032 bxx
4033 cxx
4034 dxx
4035 exx
4036 fxx
4037 gxx
4038 hxx
4039 ]
4040 e:&:editor <- new-editor s, 0/left, 4/right
4041 editor-render screen, e
4042 screen-should-contain [
4043 . .
4044 .axx .
4045 .bxx .
4046 .cxx .
4047 ]
4048 assume-console [
4049 press page-down
4050 ]
4051 run [
4052 editor-event-loop screen, console, e
4053 ]
4054 screen-should-contain [
4055 . .
4056 .cxx .
4057 .dxx .
4058 .exx .
4059 ]
4060 assume-console [
4061 press page-down
4062 ]
4063 run [
4064 editor-event-loop screen, console, e
4065 ]
4066 screen-should-contain [
4067 . .
4068 .exx .
4069 .fxx .
4070 .gxx .
4071 ]
4072
4073 assume-console [
4074 press page-up
4075 ]
4076 run [
4077 editor-event-loop screen, console, e
4078 ]
4079 screen-should-contain [
4080 . .
4081 .cxx .
4082 .dxx .
4083 .exx .
4084 ]
4085 ]
4086
4087 scenario editor-can-scroll-up-past-empty-lines [
4088 local-scope
4089 assume-screen 10/width, 4/height
4090
4091 s:text <- new [axy
4092 bxy
4093 cxy
4094
4095 dxy
4096 exy
4097 fxy
4098 gxy
4099 ]
4100 e:&:editor <- new-editor s, 0/left, 4/right
4101 editor-render screen, e
4102 screen-should-contain [
4103 . .
4104 .axy .
4105 .bxy .
4106 .cxy .
4107 ]
4108 assume-console [
4109 press page-down
4110 ]
4111 run [
4112 editor-event-loop screen, console, e
4113 ]
4114 screen-should-contain [
4115 . .
4116 .cxy .
4117 . .
4118 .dxy .
4119 ]
4120 assume-console [
4121 press page-down
4122 ]
4123 run [
4124 editor-event-loop screen, console, e
4125 ]
4126 screen-should-contain [
4127 . .
4128 .dxy .
4129 .exy .
4130 .fxy .
4131 ]
4132
4133 assume-console [
4134 press page-up
4135 ]
4136 run [
4137 editor-event-loop screen, console, e
4138 ]
4139 screen-should-contain [
4140 . .
4141 .cxy .
4142 . .
4143 .dxy .
4144 ]
4145 ]
4146
4147
4148
4149
4150 after <handle-special-character> [
4151 {
4152 scroll-up?:bool <- equal c, 19/ctrl-s
4153 break-unless scroll-up?
4154 <begin-move-cursor>
4155 go-render?:bool, editor <- line-up editor, screen-height
4156 undo-coalesce-tag:num <- copy 5/line-up
4157 <end-move-cursor>
4158 return go-render?
4159 }
4160 ]
4161
4162 def line-up editor:&:editor, screen-height:num -> go-render?:bool, editor:&:editor [
4163 local-scope
4164 load-inputs
4165 left:num <- get *editor, left:offset
4166 right:num <- get *editor, right:offset
4167 max:num <- subtract right, left
4168 old-top:&:duplex-list:char <- get *editor, top-of-screen:offset
4169 new-top:&:duplex-list:char <- before-start-of-next-line old-top, max
4170 movement?:bool <- not-equal old-top, new-top
4171 {
4172 break-unless movement?
4173 *editor <- put *editor, top-of-screen:offset, new-top
4174 }
4175 return movement?
4176 ]
4177
4178
4179
4180
4181 after <handle-special-character> [
4182 {
4183 scroll-down?:bool <- equal c, 24/ctrl-x
4184 break-unless scroll-down?
4185 <begin-move-cursor>
4186 go-render?:bool, editor <- line-down editor, screen-height
4187 undo-coalesce-tag:num <- copy 6/line-down
4188 <end-move-cursor>
4189 return go-render?
4190 }
4191 ]
4192
4193 def line-down editor:&:editor, screen-height:num -> go-render?:bool, editor:&:editor [
4194 local-scope
4195 load-inputs
4196 old-top:&:duplex-list:char <- get *editor, top-of-screen:offset
4197 new-top:&:duplex-list:char <- before-previous-screen-line old-top, editor
4198 movement?:bool <- not-equal old-top, new-top
4199 {
4200 break-unless movement?
4201 *editor <- put *editor, top-of-screen:offset, new-top
4202 }
4203 return movement?
4204 ]
4205
4206
4207
4208
4209 after <handle-special-character> [
4210 {
4211 scroll-down?:bool <- equal c, 20/ctrl-t
4212 break-unless scroll-down?
4213 <begin-move-cursor>
4214 old-top:&:duplex-list:char <- get *editor, top-of-screen:offset
4215 cursor:&:duplex-list:char <- get *editor, before-cursor:offset
4216 cursor <- next cursor
4217 new-top:&:duplex-list:char <- before-previous-screen-line cursor, editor
4218 *editor <- put *editor, top-of-screen:offset, new-top
4219 *editor <- put *editor, cursor-row:offset, 1
4220 go-render?:bool <- not-equal new-top, old-top
4221 undo-coalesce-tag:num <- copy 0/never
4222 <end-move-cursor>
4223 return go-render?
4224 }
4225 ]
4226
4227
4228
4229 after <handle-special-character> [
4230 {
4231 comment-toggle?:bool <- equal c, 31/ctrl-slash
4232 break-unless comment-toggle?
4233 cursor-column:num <- get *editor, cursor-column:offset
4234 data:&:duplex-list:char <- get *editor, data:offset
4235 <begin-insert-character>
4236 before-line-start:&:duplex-list:char <- before-start-of-screen-line editor
4237 line-start:&:duplex-list:char <- next before-line-start
4238 commented-out?:bool <- match line-start, [#? ]
4239 {
4240 break-unless commented-out?
4241
4242 data <- remove line-start, 3/length-comment-prefix, data
4243 cursor-column <- subtract cursor-column, 3/length-comment-prefix
4244 *editor <- put *editor, cursor-column:offset, cursor-column
4245 go-render? <- render-line-from-start screen, editor, 3/size-of-comment-leader
4246 }
4247 {
4248 break-if commented-out?
4249
4250 insert before-line-start, [#? ]
4251 cursor-column <- add cursor-column, 3/length-comment-prefix
4252 *editor <- put *editor, cursor-column:offset, cursor-column
4253 go-render? <- render-line-from-start screen, editor, 0
4254 }
4255 <end-insert-character>
4256 return
4257 }
4258 ]
4259
4260
4261
4262
4263 def render-line-from-start screen:&:screen, editor:&:editor, right-margin:num -> go-render?:bool, screen:&:screen [
4264 local-scope
4265 load-inputs
4266 before-line-start:&:duplex-list:char <- before-start-of-screen-line editor
4267 line-start:&:duplex-list:char <- next before-line-start
4268 color:num <- copy 7/white
4269 left:num <- get *editor, left:offset
4270 cursor-row:num <- get *editor, cursor-row:offset
4271 screen <- move-cursor screen, cursor-row, left
4272 right:num <- get *editor, right:offset
4273 end:num <- subtract right, right-margin
4274 i:num <- copy 0
4275 curr:&:duplex-list:char <- copy line-start
4276 {
4277 render-all?:bool <- greater-or-equal i, end
4278 return-if render-all?, true/go-render
4279 break-unless curr
4280 c:char <- get *curr, value:offset
4281 newline?:bool <- equal c, 10/newline
4282 break-if newline?
4283 color <- get-color color, c
4284 print screen, c, color
4285 curr <- next curr
4286 i <- add i, 1
4287 loop
4288 }
4289 clear-line-until screen, right
4290 return false/dont-render
4291 ]
4292
4293 def before-start-of-screen-line editor:&:editor -> result:&:duplex-list:char [
4294 local-scope
4295 load-inputs
4296 cursor:&:duplex-list:char <- get *editor, before-cursor:offset
4297 {
4298 next:&:duplex-list:char <- next cursor
4299 break-unless next
4300 cursor <- copy next
4301 }
4302 result <- before-previous-screen-line cursor, editor
4303 ]
4304
4305 scenario editor-comments-empty-line [
4306 local-scope
4307 assume-screen 10/width, 5/height
4308 e:&:editor <- new-editor [], 0/left, 5/right
4309 editor-render screen, e
4310 $clear-trace
4311 assume-console [
4312 press ctrl-slash
4313 ]
4314 run [
4315 editor-event-loop screen, console, e
4316 4:num/raw <- get *e, cursor-row:offset
4317 5:num/raw <- get *e, cursor-column:offset
4318 ]
4319 screen-should-contain [
4320 . .
4321 .#? .
4322 .╌╌╌╌╌ .
4323 . .
4324 ]
4325 memory-should-contain [
4326 4 <- 1
4327 5 <- 3
4328 ]
4329 check-trace-count-for-label 5, [print-character]
4330 ]
4331
4332 scenario editor-comments-at-start-of-contents [
4333 local-scope
4334 assume-screen 10/width, 5/height
4335 e:&:editor <- new-editor [ab], 0/left, 10/right
4336 editor-render screen, e
4337 $clear-trace
4338 assume-console [
4339 press ctrl-slash
4340 ]
4341 run [
4342 editor-event-loop screen, console, e
4343 4:num/raw <- get *e, cursor-row:offset
4344 5:num/raw <- get *e, cursor-column:offset
4345 ]
4346 screen-should-contain [
4347 . .
4348 .#? ab .
4349 .╌╌╌╌╌╌╌╌╌╌.
4350 . .
4351 ]
4352 memory-should-contain [
4353 4 <- 1
4354 5 <- 3
4355 ]
4356 check-trace-count-for-label 10, [print-character]
4357 ]
4358
4359 scenario editor-comments-at-end-of-contents [
4360 local-scope
4361 assume-screen 10/width, 5/height
4362 e:&:editor <- new-editor [ab], 0/left, 10/right
4363 editor-render screen, e
4364 $clear-trace
4365 assume-console [
4366 left-click 1, 7
4367 press ctrl-slash
4368 ]
4369 run [
4370 editor-event-loop screen, console, e
4371 4:num/raw <- get *e, cursor-row:offset
4372 5:num/raw <- get *e, cursor-column:offset
4373 ]
4374 screen-should-contain [
4375 . .
4376 .#? ab .
4377 .╌╌╌╌╌╌╌╌╌╌.
4378 . .
4379 ]
4380 memory-should-contain [
4381 4 <- 1
4382 5 <- 5
4383 ]
4384 check-trace-count-for-label 10, [print-character]
4385
4386 $clear-trace
4387 assume-console [
4388 press ctrl-slash
4389 ]
4390 run [
4391 editor-event-loop screen, console, e
4392 4:num/raw <- get *e, cursor-row:offset
4393 5:num/raw <- get *e, cursor-column:offset
4394 ]
4395 screen-should-contain [
4396 . .
4397 .ab .
4398 .╌╌╌╌╌╌╌╌╌╌.
4399 . .
4400 ]
4401 check-trace-count-for-label 10, [print-character]
4402 ]
4403
4404 scenario editor-comments-almost-wrapping-line [
4405 local-scope
4406 assume-screen 10/width, 5/height
4407
4408 e:&:editor <- new-editor [abcd], 0/left, 5/right
4409 editor-render screen, e
4410 screen-should-contain [
4411 . .
4412 .abcd .
4413 .╌╌╌╌╌ .
4414 . .
4415 ]
4416 $clear-trace
4417
4418 assume-console [
4419 left-click 1, 7
4420 press ctrl-slash
4421 ]
4422 run [
4423 editor-event-loop screen, console, e
4424 ]
4425 screen-should-contain [
4426 . .
4427 .#? a↩ .
4428 .bcd .
4429 .╌╌╌╌╌ .
4430 . .
4431 ]
4432 ]
4433
4434 scenario editor-uncomments-just-wrapping-line [
4435 local-scope
4436 assume-screen 10/width, 5/height
4437
4438 e:&:editor <- new-editor [#? ab], 0/left, 5/right
4439 editor-render screen, e
4440 screen-should-contain [
4441 . .
4442 .#? a↩ .
4443 .b .
4444 .╌╌╌╌╌ .
4445 . .
4446 ]
4447 $clear-trace
4448
4449 assume-console [
4450 left-click 1, 7
4451 press ctrl-slash
4452 ]
4453 run [
4454 editor-event-loop screen, console, e
4455 ]
4456 screen-should-contain [
4457 . .
4458 .ab .
4459 .╌╌╌╌╌ .
4460 . .
4461 ]
4462 ]