exclusive-container operation [
typing:insert-operation
move:move-operation
delete:delete-operation
]
container insert-operation [
before-row:number
before-column:number
before-top-of-screen:address:duplex-list:character
after-row:number
after-column:number
after-top-of-screen:address:duplex-list:character
insert-from:address:duplex-list:character
insert-until:address:duplex-list:character
tag:number
]
container move-operation [
before-row:number
before-column:number
before-top-of-screen:address:duplex-list:character
after-row:number
after-column:number
after-top-of-screen:address:duplex-list:character
tag:number
]
container delete-operation [
before-row:number
before-column:number
before-top-of-screen:address:duplex-list:character
after-row:number
after-column:number
after-top-of-screen:address:duplex-list:character
deleted-text:address:duplex-list:character
delete-from:address:duplex-list:character
delete-until:address:duplex-list:character
tag:number
]
container editor-data [
undo:address:list:address:operation
redo:address:list:address:operation
]
after <handle-special-character> [
{
undo?:boolean <- equal c, 26/ctrl-z
break-unless undo?
undo:address:list:address:operation <- get *editor, undo:offset
break-unless undo
op:address:operation <- first undo
undo <- rest undo
*editor <- put *editor, undo:offset, undo
redo:address:list:address:operation <- get *editor, redo:offset
redo <- push op, redo
*editor <- put *editor, redo:offset, redo
<handle-undo>
return screen/same-as-ingredient:0, editor/same-as-ingredient:1, 1/go-render
}
]
after <handle-special-character> [
{
redo?:boolean <- equal c, 25/ctrl-y
break-unless redo?
redo:address:list:address:operation <- get *editor, redo:offset
break-unless redo
op:address:operation <- first redo
redo <- rest redo
*editor <- put *editor, redo:offset, redo
undo:address:list:address:operation <- get *editor, undo:offset
undo <- push op, undo
*editor <- put *editor, undo:offset, undo
<handle-redo>
return screen/same-as-ingredient:0, editor/same-as-ingredient:1, 1/go-render
}
]
scenario editor-can-undo-typing [
assume-screen 10/width, 5/height
1:address:array:character <- new []
2:address:editor-data <- new-editor 1:address:array:character, screen:address:screen, 0/left, 10/right
editor-render screen, 2:address:editor-data
assume-console [
type [0]
]
editor-event-loop screen:address:screen, console:address:console, 2:address:editor-data
assume-console [
press ctrl-z
]
run [
editor-event-loop screen:address:screen, console:address:console, 2:address:editor-data
]
screen-should-contain [
. .
. .
.┈┈┈┈┈┈┈┈┈┈.
. .
]
assume-console [
type [1]
]
run [
editor-event-loop screen:address:screen, console:address:console, 2:address:editor-data
]
screen-should-contain [
. .
.1 .
.┈┈┈┈┈┈┈┈┈┈.
. .
]
]
after <insert-character-begin> [
top-before:address:duplex-list:character <- get *editor, top-of-screen:offset
cursor-before:address:duplex-list:character <- get *editor, before-cursor:offset
]
before <insert-character-end> [
top-after:address:duplex-list:character <- get *editor, top-of-screen:offset
cursor-row:number <- get *editor, cursor-row:offset
cursor-column:number <- get *editor, cursor-column:offset
undo:address:list:address:operation <- get *editor, undo:offset
{
break-unless undo
op:address:operation <- first undo
typing:insert-operation, is-insert?:boolean <- maybe-convert *op, typing:variant
break-unless is-insert?
previous-coalesce-tag:number <- get typing, tag:offset
break-unless previous-coalesce-tag
before-cursor:address:duplex-list:character <- get *editor, before-cursor:offset
insert-until:address:duplex-list:character <- next before-cursor
typing <- put typing, insert-until:offset, insert-until
typing <- put typing, after-row:offset, cursor-row
typing <- put typing, after-column:offset, cursor-column
typing <- put typing, after-top-of-screen:offset, top-after
*op <- merge 0/insert-operation, typing
break +done-adding-insert-operation:label
}
insert-from:address:duplex-list:character <- next cursor-before
insert-to:address:duplex-list:character <- next insert-from
op:address:operation <- new operation:type
*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
editor <- add-operation editor, op
+done-adding-insert-operation
]
after <insert-enter-begin> [
cursor-row-before:number <- copy cursor-row
cursor-column-before:number <- copy cursor-column
top-before:address:duplex-list:character <- get *editor, top-of-screen:offset
cursor-before:address:duplex-list:character <- get *editor, before-cursor:offset
]
before <insert-enter-end> [
top-after:address:duplex-list:character <- get *editor, top-of-screen:offset
cursor-row:number <- get *editor, cursor-row:offset
cursor-column:number <- get *editor, cursor-row:offset
insert-from:address:duplex-list:character <- next cursor-before
before-cursor:address:duplex-list:character <- get *editor, before-cursor:offset
insert-to:address:duplex-list:character <- next before-cursor
op:address:operation <- new operation:type
*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
editor <- add-operation editor, op
]
def add-operation editor:address:editor-data, op:address:operation -> editor:address:editor-data [
local-scope
load-ingredients
undo:address:list:address:operation <- get *editor, undo:offset
undo <- push op undo
*editor <- put *editor, undo:offset, undo
redo:address:list:address:operation <- get *editor, redo:offset
redo <- copy 0
*editor <- put *editor, redo:offset, redo
return editor/same-as-ingredient:0
]
after <handle-undo> [
{
typing:insert-operation, is-insert?:boolean <- maybe-convert *op, typing:variant
break-unless is-insert?
start:address:duplex-list:character <- get typing, insert-from:offset
end:address:duplex-list:character <- get typing, insert-until:offset
before-cursor:address:duplex-list:character <- prev start
*editor <- put *editor, before-cursor:offset, before-cursor
remove-between before-cursor, end
cursor-row <- get typing, before-row:offset
*editor <- put *editor, cursor-row:offset, cursor-row
cursor-column <- get typing, before-column:offset
*editor <- put *editor, cursor-column:offset, cursor-column
top:address:duplex-list:character <- get typing, before-top-of-screen:offset
*editor <- put *editor, top-of-screen:offset, top
}
]
scenario editor-can-undo-typing-multiple [
assume-screen 10/width, 5/height
1:address:array:character <- new []
2:address:editor-data <- new-editor 1:address:array:character, screen:address:screen, 0/left, 10/right
editor-render screen, 2:address:editor-data
assume-console [
type [012]
]
editor-event-loop screen:address:screen, console:address:console, 2:address:editor-data
assume-console [
press ctrl-z
]
run [
editor-event-loop screen:address:screen, console:address:console, 2:address:editor-data
]
screen-should-contain [
. .
. .
.┈┈┈┈┈┈┈┈┈┈.
. .
]
]
scenario editor-can-undo-typing-multiple-2 [
assume-screen 10/width, 5/height
1:address:array:character <- new [a]
2:address:editor-data <- new-editor 1:address:array:character, screen:address:screen, 0/left, 10/right
editor-render screen, 2:address:editor-data
assume-console [
type [012]
]
editor-event-loop screen:address:screen, console:address:console, 2:address:editor-data
screen-should-contain [
. .
.012a .
.┈┈┈┈┈┈┈┈┈┈.
. .
]
assume-console [
press ctrl-z
]
run [
editor-event-loop screen:address:screen, console:address:console, 2:address:editor-data
]
screen-should-contain [
. .
.a .
.┈┈┈┈┈┈┈┈┈┈.
. .
]
assume-console [
type [3]
]
run [
editor-event-loop screen:address:screen, console:address:console, 2:address:editor-data
]
screen-should-contain [
. .
.3a .
.┈┈┈┈┈┈┈┈┈┈.
. .
]
]
scenario editor-can-undo-typing-enter [
assume-screen 10/width, 5/height
1:address:array:character <- new [ abc]
2:address:editor-data <- new-editor 1:address:array:character, screen:address:screen, 0/left, 10/right
editor-render screen, 2:address:editor-data
assume-console [
left-click 1, 8
press enter
]
editor-event-loop screen:address:screen, console:address:console, 2:address:editor-data
screen-should-contain [
. .
. abc .
. .
.┈┈┈┈┈┈┈┈┈┈.
. .
]
3:number <- get *2:address:editor-data, cursor-row:offset
4:number <- get *2:address:editor-data, cursor-column:offset
memory-should-contain [
3 <- 2
4 <- 2
]
assume-console [
press ctrl-z
]
run [
editor-event-loop screen:address:screen, console:address:console, 2:address:editor-data
]
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 <- 5
]
screen-should-contain [
. .
. abc .
.┈┈┈┈┈┈┈┈┈┈.
. .
]
assume-console [
type [1]
]
run [
editor-event-loop screen:address:screen, console:address:console, 2:address:editor-data
]
screen-should-contain [
. .
. abc1 .
.┈┈┈┈┈┈┈┈┈┈.
. .
]
]
scenario editor-redo-typing [
assume-screen 10/width, 5/height
1:address:array:character <- new [a]
2:address:editor-data <- new-editor 1:address:array:character, screen:address:screen, 0/left, 10/right
editor-render screen, 2:address:editor-data
assume-console [
type [012]
press ctrl-z
]
editor-event-loop screen:address:screen, console:address:console, 2:address:editor-data
screen-should-contain [
. .
.a .
.┈┈┈┈┈┈┈┈┈┈.
. .
]
assume-console [
press ctrl-y
]
run [
editor-event-loop screen:address:screen, console:address:console, 2:address:editor-data
]
screen-should-contain [
. .
.012a .
.┈┈┈┈┈┈┈┈┈┈.
. .
]
assume-console [
type [3]
]
run [
editor-event-loop screen:address:screen, console:address:console, 2:address:editor-data
]
screen-should-contain [
. .
.0123a .
.┈┈┈┈┈┈┈┈┈┈.
. .
]
]
after <handle-redo> [
{
typing:insert-operation, is-insert?:boolean <- maybe-convert *op, typing:variant
break-unless is-insert?
before-cursor <- get *editor, before-cursor:offset
insert-from:address:duplex-list:character <- get typing, insert-from:offset
insert-range before-cursor, insert-from
cursor-row <- get typing, after-row:offset
*editor <- put *editor, cursor-row:offset, cursor-row
cursor-column <- get typing, after-column:offset
*editor <- put *editor, cursor-column:offset, cursor-column
top:address:duplex-list:character <- get typing, after-top-of-screen:offset
*editor <- put *editor, top-of-screen:offset, top
}
]
scenario editor-redo-typing-empty [
assume-screen 10/width, 5/height
1:address:array:character <- new []
2:address:editor-data <- new-editor 1:address:array:character, screen:address:screen, 0/left, 10/right
editor-render screen, 2:address:editor-data
assume-console [
type [012]
press ctrl-z
]
editor-event-loop screen:address:screen, console:address:console, 2:address:editor-data
screen-should-contain [
. .
. .
.┈┈┈┈┈┈┈┈┈┈.
. .
]
assume-console [
press ctrl-y
]
run [
editor-event-loop screen:address:screen, console:address:console, 2:address:editor-data
]
screen-should-contain [
. .
.012 .
.┈┈┈┈┈┈┈┈┈┈.
. .
]
assume-console [
type [3]
]
run [
editor-event-loop screen:address:screen, console:address:console, 2:address:editor-data
]
screen-should-contain [
. .
.0123 .
.┈┈┈┈┈┈┈┈┈┈.
. .
]
]
scenario editor-work-clears-redo-stack [
assume-screen 10/width, 5/height
1:address:array:character <- new [abc
def
ghi]
2:address:editor-data <- new-editor 1:address:array:character, screen:address:screen, 0/left, 10/right
editor-render screen, 2:address:editor-data
assume-console [
type [1]
press ctrl-z
]
editor-event-loop screen:address:screen, console:address:console, 2:address:editor-data
assume-console [
type [0]
]
editor-event-loop screen:address:screen, console:address:console, 2:address:editor-data
screen-should-contain [
. .
.0abc .
.def .
.ghi .
.┈┈┈┈┈┈┈┈┈┈.
]
assume-console [
press ctrl-y
]
run [
editor-event-loop screen:address:screen, console:address:console, 2:address:editor-data
]
screen-should-contain [
. .
.0abc .
.def .
.ghi .
.┈┈┈┈┈┈┈┈┈┈.
]
]
scenario editor-can-redo-typing-and-enter-and-tab [
assume-screen 10/width, 5/height
1:address:array:character <- new []
2:address:editor-data <- new-editor 1:address:array:character, screen:address:screen, 0/left, 10/right
editor-render screen, 2:address:editor-data
assume-console [
press tab
type [ab]
press tab
type [cd]
press enter
press tab
type [efg]
]
editor-event-loop screen:address:screen, console:address:console, 2:address:editor-data
screen-should-contain [
. .
. ab cd .
. efg .
.┈┈┈┈┈┈┈┈┈┈.
. .
]
3:number <- get *2:address:editor-data, cursor-row:offset
4:number <- get *2:address:editor-data, cursor-column:offset
memory-should-contain [
3 <- 2
4 <- 7
]
assume-console [
press ctrl-z
]
run [
editor-event-loop screen:address:screen, console:address:console, 2:address:editor-data
]
3:number <- get *2:address:editor-data, cursor-row:offset
4:number <- get *2:address:editor-data, cursor-column:offset
memory-should-contain [
3 <- 2
4 <- 2
]
screen-should-contain [
. .
. ab cd .
. .
.┈┈┈┈┈┈┈┈┈┈.
. .
]
assume-console [
press ctrl-z
]
run [
editor-event-loop screen:address:screen, console:address:console, 2:address:editor-data
]
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 <- 8
]
screen-should-contain [
. .
. ab cd .
.┈┈┈┈┈┈┈┈┈┈.
. .
]
assume-console [
press ctrl-z
]
run [
editor-event-loop screen:address:screen, console:address:console, 2:address:editor-data
]
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
]
screen-should-contain [
. .
. .
.┈┈┈┈┈┈┈┈┈┈.
. .
]
assume-console [
press ctrl-y
]
run [
editor-event-loop screen:address:screen, console:address:console, 2:address:editor-data
]
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 <- 8
]
screen-should-contain [
. .
. ab cd .
.┈┈┈┈┈┈┈┈┈┈.
. .
]
assume-console [
press ctrl-y
]
run [
editor-event-loop screen:address:screen, console:address:console, 2:address:editor-data
]
3:number <- get *2:address:editor-data, cursor-row:offset
4:number <- get *2:address:editor-data, cursor-column:offset
memory-should-contain [
3 <- 2
4 <- 2
]
screen-should-contain [
. .
. ab cd .
. .
.┈┈┈┈┈┈┈┈┈┈.
. .
]
assume-console [
press ctrl-y
]
run [
editor-event-loop screen:address:screen, console:address:console, 2:address:editor-data
]
3:number <- get *2:address:editor-data, cursor-row:offset
4:number <- get *2:address:editor-data, cursor-column:offset
memory-should-contain [
3 <- 2
4 <- 7
]
screen-should-contain [
. .
. ab cd .
. efg .
.┈┈┈┈┈┈┈┈┈┈.
. .
]
]
scenario editor-can-undo-touch [
assume-screen 10/width, 5/height
1:address:array:character <- new [abc
def
ghi]
2:address:editor-data <- new-editor 1:address:array:character, screen:address:screen, 0/left, 10/right
editor-render screen, 2:address:editor-data
assume-console [
left-click 3, 1
]
editor-event-loop screen:address:screen, console:address:console, 2:address:editor-data
assume-console [
press ctrl-z
]
run [
editor-event-loop screen:address:screen, console:address:console, 2:address:editor-data
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
]
assume-console [
type [1]
]
run [
editor-event-loop screen:address:screen, console:address:console, 2:address:editor-data
]
screen-should-contain [
. .
.1abc .
.def .
.ghi .
.┈┈┈┈┈┈┈┈┈┈.
]
]
after <move-cursor-begin> [
cursor-row-before:number <- get *editor, cursor-row:offset
cursor-column-before:number <- get *editor, cursor-column:offset
top-before:address:duplex-list:character <- get *editor, top-of-screen:offset
]
before <move-cursor-end> [
top-after:address:duplex-list:character <- get *editor, top-of-screen:offset
cursor-row:number <- get *editor, cursor-row:offset
cursor-column:number <- get *editor, cursor-column:offset
{
break-unless undo-coalesce-tag
undo:address:list:address:operation <- get *editor, undo:offset
break-unless undo
op:address:operation <- first undo
move:move-operation, is-move?:boolean <- maybe-convert *op, move:variant
break-unless is-move?
previous-coalesce-tag:number <- get move, tag:offset
coalesce?:boolean <- equal undo-coalesce-tag, previous-coalesce-tag
break-unless coalesce?
move <- put move, after-row:offset, cursor-row
move <- put move, after-column:offset, cursor-column
move <- put move, after-top-of-screen:offset, top-after
*op <- merge 1/move-operation, move
break +done-adding-move-operation:label
}
op:address:operation <- new operation:type
*op <- merge 1/move-operation, cursor-row-before, cursor-column-before, top-before, cursor-row/after, cursor-column/after, top-after, undo-coalesce-tag
editor <- add-operation editor, op
+done-adding-move-operation
]
after <handle-undo> [
{
move:move-operation, is-move?:boolean <- maybe-convert *op, move:variant
break-unless is-move?
cursor-row <- get move, before-row:offset
*editor <- put *editor, cursor-row:offset, cursor-row
cursor-column <- get move, before-column:offset
*editor <- put *editor, cursor-column:offset, cursor-column
top:address:duplex-list:character <- get move, before-top-of-screen:offset
*editor <- put *editor, top-of-screen:offset, top
}
]
scenario editor-can-undo-scroll [
assume-screen 5/width, 4/height
1:address:array:character <- new [a
b
cdefgh]
2:address:editor-data <- new-editor 1:address:array:character, screen:address:screen, 0/left, 5/right
assume-console [
left-click 3, 3
press right-arrow
]
editor-event-loop screen:address:screen, console:address:console, 2:address:editor-data
3:number <- get *2:address:editor-data, cursor-row:offset
4:number <- get *2:address:editor-data, cursor-column:offset
screen-should-contain [
. .
.b .
.cdef↩.
.gh .
]
memory-should-contain [
3 <- 3
4 <- 0
]
assume-console [
press ctrl-z
]
run [
editor-event-loop screen:address:screen, console:address:console, 2:address:editor-data
3:number <- get *2:address:editor-data, cursor-row:offset
4:number <- get *2:address:editor-data, cursor-column:offset
]
memory-should-contain [
3 <- 3
4 <- 3
]
screen-should-contain [
. .
.a .
.b .
.cdef↩.
]
assume-console [
type [1]
]
run [
editor-event-loop screen:address:screen, console:address:console, 2:address:editor-data
]
screen-should-contain [
. .
.b .
.cde1↩.
.fgh .
]
]
scenario editor-can-undo-left-arrow [
assume-screen 10/width, 5/height
1:address:array:character <- new [abc
def
ghi]
2:address:editor-data <- new-editor 1:address:array:character, screen:address:screen, 0/left, 10/right
editor-render screen, 2:address:editor-data
assume-console [
left-click 3, 1
press left-arrow
]
editor-event-loop screen:address:screen, console:address:console, 2:address:editor-data
assume-console [
press ctrl-z
]
run [
editor-event-loop screen:address:screen, console:address:console, 2:address:editor-data
3:number <- get *2:address:editor-data, cursor-row:offset
4:number <- get *2:address:editor-data, cursor-column:offset
]
memory-should-contain [
3 <- 3
4 <- 1
]
assume-console [
type [1]
]
run [
editor-event-loop screen:address:screen, console:address:console, 2:address:editor-data
]
screen-should-contain [
. .
.abc .
.def .
.g1hi .
.┈┈┈┈┈┈┈┈┈┈.
]
]
scenario editor-can-undo-up-arrow [
assume-screen 10/width, 5/height
1:address:array:character <- new [abc
def
ghi]
2:address:editor-data <- new-editor 1:address:array:character, screen:address:screen, 0/left, 10/right
editor-render screen, 2:address:editor-data
assume-console [
left-click 3, 1
press up-arrow
]
editor-event-loop screen:address:screen, console:address:console, 2:address:editor-data
3:number <- get *2:address:editor-data, cursor-row:offset
4:number <- get *2:address:editor-data, cursor-column:offset
memory-should-contain [
3 <- 2
4 <- 1
]
assume-console [
press ctrl-z
]
run [
editor-event-loop screen:address:screen, console:address:console, 2:address:editor-data
3:number <- get *2:address:editor-data, cursor-row:offset
4:number <- get *2:address:editor-data, cursor-column:offset
]
memory-should-contain [
3 <- 3
4 <- 1
]
assume-console [
type [1]
]
run [
editor-event-loop screen:address:screen, console:address:console, 2:address:editor-data
]
screen-should-contain [
. .
.abc .
.def .
.g1hi .
.┈┈┈┈┈┈┈┈┈┈.
]
]
scenario editor-can-undo-down-arrow [
assume-screen 10/width, 5/height
1:address:array:character <- new [abc
def
ghi]
2:address:editor-data <- new-editor 1:address:array:character, screen:address:screen, 0/left, 10/right
editor-render screen, 2:address:editor-data
assume-console [
left-click 2, 1
press down-arrow
]
editor-event-loop screen:address:screen, console:address:console, 2:address:editor-data
assume-console [
press ctrl-z
]
run [
editor-event-loop screen:address:screen, console:address:console, 2:address:editor-data
3:number <- get *2:address:editor-data, cursor-row:offset
4:number <- get *2:address:editor-data, cursor-column:offset
]
memory-should-contain [
3 <- 2
4 <- 1
]
assume-console [
type [1]
]
run [
editor-event-loop screen:address:screen, console:address:console, 2:address:editor-data
]
screen-should-contain [
. .
.abc .
.d1ef .
.ghi .
.┈┈┈┈┈┈┈┈┈┈.
]
]
scenario editor-can-undo-ctrl-f [
assume-screen 10/width, 5/height
1:address:array:character <- new [a
b
c
d
e
f]
2:address:editor-data <- new-editor 1:address:array:character, screen:address:screen, 0/left, 10/right
editor-render screen, 2:address:editor-data
assume-console [
press ctrl-f
]
editor-event-loop screen:address:screen, console:address:console, 2:address:editor-data
assume-console [
press ctrl-z
]
run [
editor-event-loop screen:address:screen, console:address:console, 2:address:editor-data
3:number <- get *2:address:editor-data, cursor-row:offset
4:number <- get *2:address:editor-data, cursor-column:offset
]
screen-should-contain [
. .
.a .
.b .
.c .
.d .
]
]
scenario editor-can-undo-page-down [
assume-screen 10/width, 5/height
1:address:array:character <- new [a
b
c
d
e
f]
2:address:editor-data <- new-editor 1:address:array:character, screen:address:screen, 0/left, 10/right
editor-render screen, 2:address:editor-data
assume-console [
press page-down
]
editor-event-loop screen:address:screen, console:address:console, 2:address:editor-data
assume-console [
press ctrl-z
]
run [
editor-event-loop screen:address:screen, console:address:console, 2:address:editor-data
3:number <- get *2:address:editor-data, cursor-row:offset
4:number <- get *2:address:editor-data, cursor-column:offset
]
screen-should-contain [
. .
.a .
.b .
.c .
.d .
]
]
scenario editor-can-undo-ctrl-b [
assume-screen 10/width, 5/height
1:address:array:character <- new [a
b
c
d
e
f]
2:address:editor-data <- new-editor 1:address:array:character, screen:address:screen, 0/left, 10/right
editor-render screen, 2:address:editor-data
assume-console [
press page-down
press ctrl-b
]
editor-event-loop screen:address:screen, console:address:console, 2:address:editor-data
assume-console [
press ctrl-z
]
run [
editor-event-loop screen:address:screen, console:address:console, 2:address:editor-data
3:number <- get *2:address:editor-data, cursor-row:offset
4:number <- get *2:address:editor-data, cursor-column:offset
]
screen-should-contain [
. .
.d .
.e .
.f .
.┈┈┈┈┈┈┈┈┈┈.
]
]
scenario editor-can-undo-page-up [
assume-screen 10/width, 5/height
1:address:array:character <- new [a
b
c
d
e
f]
2:address:editor-data <- new-editor 1:address:array:character, screen:address:screen, 0/left, 10/right
editor-render screen, 2:address:editor-data
assume-console [
press page-down
press page-up
]
editor-event-loop screen:address:screen, console:address:console, 2:address:editor-data
assume-console [
press ctrl-z
]
run [
editor-event-loop screen:address:screen, console:address:console, 2:address:editor-data
3:number <- get *2:address:editor-data, cursor-row:offset
4:number <- get *2:address:editor-data, cursor-column:offset
]
screen-should-contain [
. .
.d .
.e .
.f .
.┈┈┈┈┈┈┈┈┈┈.
]
]
scenario editor-can-undo-ctrl-a [
assume-screen 10/width, 5/height
1:address:array:character <- new [abc
def
ghi]
2:address:editor-data <- new-editor 1:address:array:character, screen:address:screen, 0/left, 10/right
editor-render screen, 2:address:editor-data
assume-console [
left-click 2, 1
press ctrl-a
]
editor-event-loop screen:address:screen, console:address:console, 2:address:editor-data
assume-console [
press ctrl-z
]
run [
editor-event-loop screen:address:screen, console:address:console, 2:address:editor-data
3:number <- get *2:address:editor-data, cursor-row:offset
4:number <- get *2:address:editor-data, cursor-column:offset
]
memory-should-contain [
3 <- 2
4 <- 1
]
assume-console [
type [1]
]
run [
editor-event-loop screen:address:screen, console:address:console, 2:address:editor-data
]
screen-should-contain [
. .
.abc .
.d1ef .
.ghi .
.┈┈┈┈┈┈┈┈┈┈.
]
]
scenario editor-can-undo-home [
assume-screen 10/width, 5/height
1:address:array:character <- new [abc
def
ghi]
2:address:editor-data <- new-editor 1:address:array:character, screen:address:screen, 0/left, 10/right
editor-render screen, 2:address:editor-data
assume-console [
left-click 2, 1
press home
]
editor-event-loop screen:address:screen, console:address:console, 2:address:editor-data
assume-console [
press ctrl-z
]
run [
editor-event-loop screen:address:screen, console:address:console, 2:address:editor-data
3:number <- get *2:address:editor-data, cursor-row:offset
4:number <- get *2:address:editor-data, cursor-column:offset
]
memory-should-contain [
3 <- 2
4 <- 1
]
assume-console [
type [1]
]
run [
editor-event-loop screen:address:screen, console:address:console, 2:address:editor-data
]
screen-should-contain [
. .
.abc .
.d1ef .
.ghi .
.┈┈┈┈┈┈┈┈┈┈.
]
]
scenario editor-can-undo-ctrl-e [
assume-screen 10/width, 5/height
1:address:array:character <- new [abc
def
ghi]
2:address:editor-data <- new-editor 1:address:array:character, screen:address:screen, 0/left, 10/right
editor-render screen, 2:address:editor-data
assume-console [
left-click 2, 1
press ctrl-e
]
editor-event-loop screen:address:screen, console:address:console, 2:address:editor-data
assume-console [
press ctrl-z
]
run [
editor-event-loop screen:address:screen, console:address:console, 2:address:editor-data
3:number <- get *2:address:editor-data, cursor-row:offset
4:number <- get *2:address:editor-data, cursor-column:offset
]
memory-should-contain [
3 <- 2
4 <- 1
]
assume-console [
type [1]
]
run [
editor-event-loop screen:address:screen, console:address:console, 2:address:editor-data
]
screen-should-contain [
. .
.abc .
.d1ef .
.ghi .
.┈┈┈┈┈┈┈┈┈┈.
]
]
scenario editor-can-undo-end [
assume-screen 10/width, 5/height
1:address:array:character <- new [abc
def
ghi]
2:address:editor-data <- new-editor 1:address:array:character, screen:address:screen, 0/left, 10/right
editor-render screen, 2:address:editor-data
assume-console [
left-click 2, 1
press end
]
editor-event-loop screen:address:screen, console:address:console, 2:address:editor-data
assume-console [
press ctrl-z
]
run [
editor-event-loop screen:address:screen, console:address:console, 2:address:editor-data
3:number <- get *2:address:editor-data, cursor-row:offset
4:number <- get *2:address:editor-data, cursor-column:offset
]
memory-should-contain [
3 <- 2
4 <- 1
]
assume-console [
type [1]
]
run [
editor-event-loop screen:address:screen, console:address:console, 2:address:editor-data
]
screen-should-contain [
. .
.abc .
.d1ef .
.ghi .
.┈┈┈┈┈┈┈┈┈┈.
]
]
scenario editor-can-undo-multiple-arrows-in-the-same-direction [
assume-screen 10/width, 5/height
1:address:array:character <- new [abc
def
ghi]
2:address:editor-data <- new-editor 1:address:array:character, screen:address:screen, 0/left, 10/right
editor-render screen, 2:address:editor-data
assume-console [
left-click 2, 1
press right-arrow
press right-arrow
press up-arrow
]
editor-event-loop screen:address:screen, console:address:console, 2:address:editor-data
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 <- 3
]
assume-console [
press ctrl-z
]
run [
editor-event-loop screen:address:screen, console:address:console, 2:address:editor-data
3:number <- get *2:address:editor-data, cursor-row:offset
4:number <- get *2:address:editor-data, cursor-column:offset
]
memory-should-contain [
3 <- 2
4 <- 3
]
assume-console [
press ctrl-z
]
run [
editor-event-loop screen:address:screen, console:address:console, 2:address:editor-data
3:number <- get *2:address:editor-data, cursor-row:offset
4:number <- get *2:address:editor-data, cursor-column:offset
]
memory-should-contain [
3 <- 2
4 <- 1
]
]
scenario editor-redo-touch [
assume-screen 10/width, 5/height
1:address:array:character <- new [abc
def
ghi]
2:address:editor-data <- new-editor 1:address:array:character, screen:address:screen, 0/left, 10/right
editor-render screen, 2:address:editor-data
assume-console [
left-click 3, 1
press ctrl-z
]
editor-event-loop screen:address:screen, console:address:console, 2:address:editor-data
assume-console [
press ctrl-y
]
run [
editor-event-loop screen:address:screen, console:address:console, 2:address:editor-data
3:number <- get *2:address:editor-data, cursor-row:offset
4:number <- get *2:address:editor-data, cursor-column:offset
]
memory-should-contain [
3 <- 3
4 <- 1
]
assume-console [
type [1]
]
run [
editor-event-loop screen:address:screen, console:address:console, 2:address:editor-data
]
screen-should-contain [
. .
.abc .
.def .
.g1hi .
.┈┈┈┈┈┈┈┈┈┈.
]
]
after <handle-redo> [
{
move:move-operation, is-move?:boolean <- maybe-convert *op, move:variant
break-unless is-move?
cursor-row <- get move, after-row:offset
*editor <- put *editor, cursor-row:offset, cursor-row
cursor-column <- get move, after-column:offset
*editor <- put *editor, cursor-column:offset, cursor-column
top:address:duplex-list:character <- get move, after-top-of-screen:offset
*editor <- put *editor, top-of-screen:offset, top
}
]
scenario editor-separates-undo-insert-from-undo-cursor-move [
assume-screen 10/width, 5/height
1:address:array:character <- new []
2:address:editor-data <- new-editor 1:address:array:character, screen:address:screen, 0/left, 10/right
editor-render screen, 2:address:editor-data
assume-console [
type [abc]
left-click 1, 1
type [d]
]
editor-event-loop screen:address:screen, console:address:console, 2:address:editor-data
3:number <- get *2:address:editor-data, cursor-row:offset
4:number <- get *2:address:editor-data, cursor-column:offset
screen-should-contain [
. .
.adbc .
.┈┈┈┈┈┈┈┈┈┈.
. .
]
memory-should-contain [
3 <- 1
4 <- 2
]
assume-console [
press ctrl-z
]
run [
editor-event-loop screen:address:screen, console:address:console, 2:address:editor-data
3:number <- get *2:address:editor-data, cursor-row:offset
4:number <- get *2:address:editor-data, cursor-column:offset
]
screen-should-contain [
. .
.abc .
.┈┈┈┈┈┈┈┈┈┈.
. .
]
memory-should-contain [
3 <- 1
4 <- 1
]
assume-console [
press ctrl-z
]
run [
editor-event-loop screen:address:screen, console:address:console, 2:address:editor-data
3:number <- get *2:address:editor-data, cursor-row:offset
4:number <- get *2:address:editor-data, cursor-column:offset
]
screen-should-contain [
. .
.abc .
.┈┈┈┈┈┈┈┈┈┈.
. .
]
memory-should-contain [
3 <- 1
4 <- 3
]
assume-console [
press ctrl-z
]
run [
editor-event-loop screen:address:screen, console:address:console, 2:address:editor-data
3:number <- get *2:address:editor-data, cursor-row:offset
4:number <- get *2:address:editor-data, cursor-column:offset
]
screen-should-contain [
. .
. .
.┈┈┈┈┈┈┈┈┈┈.
. .
]
memory-should-contain [
3 <- 1
4 <- 0
]
assume-console [
press ctrl-y
]
run [
editor-event-loop screen:address:screen, console:address:console, 2:address:editor-data
3:number <- get *2:address:editor-data, cursor-row:offset
4:number <- get *2:address:editor-data, cursor-column:offset
]
screen-should-contain [
. .
.abc .
.┈┈┈┈┈┈┈┈┈┈.
. .
]
memory-should-contain [
3 <- 1
4 <- 3
]
assume-console [
press ctrl-y
]
run [
editor-event-loop screen:address:screen, console:address:console, 2:address:editor-data
3:number <- get *2:address:editor-data, cursor-row:offset
4:number <- get *2:address:editor-data, cursor-column:offset
]
screen-should-contain [
. .
.abc .
.┈┈┈┈┈┈┈┈┈┈.
. .
]
memory-should-contain [
3 <- 1
4 <- 1
]
assume-console [
press ctrl-y
]
run [
editor-event-loop screen:address:screen, console:address:console, 2:address:editor-data
3:number <- get *2:address:editor-data, cursor-row:offset
4:number <- get *2:address:editor-data, cursor-column:offset
]
screen-should-contain [
. .
.adbc .
.┈┈┈┈┈┈┈┈┈┈.
. .
]
memory-should-contain [
3 <- 1
4 <- 2
]
]
scenario editor-can-undo-and-redo-backspace [
assume-screen 10/width, 5/height
1:address:array:character <- new []
2:address:editor-data <- new-editor 1:address:array:character, screen:address:screen, 0/left, 10/right
editor-render screen, 2:address:editor-data
assume-console [
type [abc]
press backspace
press backspace
]
editor-event-loop screen:address:screen, console:address:console, 2:address:editor-data
screen-should-contain [
. .
.a .
.┈┈┈┈┈┈┈┈┈┈.
. .
]
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
]
assume-console [
press ctrl-z
]
run [
editor-event-loop screen:address:screen, console:address:console, 2:address:editor-data
]
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 <- 3
]
screen-should-contain [
. .
.abc .
.┈┈┈┈┈┈┈┈┈┈.
. .
]
assume-console [
press ctrl-y
]
run [
editor-event-loop screen:address:screen, console:address:console, 2:address:editor-data
]
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
]
screen-should-contain [
. .
.a .
.┈┈┈┈┈┈┈┈┈┈.
. .
]
]
after <backspace-character-begin> [
top-before:address:duplex-list:character <- get *editor, top-of-screen:offset
]
before <backspace-character-end> [
{
break-unless backspaced-cell
top-after:address:duplex-list:character <- get *editor, top-of-screen:offset
cursor-row:number <- get *editor, cursor-row:offset
cursor-column:number <- get *editor, cursor-row:offset
before-cursor:address:duplex-list:character <- get *editor, before-cursor:offset
undo:address:list:address:operation <- get *editor, undo:offset
{
break-unless *undo
op:address:operation <- first undo
deletion:delete-operation, is-delete?:boolean <- maybe-convert *op, delete:variant
break-unless is-delete?
previous-coalesce-tag:number <- get deletion, tag:offset
coalesce?:boolean <- equal previous-coalesce-tag, 1/coalesce-backspace
break-unless coalesce?
deletion <- put deletion, delete-from:offset, before-cursor
backspaced-so-far:address:duplex-list:character <- get deletion, deleted-text:offset
insert-range backspaced-cell, backspaced-so-far
deletion <- put deletion, deleted-text:offset, backspaced-cell
deletion <- put deletion, after-row:offset, cursor-row
deletion <- put deletion, after-column:offset, cursor-column
deletion <- put deletion, after-top-of-screen:offset, top-after
*op <- merge 2/delete-operation, deletion
break +done-adding-backspace-operation:label
}
op:address:operation <- new operation:type
deleted-until:address:duplex-list:character <- next before-cursor
*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
editor <- add-operation editor, op
+done-adding-backspace-operation
}
]
after <handle-undo> [
{
deletion:delete-operation, is-delete?:boolean <- maybe-convert *op, delete:variant
break-unless is-delete?
anchor:address:duplex-list:character <- get deletion, delete-from:offset
break-unless anchor
deleted:address:duplex-list:character <- get deletion, deleted-text:offset
old-cursor:address:duplex-list:character <- last deleted
insert-range anchor, deleted
before-cursor <- copy old-cursor
cursor-row <- get deletion, before-row:offset
*editor <- put *editor, cursor-row:offset, cursor-row
cursor-column <- get deletion, before-column:offset
*editor <- put *editor, cursor-column:offset, cursor-column
top:address:duplex-list:character <- get deletion, before-top-of-screen:offset
*editor <- put *editor, top-of-screen:offset, top
}
]
after <handle-redo> [
{
deletion:delete-operation, is-delete?:boolean <- maybe-convert *op, delete:variant
break-unless is-delete?
start:address:duplex-list:character <- get deletion, delete-from:offset
end:address:duplex-list:character <- get deletion, delete-until:offset
data:address:duplex-list:character <- get *editor, data:offset
remove-between start, end
cursor-row <- get deletion, after-row:offset
*editor <- put *editor, cursor-row:offset, cursor-row
cursor-column <- get deletion, after-column:offset
*editor <- put *editor, cursor-column:offset, cursor-column
top:address:duplex-list:character <- get deletion, before-top-of-screen:offset
*editor <- put *editor, top-of-screen:offset, top
}
]
scenario editor-can-undo-and-redo-delete [
assume-screen 10/width, 5/height
1:address:array:character <- new []
2:address:editor-data <- new-editor 1:address:array:character, screen:address:screen, 0/left, 10/right
editor-render screen, 2:address:editor-data
assume-console [
type [abcdef]
left-click 1, 2
press delete
press backspace
press delete
press delete
]
editor-event-loop screen:address:screen, console:address:console, 2:address:editor-data
screen-should-contain [
. .
.af .
.┈┈┈┈┈┈┈┈┈┈.
. .
]
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
]
assume-console [
press ctrl-z
]
run [
editor-event-loop screen:address:screen, console:address:console, 2:address:editor-data
]
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
]
screen-should-contain [
. .
.adef .
.┈┈┈┈┈┈┈┈┈┈.
. .
]
assume-console [
press ctrl-z
]
run [
editor-event-loop screen:address:screen, console:address:console, 2:address:editor-data
]
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
]
screen-should-contain [
. .
.abdef .
.┈┈┈┈┈┈┈┈┈┈.
. .
]
assume-console [
press ctrl-z
]
run [
editor-event-loop screen:address:screen, console:address:console, 2:address:editor-data
]
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
]
screen-should-contain [
. .
.abcdef .
.┈┈┈┈┈┈┈┈┈┈.
. .
]
assume-console [
press ctrl-y
]
run [
editor-event-loop screen:address:screen, console:address:console, 2:address:editor-data
]
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
]
screen-should-contain [
. .
.abdef .
.┈┈┈┈┈┈┈┈┈┈.
. .
]
assume-console [
press ctrl-y
]
run [
editor-event-loop screen:address:screen, console:address:console, 2:address:editor-data
]
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
]
screen-should-contain [
. .
.adef .
.┈┈┈┈┈┈┈┈┈┈.
. .
]
assume-console [
press ctrl-y
]
run [
editor-event-loop screen:address:screen, console:address:console, 2:address:editor-data
]
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
]
screen-should-contain [
. .
.af .
.┈┈┈┈┈┈┈┈┈┈.
. .
]
]
after <delete-character-begin> [
top-before:address:duplex-list:character <- get *editor, top-of-screen:offset
]
before <delete-character-end> [
{
break-unless deleted-cell
top-after:address:duplex-list:character <- get *editor, top-of-screen:offset
cursor-row:number <- get *editor, cursor-row:offset
cursor-column:number <- get *editor, cursor-column:offset
before-cursor:address:duplex-list:character <- get *editor, before-cursor:offset
undo:address:list:address:operation <- get *editor, undo:offset
{
break-unless undo
op:address:operation <- first undo
deletion:delete-operation, is-delete?:boolean <- maybe-convert *op, delete:variant
break-unless is-delete?
previous-coalesce-tag:number <- get deletion, tag:offset
coalesce?:boolean <- equal previous-coalesce-tag, 2/coalesce-delete
break-unless coalesce?
delete-until:address:duplex-list:character <- next before-cursor
deletion <- put deletion, delete-until:offset, delete-until
deleted-so-far:address:duplex-list:character <- get deletion, deleted-text:offset
deleted-so-far <- append deleted-so-far, deleted-cell
deletion <- put deletion, deleted-text:offset, deleted-so-far
deletion <- put deletion, after-row:offset, cursor-row
deletion <- put deletion, after-column:offset, cursor-column
deletion <- put deletion, after-top-of-screen:offset, top-after
*op <- merge 2/delete-operation, deletion
break +done-adding-delete-operation:label
}
op:address:operation <- new operation:type
deleted-until:address:duplex-list:character <- next before-cursor
*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
editor <- add-operation editor, op
+done-adding-delete-operation
}
]
scenario editor-can-undo-and-redo-ctrl-k [
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:screen, 0/left, 10/right
editor-render screen, 2:address:editor-data
assume-console [
left-click 1, 1
press ctrl-k
]
editor-event-loop screen:address:screen, console:address:console, 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
]
assume-console [
press ctrl-z
]
run [
editor-event-loop screen:address:screen, console:address:console, 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
]
assume-console [
press ctrl-y
]
run [
editor-event-loop screen:address:screen, console:address:console, 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
]
assume-console [
type [1]
]
run [
editor-event-loop screen:address:screen, console:address:console, 2:address:editor-data
]
screen-should-contain [
. .
.a1 .
.def .
.┈┈┈┈┈┈┈┈┈┈.
. .
]
]
after <delete-to-end-of-line-begin> [
top-before:address:duplex-list:character <- get *editor, top-of-screen:offset
]
before <delete-to-end-of-line-end> [
{
break-unless deleted-cells
top-after:address:duplex-list:character <- get *editor, top-of-screen:offset
cursor-row:number <- get *editor, cursor-row:offset
cursor-column:number <- get *editor, cursor-column:offset
deleted-until:address:duplex-list:character <- next before-cursor
op:address:operation <- new operation:type
*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
}
]
scenario editor-can-undo-and-redo-ctrl-u [
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:screen, 0/left, 10/right
editor-render screen, 2:address:editor-data
assume-console [
left-click 1, 2
press ctrl-u
]
editor-event-loop screen:address:screen, console:address:console, 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
]
assume-console [
press ctrl-z
]
run [
editor-event-loop screen:address:screen, console:address:console, 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
]
assume-console [
press ctrl-y
]
run [
editor-event-loop screen:address:screen, console:address:console, 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
]
assume-console [
type [1]
]
run [
editor-event-loop screen:address:screen, console:address:console, 2:address:editor-data
]
screen-should-contain [
. .
.1c .
.def .
.┈┈┈┈┈┈┈┈┈┈.
. .
]
]
after <delete-to-start-of-line-begin> [
top-before:address:duplex-list:character <- get *editor, top-of-screen:offset
]
before <delete-to-start-of-line-end> [
{
break-unless deleted-cells
top-after:address:duplex-list:character <- get *editor, top-of-screen:offset
op:address:operation <- new operation:type
before-cursor:address:duplex-list:character <- get *editor, before-cursor:offset
deleted-until:address:duplex-list:character <- next before-cursor
cursor-row:number <- get *editor, cursor-row:offset
cursor-column:number <- get *editor, cursor-column:offset
*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
}
]
scenario editor-can-undo-and-redo-ctrl-u-2 [
assume-screen 10/width, 5/height
1:address:array:character <- new []
2:address:editor-data <- new-editor 1:address:array:character, screen:address:screen, 0/left, 10/right
editor-render screen, 2:address:editor-data
assume-console [
type [abc]
press ctrl-u
press ctrl-z
]
editor-event-loop screen:address:screen, console:address:console, 2:address:editor-data
screen-should-contain [
. .
.abc .
.┈┈┈┈┈┈┈┈┈┈.
. .
]
]