mu/baremetal/shell/line.mu

235 lines
7.7 KiB
Forth

type line {
name: (handle array byte)
data: (handle word)
cursor: (handle word)
next: (handle line)
prev: (handle line)
}
# initialize line with a single empty word
fn initialize-line _line: (addr line) {
var line/esi: (addr line) <- copy _line
var word-ah/eax: (addr handle word) <- get line, data
allocate word-ah
var cursor-ah/ecx: (addr handle word) <- get line, cursor
copy-object word-ah, cursor-ah
var word/eax: (addr word) <- lookup *word-ah
initialize-word word
}
fn num-words-in-line _in: (addr line) -> _/eax: int {
var in/esi: (addr line) <- copy _in
var curr-ah/ecx: (addr handle word) <- get in, data
var result/edi: int <- copy 0
{
var curr/eax: (addr word) <- lookup *curr-ah
compare curr, 0
break-if-=
curr-ah <- get curr, next
result <- increment
loop
}
return result
}
fn line-list-length lines: (addr handle line) -> _/eax: int {
var curr-ah/esi: (addr handle line) <- copy lines
var result/edi: int <- copy 0
{
var curr/eax: (addr line) <- lookup *curr-ah
compare curr, 0
break-if-=
curr-ah <- get curr, next
result <- increment
loop
}
return result
}
fn render-line screen: (addr screen), _line: (addr line), x: int, y: int, render-cursor?: boolean -> _/eax: int {
var line/eax: (addr line) <- copy _line
var first-word-ah/esi: (addr handle word) <- get line, data
# cursor-word
var cursor-word/edi: int <- copy 0
compare render-cursor?, 0/false
{
break-if-=
var cursor-word-ah/eax: (addr handle word) <- get line, cursor
var _cursor-word/eax: (addr word) <- lookup *cursor-word-ah
cursor-word <- copy _cursor-word
}
#
var result/eax: int <- render-words screen, first-word-ah, x, y, cursor-word
return result
}
fn parse-line in: (addr array byte), _out: (addr line) {
var out/edi: (addr line) <- copy _out
initialize-line out
var dest/eax: (addr handle word) <- get out, data
parse-words in, dest
}
#? fn main {
#? # line = [aaa, bbb, ccc, ddd]
#? var line-storage: line
#? var w-ah/eax: (addr handle word) <- get line-storage, data
#? allocate-word-with w-ah, "aaa"
#? append-word-at-end-with w-ah, "bbb"
#? append-word-at-end-with w-ah, "ccc"
#? append-word-at-end-with w-ah, "ddd"
#? var cursor-ah/ecx: (addr handle word) <- get line-storage, cursor
#? var w/eax: (addr word) <- lookup *w-ah
#? var next-ah/eax: (addr handle word) <- get w, next
#? copy-object next-ah, cursor-ah
#? var line-addr/eax: (addr line) <- address line-storage
#? var dummy/eax: int <- render-line 0/screen, line-addr, 0/x, 0/y, 1/render-cursor
#? }
fn render-line-with-stack screen: (addr screen), _line: (addr line), x: int, y: int, render-cursor?: boolean -> _/eax: int, _/ecx: int {
var line/esi: (addr line) <- copy _line
# cursor-word
var cursor-word/edi: int <- copy 0
compare render-cursor?, 0/false
{
break-if-=
var cursor-word-ah/eax: (addr handle word) <- get line, cursor
var _cursor-word/eax: (addr word) <- lookup *cursor-word-ah
cursor-word <- copy _cursor-word
}
#
var curr-word-ah/eax: (addr handle word) <- get line, data
var _curr-word/eax: (addr word) <- lookup *curr-word-ah
var curr-word/edx: (addr word) <- copy _curr-word
var new-x/eax: int <- copy x # increases each iteration
var new-y/ebx: int <- copy y # compute max across all iterations
{
compare curr-word, 0
break-if-=
var curr-y/ecx: int <- copy 0
new-x, curr-y <- render-word-with-stack-and-cursor screen, line, curr-word, new-x, y, cursor-word
compare curr-y, new-y
{
break-if-<=
new-y <- copy curr-y
}
new-x <- add 1/inter-word-spacing
# update
var next-word-ah/eax: (addr handle word) <- get curr-word, next
var next-word/eax: (addr word) <- lookup *next-word-ah
curr-word <- copy next-word
loop
}
return new-x, new-y
}
fn render-word-with-stack-and-cursor screen: (addr screen), line: (addr line), curr-word: (addr word), x: int, y: int, _cursor-word-addr: int -> _/eax: int, _/ecx: int {
# print curr-word, with cursor if necessary
var render-cursor?/eax: boolean <- copy 0/false
var cursor-word-addr/ecx: int <- copy _cursor-word-addr
{
compare cursor-word-addr, curr-word
break-if-!=
render-cursor? <- copy 1/true
}
var new-x/eax: int <- render-word screen, curr-word, x, y, render-cursor?
add-to x, 1/word-stack-indent
var new-x-saved/edx: int <- copy new-x
add-to y, 2/word-stack-spacing
# compute stack until word
var stack-storage: value-stack
var stack/edi: (addr value-stack) <- address stack-storage
evaluate line, curr-word, stack
# render stack
var new-y/ecx: int <- copy 0
new-x, new-y <- render-value-stack screen, stack, x, y
#? draw-int32-decimal-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, new-x, 0xc/fg, 0/bg
#? draw-int32-decimal-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, new-y, 3/fg, 0/bg
compare new-x, new-x-saved
{
break-if->=
new-x <- copy new-x-saved
}
#? draw-int32-decimal-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, new-x, 7/fg, 0/bg
return new-x, new-y
}
fn test-render-line-with-stack-singleton {
# line = [1]
var line-storage: line
var line/esi: (addr line) <- address line-storage
parse-line "1", line
# setup: screen
var screen-on-stack: screen
var screen/edi: (addr screen) <- address screen-on-stack
initialize-screen screen, 0x20, 4
#
var new-x/eax: int <- copy 0
var new-y/ecx: int <- copy 0
new-x, new-y <- render-line-with-stack screen, line, 0/x, 0/y, 0/no-cursor
check-screen-row screen, 0/y, "1 ", "F - test-render-line-with-stack-singleton/0"
check-screen-row screen, 1/y, " ", "F - test-render-line-with-stack-singleton/1"
# ___
check-screen-row screen, 2/y, " 1 ", "F - test-render-line-with-stack-singleton/2"
# not bothering to test hash colors for numbers
}
fn test-render-line-with-stack {
# line = [1 2]
var line-storage: line
var line/esi: (addr line) <- address line-storage
parse-line "1 2", line
# setup: screen
var screen-on-stack: screen
var screen/edi: (addr screen) <- address screen-on-stack
initialize-screen screen, 0x20, 4
#
var new-x/eax: int <- copy 0
var new-y/ecx: int <- copy 0
new-x, new-y <- render-line-with-stack screen, line, 0/x, 0/y, 0/no-cursor
check-screen-row screen, 0/y, "1 2 ", "F - test-render-line-with-stack/0"
check-screen-row screen, 1/y, " ", "F - test-render-line-with-stack/1"
# ___ ___
check-screen-row screen, 2/y, " 1 2 ", "F - test-render-line-with-stack/2"
check-screen-row screen, 3/y, " 1 ", "F - test-render-line-with-stack/3"
# not bothering to test hash colors for numbers
}
fn edit-line _self: (addr line), key: byte {
var self/esi: (addr line) <- copy _self
var cursor-word-ah/edx: (addr handle word) <- get self, cursor
var _cursor-word/eax: (addr word) <- lookup *cursor-word-ah
var cursor-word/ecx: (addr word) <- copy _cursor-word
compare key, 0x20/space
$edit-line:space: {
break-if-!=
append-word cursor-word-ah
var next-word-ah/eax: (addr handle word) <- get cursor-word, next
copy-object next-word-ah, cursor-word-ah
return
}
# otherwise insert key within current word
var g/edx: grapheme <- copy key
add-grapheme-to-word cursor-word, g
# silently ignore other hotkeys
}
fn main {
var line-storage: line
var line/esi: (addr line) <- address line-storage
initialize-line line
{
clear-screen 0/screen
var dummy1/eax: int <- copy 0
var dummy2/ecx: int <- copy 0
dummy1, dummy2 <- render-line-with-stack 0/screen, line, 2/x, 2/y, 1/show-cursor
{
var key/eax: byte <- read-key 0/keyboard
compare key, 0
loop-if-=
edit-line line, key
}
loop
}
}