recipe main [
default-space:address:array:location <- new location:type, 30:literal
open-console
width:number <- display-width
height:number <- display-height
divider:number, _ <- divide-with-remainder width:number, 2:literal
draw-vertical 0:literal/screen, divider:number, 0:literal/top, height:number
in:address:array:character <- new [abcdef
def
ghi
jkl
]
editor:address:editor-data <- new-editor in:address:array:character, 0:literal/screen, 0:literal/top, 0:literal/left, divider:number/right
event-loop 0:literal/screen, 0:literal/events, editor:address:editor-data
close-console
]
scenario editor-initially-prints-string-to-screen [
assume-screen 10:literal/width, 5:literal/height
run [
s:address:array:character <- new [abc]
new-editor s:address:array:character, screen:address, 0:literal/top, 0:literal/left, 5:literal/right
]
screen-should-contain [
.abc .
. .
]
]
container editor-data [
data:address:duplex-list
top-of-screen:address:duplex-list
cursor:address:duplex-list
screen:address:screen
top:number
left:number
bottom:number
right:number
cursor-row:number
cursor-column:number
]
recipe new-editor [
default-space:address:array:location <- new location:type, 30:literal
s:address:array:character <- next-ingredient
screen:address <- next-ingredient
top:number <- next-ingredient
left:number <- next-ingredient
right:number <- next-ingredient
right:number <- subtract right:number, 1:literal
result:address:editor-data <- new editor-data:type
sc:address:address:screen <- get-address result:address:editor-data/deref, screen:offset
sc:address:address:screen/deref <- copy screen:address
x:address:number <- get-address result:address:editor-data/deref, top:offset
x:address:number/deref <- copy top:number
x:address:number <- get-address result:address:editor-data/deref, left:offset
x:address:number/deref <- copy left:number
x:address:number <- get-address result:address:editor-data/deref, right:offset
x:address:number/deref <- copy right:number
x:address:number <- get-address result:address:editor-data/deref, bottom:offset
x:address:number/deref <- copy top:number
x:address:number <- get-address result:address:editor-data/deref, cursor-row:offset
x:address:number/deref <- copy top:number
x:address:number <- get-address result:address:editor-data/deref, cursor-column:offset
x:address:number/deref <- copy left:number
reply-unless s:address:array:character, result:address:editor-data
len:number <- length s:address:array:character/deref
reply-unless len:number, result:address:editor-data
idx:number <- copy 0:literal
init:address:address:duplex-list <- get-address result:address:editor-data/deref, top-of-screen:offset
init:address:address:duplex-list/deref <- copy 0:literal
c:character <- index s:address:array:character/deref, idx:number
idx:number <- add idx:number, 1:literal
init:address:address:duplex-list/deref <- push c:character, init:address:address:duplex-list/deref
curr:address:duplex-list <- copy init:address:address:duplex-list/deref
{
done?:boolean <- greater-or-equal idx:number, len:number
break-if done?:boolean
c:character <- index s:address:array:character/deref, idx:number
insert-duplex c:character, curr:address:duplex-list
curr:address:duplex-list <- next-duplex curr:address:duplex-list
idx:number <- add idx:number, 1:literal
loop
}
y:address:address:duplex-list <- get-address result:address:editor-data/deref, cursor:offset
y:address:address:duplex-list/deref <- copy init:address:address:duplex-list/deref
bottom:address:number <- get-address result:address:editor-data/deref, bottom:offset
bottom:address:number/deref, screen:address <- render result:address:editor-data, screen:address, top:number, left:number, right:number
reply result:address:editor-data
]
scenario editor-initializes-without-data [
assume-screen 5:literal/width, 3:literal/height
run [
1:address:editor-data <- new-editor 0:literal/data, screen:address, 1:literal/top, 2:literal/left, 5:literal/right
2:editor-data <- copy 1:address:editor-data/deref
]
memory-should-contain [
2 <- 0
3 <- 0
4 <- 0
6 <- 1
7 <- 2
8 <- 1
9 <- 4
10 <- 1
11 <- 2
]
screen-should-contain [
. .
. .
. .
]
]
recipe render [
default-space:address:array:location <- new location:type, 30:literal
editor:address:editor-data <- next-ingredient
screen:address <- next-ingredient
top:number <- next-ingredient
left:number <- next-ingredient
screen-height:number <- screen-height screen:address
right:number <- next-ingredient
cursor:address:duplex-list <- get editor:address:editor-data/deref, cursor:offset
curr:address:duplex-list <- get editor:address:editor-data/deref, top-of-screen:offset
row:number <- copy top:number
column:number <- copy left:number
move-cursor screen:address, row:number, column:number
{
+next-character
break-unless curr:address:duplex-list
off-screen?:boolean <- greater-or-equal row:number, screen-height:number
break-if off-screen?:boolean