diff options
-rw-r--r-- | 065duplex_list.mu | 25 | ||||
-rw-r--r-- | edit.mu | 241 |
2 files changed, 244 insertions, 22 deletions
diff --git a/065duplex_list.mu b/065duplex_list.mu index a8091a22..409f88cd 100644 --- a/065duplex_list.mu +++ b/065duplex_list.mu @@ -379,6 +379,8 @@ recipe remove-duplex-between [ # start->next->prev = 0 # start->next = end next:address:address:duplex-list <- get-address *start, next:offset + nothing-to-delete?:boolean <- equal *next, end + reply-if nothing-to-delete?, start prev:address:address:duplex-list <- get-address **next, prev:offset *prev <- copy 0 *next <- copy end @@ -458,6 +460,29 @@ scenario remove-range-to-end [ ] ] +scenario remove-range-empty [ + # construct a duplex list with six elements [13, 14, 15, 16, 17, 18] + 1:address:duplex-list <- copy 0 # 1 points to singleton list + 1:address:duplex-list <- push-duplex 14, 1:address:duplex-list + 1:address:duplex-list <- push-duplex 13, 1:address:duplex-list + run [ + # delete 16 onwards + # first pointer: to the third element + 2:address:duplex-list <- next-duplex 1:address:duplex-list + remove-duplex-between 1:address:duplex-list, 2:address:duplex-list + # now check the list + 4:number <- get *1:address:duplex-list, value:offset + 5:address:duplex-list <- next-duplex 1:address:duplex-list + 6:number <- get *5:address:duplex-list, value:offset + 7:address:duplex-list <- next-duplex 5:address:duplex-list + ] + memory-should-contain [ + 4 <- 13 + 6 <- 14 + 7 <- 0 + ] +] + # l:address:duplex-list <- insert-duplex-range in:address:duplex-list, new:address:duplex-list # Inserts list beginning at 'new' after 'in'. Returns some pointer into the list. recipe insert-duplex-range [ diff --git a/edit.mu b/edit.mu index 116eac9d..30131253 100644 --- a/edit.mu +++ b/edit.mu @@ -2993,7 +2993,9 @@ after +handle-special-character [ { delete-to-start-of-line?:boolean <- equal *c, 21/ctrl-u break-unless delete-to-start-of-line? - delete-to-start-of-line editor + +delete-to-start-of-line-begin + deleted-cells:address:duplex-list <- delete-to-start-of-line editor + +delete-to-start-of-line-end reply screen/same-as-ingredient:0, editor/same-as-ingredient:1, 1/go-render } ] @@ -3017,18 +3019,14 @@ recipe delete-to-start-of-line [ loop } # snip it out - start-next:address:address:duplex-list <- get-address *start, next:offset - *start-next <- copy end - { - break-unless end - end-prev:address:address:duplex-list <- get-address *end, prev:offset - *end-prev <- copy start - } + result:address:duplex-list <- next-duplex start + remove-duplex-between start, end # adjust cursor *before-cursor <- prev-duplex end left:number <- get *editor, left:offset cursor-column:address:number <- get-address *editor, cursor-column:offset *cursor-column <- copy left + reply result ] scenario editor-deletes-to-start-of-line-with-ctrl-u-2 [ @@ -3129,7 +3127,9 @@ after +handle-special-character [ { delete-to-end-of-line?:boolean <- equal *c, 11/ctrl-k break-unless delete-to-end-of-line? - delete-to-end-of-line editor + +delete-to-end-of-line-begin + deleted-cells:address:duplex-list <- delete-to-end-of-line editor + +delete-to-end-of-line-end reply screen/same-as-ingredient:0, editor/same-as-ingredient:1, 1/go-render } ] @@ -3150,13 +3150,9 @@ recipe delete-to-end-of-line [ loop } # snip it out - start-next:address:address:duplex-list <- get-address *start, next:offset - *start-next <- copy end - { - break-unless end - end-prev:address:address:duplex-list <- get-address *end, prev:offset - *end-prev <- copy start - } + result:address:duplex-list <- next-duplex start + remove-duplex-between start, end + reply result ] scenario editor-deletes-to-end-of-line-with-ctrl-k-2 [ @@ -3195,7 +3191,7 @@ scenario editor-deletes-to-end-of-line-with-ctrl-k-3 [ run [ editor-event-loop screen:address, console:address, 2:address:editor-data ] - # cursor deletes to end of line + # cursor deletes just last character screen-should-contain [ . . .12 . @@ -3218,7 +3214,7 @@ scenario editor-deletes-to-end-of-line-with-ctrl-k-4 [ run [ editor-event-loop screen:address, console:address, 2:address:editor-data ] - # cursor deletes to end of line + # cursor deletes nothing screen-should-contain [ . . .123 . @@ -3241,7 +3237,7 @@ scenario editor-deletes-to-end-of-line-with-ctrl-k-5 [ run [ editor-event-loop screen:address, console:address, 2:address:editor-data ] - # cursor deletes to end of line + # cursor deletes just the final character screen-should-contain [ . . .123 . @@ -3264,7 +3260,7 @@ scenario editor-deletes-to-end-of-line-with-ctrl-k-6 [ run [ editor-event-loop screen:address, console:address, 2:address:editor-data ] - # cursor deletes to end of line + # cursor deletes nothing screen-should-contain [ . . .123 . @@ -8403,10 +8399,8 @@ scenario editor-can-undo-and-redo-delete [ ] ] -# save operation to undo after +delete-character-begin [ top-before:address:duplex-list <- get *editor, top-of-screen:offset - undo:address:address:list <- get-address *editor, undo:offset ] before +delete-character-end [ { @@ -8443,6 +8437,209 @@ before +delete-character-end [ } ] +# undo ctrl-k + +scenario editor-can-undo-and-redo-ctrl-k [ + # create an editor + assume-screen 10/width, 5/height + 1:address:array:character <- new [abc +def] + 2:address:editor-data <- new-editor 1:address:array:character, screen:address, 0/left, 10/right + editor-render screen, 2:address:editor-data + # insert some text and hit delete and backspace a few times + assume-console [ + left-click 1, 1 + press ctrl-k + ] + editor-event-loop screen:address, console:address, 2:address:editor-data + screen-should-contain [ + . . + .a . + .def . + .┈┈┈┈┈┈┈┈┈┈. + . . + ] + 3:number <- get *2:address:editor-data, cursor-row:offset + 4:number <- get *2:address:editor-data, cursor-column:offset + memory-should-contain [ + 3 <- 1 + 4 <- 1 + ] + # undo + assume-console [ + press ctrl-z + ] + run [ + editor-event-loop screen:address, console:address, 2:address:editor-data + ] + screen-should-contain [ + . . + .abc . + .def . + .┈┈┈┈┈┈┈┈┈┈. + . . + ] + 3:number <- get *2:address:editor-data, cursor-row:offset + 4:number <- get *2:address:editor-data, cursor-column:offset + memory-should-contain [ + 3 <- 1 + 4 <- 1 + ] + # redo + assume-console [ + press ctrl-y + ] + run [ + editor-event-loop screen:address, console:address, 2:address:editor-data + ] + # first line inserted + screen-should-contain [ + . . + .a . + .def . + .┈┈┈┈┈┈┈┈┈┈. + . . + ] + 3:number <- get *2:address:editor-data, cursor-row:offset + 4:number <- get *2:address:editor-data, cursor-column:offset + memory-should-contain [ + 3 <- 1 + 4 <- 1 + ] + # cursor should be in the right place + assume-console [ + type [1] + ] + run [ + editor-event-loop screen:address, console:address, 2:address:editor-data + ] + screen-should-contain [ + . . + .a1 . + .def . + .┈┈┈┈┈┈┈┈┈┈. + . . + ] +] + +after +delete-to-end-of-line-begin [ + top-before:address:duplex-list <- get *editor, top-of-screen:offset +] +before +delete-to-end-of-line-end [ + { + break-unless deleted-cells # delete failed; don't add an undo operation + top-after:address:duplex-list <- get *editor, top-of-screen:offset + undo:address:address:list <- get-address *editor, undo:offset + op:address:operation <- new operation:type + deleted-until:address:duplex-list <- next-duplex *before-cursor + *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 + editor <- add-operation editor, op + +done-adding-delete-operation + } +] + +# undo ctrl-u + +scenario editor-can-undo-and-redo-ctrl-u [ + # create an editor + assume-screen 10/width, 5/height + 1:address:array:character <- new [abc +def] + 2:address:editor-data <- new-editor 1:address:array:character, screen:address, 0/left, 10/right + editor-render screen, 2:address:editor-data + # insert some text and hit delete and backspace a few times + assume-console [ + left-click 1, 2 + press ctrl-u + ] + editor-event-loop screen:address, console:address, 2:address:editor-data + screen-should-contain [ + . . + .c . + .def . + .┈┈┈┈┈┈┈┈┈┈. + . . + ] + 3:number <- get *2:address:editor-data, cursor-row:offset + 4:number <- get *2:address:editor-data, cursor-column:offset + memory-should-contain [ + 3 <- 1 + 4 <- 0 + ] + # undo + assume-console [ + press ctrl-z + ] + run [ + editor-event-loop screen:address, console:address, 2:address:editor-data + ] + screen-should-contain [ + . . + .abc . + .def . + .┈┈┈┈┈┈┈┈┈┈. + . . + ] + 3:number <- get *2:address:editor-data, cursor-row:offset + 4:number <- get *2:address:editor-data, cursor-column:offset + memory-should-contain [ + 3 <- 1 + 4 <- 2 + ] + # redo + assume-console [ + press ctrl-y + ] + run [ + editor-event-loop screen:address, console:address, 2:address:editor-data + ] + # first line inserted + screen-should-contain [ + . . + .c . + .def . + .┈┈┈┈┈┈┈┈┈┈. + . . + ] + 3:number <- get *2:address:editor-data, cursor-row:offset + 4:number <- get *2:address:editor-data, cursor-column:offset + memory-should-contain [ + 3 <- 1 + 4 <- 0 + ] + # cursor should be in the right place + assume-console [ + type [1] + ] + run [ + editor-event-loop screen:address, console:address, 2:address:editor-data + ] + screen-should-contain [ + . . + .1c . + .def . + .┈┈┈┈┈┈┈┈┈┈. + . . + ] +] + +after +delete-to-start-of-line-begin [ + top-before:address:duplex-list <- get *editor, top-of-screen:offset +] +before +delete-to-start-of-line-end [ + { + break-unless deleted-cells # delete failed; don't add an undo operation + top-after:address:duplex-list <- get *editor, top-of-screen:offset + undo:address:address:list <- get-address *editor, undo:offset + op:address:operation <- new operation:type + deleted-until:address:duplex-list <- next-duplex *before-cursor + *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 + editor <- add-operation editor, op + +done-adding-delete-operation + } +] + + # todo: # operations for recipe side and each sandbox-data # undo delete sandbox as a separate primitive on the status bar |