https://github.com/akkartik/mu1/blob/master/edit/012-editor-undo.mu
1
2
3
4
5 exclusive-container operation [
6 typing:insert-operation
7 move:move-operation
8 delete:delete-operation
9 ]
10
11 container insert-operation [
12 before-row:num
13 before-column:num
14 before-top-of-screen:&:duplex-list:char
15 after-row:num
16 after-column:num
17 after-top-of-screen:&:duplex-list:char
18
19 insert-from:&:duplex-list:char
20 insert-until:&:duplex-list:char
21 tag:num
22
23
24 ]
25
26 container move-operation [
27 before-row:num
28 before-column:num
29 before-top-of-screen:&:duplex-list:char
30 after-row:num
31 after-column:num
32 after-top-of-screen:&:duplex-list:char
33 tag:num
34
35
36
37
38
39
40
41 ]
42
43 container delete-operation [
44 before-row:num
45 before-column:num
46 before-top-of-screen:&:duplex-list:char
47 after-row:num
48 after-column:num
49 after-top-of-screen:&:duplex-list:char
50 deleted-text:&:duplex-list:char
51 delete-from:&:duplex-list:char
52 delete-until:&:duplex-list:char
53 tag:num
54
55
56
57 ]
58
59
60 container editor [
61 undo:&:list:&:operation
62 redo:&:list:&:operation
63 ]
64
65
66 after <handle-special-character> [
67 {
68 undo?:bool <- equal c, 26/ctrl-z
69 break-unless undo?
70 undo:&:list:&:operation <- get *editor, undo:offset
71 break-unless undo
72 op:&:operation <- first undo
73 undo <- rest undo
74 *editor <- put *editor, undo:offset, undo
75 redo:&:list:&:operation <- get *editor, redo:offset
76 redo <- push op, redo
77 *editor <- put *editor, redo:offset, redo
78 <handle-undo>
79 return true/go-render
80 }
81 ]
82
83
84 after <handle-special-character> [
85 {
86 redo?:bool <- equal c, 25/ctrl-y
87 break-unless redo?
88 redo:&:list:&:operation <- get *editor, redo:offset
89 break-unless redo
90 op:&:operation <- first redo
91 redo <- rest redo
92 *editor <- put *editor, redo:offset, redo
93 undo:&:list:&:operation <- get *editor, undo:offset
94 undo <- push op, undo
95 *editor <- put *editor, undo:offset, undo
96 <handle-redo>
97 return true/go-render
98 }
99 ]
100
101
102
103 scenario editor-can-undo-typing [
104 local-scope
105
106 assume-screen 10/width, 5/height
107 e:&:editor <- new-editor [], 0/left, 10/right
108 editor-render screen, e
109 assume-console [
110 type [0]
111 ]
112 editor-event-loop screen, console, e
113
114 assume-console [
115 press ctrl-z
116 ]
117 run [
118 editor-event-loop screen, console, e
119 ]
120
121 screen-should-contain [
122 . .
123 . .
124 .╌╌╌╌╌╌╌╌╌╌.
125 . .
126 ]
127
128 assume-console [
129 type [1]
130 ]
131 run [
132 editor-event-loop screen, console, e
133 ]
134 screen-should-contain [
135 . .
136 .1 .
137 .╌╌╌╌╌╌╌╌╌╌.
138 . .
139 ]
140 ]
141
142
143 after <begin-insert-character> [
144 top-before:&:duplex-list:char <- get *editor, top-of-screen:offset
145 cursor-before:&:duplex-list:char <- get *editor, before-cursor:offset
146 ]
147 before <end-insert-character> [
148 top-after:&:duplex-list:char <- get *editor, top-of-screen:offset
149 cursor-row:num <- get *editor, cursor-row:offset
150 cursor-column:num <- get *editor, cursor-column:offset
151 undo:&:list:&:operation <- get *editor, undo:offset
152 {
153
154 break-unless undo
155 op:&:operation <- first undo
156 typing:insert-operation, is-insert?:bool <- maybe-convert *op, typing:variant
157 break-unless is-insert?
158 previous-coalesce-tag:num <- get typing, tag:offset
159 break-unless previous-coalesce-tag
160 before-cursor:&:duplex-list:char <- get *editor, before-cursor:offset
161 insert-until:&:duplex-list:char <- next before-cursor
162 typing <- put typing, insert-until:offset, insert-until
163 typing <- put typing, after-row:offset, cursor-row
164 typing <- put typing, after-column:offset, cursor-column
165 typing <- put typing, after-top-of-screen:offset, top-after
166 *op <- merge 0/insert-operation, typing
167 break +done-adding-insert-operation
168 }
169
170 insert-from:&:duplex-list:char <- next cursor-before
171 insert-to:&:duplex-list:char <- next insert-from
172 op:&:operation <- new operation:type
173 *op <- merge 0/insert-operation, save-row/before, save-column/before, top-before, cursor-row/after, cursor-column/after, top-after, insert-from, insert-to, 1/coalesce
174 editor <- add-operation editor, op
175 +done-adding-insert-operation
176 ]
177
178
179 after <begin-insert-enter> [
180 cursor-row-before:num <- copy cursor-row
181 cursor-column-before:num <- copy cursor-column
182 top-before:&:duplex-list:char <- get *editor, top-of-screen:offset
183 cursor-before:&:duplex-list:char <- get *editor, before-cursor:offset
184 ]
185 before <end-insert-enter> [
186 top-after:&:duplex-list:char <- get *editor, top-of-screen:offset
187 cursor-row:num <- get *editor, cursor-row:offset
188 cursor-column:num <- get *editor, cursor-row:offset
189
190 insert-from:&:duplex-list:char <- next cursor-before
191 before-cursor:&:duplex-list:char <- get *editor, before-cursor:offset
192 insert-to:&:duplex-list:char <- next before-cursor
193 op:&:operation <- new operation:type
194 *op <- merge 0/insert-operation, cursor-row-before, cursor-column-before, top-before, cursor-row/after, cursor-column/after, top-after, insert-from, insert-to, 0/never-coalesce
195 editor <- add-operation editor, op
196 ]
197
198
199
200
201
202 def add-operation editor:&:editor, op:&:operation -> editor:&:editor [
203 local-scope
204 load-inputs
205 undo:&:list:&:operation <- get *editor, undo:offset
206 undo <- push op undo
207 *editor <- put *editor, undo:offset, undo
208 redo:&:list:&:operation <- get *editor, redo:offset
209 redo <- copy null
210 *editor <- put *editor, redo:offset, redo
211 ]
212
213 after <handle-undo> [
214 {
215 typing:insert-operation, is-insert?:bool <- maybe-convert *op, typing:variant
216 break-unless is-insert?
217 start:&:duplex-list:char <- get typing, insert-from:offset
218 end:&:duplex-list:char <- get typing, insert-until:offset
219
220 before-cursor:&:duplex-list:char <- prev start
221 *editor <- put *editor, before-cursor:offset, before-cursor
222 remove-between before-cursor, end
223 cursor-row <- get typing, before-row:offset
224 *editor <- put *editor, cursor-row:offset, cursor-row
225 cursor-column <- get typing, before-column:offset
226 *editor <- put *editor, cursor-column:offset, cursor-column
227 top:&:duplex-list:char <- get typing, before-top-of-screen:offset
228 *editor <- put *editor, top-of-screen:offset, top
229 }
230 ]
231
232 scenario editor-can-undo-typing-multiple [
233 local-scope
234
235 assume-screen 10/width, 5/height
236 e:&:editor <- new-editor [], 0/left, 10/right
237 editor-render screen, e
238 assume-console [
239 type [012]
240 ]
241 editor-event-loop screen, console, e
242
243 assume-console [
244 press ctrl-z
245 ]
246 run [
247 editor-event-loop screen, console, e
248 ]
249
250 screen-should-contain [
251 . .
252 . .
253 .╌╌╌╌╌╌╌╌╌╌.
254 . .
255 ]
256 ]
257
258 scenario editor-can-undo-typing-multiple-2 [
259 local-scope
260
261 assume-screen 10/width, 5/height
262 e:&:editor <- new-editor [a], 0/left, 10/right
263 editor-render screen, e
264
265 assume-console [
266 type [012]
267 ]
268 editor-event-loop screen, console, e
269 screen-should-contain [
270 . .
271 .012a .
272 .╌╌╌╌╌╌╌╌╌╌.
273 . .
274 ]
275
276 assume-console [
277 press ctrl-z
278 ]
279 run [
280 editor-event-loop screen, console, e
281 ]
282
283 screen-should-contain [
284 . .
285 .a .
286 .╌╌╌╌╌╌╌╌╌╌.
287 . .
288 ]
289
290 assume-console [
291 type [3]
292 ]
293 run [
294 editor-event-loop screen, console, e
295 ]
296 screen-should-contain [
297 . .
298 .3a .
299 .╌╌╌╌╌╌╌╌╌╌.
300 . .
301 ]
302 ]
303
304 scenario editor-can-undo-typing-enter [
305 local-scope
306
307 assume-screen 10/width, 5/height
308 e:&:editor <- new-editor [ abc], 0/left, 10/right
309 editor-render screen, e
310
311 assume-console [
312 left-click 1, 8
313 press enter
314 ]
315 editor-event-loop screen, console, e
316 screen-should-contain [
317 . .
318 . abc .
319 . .
320 .╌╌╌╌╌╌╌╌╌╌.
321 . .
322 ]
323
324 3:num/raw <- get *e, cursor-row:offset
325 4:num/raw <- get *e, cursor-column:offset
326 memory-should-contain [
327 3 <- 2
328 4 <- 2
329 ]
330
331 assume-console [
332 press ctrl-z
333 ]
334 run [
335 editor-event-loop screen, console, e
336 ]
337 3:num/raw <- get *e, cursor-row:offset
338 4:num/raw <- get *e, cursor-column:offset
339 memory-should-contain [
340 3 <- 1
341 4 <- 5
342 ]
343
344 screen-should-contain [
345 . .
346 . abc .
347 .╌╌╌╌╌╌╌╌╌╌.
348 . .
349 ]
350
351 assume-console [
352 type [1]
353 ]
354 run [
355 editor-event-loop screen, console, e
356 ]
357 screen-should-contain [
358 . .
359 . abc1 .
360 .╌╌╌╌╌╌╌╌╌╌.
361 . .
362 ]
363 ]
364
365
366
367 scenario editor-redo-typing [
368 local-scope
369
370 assume-screen 10/width, 5/height
371 e:&:editor <- new-editor [a], 0/left, 10/right
372 editor-render screen, e
373 assume-console [
374 type [012]
375 press ctrl-z
376 ]
377 editor-event-loop screen, console, e
378 screen-should-contain [
379 . .
380 .a .
381 .╌╌╌╌╌╌╌╌╌╌.
382 . .
383 ]
384
385 assume-console [
386 press ctrl-y
387 ]
388 run [
389 editor-event-loop screen, console, e
390 ]
391
392 screen-should-contain [
393 . .
394 .012a .
395 .╌╌╌╌╌╌╌╌╌╌.
396 . .
397 ]
398
399 assume-console [
400 type [3]
401 ]
402 run [
403 editor-event-loop screen, console, e
404 ]
405 screen-should-contain [
406 . .
407 .0123a .
408 .╌╌╌╌╌╌╌╌╌╌.
409 . .
410 ]
411 ]
412
413 after <handle-redo> [
414 {
415 typing:insert-operation, is-insert?:bool <- maybe-convert *op, typing:variant
416 break-unless is-insert?
417 before-cursor <- get *editor, before-cursor:offset
418 insert-from:&:duplex-list:char <- get typing, insert-from:offset
419
420 splice before-cursor, insert-from
421
422 cursor-row <- get typing, after-row:offset
423 *editor <- put *editor, cursor-row:offset, cursor-row
424 cursor-column <- get typing, after-column:offset
425 *editor <- put *editor, cursor-column:offset, cursor-column
426 top:&:duplex-list:char <- get typing, after-top-of-screen:offset
427 *editor <- put *editor, top-of-screen:offset, top
428 }
429 ]
430
431 scenario editor-redo-typing-empty [
432 local-scope
433
434 assume-screen 10/width, 5/height
435 e:&:editor <- new-editor [], 0/left, 10/right
436 editor-render screen, e
437 assume-console [
438 type [012]
439 press ctrl-z
440 ]
441 editor-event-loop screen, console, e
442 screen-should-contain [
443 . .
444 . .
445 .╌╌╌╌╌╌╌╌╌╌.
446 . .
447 ]
448
449 assume-console [
450 press ctrl-y
451 ]
452 run [
453 editor-event-loop screen, console, e
454 ]
455
456 screen-should-contain [
457 . .
458 .012 .
459 .╌╌╌╌╌╌╌╌╌╌.
460 . .
461 ]
462
463 assume-console [
464 type [3]
465 ]
466 run [
467 editor-event-loop screen, console, e
468 ]
469 screen-should-contain [
470 . .
471 .0123 .
472 .╌╌╌╌╌╌╌╌╌╌.
473 . .
474 ]
475 ]
476
477 scenario editor-work-clears-redo-stack [
478 local-scope
479
480 assume-screen 10/width, 5/height
481 contents:text <- new [abc
482 def
483 ghi]
484 e:&:editor <- new-editor contents, 0/left, 10/right
485 editor-render screen, e
486 assume-console [
487 type [1]
488 press ctrl-z
489 ]
490 editor-event-loop screen, console, e
491
492 assume-console [
493 type [0]
494 ]
495 editor-event-loop screen, console, e
496 screen-should-contain [
497 . .
498 .0abc .
499 .def .
500 .ghi .
501 .╌╌╌╌╌╌╌╌╌╌.
502 ]
503
504 assume-console [
505 press ctrl-y
506 ]
507 run [
508 editor-event-loop screen, console, e
509 ]
510
511 screen-should-contain [
512 . .
513 .0abc .
514 .def .
515 .ghi .
516 .╌╌╌╌╌╌╌╌╌╌.
517 ]
518 ]
519
520 scenario editor-can-redo-typing-and-enter-and-tab [
521 local-scope
522
523 assume-screen 10/width, 5/height
524 e:&:editor <- new-editor [], 0/left, 10/right
525 editor-render screen, e
526
527 assume-console [
528 press tab
529 type [ab]
530 press tab
531 type [cd]
532 press enter
533 press tab
534 type [efg]
535 ]
536 editor-event-loop screen, console, e
537 screen-should-contain [
538 . .
539 . ab cd .
540 . efg .
541 .╌╌╌╌╌╌╌╌╌╌.
542 . .
543 ]
544 3:num/raw <- get *e, cursor-row:offset
545 4:num/raw <- get *e, cursor-column:offset
546 memory-should-contain [
547 3 <- 2
548 4 <- 7
549 ]
550
551 assume-console [
552 press ctrl-z
553 ]
554 run [
555 editor-event-loop screen, console, e
556 ]
557
558 3:num/raw <- get *e, cursor-row:offset
559 4:num/raw <- get *e, cursor-column:offset
560 memory-should-contain [
561 3 <- 2
562 4 <- 2
563 ]
564 screen-should-contain [
565 . .
566 . ab cd .
567 . .
568 .╌╌╌╌╌╌╌╌╌╌.
569 . .
570 ]
571
572 assume-console [
573 press ctrl-z
574 ]
575 run [
576 editor-event-loop screen, console, e
577 ]
578
579 3:num/raw <- get *e, cursor-row:offset
580 4:num/raw <- get *e, cursor-column:offset
581 memory-should-contain [
582 3 <- 1
583 4 <- 8
584 ]
585 screen-should-contain [
586 . .
587 . ab cd .
588 .╌╌╌╌╌╌╌╌╌╌.
589 . .
590 ]
591
592 assume-console [
593 press ctrl-z
594 ]
595 run [
596 editor-event-loop screen, console, e
597 ]
598
599 3:num/raw <- get *e, cursor-row:offset
600 4:num/raw <- get *e, cursor-column:offset
601 memory-should-contain [
602 3 <- 1
603 4 <- 0
604 ]
605 screen-should-contain [
606 . .
607 . .
608 .╌╌╌╌╌╌╌╌╌╌.
609 . .
610 ]
611
612 assume-console [
613 press ctrl-y
614 ]
615 run [
616 editor-event-loop screen, console, e
617 ]
618
619 3:num/raw <- get *e, cursor-row:offset
620 4:num/raw <- get *e, cursor-column:offset
621 memory-should-contain [
622 3 <- 1
623 4 <- 8
624 ]
625 screen-should-contain [
626 . .
627 . ab cd .
628 .╌╌╌╌╌╌╌╌╌╌.
629 . .
630 ]
631
632 assume-console [
633 press ctrl-y
634 ]
635 run [
636 editor-event-loop screen, console, e
637 ]
638
639 3:num/raw <- get *e, cursor-row:offset
640 4:num/raw <- get *e, cursor-column:offset
641 memory-should-contain [
642 3 <- 2
643 4 <- 2
644 ]
645 screen-should-contain [
646 . .
647 . ab cd .
648 . .
649 .╌╌╌╌╌╌╌╌╌╌.
650 . .
651 ]
652
653 assume-console [
654 press ctrl-y
655 ]
656 run [
657 editor-event-loop screen, console, e
658 ]
659
660 3:num/raw <- get *e, cursor-row:offset
661 4:num/raw <- get *e, cursor-column:offset
662 memory-should-contain [
663 3 <- 2
664 4 <- 7
665 ]
666 screen-should-contain [
667 . .
668 . ab cd .
669 . efg .
670 .╌╌╌╌╌╌╌╌╌╌.
671 . .
672 ]
673 ]
674
675
676
677 scenario editor-can-undo-touch [
678 local-scope
679
680 assume-screen 10/width, 5/height
681 contents:text <- new [abc
682 def
683 ghi]
684 e:&:editor <- new-editor contents, 0/left, 10/right
685 editor-render screen, e
686
687 assume-console [
688 left-click 3, 1
689 ]
690 editor-event-loop screen, console, e
691
692 assume-console [
693 press ctrl-z
694 ]
695 run [
696 editor-event-loop screen, console, e
697 ]
698
699 3:num/raw <- get *e, cursor-row:offset
700 4:num/raw <- get *e, cursor-column:offset
701 memory-should-contain [
702 3 <- 1
703 4 <- 0
704 ]
705
706 assume-console [
707 type [1]
708 ]
709 run [
710 editor-event-loop screen, console, e
711 ]
712 screen-should-contain [
713 . .
714 .1abc .
715 .def .
716 .ghi .
717 .╌╌╌╌╌╌╌╌╌╌.
718 ]
719 ]
720
721 after <begin-move-cursor> [
722 cursor-row-before:num <- get *editor, cursor-row:offset
723 cursor-column-before:num <- get *editor, cursor-column:offset
724 top-before:&:duplex-list:char <- get *editor, top-of-screen:offset
725 ]
726 before <end-move-cursor> [
727 top-after:&:duplex-list:char <- get *editor, top-of-screen:offset
728 cursor-row:num <- get *editor, cursor-row:offset
729 cursor-column:num <- get *editor, cursor-column:offset
730 {
731 break-unless undo-coalesce-tag
732
733
734 undo:&:list:&:operation <- get *editor, undo:offset
735 break-unless undo
736 op:&:operation <- first undo
737 move:move-operation, is-move?:bool <- maybe-convert *op, move:variant
738 break-unless is-move?
739 previous-coalesce-tag:num <- get move, tag:offset
740 coalesce?:bool <- equal undo-coalesce-tag, previous-coalesce-tag
741 break-unless coalesce?
742 move <- put move, after-row:offset, cursor-row
743 move <- put move, after-column:offset, cursor-column
744 move <- put move, after-top-of-screen:offset, top-after
745 *op <- merge 1/move-operation, move
746 break +done-adding-move-operation
747 }
748 op:&:operation <- new operation:type
749 *op <- merge 1/move-operation, cursor-row-before, cursor-column-before, top-before, cursor-row/after, cursor-column/after, top-after, undo-coalesce-tag
750 editor <- add-operation editor, op
751 +done-adding-move-operation
752 ]
753
754 after <handle-undo> [
755 {
756 move:move-operation, is-move?:bool <- maybe-convert *op, move:variant
757 break-unless is-move?
758
759 cursor-row <- get move, before-row:offset
760 *editor <- put *editor, cursor-row:offset, cursor-row
761 cursor-column <- get move, before-column:offset
762 *editor <- put *editor, cursor-column:offset, cursor-column
763 top:&:duplex-list:char <- get move, before-top-of-screen:offset
764 *editor <- put *editor, top-of-screen:offset, top
765 }
766 ]
767
768 scenario editor-can-undo-scroll [
769 local-scope
770
771 assume-screen 5/width, 4/height
772
773 contents:text <- new [a
774 b
775 cdefgh]
776 e:&:editor <- new-editor contents, 0/left, 5/right
777
778 assume-console [
779 left-click 3, 3
780 press right-arrow
781 ]
782 editor-event-loop screen, console, e
783 3:num/raw <- get *e, cursor-row:offset
784 4:num/raw <- get *e, cursor-column:offset
785
786 screen-should-contain [
787 . .
788 .b .
789 .cdef↩.
790 .gh .
791 ]
792 memory-should-contain [
793 3 <- 3
794 4 <- 0
795 ]
796
797 assume-console [
798 press ctrl-z
799 ]
800 run [
801 editor-event-loop screen, console, e
802 ]
803
804 3:num/raw <- get *e, cursor-row:offset
805 4:num/raw <- get *e, cursor-column:offset
806 memory-should-contain [
807 3 <- 3
808 4 <- 3
809 ]
810
811 screen-should-contain [
812 . .
813 .a .
814 .b .
815 .cdef↩.
816 ]
817
818 assume-console [
819 type [1]
820 ]
821 run [
822 editor-event-loop screen, console, e
823 ]
824 screen-should-contain [
825 . .
826 .b .
827 .cde1↩.
828 .fgh .
829 ]
830 ]
831
832 scenario editor-can-undo-left-arrow [
833 local-scope
834
835 assume-screen 10/width, 5/height
836 contents:text <- new [abc
837 def
838 ghi]
839 e:&:editor <- new-editor contents, 0/left, 10/right
840 editor-render screen, e
841
842 assume-console [
843 left-click 3, 1
844 press left-arrow
845 ]
846 editor-event-loop screen, console, e
847
848 assume-console [
849 press ctrl-z
850 ]
851 run [
852 editor-event-loop screen, console, e
853 ]
854
855 3:num/raw <- get *e, cursor-row:offset
856 4:num/raw <- get *e, cursor-column:offset
857 memory-should-contain [
858 3 <- 3
859 4 <- 1
860 ]
861
862 assume-console [
863 type [1]
864 ]
865 run [
866 editor-event-loop screen, console, e
867 ]
868 screen-should-contain [
869 . .
870 .abc .
871 .def .
872 .g1hi .
873 .╌╌╌╌╌╌╌╌╌╌.
874 ]
875 ]
876
877 scenario editor-can-undo-up-arrow [
878 local-scope
879
880 assume-screen 10/width, 5/height
881 contents:text <- new [abc
882 def
883 ghi]
884 e:&:editor <- new-editor contents, 0/left, 10/right
885 editor-render screen, e
886
887 assume-console [
888 left-click 3, 1
889 press up-arrow
890 ]
891 editor-event-loop screen, console, e
892 3:num/raw <- get *e, cursor-row:offset
893 4:num/raw <- get *e, cursor-column:offset
894 memory-should-contain [
895 3 <- 2
896 4 <- 1
897 ]
898
899 assume-console [
900 press ctrl-z
901 ]
902 run [
903 editor-event-loop screen, console, e
904 ]
905
906 3:num/raw <- get *e, cursor-row:offset
907 4:num/raw <- get *e, cursor-column:offset
908 memory-should-contain [
909 3 <- 3
910 4 <- 1
911 ]
912
913 assume-console [
914 type [1]
915 ]
916 run [
917 editor-event-loop screen, console, e
918 ]
919 screen-should-contain [
920 . .
921 .abc .
922 .def .
923 .g1hi .
924 .╌╌╌╌╌╌╌╌╌╌.
925 ]
926 ]
927
928 scenario editor-can-undo-down-arrow [
929 local-scope
930
931 assume-screen 10/width, 5/height
932 contents:text <- new [abc
933 def
934 ghi]
935 e:&:editor <- new-editor contents, 0/left, 10/right
936 editor-render screen, e
937
938 assume-console [
939 left-click 2, 1
940 press down-arrow
941 ]
942 editor-event-loop screen, console, e
943
944 assume-console [
945 press ctrl-z
946 ]
947 run [
948 editor-event-loop screen, console, e
949 ]
950
951 3:num/raw <- get *e, cursor-row:offset
952 4:num/raw <- get *e, cursor-column:offset
953 memory-should-contain [
954 3 <- 2
955 4 <- 1
956 ]
957
958 assume-console [
959 type [1]
960 ]
961 run [
962 editor-event-loop screen, console, e
963 ]
964 screen-should-contain [
965 . .
966 .abc .
967 .d1ef .
968 .ghi .
969 .╌╌╌╌╌╌╌╌╌╌.
970 ]
971 ]
972
973 scenario editor-can-undo-ctrl-f [
974 local-scope
975
976 assume-screen 10/width, 5/height
977 contents:text <- new [a
978 b
979 c
980 d
981 e
982 f]
983 e:&:editor <- new-editor contents, 0/left, 10/right
984 editor-render screen, e
985
986 assume-console [
987 press ctrl-f
988 ]
989 editor-event-loop screen, console, e
990
991 assume-console [
992 press ctrl-z
993 ]
994 run [
995 editor-event-loop screen, console, e
996 ]
997
998 screen-should-contain [
999 . .
1000 .a .
1001 .b .
1002 .c .
1003 .d .
1004 ]
1005 ]
1006
1007 scenario editor-can-undo-page-down [
1008 local-scope
1009
1010 assume-screen 10/width, 5/height
1011 contents:text <- new [a
1012 b
1013 c
1014 d
1015 e
1016 f]
1017 e:&:editor <- new-editor contents, 0/left, 10/right
1018 editor-render screen, e
1019
1020 assume-console [
1021 press page-down
1022 ]
1023 editor-event-loop screen, console, e
1024
1025 assume-console [
1026 press ctrl-z
1027 ]
1028 run [
1029 editor-event-loop screen, console, e
1030 ]
1031
1032 screen-should-contain [
1033 . .
1034 .a .
1035 .b .
1036 .c .
1037 .d .
1038 ]
1039 ]
1040
1041 scenario editor-can-undo-ctrl-b [
1042 local-scope
1043
1044 assume-screen 10/width, 5/height
1045 contents:text <- new [a
1046 b
1047 c
1048 d
1049 e
1050 f]
1051 e:&:editor <- new-editor contents, 0/left, 10/right
1052 editor-render screen, e
1053
1054 assume-console [
1055 press page-down
1056 press ctrl-b
1057 ]
1058 editor-event-loop screen, console, e
1059
1060 assume-console [
1061 press ctrl-z
1062 ]
1063 run [
1064 editor-event-loop screen, console, e
1065 ]
1066
1067 screen-should-contain [
1068 . .
1069 .d .
1070 .e .
1071 .f .
1072 .╌╌╌╌╌╌╌╌╌╌.
1073 ]
1074 ]
1075
1076 scenario editor-can-undo-page-up [
1077 local-scope
1078
1079 assume-screen 10/width, 5/height
1080 contents:text <- new [a
1081 b
1082 c
1083 d
1084 e
1085 f]
1086 e:&:editor <- new-editor contents, 0/left, 10/right
1087 editor-render screen, e
1088
1089 assume-console [
1090 press page-down
1091 press page-up
1092 ]
1093 editor-event-loop screen, console, e
1094
1095 assume-console [
1096 press ctrl-z
1097 ]
1098 run [
1099 editor-event-loop screen, console, e
1100 ]
1101
1102 screen-should-contain [
1103 . .
1104 .d .
1105 .e .
1106 .f .
1107 .╌╌╌╌╌╌╌╌╌╌.
1108 ]
1109 ]
1110
1111 scenario editor-can-undo-ctrl-a [
1112 local-scope
1113
1114 assume-screen 10/width, 5/height
1115 contents:text <- new [abc
1116 def
1117 ghi]
1118 e:&:editor <- new-editor contents, 0/left, 10/right
1119 editor-render screen, e
1120
1121 assume-console [
1122 left-click 2, 1
1123 press ctrl-a
1124 ]
1125 editor-event-loop screen, console, e
1126
1127 assume-console [
1128 press ctrl-z
1129 ]
1130 run [
1131 editor-event-loop screen, console, e
1132 ]
1133
1134 3:num/raw <- get *e, cursor-row:offset
1135 4:num/raw <- get *e, cursor-column:offset
1136 memory-should-contain [
1137 3 <- 2
1138 4 <- 1
1139 ]
1140
1141 assume-console [
1142 type [1]
1143 ]
1144 run [
1145 editor-event-loop screen, console, e
1146 ]
1147 screen-should-contain [
1148 . .
1149 .abc .
1150 .d1ef .
1151 .ghi .
1152 .╌╌╌╌╌╌╌╌╌╌.
1153 ]
1154 ]
1155
1156 scenario editor-can-undo-home [
1157 local-scope
1158
1159 assume-screen 10/width, 5/height
1160 contents:text <- new [abc
1161 def
1162 ghi]
1163 e:&:editor <- new-editor contents, 0/left, 10/right
1164 editor-render screen, e
1165
1166 assume-console [
1167 left-click 2, 1
1168 press home
1169 ]
1170 editor-event-loop screen, console, e
1171
1172 assume-console [
1173 press ctrl-z
1174 ]
1175 run [
1176 editor-event-loop screen, console, e
1177 ]
1178
1179 3:num/raw <- get *e, cursor-row:offset
1180 4:num/raw <- get *e, cursor-column:offset
1181 memory-should-contain [
1182 3 <- 2
1183 4 <- 1
1184 ]
1185
1186 assume-console [
1187 type [1]
1188 ]
1189 run [
1190 editor-event-loop screen, console, e
1191 ]
1192 screen-should-contain [
1193 . .
1194 .abc .
1195 .d1ef .
1196 .ghi .
1197 .╌╌╌╌╌╌╌╌╌╌.
1198 ]
1199 ]
1200
1201 scenario editor-can-undo-ctrl-e [
1202 local-scope
1203
1204 assume-screen 10/width, 5/height
1205 contents:text <- new [abc
1206 def
1207 ghi]
1208 e:&:editor <- new-editor contents, 0/left, 10/right
1209 editor-render screen, e
1210
1211 assume-console [
1212 left-click 2, 1
1213 press ctrl-e
1214 ]
1215 editor-event-loop screen, console, e
1216
1217 assume-console [
1218 press ctrl-z
1219 ]
1220 run [
1221 editor-event-loop screen, console, e
1222 ]
1223
1224 3:num/raw <- get *e, cursor-row:offset
1225 4:num/raw <- get *e, cursor-column:offset
1226 memory-should-contain [
1227 3 <- 2
1228 4 <- 1
1229 ]
1230
1231 assume-console [
1232 type [1]
1233 ]
1234 run [
1235 editor-event-loop screen, console, e
1236 ]
1237 screen-should-contain [
1238 . .
1239 .abc .
1240 .d1ef .
1241 .ghi .
1242 .╌╌╌╌╌╌╌╌╌╌.
1243 ]
1244 ]
1245
1246 scenario editor-can-undo-end [
1247 local-scope
1248
1249 assume-screen 10/width, 5/height
1250 contents:text <- new [abc
1251 def
1252 ghi]
1253 e:&:editor <- new-editor contents, 0/left, 10/right
1254 editor-render screen, e
1255
1256 assume-console [
1257 left-click 2, 1
1258 press end
1259 ]
1260 editor-event-loop screen, console, e
1261
1262 assume-console [
1263 press ctrl-z
1264 ]
1265 run [
1266 editor-event-loop screen, console, e
1267 ]
1268
1269 3:num/raw <- get *e, cursor-row:offset
1270 4:num/raw <- get *e, cursor-column:offset
1271 memory-should-contain [
1272 3 <- 2
1273 4 <- 1
1274 ]
1275
1276 assume-console [
1277 type [1]
1278 ]
1279 run [
1280 editor-event-loop screen, console, e
1281 ]
1282 screen-should-contain [
1283 . .
1284 .abc .
1285 .d1ef .
1286 .ghi .
1287 .╌╌╌╌╌╌╌╌╌╌.
1288 ]
1289 ]
1290
1291 scenario editor-can-undo-multiple-arrows-in-the-same-direction [
1292 local-scope
1293
1294 assume-screen 10/width, 5/height
1295 contents:text <- new [abc
1296 def
1297 ghi]
1298 e:&:editor <- new-editor contents, 0/left, 10/right
1299 editor-render screen, e
1300
1301 assume-console [
1302 left-click 2, 1
1303 press right-arrow
1304 press right-arrow
1305 press up-arrow
1306 ]
1307 editor-event-loop screen, console, e
1308 3:num/raw <- get *e, cursor-row:offset
1309 4:num/raw <- get *e, cursor-column:offset
1310 memory-should-contain [
1311 3 <- 1
1312 4 <- 3
1313 ]
1314
1315 assume-console [
1316 press ctrl-z
1317 ]
1318 run [
1319 editor-event-loop screen, console, e
1320 ]
1321
1322 3:num/raw <- get *e, cursor-row:offset
1323 4:num/raw <- get *e, cursor-column:offset
1324 memory-should-contain [
1325 3 <- 2
1326 4 <- 3
1327 ]
1328
1329 assume-console [
1330 press ctrl-z
1331 ]
1332 run [
1333 editor-event-loop screen, console, e
1334 ]
1335
1336 3:num/raw <- get *e, cursor-row:offset
1337 4:num/raw <- get *e, cursor-column:offset
1338 memory-should-contain [
1339 3 <- 2
1340 4 <- 1
1341 ]
1342 ]
1343
1344
1345
1346 scenario editor-redo-touch [
1347 local-scope
1348
1349 assume-screen 10/width, 5/height
1350 contents:text <- new [abc
1351 def
1352 ghi]
1353 e:&:editor <- new-editor contents, 0/left, 10/right
1354 editor-render screen, e
1355 assume-console [
1356 left-click 3, 1
1357 press ctrl-z
1358 ]
1359 editor-event-loop screen, console, e
1360
1361 assume-console [
1362 press ctrl-y
1363 ]
1364 run [
1365 editor-event-loop screen, console, e
1366 ]
1367
1368 3:num/raw <- get *e, cursor-row:offset
1369 4:num/raw <- get *e, cursor-column:offset
1370 memory-should-contain [
1371 3 <- 3
1372 4 <- 1
1373 ]
1374
1375 assume-console [
1376 type [1]
1377 ]
1378 run [
1379 editor-event-loop screen, console, e
1380 ]
1381 screen-should-contain [
1382 . .
1383 .abc .
1384 .def .
1385 .g1hi .
1386 .╌╌╌╌╌╌╌╌╌╌.
1387 ]
1388 ]
1389
1390 after <handle-redo> [
1391 {
1392 move:move-operation, is-move?:bool <- maybe-convert *op, move:variant
1393 break-unless is-move?
1394
1395 cursor-row <- get move, after-row:offset
1396 *editor <- put *editor, cursor-row:offset, cursor-row
1397 cursor-column <- get move, after-column:offset
1398 *editor <- put *editor, cursor-column:offset, cursor-column
1399 top:&:duplex-list:char <- get move, after-top-of-screen:offset
1400 *editor <- put *editor, top-of-screen:offset, top
1401 }
1402 ]
1403
1404 scenario editor-separates-undo-insert-from-undo-cursor-move [
1405 local-scope
1406
1407 assume-screen 10/width, 5/height
1408 e:&:editor <- new-editor [], 0/left, 10/right
1409 editor-render screen, e
1410 assume-console [
1411 type [abc]
1412 left-click 1, 1
1413 type [d]
1414 ]
1415 editor-event-loop screen, console, e
1416 3:num/raw <- get *e, cursor-row:offset
1417 4:num/raw <- get *e, cursor-column:offset
1418 screen-should-contain [
1419 . .
1420 .adbc .
1421 .╌╌╌╌╌╌╌╌╌╌.
1422 . .
1423 ]
1424 memory-should-contain [
1425 3 <- 1
1426 4 <- 2
1427 ]
1428
1429 assume-console [
1430 press ctrl-z
1431 ]
1432 run [
1433 editor-event-loop screen, console, e
1434 3:num/raw <- get *e, cursor-row:offset
1435 4:num/raw <- get *e, cursor-column:offset
1436 ]
1437
1438 screen-should-contain [
1439 . .
1440 .abc .
1441 .╌╌╌╌╌╌╌╌╌╌.
1442 . .
1443 ]
1444 memory-should-contain [
1445 3 <- 1
1446 4 <- 1
1447 ]
1448
1449 assume-console [
1450 press ctrl-z
1451 ]
1452 run [
1453 editor-event-loop screen, console, e
1454 3:num/raw <- get *e, cursor-row:offset
1455 4:num/raw <- get *e, cursor-column:offset
1456 ]
1457
1458 screen-should-contain [
1459 . .
1460 .abc .
1461 .╌╌╌╌╌╌╌╌╌╌.
1462 . .
1463 ]
1464 memory-should-contain [
1465 3 <- 1
1466 4 <- 3
1467 ]
1468
1469 assume-console [
1470 press ctrl-z
1471 ]
1472 run [
1473 editor-event-loop screen, console, e
1474 3:num/raw <- get *e, cursor-row:offset
1475 4:num/raw <- get *e, cursor-column:offset
1476 ]
1477
1478 screen-should-contain [
1479 . .
1480 . .
1481 .╌╌╌╌╌╌╌╌╌╌.
1482 . .
1483 ]
1484 memory-should-contain [
1485 3 <- 1
1486 4 <- 0
1487 ]
1488
1489 assume-console [
1490 press ctrl-y
1491 ]
1492 run [
1493 editor-event-loop screen, console, e
1494 3:num/raw <- get *e, cursor-row:offset
1495 4:num/raw <- get *e, cursor-column:offset
1496 ]
1497
1498 screen-should-contain [
1499 . .
1500 .abc .
1501 .╌╌╌╌╌╌╌╌╌╌.
1502 . .
1503 ]
1504 memory-should-contain [
1505 3 <- 1
1506 4 <- 3
1507 ]
1508
1509 assume-console [
1510 press ctrl-y
1511 ]
1512 run [
1513 editor-event-loop screen, console, e
1514 3:num/raw <- get *e, cursor-row:offset
1515 4:num/raw <- get *e, cursor-column:offset
1516 ]
1517
1518 screen-should-contain [
1519 . .
1520 .abc .
1521 .╌╌╌╌╌╌╌╌╌╌.
1522 . .
1523 ]
1524
1525 memory-should-contain [
1526 3 <- 1
1527 4 <- 1
1528 ]
1529
1530 assume-console [
1531 press ctrl-y
1532 ]
1533 run [
1534 editor-event-loop screen, console, e
1535 3:num/raw <- get *e, cursor-row:offset
1536 4:num/raw <- get *e, cursor-column:offset
1537 ]
1538
1539 screen-should-contain [
1540 . .
1541 .adbc .
1542 .╌╌╌╌╌╌╌╌╌╌.
1543 . .
1544 ]
1545 memory-should-contain [
1546 3 <- 1
1547 4 <- 2
1548 ]
1549 ]
1550
1551
1552
1553 scenario editor-can-undo-and-redo-backspace [
1554 local-scope
1555
1556 assume-screen 10/width, 5/height
1557 e:&:editor <- new-editor [], 0/left, 10/right
1558 editor-render screen, e
1559
1560 assume-console [
1561 type [abc]
1562 press backspace
1563 press backspace
1564 ]
1565 editor-event-loop screen, console, e
1566 screen-should-contain [
1567 . .
1568 .a .
1569 .╌╌╌╌╌╌╌╌╌╌.
1570 . .
1571 ]
1572 3:num/raw <- get *e, cursor-row:offset
1573 4:num/raw <- get *e, cursor-column:offset
1574 memory-should-contain [
1575 3 <- 1
1576 4 <- 1
1577 ]
1578
1579 assume-console [
1580 press ctrl-z
1581 ]
1582 run [
1583 editor-event-loop screen, console, e
1584 ]
1585 3:num/raw <- get *e, cursor-row:offset
1586 4:num/raw <- get *e, cursor-column:offset
1587 memory-should-contain [
1588 3 <- 1
1589 4 <- 3
1590 ]
1591 screen-should-contain [
1592 . .
1593 .abc .
1594 .╌╌╌╌╌╌╌╌╌╌.
1595 . .
1596 ]
1597
1598 assume-console [
1599 press ctrl-y
1600 ]
1601 run [
1602 editor-event-loop screen, console, e
1603 ]
1604 3:num/raw <- get *e, cursor-row:offset
1605 4:num/raw <- get *e, cursor-column:offset
1606 memory-should-contain [
1607 3 <- 1
1608 4 <- 1
1609 ]
1610 screen-should-contain [
1611 . .
1612 .a .
1613 .╌╌╌╌╌╌╌╌╌╌.
1614 . .
1615 ]
1616 ]
1617
1618
1619 after <begin-backspace-character> [
1620 top-before:&:duplex-list:char <- get *editor, top-of-screen:offset
1621 ]
1622 before <end-backspace-character> [
1623 {
1624 break-unless backspaced-cell
1625 top-after:&:duplex-list:char <- get *editor, top-of-screen:offset
1626 cursor-row:num <- get *editor, cursor-row:offset
1627 cursor-column:num <- get *editor, cursor-row:offset
1628 before-cursor:&:duplex-list:char <- get *editor, before-cursor:offset
1629 undo:&:list:&:operation <- get *editor, undo:offset
1630 {
1631
1632 break-unless undo
1633 op:&:operation <- first undo
1634 deletion:delete-operation, is-delete?:bool <- maybe-convert *op, delete:variant
1635 break-unless is-delete?
1636 previous-coalesce-tag:num <- get deletion, tag:offset
1637 coalesce?:bool <- equal previous-coalesce-tag, 1/coalesce-backspace
1638 break-unless coalesce?
1639 deletion <- put deletion, delete-from:offset, before-cursor
1640 backspaced-so-far:&:duplex-list:char <- get deletion, deleted-text:offset
1641 splice backspaced-cell, backspaced-so-far
1642 deletion <- put deletion, deleted-text:offset, backspaced-cell
1643 deletion <- put deletion, after-row:offset, cursor-row
1644 deletion <- put deletion, after-column:offset, cursor-column
1645 deletion <- put deletion, after-top-of-screen:offset, top-after
1646 *op <- merge 2/delete-operation, deletion
1647 break +done-adding-backspace-operation
1648 }
1649
1650 op:&:operation <- new operation:type
1651 deleted-until:&:duplex-list:char <- next before-cursor
1652 *op <- merge 2/delete-operation, save-row/before, save-column/before, top-before, cursor-row/after, cursor-column/after, top-after, backspaced-cell/deleted, before-cursor/delete-from, deleted-until, 1/coalesce-backspace
1653 editor <- add-operation editor, op
1654 +done-adding-backspace-operation
1655 }
1656 ]
1657
1658 after <handle-undo> [
1659 {
1660 deletion:delete-operation, is-delete?:bool <- maybe-convert *op, delete:variant
1661 break-unless is-delete?
1662 anchor:&:duplex-list:char <- get deletion, delete-from:offset
1663 break-unless anchor
1664 deleted:&:duplex-list:char <- get deletion, deleted-text:offset
1665 old-cursor:&:duplex-list:char <- last deleted
1666 splice anchor, deleted
1667
1668 before-cursor <- copy old-cursor
1669 cursor-row <- get deletion, before-row:offset
1670 *editor <- put *editor, cursor-row:offset, cursor-row
1671 cursor-column <- get deletion, before-column:offset
1672 *editor <- put *editor, cursor-column:offset, cursor-column
1673 top:&:duplex-list:char <- get deletion, before-top-of-screen:offset
1674 *editor <- put *editor, top-of-screen:offset, top
1675 }
1676 ]
1677
1678 after <handle-redo> [
1679 {
1680 deletion:delete-operation, is-delete?:bool <- maybe-convert *op, delete:variant
1681 break-unless is-delete?
1682 start:&:duplex-list:char <- get deletion, delete-from:offset
1683 end:&:duplex-list:char <- get deletion, delete-until:offset
1684 data:&:duplex-list:char <- get *editor, data:offset
1685 remove-between start, end
1686
1687 cursor-row <- get deletion, after-row:offset
1688 *editor <- put *editor, cursor-row:offset, cursor-row
1689 cursor-column <- get deletion, after-column:offset
1690 *editor <- put *editor, cursor-column:offset, cursor-column
1691 top:&:duplex-list:char <- get deletion, before-top-of-screen:offset
1692 *editor <- put *editor, top-of-screen:offset, top
1693 }
1694 ]
1695
1696
1697
1698 scenario editor-can-undo-and-redo-delete [
1699 local-scope
1700
1701 assume-screen 10/width, 5/height
1702 e:&:editor <- new-editor [], 0/left, 10/right
1703 editor-render screen, e
1704
1705 assume-console [
1706 type [abcdef]
1707 left-click 1, 2
1708 press delete
1709 press backspace
1710 press delete
1711 press delete
1712 ]
1713 editor-event-loop screen, console, e
1714 screen-should-contain [
1715 . .
1716 .af .
1717 .╌╌╌╌╌╌╌╌╌╌.
1718 . .
1719 ]
1720 3:num/raw <- get *e, cursor-row:offset
1721 4:num/raw <- get *e, cursor-column:offset
1722 memory-should-contain [
1723 3 <- 1
1724 4 <- 1
1725 ]
1726
1727 assume-console [
1728 press ctrl-z
1729 ]
1730 run [
1731 editor-event-loop screen, console, e
1732 ]
1733 3:num/raw <- get *e, cursor-row:offset
1734 4:num/raw <- get *e, cursor-column:offset
1735 memory-should-contain [
1736 3 <- 1
1737 4 <- 1
1738 ]
1739 screen-should-contain [
1740 . .
1741 .adef .
1742 .╌╌╌╌╌╌╌╌╌╌.
1743 . .
1744 ]
1745
1746 assume-console [
1747 press ctrl-z
1748 ]
1749 run [
1750 editor-event-loop screen, console, e
1751 ]
1752 3:num/raw <- get *e, cursor-row:offset
1753 4:num/raw <- get *e, cursor-column:offset
1754 memory-should-contain [
1755 3 <- 1
1756 4 <- 2
1757 ]
1758 screen-should-contain [
1759 . .
1760 .abdef .
1761 .╌╌╌╌╌╌╌╌╌╌.
1762 . .
1763 ]
1764
1765 assume-console [
1766 press ctrl-z
1767 ]
1768 run [
1769 editor-event-loop screen, console, e
1770 ]
1771 3:num/raw <- get *e, cursor-row:offset
1772 4:num/raw <- get *e, cursor-column:offset
1773 memory-should-contain [
1774 3 <- 1
1775 4 <- 2
1776 ]
1777 screen-should-contain [
1778 . .
1779 .abcdef .
1780 .╌╌╌╌╌╌╌╌╌╌.
1781 . .
1782 ]
1783
1784 assume-console [
1785 press ctrl-y
1786 ]
1787 run [
1788 editor-event-loop screen, console, e
1789 ]
1790
1791 3:num/raw <- get *e, cursor-row:offset
1792 4:num/raw <- get *e, cursor-column:offset
1793 memory-should-contain [
1794 3 <- 1
1795 4 <- 2
1796 ]
1797 screen-should-contain [
1798 . .
1799 .abdef .
1800 .╌╌╌╌╌╌╌╌╌╌.
1801 . .
1802 ]
1803
1804 assume-console [
1805 press ctrl-y
1806 ]
1807 run [
1808 editor-event-loop screen, console, e
1809 ]
1810
1811 3:num/raw <- get *e, cursor-row:offset
1812 4:num/raw <- get *e, cursor-column:offset
1813 memory-should-contain [
1814 3 <- 1
1815 4 <- 1
1816 ]
1817 screen-should-contain [
1818 . .
1819 .adef .
1820 .╌╌╌╌╌╌╌╌╌╌.
1821 . .
1822 ]
1823
1824 assume-console [
1825 press ctrl-y
1826 ]
1827 run [
1828 editor-event-loop screen, console, e
1829 ]
1830
1831 3:num/raw <- get *e, cursor-row:offset
1832 4:num/raw <- get *e, cursor-column:offset
1833 memory-should-contain [
1834 3 <- 1
1835 4 <- 1
1836 ]
1837 screen-should-contain [
1838 . .
1839 .af .
1840 .╌╌╌╌╌╌╌╌╌╌.
1841 . .
1842 ]
1843 ]
1844
1845 after <begin-delete-character> [
1846 top-before:&:duplex-list:char <- get *editor, top-of-screen:offset
1847 ]
1848 before <end-delete-character> [
1849 {
1850 break-unless deleted-cell
1851 top-after:&:duplex-list:char <- get *editor, top-of-screen:offset
1852 cursor-row:num <- get *editor, cursor-row:offset
1853 cursor-column:num <- get *editor, cursor-column:offset
1854 before-cursor:&:duplex-list:char <- get *editor, before-cursor:offset
1855 undo:&:list:&:operation <- get *editor, undo:offset
1856 {
1857
1858 break-unless undo
1859 op:&:operation <- first undo
1860 deletion:delete-operation, is-delete?:bool <- maybe-convert *op, delete:variant
1861 break-unless is-delete?
1862 previous-coalesce-tag:num <- get deletion, tag:offset
1863 coalesce?:bool <- equal previous-coalesce-tag, 2/coalesce-delete
1864 break-unless coalesce?
1865 delete-until:&:duplex-list:char <- next before-cursor
1866 deletion <- put deletion, delete-until:offset, delete-until
1867 deleted-so-far:&:duplex-list:char <- get deletion, deleted-text:offset
1868 deleted-so-far <- append deleted-so-far, deleted-cell
1869 deletion <- put deletion, deleted-text:offset, deleted-so-far
1870 deletion <- put deletion, after-row:offset, cursor-row
1871 deletion <- put deletion, after-column:offset, cursor-column
1872 deletion <- put deletion, after-top-of-screen:offset, top-after
1873 *op <- merge 2/delete-operation, deletion
1874 break +done-adding-delete-operation
1875 }
1876
1877 op:&:operation <- new operation:type
1878 deleted-until:&:duplex-list:char <- next before-cursor
1879 *op <- merge 2/delete-operation, save-row/before, save-column/before, top-before, cursor-row/after, cursor-column/after, top-after, deleted-cell/deleted, before-cursor/delete-from, deleted-until, 2/coalesce-delete
1880 editor <- add-operation editor, op
1881 +done-adding-delete-operation
1882 }
1883 ]
1884
1885
1886
1887 scenario editor-can-undo-and-redo-ctrl-k [
1888 local-scope
1889
1890 assume-screen 10/width, 5/height
1891 contents:text <- new [abc
1892 def]
1893 e:&:editor <- new-editor contents, 0/left, 10/right
1894 editor-render screen, e
1895
1896 assume-console [
1897 left-click 1, 1
1898 press ctrl-k
1899 ]
1900 editor-event-loop screen, console, e
1901 screen-should-contain [
1902 . .
1903 .a .
1904 .def .
1905 .╌╌╌╌╌╌╌╌╌╌.
1906 . .
1907 ]
1908 3:num/raw <- get *e, cursor-row:offset
1909 4:num/raw <- get *e, cursor-column:offset
1910 memory-should-contain [
1911 3 <- 1
1912 4 <- 1
1913 ]
1914
1915 assume-console [
1916 press ctrl-z
1917 ]
1918 run [
1919 editor-event-loop screen, console, e
1920 ]
1921 screen-should-contain [
1922 . .
1923 .abc .
1924 .def .
1925 .╌╌╌╌╌╌╌╌╌╌.
1926 . .
1927 ]
1928 3:num/raw <- get *e, cursor-row:offset
1929 4:num/raw <- get *e, cursor-column:offset
1930 memory-should-contain [
1931 3 <- 1
1932 4 <- 1
1933 ]
1934
1935 assume-console [
1936 press ctrl-y
1937 ]
1938 run [
1939 editor-event-loop screen, console, e
1940 ]
1941
1942 screen-should-contain [
1943 . .
1944 .a .
1945 .def .
1946 .╌╌╌╌╌╌╌╌╌╌.
1947 . .
1948 ]
1949 3:num/raw <- get *e, cursor-row:offset
1950 4:num/raw <- get *e, cursor-column:offset
1951 memory-should-contain [
1952 3 <- 1
1953 4 <- 1
1954 ]
1955
1956 assume-console [
1957 type [1]
1958 ]
1959 run [
1960 editor-event-loop screen, console, e
1961 ]
1962 screen-should-contain [
1963 . .
1964 .a1 .
1965 .def .
1966 .╌╌╌╌╌╌╌╌╌╌.
1967 . .
1968 ]
1969 ]
1970
1971 after <begin-delete-to-end-of-line> [
1972 top-before:&:duplex-list:char <- get *editor, top-of-screen:offset
1973 ]
1974 before <end-delete-to-end-of-line> [
1975 {
1976 break-unless deleted-cells
1977 top-after:&:duplex-list:char <- get *editor, top-of-screen:offset
1978 cursor-row:num <- get *editor, cursor-row:offset
1979 cursor-column:num <- get *editor, cursor-column:offset
1980 deleted-until:&:duplex-list:char <- next before-cursor
1981 op:&:operation <- new operation:type
1982 *op <- merge 2/delete-operation, save-row/before, save-column/before, top-before, cursor-row/after, cursor-column/after, top-after, deleted-cells/deleted, before-cursor/delete-from, deleted-until, 0/never-coalesce
1983 editor <- add-operation editor, op
1984 +done-adding-delete-operation
1985 }
1986 ]
1987
1988
1989
1990 scenario editor-can-undo-and-redo-ctrl-u [
1991 local-scope
1992
1993 assume-screen 10/width, 5/height
1994 contents:text <- new [abc
1995 def]
1996 e:&:editor <- new-editor contents, 0/left, 10/right
1997 editor-render screen, e
1998
1999 assume-console [
2000 left-click 1, 2
2001 press ctrl-u
2002 ]
2003 editor-event-loop screen, console, e
2004 screen-should-contain [
2005 . .
2006 .c .
2007 .def .
2008 .╌╌╌╌╌╌╌╌╌╌.
2009 . .
2010 ]
2011 3:num/raw <- get *e, cursor-row:offset
2012 4:num/raw <- get *e, cursor-column:offset
2013 memory-should-contain [
2014 3 <- 1
2015 4 <- 0
2016 ]
2017
2018 assume-console [
2019 press ctrl-z
2020 ]
2021 run [
2022 editor-event-loop screen, console, e
2023 ]
2024 screen-should-contain [
2025 . .
2026 .abc .
2027 .def .
2028 .╌╌╌╌╌╌╌╌╌╌.
2029 . .
2030 ]
2031 3:num/raw <- get *e, cursor-row:offset
2032 4:num/raw <- get *e, cursor-column:offset
2033 memory-should-contain [
2034 3 <- 1
2035 4 <- 2
2036 ]
2037
2038 assume-console [
2039 press ctrl-y
2040 ]
2041 run [
2042 editor-event-loop screen, console, e
2043 ]
2044
2045 screen-should-contain [
2046 . .
2047 .c .
2048 .def .
2049 .╌╌╌╌╌╌╌╌╌╌.
2050 . .
2051 ]
2052 3:num/raw <- get *e, cursor-row:offset
2053 4:num/raw <- get *e, cursor-column:offset
2054 memory-should-contain [
2055 3 <- 1
2056 4 <- 0
2057 ]
2058
2059 assume-console [
2060 type [1]
2061 ]
2062 run [
2063 editor-event-loop screen, console, e
2064 ]
2065 screen-should-contain [
2066 . .
2067 .1c .
2068 .def .
2069 .╌╌╌╌╌╌╌╌╌╌.
2070 . .
2071 ]
2072 ]
2073
2074 after <begin-delete-to-start-of-line> [
2075 top-before:&:duplex-list:char <- get *editor, top-of-screen:offset
2076 ]
2077 before <end-delete-to-start-of-line> [
2078 {
2079 break-unless deleted-cells
2080 top-after:&:duplex-list:char <- get *editor, top-of-screen:offset
2081 op:&:operation <- new operation:type
2082 before-cursor:&:duplex-list:char <- get *editor, before-cursor:offset
2083 deleted-until:&:duplex-list:char <- next before-cursor
2084 cursor-row:num <- get *editor, cursor-row:offset
2085 cursor-column:num <- get *editor, cursor-column:offset
2086 *op <- merge 2/delete-operation, save-row/before, save-column/before, top-before, cursor-row/after, cursor-column/after, top-after, deleted-cells/deleted, before-cursor/delete-from, deleted-until, 0/never-coalesce
2087 editor <- add-operation editor, op
2088 +done-adding-delete-operation
2089 }
2090 ]
2091
2092 scenario editor-can-undo-and-redo-ctrl-u-2 [
2093 local-scope
2094
2095 assume-screen 10/width, 5/height
2096 e:&:editor <- new-editor [], 0/left, 10/right
2097 editor-render screen, e
2098
2099 assume-console [
2100 type [abc]
2101 press ctrl-u
2102 press ctrl-z
2103 ]
2104 editor-event-loop screen, console, e
2105 screen-should-contain [
2106 . .
2107 .abc .
2108 .╌╌╌╌╌╌╌╌╌╌.
2109 . .
2110 ]
2111 ]