diff options
Diffstat (limited to 'prototypes')
-rw-r--r-- | prototypes/README.md | 23 | ||||
-rw-r--r-- | prototypes/browse/1-print-file.mu | 32 | ||||
-rw-r--r-- | prototypes/browse/10.mu | 176 | ||||
-rw-r--r-- | prototypes/browse/11.mu | 172 | ||||
-rw-r--r-- | prototypes/browse/12.mu | 175 | ||||
-rw-r--r-- | prototypes/browse/13.mu | 176 | ||||
-rw-r--r-- | prototypes/browse/14.mu | 174 | ||||
-rw-r--r-- | prototypes/browse/15-headers-broken.mu | 216 | ||||
-rw-r--r-- | prototypes/browse/16-screen-state-broken.mu | 188 | ||||
-rw-r--r-- | prototypes/browse/17-file-state-broken/README.md | 7 | ||||
-rw-r--r-- | prototypes/browse/17-file-state-broken/file-state.mu | 33 | ||||
-rw-r--r-- | prototypes/browse/17-file-state-broken/main.mu | 106 | ||||
-rw-r--r-- | prototypes/browse/17-file-state-broken/screen-position-state.mu | 50 | ||||
-rw-r--r-- | prototypes/browse/2.mu | 31 | ||||
-rw-r--r-- | prototypes/browse/3.mu | 29 | ||||
-rw-r--r-- | prototypes/browse/4-render-page.mu | 81 | ||||
-rw-r--r-- | prototypes/browse/5.mu | 83 | ||||
-rw-r--r-- | prototypes/browse/6.mu | 94 | ||||
-rw-r--r-- | prototypes/browse/7.mu | 99 | ||||
-rw-r--r-- | prototypes/browse/8-multiple-pages.mu | 115 | ||||
-rw-r--r-- | prototypes/browse/9-bold.mu | 152 | ||||
-rw-r--r-- | prototypes/browse/README.md | 8 |
22 files changed, 2220 insertions, 0 deletions
diff --git a/prototypes/README.md b/prototypes/README.md new file mode 100644 index 00000000..28d3b298 --- /dev/null +++ b/prototypes/README.md @@ -0,0 +1,23 @@ +# Prototypes + +Each directory here is a series of prototypes for a single app. + +To build prototype #n of app X under this directory: + +``` +$ ./translate_mu prototypes/__X__/__n__.mu +``` + +Now try running it with some text file: + +``` +$ ./a.elf __text_file__ +``` + +Sub-directories are prototypes with multiple files. Build them like this: + +``` +$ ./translate_mu prototypes/__X__/__n__/*.mu +``` + +Run them as before. diff --git a/prototypes/browse/1-print-file.mu b/prototypes/browse/1-print-file.mu new file mode 100644 index 00000000..ea441572 --- /dev/null +++ b/prototypes/browse/1-print-file.mu @@ -0,0 +1,32 @@ +fn main args: (addr array (addr array byte)) -> exit-status/ebx: int { + var filename/eax: (addr array byte) <- first-arg args + var file/ecx: (addr buffered-file) <- load-file filename + dump file + exit-status <- copy 0 +} + +fn first-arg args-on-stack: (addr array (addr array byte)) -> out/eax: (addr array byte) { + var args/eax: (addr array (addr array byte)) <- copy args-on-stack + var result/eax: (addr addr array byte) <- index args, 1 + out <- copy *result +} + +fn load-file filename: (addr array byte) -> out/ecx: (addr buffered-file) { + var result: (handle buffered-file) + { + var tmp1/eax: (addr handle buffered-file) <- address result + open filename, 0, tmp1 + } + var tmp2/eax: (addr buffered-file) <- lookup result + out <- copy tmp2 +} + +fn dump in: (addr buffered-file) { + { + var c/eax: byte <- read-byte-buffered in + compare c, 0xffffffff # EOF marker + break-if-= + print-byte c + loop + } +} diff --git a/prototypes/browse/10.mu b/prototypes/browse/10.mu new file mode 100644 index 00000000..4e79aa65 --- /dev/null +++ b/prototypes/browse/10.mu @@ -0,0 +1,176 @@ +# We're not going to render italics since they still feel like an advanced +# feature for terminals, and since they often look weird to my eyes on the +# monospace font of a terminal window. So underscores and asterisks will both +# be bold. + +fn main args: (addr array (addr array byte)) -> exit-status/ebx: int { + var filename/eax: (addr array byte) <- first-arg args + var file/esi: (addr buffered-file) <- load-file filename + enable-screen-grid-mode + var nrows/eax: int <- copy 0 + var ncols/ecx: int <- copy 0 + nrows, ncols <- screen-size + enable-keyboard-immediate-mode + { + render file, nrows, ncols + var key/eax: byte <- read-key + compare key, 0x71 # 'q' + loop-if-!= + } + enable-keyboard-type-mode + enable-screen-type-mode + exit-status <- copy 0 +} + +type render-state { + current-state: int # enum 0: normal, 1: bold +} + +# decide how to lay out pages on screen +fn render in: (addr buffered-file), nrows: int, ncols: int { + # Fit multiple pages on screen on separate columns, each wide enough to read + # comfortably. + # Pages are separated horizontally by a 'page margin'. Among other reasons, + # this allows the odd line to bleed out on the right if necessary. + # + # hardcoded parameters: + # top-margin + # page-margin + # text-width + var _r: render-state + var r/edi: (addr render-state) <- address _r + var toprow/eax: int <- copy 2 # top-margin + var botrow/ecx: int <- copy nrows + var leftcol/edx: int <- copy 5 # page-margin + var rightcol/ebx: int <- copy leftcol + rightcol <- add 0x40 # text-width = 64 characters + start-color 0xec, 7 # 236 = darkish gray + { + compare rightcol, ncols + break-if->= + render-page in, toprow, leftcol, botrow, rightcol, r + leftcol <- copy rightcol + leftcol <- add 5 # page-margin + rightcol <- copy leftcol + rightcol <- add 0x40 # text-width + loop + } +} + +fn render-page in: (addr buffered-file), toprow: int, leftcol: int, botrow: int, rightcol: int, r: (addr render-state) { + clear toprow, leftcol, botrow, rightcol + var row/ecx: int <- copy toprow +$line-loop: { + compare row, botrow + break-if->= + var col/edx: int <- copy leftcol + move-cursor row, col + { + compare col, rightcol + break-if->= + var c/eax: byte <- read-byte-buffered in + compare c, 0xffffffff # EOF marker + break-if-= $line-loop + update-attributes c, r + compare c, 0xa # newline + break-if-= # no need to print newlines + # print c + print-byte c + col <- increment + loop + } # $char-loop + row <- increment + loop + } # $line-loop +} + +fn update-attributes c: byte, _r: (addr render-state) { + var r/edi: (addr render-state) <- copy _r + var state/esi: (addr int) <- get r, current-state +$check-state: { + compare *state, 0 # normal + { + break-if-!= + compare c, 0x2a # '*' + { + break-if-!= + # r->current-state == 0 && c == '*' => bold text + start-bold + copy-to *state, 1 + break $check-state + } + compare c, 0x5f # '_' + { + break-if-!= + # r->current-state == 0 && c == '_' => bold text + start-bold + copy-to *state, 1 + break $check-state + } + break $check-state + } + { + break-if-= + compare c, 0x2a # '*' + { + break-if-!= + # r->current-state == 1 && c == '*' => normal text + reset-formatting + copy-to *state, 0 + break $check-state + } + compare c, 0x5f # '_' + { + break-if-!= + # r->current-state == 1 && c == '_' => normal text + reset-formatting + copy-to *state, 0 + break $check-state + } + break $check-state + } + } # $check-state +} + +fn clear toprow: int, leftcol: int, botrow: int, rightcol: int { + var row/ecx: int <- copy toprow + { + compare row, botrow + break-if->= + var col/edx: int <- copy leftcol + move-cursor row, col + { + compare col, rightcol + break-if->= + print-string " " + col <- increment + loop + } + row <- increment + loop + } +} + +fn first-arg args-on-stack: (addr array (addr array byte)) -> out/eax: (addr array byte) { + var args/eax: (addr array (addr array byte)) <- copy args-on-stack + var result/eax: (addr addr array byte) <- index args, 1 + out <- copy *result +} + +fn load-file filename: (addr array byte) -> out/esi: (addr buffered-file) { + var result: (handle buffered-file) + { + var tmp1/eax: (addr handle buffered-file) <- address result + open filename, 0, tmp1 + } + var tmp2/eax: (addr buffered-file) <- lookup result + out <- copy tmp2 +} + +fn dump in: (addr buffered-file) { + var c/eax: byte <- read-byte-buffered in + compare c, 0xffffffff # EOF marker + break-if-= + print-byte c + loop +} diff --git a/prototypes/browse/11.mu b/prototypes/browse/11.mu new file mode 100644 index 00000000..19a65353 --- /dev/null +++ b/prototypes/browse/11.mu @@ -0,0 +1,172 @@ +# The current organization doesn't really work for the next feature (section +# headings) so let's inline attribute-handling. + +fn main args: (addr array (addr array byte)) -> exit-status/ebx: int { + var filename/eax: (addr array byte) <- first-arg args + var file/esi: (addr buffered-file) <- load-file filename + enable-screen-grid-mode + var nrows/eax: int <- copy 0 + var ncols/ecx: int <- copy 0 + nrows, ncols <- screen-size + enable-keyboard-immediate-mode + { + render file, nrows, ncols + var key/eax: byte <- read-key + compare key, 0x71 # 'q' + loop-if-!= + } + enable-keyboard-type-mode + enable-screen-type-mode + exit-status <- copy 0 +} + +type render-state { + current-state: int # enum 0: normal, 1: bold +} + +# decide how to lay out pages on screen +fn render in: (addr buffered-file), nrows: int, ncols: int { + # Fit multiple pages on screen on separate columns, each wide enough to read + # comfortably. + # Pages are separated horizontally by a 'page margin'. Among other reasons, + # this allows the odd line to bleed out on the right if necessary. + # + # hardcoded parameters: + # top-margin + # page-margin + # text-width + var _r: render-state + var r/edi: (addr render-state) <- address _r + var toprow/eax: int <- copy 2 # top-margin + var botrow/ecx: int <- copy nrows + var leftcol/edx: int <- copy 5 # page-margin + var rightcol/ebx: int <- copy leftcol + rightcol <- add 0x40 # text-width = 64 characters + start-color 0xec, 7 # 236 = darkish gray + { + compare rightcol, ncols + break-if->= + render-page in, toprow, leftcol, botrow, rightcol, r + leftcol <- copy rightcol + leftcol <- add 5 # page-margin + rightcol <- copy leftcol + rightcol <- add 0x40 # text-width + loop + } +} + +fn render-page in: (addr buffered-file), toprow: int, leftcol: int, botrow: int, rightcol: int, _r: (addr render-state) { + var r/edi: (addr render-state) <- copy _r + var state/esi: (addr int) <- get r, current-state + clear toprow, leftcol, botrow, rightcol + var row/ecx: int <- copy toprow +$line-loop: { + compare row, botrow + break-if->= + var col/edx: int <- copy leftcol + move-cursor row, col +$char-loop: { + compare col, rightcol + break-if->= + var c/eax: byte <- read-byte-buffered in + compare c, 0xffffffff # EOF marker + break-if-= $line-loop +$update-attributes:check-state: { + compare *state, 0 # normal + { + break-if-!= + compare c, 0x2a # '*' + { + break-if-!= + # r->current-state == 0 && c == '*' => bold text + start-bold + copy-to *state, 1 + break $update-attributes:check-state + } + compare c, 0x5f # '_' + { + break-if-!= + # r->current-state == 0 && c == '_' => bold text + start-bold + copy-to *state, 1 + break $update-attributes:check-state + } + break $update-attributes:check-state + } + { + break-if-= + compare c, 0x2a # '*' + { + break-if-!= + # r->current-state == 1 && c == '*' => normal text + reset-formatting + start-color 0xec, 7 # 236 = darkish gray + copy-to *state, 0 + break $update-attributes:check-state + } + compare c, 0x5f # '_' + { + break-if-!= + # r->current-state == 1 && c == '_' => normal text + reset-formatting + start-color 0xec, 7 # 236 = darkish gray + copy-to *state, 0 + break $update-attributes:check-state + } + break $update-attributes:check-state + } + } # $change-state + compare c, 0xa # newline + break-if-= # no need to print newlines + # print c + print-byte c + col <- increment + loop + } # $char-loop + row <- increment + loop + } # $line-loop +} + +fn clear toprow: int, leftcol: int, botrow: int, rightcol: int { + var row/ecx: int <- copy toprow + { + compare row, botrow + break-if->= + var col/edx: int <- copy leftcol + move-cursor row, col + { + compare col, rightcol + break-if->= + print-string " " + col <- increment + loop + } + row <- increment + loop + } +} + +fn first-arg args-on-stack: (addr array (addr array byte)) -> out/eax: (addr array byte) { + var args/eax: (addr array (addr array byte)) <- copy args-on-stack + var result/eax: (addr addr array byte) <- index args, 1 + out <- copy *result +} + +fn load-file filename: (addr array byte) -> out/esi: (addr buffered-file) { + var result: (handle buffered-file) + { + var tmp1/eax: (addr handle buffered-file) <- address result + open filename, 0, tmp1 + } + var tmp2/eax: (addr buffered-file) <- lookup result + out <- copy tmp2 +} + +fn dump in: (addr buffered-file) { + var c/eax: byte <- read-byte-buffered in + compare c, 0xffffffff # EOF marker + break-if-= + print-byte c + loop +} diff --git a/prototypes/browse/12.mu b/prototypes/browse/12.mu new file mode 100644 index 00000000..e2f0a9c8 --- /dev/null +++ b/prototypes/browse/12.mu @@ -0,0 +1,175 @@ +# Now the trailing asterisk or underscore renders correctly, for starters. + +fn main args: (addr array (addr array byte)) -> exit-status/ebx: int { + var filename/eax: (addr array byte) <- first-arg args + var file/esi: (addr buffered-file) <- load-file filename + enable-screen-grid-mode + var nrows/eax: int <- copy 0 + var ncols/ecx: int <- copy 0 + nrows, ncols <- screen-size + enable-keyboard-immediate-mode + { + render file, nrows, ncols + var key/eax: byte <- read-key + compare key, 0x71 # 'q' + loop-if-!= + } + enable-keyboard-type-mode + enable-screen-type-mode + exit-status <- copy 0 +} + +type render-state { + current-state: int # enum 0: normal, 1: bold +} + +# decide how to lay out pages on screen +fn render in: (addr buffered-file), nrows: int, ncols: int { + # Fit multiple pages on screen on separate columns, each wide enough to read + # comfortably. + # Pages are separated horizontally by a 'page margin'. Among other reasons, + # this allows the odd line to bleed out on the right if necessary. + # + # hardcoded parameters: + # top-margin + # page-margin + # text-width + var _r: render-state + var r/edi: (addr render-state) <- address _r + var toprow/eax: int <- copy 2 # top-margin + var botrow/ecx: int <- copy nrows + var leftcol/edx: int <- copy 5 # page-margin + var rightcol/ebx: int <- copy leftcol + rightcol <- add 0x40 # text-width = 64 characters + start-color 0xec, 7 # 236 = darkish gray + { + compare rightcol, ncols + break-if->= + render-page in, toprow, leftcol, botrow, rightcol, r + leftcol <- copy rightcol + leftcol <- add 5 # page-margin + rightcol <- copy leftcol + rightcol <- add 0x40 # text-width + loop + } +} + +fn render-page in: (addr buffered-file), toprow: int, leftcol: int, botrow: int, rightcol: int, _r: (addr render-state) { + var r/edi: (addr render-state) <- copy _r + var state/esi: (addr int) <- get r, current-state + clear toprow, leftcol, botrow, rightcol + var row/ecx: int <- copy toprow +$line-loop: { + compare row, botrow + break-if->= + var col/edx: int <- copy leftcol + move-cursor row, col +$char-loop: { + compare col, rightcol + break-if->= + var c/eax: byte <- read-byte-buffered in + compare c, 0xffffffff # EOF marker + break-if-= $line-loop +$update-attributes:check-state: { + compare *state, 0 # normal + { + break-if-!= + compare c, 0x2a # '*' + { + break-if-!= + # r->current-state == 0 && c == '*' => bold text + start-bold + copy-to *state, 1 + break $update-attributes:check-state + } + compare c, 0x5f # '_' + { + break-if-!= + # r->current-state == 0 && c == '_' => bold text + start-bold + copy-to *state, 1 + break $update-attributes:check-state + } + break $update-attributes:check-state + } + { + break-if-= + compare c, 0x2a # '*' + { + break-if-!= + # r->current-state == 1 && c == '*' => print c, then normal text + print-byte c + col <- increment + reset-formatting + start-color 0xec, 7 # 236 = darkish gray + copy-to *state, 0 + loop $char-loop + } + compare c, 0x5f # '_' + { + break-if-!= + # r->current-state == 1 && c == '_' => print c, then normal text + print-byte c + col <- increment + reset-formatting + start-color 0xec, 7 # 236 = darkish gray + copy-to *state, 0 + loop $char-loop + } + break $update-attributes:check-state + } + } # $change-state + compare c, 0xa # newline + break-if-= # no need to print newlines + # print c + print-byte c + col <- increment + loop + } # $char-loop + row <- increment + loop + } # $line-loop +} + +fn clear toprow: int, leftcol: int, botrow: int, rightcol: int { + var row/ecx: int <- copy toprow + { + compare row, botrow + break-if->= + var col/edx: int <- copy leftcol + move-cursor row, col + { + compare col, rightcol + break-if->= + print-string " " + col <- increment + loop + } + row <- increment + loop + } +} + +fn first-arg args-on-stack: (addr array (addr array byte)) -> out/eax: (addr array byte) { + var args/eax: (addr array (addr array byte)) <- copy args-on-stack + var result/eax: (addr addr array byte) <- index args, 1 + out <- copy *result +} + +fn load-file filename: (addr array byte) -> out/esi: (addr buffered-file) { + var result: (handle buffered-file) + { + var tmp1/eax: (addr handle buffered-file) <- address result + open filename, 0, tmp1 + } + var tmp2/eax: (addr buffered-file) <- lookup result + out <- copy tmp2 +} + +fn dump in: (addr buffered-file) { + var c/eax: byte <- read-byte-buffered in + compare c, 0xffffffff # EOF marker + break-if-= + print-byte c + loop +} diff --git a/prototypes/browse/13.mu b/prototypes/browse/13.mu new file mode 100644 index 00000000..22a5c0d7 --- /dev/null +++ b/prototypes/browse/13.mu @@ -0,0 +1,176 @@ +# Support more than two states. + +fn main args: (addr array (addr array byte)) -> exit-status/ebx: int { + var filename/eax: (addr array byte) <- first-arg args + var file/esi: (addr buffered-file) <- load-file filename + enable-screen-grid-mode + var nrows/eax: int <- copy 0 + var ncols/ecx: int <- copy 0 + nrows, ncols <- screen-size + enable-keyboard-immediate-mode + { + render file, nrows, ncols + var key/eax: byte <- read-key + compare key, 0x71 # 'q' + loop-if-!= + } + enable-keyboard-type-mode + enable-screen-type-mode + exit-status <- copy 0 +} + +type render-state { + current-state: int # enum 0: normal, 1: bold, 2: heading +} + +# decide how to lay out pages on screen +fn render in: (addr buffered-file), nrows: int, ncols: int { + # Fit multiple pages on screen on separate columns, each wide enough to read + # comfortably. + # Pages are separated horizontally by a 'page margin'. Among other reasons, + # this allows the odd line to bleed out on the right if necessary. + # + # hardcoded parameters: + # top-margin + # page-margin + # text-width + var _r: render-state + var r/edi: (addr render-state) <- address _r + var toprow/eax: int <- copy 2 # top-margin + var botrow/ecx: int <- copy nrows + var leftcol/edx: int <- copy 5 # page-margin + var rightcol/ebx: int <- copy leftcol + rightcol <- add 0x40 # text-width = 64 characters + start-color 0xec, 7 # 236 = darkish gray + { + compare rightcol, ncols + break-if->= + render-page in, toprow, leftcol, botrow, rightcol, r + leftcol <- copy rightcol + leftcol <- add 5 # page-margin + rightcol <- copy leftcol + rightcol <- add 0x40 # text-width + loop + } +} + +fn render-page in: (addr buffered-file), toprow: int, leftcol: int, botrow: int, rightcol: int, _r: (addr render-state) { + var r/edi: (addr render-state) <- copy _r + var state/esi: (addr int) <- get r, current-state + clear toprow, leftcol, botrow, rightcol + var row/ecx: int <- copy toprow +$line-loop: { + compare row, botrow + break-if->= + var col/edx: int <- copy leftcol + move-cursor row, col +$char-loop: { + compare col, rightcol + break-if->= + var c/eax: byte <- read-byte-buffered in + compare c, 0xffffffff # EOF marker + break-if-= $line-loop +$update-attributes:check-state: { + compare *state, 0 # normal + { + break-if-!= + compare c, 0x2a # '*' + { + break-if-!= + # r->current-state == 0 && c == '*' => bold text + start-bold + copy-to *state, 1 + break $update-attributes:check-state + } + compare c, 0x5f # '_' + { + break-if-!= + # r->current-state == 0 && c == '_' => bold text + start-bold + copy-to *state, 1 + break $update-attributes:check-state + } + break $update-attributes:check-state + } + compare *state, 1 # bold + { + break-if-!= + compare c, 0x2a # '*' + { + break-if-!= + # r->current-state == 1 && c == '*' => print c, then normal text + print-byte c + col <- increment + reset-formatting + start-color 0xec, 7 # 236 = darkish gray + copy-to *state, 0 + loop $char-loop + } + compare c, 0x5f # '_' + { + break-if-!= + # r->current-state == 1 && c == '_' => print c, then normal text + print-byte c + col <- increment + reset-formatting + start-color 0xec, 7 # 236 = darkish gray + copy-to *state, 0 + loop $char-loop + } + break $update-attributes:check-state + } + } # $change-state + compare c, 0xa # newline + break-if-= # no need to print newlines + # print c + print-byte c + col <- increment + loop + } # $char-loop + row <- increment + loop + } # $line-loop +} + +fn clear toprow: int, leftcol: int, botrow: int, rightcol: int { + var row/ecx: int <- copy toprow + { + compare row, botrow + break-if->= + var col/edx: int <- copy leftcol + move-cursor row, col + { + compare col, rightcol + break-if->= + print-string " " + col <- increment + loop + } + row <- increment + loop + } +} + +fn first-arg args-on-stack: (addr array (addr array byte)) -> out/eax: (addr array byte) { + var args/eax: (addr array (addr array byte)) <- copy args-on-stack + var result/eax: (addr addr array byte) <- index args, 1 + out <- copy *result +} + +fn load-file filename: (addr array byte) -> out/esi: (addr buffered-file) { + var result: (handle buffered-file) + { + var tmp1/eax: (addr handle buffered-file) <- address result + open filename, 0, tmp1 + } + var tmp2/eax: (addr buffered-file) <- lookup result + out <- copy tmp2 +} + +fn dump in: (addr buffered-file) { + var c/eax: byte <- read-byte-buffered in + compare c, 0xffffffff # EOF marker + break-if-= + print-byte c + loop +} diff --git a/prototypes/browse/14.mu b/prototypes/browse/14.mu new file mode 100644 index 00000000..29a92489 --- /dev/null +++ b/prototypes/browse/14.mu @@ -0,0 +1,174 @@ +fn main args: (addr array (addr array byte)) -> exit-status/ebx: int { + var filename/eax: (addr array byte) <- first-arg args + var file/esi: (addr buffered-file) <- load-file filename + enable-screen-grid-mode + var nrows/eax: int <- copy 0 + var ncols/ecx: int <- copy 0 + nrows, ncols <- screen-size + enable-keyboard-immediate-mode + { + render file, nrows, ncols + var key/eax: byte <- read-key + compare key, 0x71 # 'q' + loop-if-!= + } + enable-keyboard-type-mode + enable-screen-type-mode + exit-status <- copy 0 +} + +type render-state { + current-state: int # enum 0: normal, 1: bold, 2: heading +} + +# decide how to lay out pages on screen +fn render in: (addr buffered-file), nrows: int, ncols: int { + # Fit multiple pages on screen on separate columns, each wide enough to read + # comfortably. + # Pages are separated horizontally by a 'page margin'. Among other reasons, + # this allows the odd line to bleed out on the right if necessary. + # + # hardcoded parameters: + # top-margin + # page-margin + # text-width + var _r: render-state + var r/edi: (addr render-state) <- address _r + var toprow/eax: int <- copy 2 # top-margin + var botrow/ecx: int <- copy nrows + var leftcol/edx: int <- copy 5 # page-margin + var rightcol/ebx: int <- copy leftcol + rightcol <- add 0x40 # text-width = 64 characters + start-color 0xec, 7 # 236 = darkish gray + { + compare rightcol, ncols + break-if->= + render-page in, toprow, leftcol, botrow, rightcol, r + leftcol <- copy rightcol + leftcol <- add 5 # page-margin + rightcol <- copy leftcol + rightcol <- add 0x40 # text-width + loop + } +} + +fn render-page in: (addr buffered-file), toprow: int, leftcol: int, botrow: int, rightcol: int, _r: (addr render-state) { + var r/edi: (addr render-state) <- copy _r + var state/esi: (addr int) <- get r, current-state + clear toprow, leftcol, botrow, rightcol + var row/ecx: int <- copy toprow +$line-loop: { + compare row, botrow + break-if->= + var col/edx: int <- copy leftcol + move-cursor row, col +$char-loop: { + compare col, rightcol + break-if->= + var c/eax: byte <- read-byte-buffered in + compare c, 0xffffffff # EOF marker + break-if-= $line-loop +$change-state: { + compare *state, 0 # normal + { + break-if-!= + compare c, 0x2a # '*' + { + break-if-!= + # r->current-state == 0 && c == '*' => bold text + start-bold + copy-to *state, 1 + break $change-state + } + compare c, 0x5f # '_' + { + break-if-!= + # r->current-state == 0 && c == '_' => bold text + start-bold + copy-to *state, 1 + break $change-state + } + break $change-state + } + compare *state, 1 # bold + { + break-if-!= + compare c, 0x2a # '*' + { + break-if-!= + # r->current-state == 1 && c == '*' => print c, then normal text + print-byte c + col <- increment + reset-formatting + start-color 0xec, 7 # 236 = darkish gray + copy-to *state, 0 + loop $char-loop + } + compare c, 0x5f # '_' + { + break-if-!= + # r->current-state == 1 && c == '_' => print c, then normal text + print-byte c + col <- increment + reset-formatting + start-color 0xec, 7 # 236 = darkish gray + copy-to *state, 0 + loop $char-loop + } + break $change-state + } + } # $change-state + compare c, 0xa # newline + break-if-= # no need to print newlines + # print c + print-byte c + col <- increment + loop + } # $char-loop + row <- increment + loop + } # $line-loop +} + +fn clear toprow: int, leftcol: int, botrow: int, rightcol: int { + var row/ecx: int <- copy toprow + { + compare row, botrow + break-if->= + var col/edx: int <- copy leftcol + move-cursor row, col + { + compare col, rightcol + break-if->= + print-string " " + col <- increment + loop + } + row <- increment + loop + } +} + +fn first-arg args-on-stack: (addr array (addr array byte)) -> out/eax: (addr array byte) { + var args/eax: (addr array (addr array byte)) <- copy args-on-stack + var result/eax: (addr addr array byte) <- index args, 1 + out <- copy *result +} + +fn load-file filename: (addr array byte) -> out/esi: (addr buffered-file) { + var result: (handle buffered-file) + { + var tmp1/eax: (addr handle buffered-file) <- address result + open filename, 0, tmp1 + } + var tmp2/eax: (addr buffered-file) <- lookup result + out <- copy tmp2 +} + +fn dump in: (addr buffered-file) { + var c/eax: byte <- read-byte-buffered in + compare c, 0xffffffff # EOF marker + break-if-= + print-byte c + loop +} diff --git a/prototypes/browse/15-headers-broken.mu b/prototypes/browse/15-headers-broken.mu new file mode 100644 index 00000000..7b152bbc --- /dev/null +++ b/prototypes/browse/15-headers-broken.mu @@ -0,0 +1,216 @@ +# Incomplete first attempt at parsing headings. +# +# The state machine is getting out of control, and I notice old bugs like +# turning '*abc_' into bold text. + +fn main args: (addr array (addr array byte)) -> exit-status/ebx: int { + var filename/eax: (addr array byte) <- first-arg args + var file/esi: (addr buffered-file) <- load-file filename + enable-screen-grid-mode + var nrows/eax: int <- copy 0 + var ncols/ecx: int <- copy 0 + nrows, ncols <- screen-size + enable-keyboard-immediate-mode + { + render file, nrows, ncols + var key/eax: byte <- read-key + compare key, 0x71 # 'q' + loop-if-!= + } + enable-keyboard-type-mode + enable-screen-type-mode + exit-status <- copy 0 +} + +type render-state { + current-state: int # enum 0: normal, 1: bold, 2: heading + start-of-line?: boolean + num-hashes-seen?: int +} + +# decide how to lay out pages on screen +fn render in: (addr buffered-file), nrows: int, ncols: int { + # Fit multiple pages on screen on separate columns, each wide enough to read + # comfortably. + # Pages are separated horizontally by a 'page margin'. Among other reasons, + # this allows the odd line to bleed out on the right if necessary. + # + # hardcoded parameters: + # top-margin + # page-margin + # text-width + var _r: render-state + var r/edi: (addr render-state) <- address _r + # r->start-of-line? = true + var s/eax: (addr boolean) <- get r, start-of-line? + copy-to *s, 1 # true + var toprow/eax: int <- copy 2 # top-margin + var botrow/ecx: int <- copy nrows + var leftcol/edx: int <- copy 5 # page-margin + var rightcol/ebx: int <- copy leftcol + rightcol <- add 0x40 # text-width = 64 characters + start-color 0xec, 7 # 236 = darkish gray + { + compare rightcol, ncols + break-if->= + render-page in, toprow, leftcol, botrow, rightcol, r + leftcol <- copy rightcol + leftcol <- add 5 # page-margin + rightcol <- copy leftcol + rightcol <- add 0x40 # text-width + loop + } +} + +fn render-page in: (addr buffered-file), toprow: int, leftcol: int, botrow: int, rightcol: int, _r: (addr render-state) { + var r/edi: (addr render-state) <- copy _r + var state/esi: (addr int) <- get r, current-state + clear toprow, leftcol, botrow, rightcol + var row/ecx: int <- copy toprow +$line-loop: { + compare row, botrow + break-if->= + var col/edx: int <- copy leftcol + move-cursor row, col +$char-loop: { + compare col, rightcol + break-if->= + var c/eax: byte <- read-byte-buffered in + compare c, 0xffffffff # EOF marker + break-if-= $line-loop +$change-state: { + compare *state, 0 # normal + { + break-if-!= + compare c, 0x2a # '*' + { + break-if-!= + # r->current-state == 0 && c == '*' => bold text + start-bold + copy-to *state, 1 + break $change-state + } + compare c, 0x5f # '_' + { + break-if-!= + # r->current-state == 0 && c == '_' => bold text + start-bold + copy-to *state, 1 + break $change-state + } + compare c, 0x23 # '#' + { + break-if-!= + var s/eax: (addr boolean) <- get r, start-of-line? + compare *s, 1 + { + break-if-!= + # r->current-state == 0 && c == '#' && at start of line => count '#'s + var h/eax: (addr int) <- get r, num-hashes-seen? + increment *h + break $change-state + } + break $change-state + } + break $change-state + } + compare *state, 1 # bold + { + break-if-!= + compare c, 0x2a # '*' + { + break-if-!= + # r->current-state == 1 && c == '*' => print c, then normal text + print-byte c + col <- increment + reset-formatting + start-color 0xec, 7 # 236 = darkish gray + copy-to *state, 0 + loop $char-loop + } + compare c, 0x5f # '_' + { + break-if-!= + # r->current-state == 1 && c == '_' => print c, then normal text + print-byte c + col <- increment + reset-formatting + start-color 0xec, 7 # 236 = darkish gray + copy-to *state, 0 + loop $char-loop + } + break $change-state + } + } # $change-state + # update a few attributes of the state based on c without changing the state itself + compare c, 0xa # newline + { + break-if-!= + # c is newline + var s/eax: (addr boolean) <- get r, start-of-line? + copy-to *s, 1 # true + # switch to normal text + reset-formatting + start-color 0xec, 7 # 236 = darkish gray + # no need to print newlines + break $char-loop + } + compare c, 0x20 # space + { + break-if-= + # c is not newline or space + var s/eax: (addr boolean) <- get r, start-of-line? + copy-to *s, 0 # false + } + # print c + print-byte c + col <- increment + loop + } + row <- increment + loop + } +} + +fn clear toprow: int, leftcol: int, botrow: int, rightcol: int { + var row/ecx: int <- copy toprow + { + compare row, botrow + break-if->= + var col/edx: int <- copy leftcol + move-cursor row, col + { + compare col, rightcol + break-if->= + print-string " " + col <- increment + loop + } + row <- increment + loop + } +} + +fn first-arg args-on-stack: (addr array (addr array byte)) -> out/eax: (addr array byte) { + var args/eax: (addr array (addr array byte)) <- copy args-on-stack + var result/eax: (addr addr array byte) <- index args, 1 + out <- copy *result +} + +fn load-file filename: (addr array byte) -> out/esi: (addr buffered-file) { + var result: (handle buffered-file) + { + var tmp1/eax: (addr handle buffered-file) <- address result + open filename, 0, tmp1 + } + var tmp2/eax: (addr buffered-file) <- lookup result + out <- copy tmp2 +} + +fn dump in: (addr buffered-file) { + var c/eax: byte <- read-byte-buffered in + compare c, 0xffffffff # EOF marker + break-if-= + print-byte c + loop +} diff --git a/prototypes/browse/16-screen-state-broken.mu b/prototypes/browse/16-screen-state-broken.mu new file mode 100644 index 00000000..d80d8375 --- /dev/null +++ b/prototypes/browse/16-screen-state-broken.mu @@ -0,0 +1,188 @@ +# Incomplete second attempt at parsing headings. +# +# This 'OO' approach seems more scalable. We hoist out all the outer framework +# for deciding when to increment 'col', when to increment 'row' and when to +# start a new page in a whole new part of the screen. Now it gets encapsulated +# into a series of small helpers that can be called from multiple places. +# Objects as coroutines. +# +# In spite of these advances, I need to first wrestle with a parsing issue. +# This text has a heading: +# +# abc *def +# # ghi* +# +# Ugh, so I can't do this translation in a single pass. At the first asterisk +# there's just not enough information to know whether it starts a bold text or +# not. +# +# Then again, maybe I should just keep going and not try to be compatible with +# GitHub-Flavored Markdown. Require that new headings are also new paragraphs. + +fn main args: (addr array (addr array byte)) -> exit-status/ebx: int { + var filename/eax: (addr array byte) <- first-arg args + var file/esi: (addr buffered-file) <- load-file filename + enable-screen-grid-mode + enable-keyboard-immediate-mode + var nrows/eax: int <- copy 0 + var ncols/ecx: int <- copy 0 + nrows, ncols <- screen-size + var screen-position-state-storage: screen-position-state + var screen-position-state: (addr screen-position-state) = address screen-position-state-storage + init-screen-position-state screen-position-state, nrows, ncols + { + render file, screen-position-state + var key/eax: byte <- read-key + compare key, 0x71 # 'q' + loop-if-!= + } + enable-keyboard-type-mode + enable-screen-type-mode + exit-status <- copy 0 +} + +type screen-position-state { + nrows: int # const + ncols: int # const + toprow: int + botrow: int + leftcol: int + rightcol: int + row: int + col: int +} + +fn render in: (addr buffered-file), state: (addr screen-position-state) { + start-drawing state + render-normal in, state +} + +fn render-normal in: (addr buffered-file), state: (addr screen-position-state) { + { + # if done-drawing?(state) break + var done?/eax: boolean <- done-drawing? state + compare done?, 0 + break-if-!= + # + var c/eax: byte <- read-byte-buffered in + # if (c == EOF) break + compare c, 0xffffffff # EOF marker + break-if-= + # if (c == '*') start-bold, render-until-asterisk(in, state), reset + # else if (c == '_') start-bold, render-until-underscore(in, state), reset + # else if (c == '#') compute-color, start color, render-header-line(in, state), reset + # else add-char(state, c) + } +} + +fn render-until-asterisk in: (addr buffered-file), state: (addr screen-position-state) { + { + # if done-drawing?(state) break + var done?/eax: boolean <- done-drawing? state + compare done?, 0 + break-if-!= + # + var c/eax: byte <- read-byte-buffered in + # if (c == EOF) break + compare c, 0xffffffff # EOF marker + break-if-= + # if (c == '*') break + # else add-char(state, c) + } +} + +fn render-until-underscore in: (addr buffered-file), state: (addr screen-position-state) { + { + # if done-drawing?(state) break + var done?/eax: boolean <- done-drawing? state + compare done?, 0 + break-if-!= + # + var c/eax: byte <- read-byte-buffered in + # if (c == EOF) break + compare c, 0xffffffff # EOF marker + break-if-= + # if (c == '_') break + # else add-char(state, c) + } +} + +fn render-header-line in: (addr buffered-file), state: (addr screen-position-state) { + { + # if done-drawing?(state) break + var done?/eax: boolean <- done-drawing? state + compare done?, 0 + break-if-!= + # + var c/eax: byte <- read-byte-buffered in + # if (c == EOF) break + compare c, 0xffffffff # EOF marker + break-if-= + # if (c == '*') break + # else add-char(state, c) + } +} + +fn init-screen-position-state self: (addr screen-position-state), nrows: int, ncols: int { + # hardcoded parameters: + # top-margin + # page-margin + # text-width + var dest/eax: (addr int) <- copy 0 + # self->nrows = nrows + # self->ncols = ncols + # self->toprow = top-margin + # self->botrow = nrows + # self->leftcol = page-margin + # self->rightcol = self->leftcol + text-width + # start-drawing(self) +} + +fn start-drawing self: (addr screen-position-state) { + # self->row = toprow + # self->col = leftcol +} + +fn add-char self: (addr screen-position-state), c: byte { + # print c + # self->col++ + # if (self->col > self->rightcol) next-line(self) +} + +fn next-line self: (addr screen-position-state) { + # self->row++ + # if (self->row > self->botrow) next-page(self) +} + +fn next-page self: (addr screen-position-state) { + # self->leftcol = self->rightcol + 5 + # self->rightcol = self->leftcol + text-width +} + +fn done-drawing? self: (addr screen-position-state) -> result/eax: boolean { + # self->rightcol >= self->ncols +} + +fn first-arg args-on-stack: (addr array (addr array byte)) -> out/eax: (addr array byte) { + var args/eax: (addr array (addr array byte)) <- copy args-on-stack + var result/eax: (addr addr array byte) <- index args, 1 + out <- copy *result +} + +fn load-file filename: (addr array byte) -> out/esi: (addr buffered-file) { + var result: (handle buffered-file) + { + var tmp1/eax: (addr handle buffered-file) <- address result + open filename, 0, tmp1 + } + var tmp2/eax: (addr buffered-file) <- lookup result + out <- copy tmp2 +} + +fn dump in: (addr buffered-file) { + var c/eax: byte <- read-byte-buffered in + compare c, 0xffffffff # EOF marker + break-if-= + print-byte c + loop +} diff --git a/prototypes/browse/17-file-state-broken/README.md b/prototypes/browse/17-file-state-broken/README.md new file mode 100644 index 00000000..7605c390 --- /dev/null +++ b/prototypes/browse/17-file-state-broken/README.md @@ -0,0 +1,7 @@ +More OO. Create a similar set of helpers for reading characters from disk. + +It's surprising that state for supporting headings needs to go into the state +maintained while reading the file from disk. + +Since we now have two 'classes', it seems worth splitting up into multiple +files. diff --git a/prototypes/browse/17-file-state-broken/file-state.mu b/prototypes/browse/17-file-state-broken/file-state.mu new file mode 100644 index 00000000..12fb75c3 --- /dev/null +++ b/prototypes/browse/17-file-state-broken/file-state.mu @@ -0,0 +1,33 @@ +type file-state { + source: (handle buffered-file) + at-start-of-line?: boolean + heading-level?: int +} + +fn init-file-state self: (addr file-state), filename: (addr array byte) { +#? var file/esi: (addr buffered-file) <- load-file filename + load-buffer-file self, filename + # self->at-start-of-line? = true + # self->heading-level? = 0 +} + +fn done-reading? self: (addr file-state) -> result/eax: boolean { +} + +fn load-file filename: (addr array byte) -> out/esi: (addr buffered-file) { + var result: (handle buffered-file) + { + var tmp1/eax: (addr handle buffered-file) <- address result + open filename, 0, tmp1 + } + var tmp2/eax: (addr buffered-file) <- lookup result + out <- copy tmp2 +} + +fn dump in: (addr buffered-file) { + var c/eax: byte <- read-byte-buffered in + compare c, 0xffffffff # EOF marker + break-if-= + print-byte c + loop +} diff --git a/prototypes/browse/17-file-state-broken/main.mu b/prototypes/browse/17-file-state-broken/main.mu new file mode 100644 index 00000000..e95aff73 --- /dev/null +++ b/prototypes/browse/17-file-state-broken/main.mu @@ -0,0 +1,106 @@ +fn main args: (addr array (addr array byte)) -> exit-status/ebx: int { + # initialize fs from args[1] + var filename/eax: (addr array byte) <- first-arg args + var file-state-storage: file-state + var fs/esi: (addr file-state) <- address file-state-storage + init-file-state fs, filename + # + enable-screen-grid-mode + enable-keyboard-immediate-mode + # initialize screen state from screen size + var nrows/eax: int <- copy 0 + var ncols/ecx: int <- copy 0 + nrows, ncols <- screen-size + var screen-position-state-storage: screen-position-state + var screen-position-state: (addr screen-position-state) = address screen-position-state-storage + init-screen-position-state screen-position-state, nrows, ncols + { + var done?/eax: boolean <- done-reading? fs + compare done?, 0 + break-if-= + render fs, screen-position-state + var key/eax: byte <- read-key + compare key, 0x71 # 'q' + loop-if-!= + } + enable-keyboard-type-mode + enable-screen-type-mode + exit-status <- copy 0 +} + +fn render fs: (addr file-state), state: (addr screen-position-state) { + start-drawing state + render-normal fs, state +} + +fn render-normal fs: (addr file-state), state: (addr screen-position-state) { + { + # if done-drawing?(state) break + var done?/eax: boolean <- done-drawing? state + compare done?, 0 + break-if-!= + # + var c/eax: byte <- next-char fs + # if (c == EOF) break + compare c, 0xffffffff # EOF marker + break-if-= + # if (c == '*') start-bold, render-until-asterisk(fs, state), reset + # else if (c == '_') start-bold, render-until-underscore(fs, state), reset + # else if (c == '#' and fs is at start of line) compute-color, start color, render-header-line(fs, state), reset + # else add-char(state, c) + } +} + +fn render-until-asterisk fs: (addr file-state), state: (addr screen-position-state) { + { + # if done-drawing?(state) break + var done?/eax: boolean <- done-drawing? state + compare done?, 0 + break-if-!= + # + var c/eax: byte <- next-char fs + # if (c == EOF) break + compare c, 0xffffffff # EOF marker + break-if-= + # if (c == '*') break + # else add-char(state, c) + } +} + +fn render-until-underscore fs: (addr file-state), state: (addr screen-position-state) { + { + # if done-drawing?(state) break + var done?/eax: boolean <- done-drawing? state + compare done?, 0 + break-if-!= + # + var c/eax: byte <- next-char fs + # if (c == EOF) break + compare c, 0xffffffff # EOF marker + break-if-= + # if (c == '_') break + # else add-char(state, c) + } +} + +fn render-header-line fs: (addr file-state), state: (addr screen-position-state) { + { + # if done-drawing?(state) break + var done?/eax: boolean <- done-drawing? state + compare done?, 0 + break-if-!= + # + var c/eax: byte <- next-char fs + # if (c == EOF) break + compare c, 0xffffffff # EOF marker + break-if-= + # if (c == '*') break + # else add-char(state, c) + } +} + +fn first-arg args-on-stack: (addr array (addr array byte)) -> out/eax: (addr array byte) { + var args/eax: (addr array (addr array byte)) <- copy args-on-stack + var result/eax: (addr addr array byte) <- index args, 1 + out <- copy *result +} diff --git a/prototypes/browse/17-file-state-broken/screen-position-state.mu b/prototypes/browse/17-file-state-broken/screen-position-state.mu new file mode 100644 index 00000000..af623d16 --- /dev/null +++ b/prototypes/browse/17-file-state-broken/screen-position-state.mu @@ -0,0 +1,50 @@ +type screen-position-state { + nrows: int # const + ncols: int # const + toprow: int + botrow: int + leftcol: int + rightcol: int + row: int + col: int +} + +fn init-screen-position-state self: (addr screen-position-state), nrows: int, ncols: int { + # hardcoded parameters: + # top-margin + # page-margin + # text-width + var dest/eax: (addr int) <- copy 0 + # self->nrows = nrows + # self->ncols = ncols + # self->toprow = top-margin + # self->botrow = nrows + # self->leftcol = page-margin + # self->rightcol = self->leftcol + text-width + # start-drawing(self) +} + +fn start-drawing self: (addr screen-position-state) { + # self->row = toprow + # self->col = leftcol +} + +fn add-char self: (addr screen-position-state), c: byte { + # print c + # self->col++ + # if (self->col > self->rightcol) next-line(self) +} + +fn next-line self: (addr screen-position-state) { + # self->row++ + # if (self->row > self->botrow) next-page(self) +} + +fn next-page self: (addr screen-position-state) { + # self->leftcol = self->rightcol + 5 + # self->rightcol = self->leftcol + text-width +} + +fn done-drawing? self: (addr screen-position-state) -> result/eax: boolean { + # self->rightcol >= self->ncols +} diff --git a/prototypes/browse/2.mu b/prototypes/browse/2.mu new file mode 100644 index 00000000..26d0637e --- /dev/null +++ b/prototypes/browse/2.mu @@ -0,0 +1,31 @@ +fn main args: (addr array (addr array byte)) -> exit-status/ebx: int { + var filename/eax: (addr array byte) <- first-arg args + var file/eax: (addr buffered-file) <- load-file filename + dump file + exit-status <- copy 0 +} + +fn first-arg args-on-stack: (addr array (addr array byte)) -> out/eax: (addr array byte) { + var args/eax: (addr array (addr array byte)) <- copy args-on-stack + var result/eax: (addr addr array byte) <- index args, 1 + out <- copy *result +} + +fn load-file filename: (addr array byte) -> out/eax: (addr buffered-file) { + var result: (handle buffered-file) + { + var tmp1/eax: (addr handle buffered-file) <- address result + open filename, 0, tmp1 + } + out <- lookup result +} + +fn dump in: (addr buffered-file) { + { + var c/eax: byte <- read-byte-buffered in + compare c, 0xffffffff # EOF marker + break-if-= + print-byte c + loop + } +} diff --git a/prototypes/browse/3.mu b/prototypes/browse/3.mu new file mode 100644 index 00000000..3282f3be --- /dev/null +++ b/prototypes/browse/3.mu @@ -0,0 +1,29 @@ +fn main args: (addr array (addr array byte)) -> exit-status/ebx: int { + var filename/eax: (addr array byte) <- first-arg args + var file/eax: (addr buffered-file) <- load-file filename + dump file + exit-status <- copy 0 +} + +fn first-arg args-on-stack: (addr array (addr array byte)) -> out/eax: (addr array byte) { + var args/eax: (addr array (addr array byte)) <- copy args-on-stack + var result/eax: (addr addr array byte) <- index args, 1 + out <- copy *result +} + +fn load-file filename: (addr array byte) -> out/eax: (addr buffered-file) { + var result: (handle buffered-file) + { + var tmp1/eax: (addr handle buffered-file) <- address result + open filename, 0, tmp1 + } + out <- lookup result +} + +fn dump in: (addr buffered-file) { + var c/eax: byte <- read-byte-buffered in + compare c, 0xffffffff # EOF marker + break-if-= + print-byte c + loop +} diff --git a/prototypes/browse/4-render-page.mu b/prototypes/browse/4-render-page.mu new file mode 100644 index 00000000..bc8c6a55 --- /dev/null +++ b/prototypes/browse/4-render-page.mu @@ -0,0 +1,81 @@ +fn main args: (addr array (addr array byte)) -> exit-status/ebx: int { + var filename/eax: (addr array byte) <- first-arg args + var file/eax: (addr buffered-file) <- load-file filename + enable-screen-grid-mode + enable-keyboard-immediate-mode + { + render file, 5, 5, 30, 30 + var key/eax: byte <- read-key + compare key, 0x71 # 'q' + loop-if-!= + } + enable-keyboard-type-mode + enable-screen-type-mode + exit-status <- copy 0 +} + +fn render in: (addr buffered-file), toprow: int, leftcol: int, botrow: int, rightcol: int { + clear toprow, leftcol, botrow, rightcol + var row/ecx: int <- copy toprow +$line-loop: { + compare row, botrow + break-if->= + var col/edx: int <- copy leftcol + move-cursor row, col + { + compare col, rightcol + break-if->= + var c/eax: byte <- read-byte-buffered in + compare c, 0xffffffff # EOF marker + break-if-= $line-loop + # print c + print-byte c + col <- increment + loop + } # $char-loop + row <- increment + loop + } # $line-loop +} + +fn clear toprow: int, leftcol: int, botrow: int, rightcol: int { + var row/ecx: int <- copy toprow + { + compare row, botrow + break-if->= + var col/edx: int <- copy leftcol + move-cursor row, col + { + compare col, rightcol + break-if->= + print-string " " + col <- increment + loop + } + row <- increment + loop + } +} + +fn first-arg args-on-stack: (addr array (addr array byte)) -> out/eax: (addr array byte) { + var args/eax: (addr array (addr array byte)) <- copy args-on-stack + var result/eax: (addr addr array byte) <- index args, 1 + out <- copy *result +} + +fn load-file filename: (addr array byte) -> out/eax: (addr buffered-file) { + var result: (handle buffered-file) + { + var tmp1/eax: (addr handle buffered-file) <- address result + open filename, 0, tmp1 + } + out <- lookup result +} + +fn dump in: (addr buffered-file) { + var c/eax: byte <- read-byte-buffered in + compare c, 0xffffffff # EOF marker + break-if-= + print-byte c + loop +} diff --git a/prototypes/browse/5.mu b/prototypes/browse/5.mu new file mode 100644 index 00000000..d2d619cc --- /dev/null +++ b/prototypes/browse/5.mu @@ -0,0 +1,83 @@ +fn main args: (addr array (addr array byte)) -> exit-status/ebx: int { + var filename/eax: (addr array byte) <- first-arg args + var file/eax: (addr buffered-file) <- load-file filename + enable-screen-grid-mode + enable-keyboard-immediate-mode + { + render file, 5, 5, 30, 30 + var key/eax: byte <- read-key + compare key, 0x71 # 'q' + loop-if-!= + } + enable-keyboard-type-mode + enable-screen-type-mode + exit-status <- copy 0 +} + +fn render in: (addr buffered-file), toprow: int, leftcol: int, botrow: int, rightcol: int { + clear toprow, leftcol, botrow, rightcol + var row/ecx: int <- copy toprow +$line-loop: { + compare row, botrow + break-if->= + var col/edx: int <- copy leftcol + move-cursor row, col + { + compare col, rightcol + break-if->= + var c/eax: byte <- read-byte-buffered in + compare c, 0xffffffff # EOF marker + break-if-= $line-loop + compare c, 0xa # newline + break-if-= # no need to print newlines + # print c + print-byte c + col <- increment + loop + } # $char-loop + row <- increment + loop + } # $line-loop +} + +fn clear toprow: int, leftcol: int, botrow: int, rightcol: int { + var row/ecx: int <- copy toprow + { + compare row, botrow + break-if->= + var col/edx: int <- copy leftcol + move-cursor row, col + { + compare col, rightcol + break-if->= + print-string " " + col <- increment + loop + } + row <- increment + loop + } +} + +fn first-arg args-on-stack: (addr array (addr array byte)) -> out/eax: (addr array byte) { + var args/eax: (addr array (addr array byte)) <- copy args-on-stack + var result/eax: (addr addr array byte) <- index args, 1 + out <- copy *result +} + +fn load-file filename: (addr array byte) -> out/eax: (addr buffered-file) { + var result: (handle buffered-file) + { + var tmp1/eax: (addr handle buffered-file) <- address result + open filename, 0, tmp1 + } + out <- lookup result +} + +fn dump in: (addr buffered-file) { + var c/eax: byte <- read-byte-buffered in + compare c, 0xffffffff # EOF marker + break-if-= + print-byte c + loop +} diff --git a/prototypes/browse/6.mu b/prototypes/browse/6.mu new file mode 100644 index 00000000..520a13fd --- /dev/null +++ b/prototypes/browse/6.mu @@ -0,0 +1,94 @@ +fn main args: (addr array (addr array byte)) -> exit-status/ebx: int { + var filename/eax: (addr array byte) <- first-arg args + var file/eax: (addr buffered-file) <- load-file filename + enable-screen-grid-mode + enable-keyboard-immediate-mode + { + render file, 0x20, 0x30 # nrows, ncols + var key/eax: byte <- read-key + compare key, 0x71 # 'q' + loop-if-!= + } + enable-keyboard-type-mode + enable-screen-type-mode + exit-status <- copy 0 +} + +fn render in: (addr buffered-file), nrows: int, ncols: int { + # hardcoded parameter: text-width + var toprow/eax: int <- copy 2 + var botrow/ecx: int <- copy toprow + botrow <- add nrows + var leftcol/edx: int <- copy 5 + var rightcol/ebx: int <- copy leftcol + rightcol <- add ncols + render-page in, toprow, leftcol, botrow, rightcol +} + +fn render-page in: (addr buffered-file), toprow: int, leftcol: int, botrow: int, rightcol: int { + clear toprow, leftcol, botrow, rightcol + var row/ecx: int <- copy toprow +$line-loop: { + compare row, botrow + break-if->= + var col/edx: int <- copy leftcol + move-cursor row, col + { + compare col, rightcol + break-if->= + var c/eax: byte <- read-byte-buffered in + compare c, 0xffffffff # EOF marker + break-if-= $line-loop + compare c, 0xa # newline + break-if-= # no need to print newlines + # print c + print-byte c + col <- increment + loop + } # $char-loop + row <- increment + loop + } # $line-loop +} + +fn clear toprow: int, leftcol: int, botrow: int, rightcol: int { + var row/ecx: int <- copy toprow + { + compare row, botrow + break-if->= + var col/edx: int <- copy leftcol + move-cursor row, col + { + compare col, rightcol + break-if->= + print-string " " + col <- increment + loop + } + row <- increment + loop + } +} + +fn first-arg args-on-stack: (addr array (addr array byte)) -> out/eax: (addr array byte) { + var args/eax: (addr array (addr array byte)) <- copy args-on-stack + var result/eax: (addr addr array byte) <- index args, 1 + out <- copy *result +} + +fn load-file filename: (addr array byte) -> out/eax: (addr buffered-file) { + var result: (handle buffered-file) + { + var tmp1/eax: (addr handle buffered-file) <- address result + open filename, 0, tmp1 + } + out <- lookup result +} + +fn dump in: (addr buffered-file) { + var c/eax: byte <- read-byte-buffered in + compare c, 0xffffffff # EOF marker + break-if-= + print-byte c + loop +} diff --git a/prototypes/browse/7.mu b/prototypes/browse/7.mu new file mode 100644 index 00000000..b319d4a2 --- /dev/null +++ b/prototypes/browse/7.mu @@ -0,0 +1,99 @@ +fn main args: (addr array (addr array byte)) -> exit-status/ebx: int { + var filename/eax: (addr array byte) <- first-arg args + var file/esi: (addr buffered-file) <- load-file filename + enable-screen-grid-mode + var nrows/eax: int <- copy 0 + var ncols/ecx: int <- copy 0 + nrows, ncols <- screen-size + enable-keyboard-immediate-mode + { + render file, nrows, ncols + var key/eax: byte <- read-key + compare key, 0x71 # 'q' + loop-if-!= + } + enable-keyboard-type-mode + enable-screen-type-mode + exit-status <- copy 0 +} + +# decide how to lay out pages on screen +fn render in: (addr buffered-file), nrows: int, ncols: int { + # hardcoded parameter: text-width + var toprow/eax: int <- copy 2 + var botrow/ecx: int <- copy toprow + botrow <- add 0x20 + var leftcol/edx: int <- copy 5 + var rightcol/ebx: int <- copy leftcol + rightcol <- add 0x30 + render-page in, toprow, leftcol, botrow, rightcol +} + +fn render-page in: (addr buffered-file), toprow: int, leftcol: int, botrow: int, rightcol: int { + clear toprow, leftcol, botrow, rightcol + var row/ecx: int <- copy toprow +$line-loop: { + compare row, botrow + break-if->= + var col/edx: int <- copy leftcol + move-cursor row, col + { + compare col, rightcol + break-if->= + var c/eax: byte <- read-byte-buffered in + compare c, 0xffffffff # EOF marker + break-if-= $line-loop + compare c, 0xa # newline + break-if-= # no need to print newlines + # print c + print-byte c + col <- increment + loop + } # $char-loop + row <- increment + loop + } # $line-loop +} + +fn clear toprow: int, leftcol: int, botrow: int, rightcol: int { + var row/ecx: int <- copy toprow + { + compare row, botrow + break-if->= + var col/edx: int <- copy leftcol + move-cursor row, col + { + compare col, rightcol + break-if->= + print-string " " + col <- increment + loop + } + row <- increment + loop + } +} + +fn first-arg args-on-stack: (addr array (addr array byte)) -> out/eax: (addr array byte) { + var args/eax: (addr array (addr array byte)) <- copy args-on-stack + var result/eax: (addr addr array byte) <- index args, 1 + out <- copy *result +} + +fn load-file filename: (addr array byte) -> out/esi: (addr buffered-file) { + var result: (handle buffered-file) + { + var tmp1/eax: (addr handle buffered-file) <- address result + open filename, 0, tmp1 + } + var tmp2/eax: (addr buffered-file) <- lookup result + out <- copy tmp2 +} + +fn dump in: (addr buffered-file) { + var c/eax: byte <- read-byte-buffered in + compare c, 0xffffffff # EOF marker + break-if-= + print-byte c + loop +} diff --git a/prototypes/browse/8-multiple-pages.mu b/prototypes/browse/8-multiple-pages.mu new file mode 100644 index 00000000..009a9aeb --- /dev/null +++ b/prototypes/browse/8-multiple-pages.mu @@ -0,0 +1,115 @@ +fn main args: (addr array (addr array byte)) -> exit-status/ebx: int { + var filename/eax: (addr array byte) <- first-arg args + var file/esi: (addr buffered-file) <- load-file filename + enable-screen-grid-mode + var nrows/eax: int <- copy 0 + var ncols/ecx: int <- copy 0 + nrows, ncols <- screen-size + enable-keyboard-immediate-mode + { + render file, nrows, ncols + var key/eax: byte <- read-key + compare key, 0x71 # 'q' + loop-if-!= + } + enable-keyboard-type-mode + enable-screen-type-mode + exit-status <- copy 0 +} + +# decide how to lay out pages on screen +fn render in: (addr buffered-file), nrows: int, ncols: int { + # Fit n pages on screen on separate columns, each wide enough to read + # comfortably. + # Pages are separated horizontally by a 'page margin'. Among other reasons, + # this allows the odd line to bleed out on the right if necessary. + # + # hardcoded parameters: + # top-margin + # page-margin + # text-width + var toprow/eax: int <- copy 2 # top-margin + var botrow/ecx: int <- copy nrows + var leftcol/edx: int <- copy 5 # page-margin + var rightcol/ebx: int <- copy leftcol + rightcol <- add 0x40 # text-width = 64 characters + { + compare rightcol, ncols + break-if->= + render-page in, toprow, leftcol, botrow, rightcol + leftcol <- copy rightcol + leftcol <- add 5 # page-margin + rightcol <- copy leftcol + rightcol <- add 0x40 # text-width + loop + } +} + +fn render-page in: (addr buffered-file), toprow: int, leftcol: int, botrow: int, rightcol: int { + clear toprow, leftcol, botrow, rightcol + var row/ecx: int <- copy toprow +$line-loop: { + compare row, botrow + break-if->= + var col/edx: int <- copy leftcol + move-cursor row, col + { + compare col, rightcol + break-if->= + var c/eax: byte <- read-byte-buffered in + compare c, 0xffffffff # EOF marker + break-if-= $line-loop + compare c, 0xa # newline + break-if-= # no need to print newlines + # print c + print-byte c + col <- increment + loop + } # $char-loop + row <- increment + loop + } # $line-loop +} + +fn clear toprow: int, leftcol: int, botrow: int, rightcol: int { + var row/ecx: int <- copy toprow + { + compare row, botrow + break-if->= + var col/edx: int <- copy leftcol + move-cursor row, col + { + compare col, rightcol + break-if->= + print-string " " + col <- increment + loop + } + row <- increment + loop + } +} + +fn first-arg args-on-stack: (addr array (addr array byte)) -> out/eax: (addr array byte) { + var args/eax: (addr array (addr array byte)) <- copy args-on-stack + var result/eax: (addr addr array byte) <- index args, 1 + out <- copy *result +} + +fn load-file filename: (addr array byte) -> out/esi: (addr buffered-file) { + var result: (handle buffered-file) + { + var tmp1/eax: (addr handle buffered-file) <- address result + open filename, 0, tmp1 + } + var tmp2/eax: (addr buffered-file) <- lookup result + out <- copy tmp2 +} + +fn dump in: (addr buffered-file) { + var c/eax: byte <- read-byte-buffered in + compare c, 0xffffffff # EOF marker + break-if-= + print-byte c + loop +} diff --git a/prototypes/browse/9-bold.mu b/prototypes/browse/9-bold.mu new file mode 100644 index 00000000..5236365f --- /dev/null +++ b/prototypes/browse/9-bold.mu @@ -0,0 +1,152 @@ +fn main args: (addr array (addr array byte)) -> exit-status/ebx: int { + var filename/eax: (addr array byte) <- first-arg args + var file/esi: (addr buffered-file) <- load-file filename + enable-screen-grid-mode + var nrows/eax: int <- copy 0 + var ncols/ecx: int <- copy 0 + nrows, ncols <- screen-size + enable-keyboard-immediate-mode + { + render file, nrows, ncols + var key/eax: byte <- read-key + compare key, 0x71 # 'q' + loop-if-!= + } + enable-keyboard-type-mode + enable-screen-type-mode + exit-status <- copy 0 +} + +type render-state { + current-state: int # enum 0: normal, 1: bold +} + +# decide how to lay out pages on screen +fn render in: (addr buffered-file), nrows: int, ncols: int { + # Fit multiple pages on screen on separate columns, each wide enough to read + # comfortably. + # Pages are separated horizontally by a 'page margin'. Among other reasons, + # this allows the odd line to bleed out on the right if necessary. + # + # hardcoded parameters: + # top-margin + # page-margin + # text-width + var _r: render-state + var r/edi: (addr render-state) <- address _r + var toprow/eax: int <- copy 2 # top-margin + var botrow/ecx: int <- copy nrows + var leftcol/edx: int <- copy 5 # page-margin + var rightcol/ebx: int <- copy leftcol + rightcol <- add 0x40 # text-width = 64 characters + start-color 0xec, 7 # 236 = darkish gray + { + compare rightcol, ncols + break-if->= + render-page in, toprow, leftcol, botrow, rightcol, r + leftcol <- copy rightcol + leftcol <- add 5 # page-margin + rightcol <- copy leftcol + rightcol <- add 0x40 # text-width + loop + } +} + +fn render-page in: (addr buffered-file), toprow: int, leftcol: int, botrow: int, rightcol: int, r: (addr render-state) { + clear toprow, leftcol, botrow, rightcol + var row/ecx: int <- copy toprow +$line-loop: { + compare row, botrow + break-if->= + var col/edx: int <- copy leftcol + move-cursor row, col + { + compare col, rightcol + break-if->= + var c/eax: byte <- read-byte-buffered in + compare c, 0xffffffff # EOF marker + break-if-= $line-loop + update-attributes c, r + compare c, 0xa # newline + break-if-= # no need to print newlines + # print c + print-byte c + col <- increment + loop + } # $char-loop + row <- increment + loop + } # $line-loop +} + +fn update-attributes c: byte, _r: (addr render-state) { + var r/edi: (addr render-state) <- copy _r + var state/esi: (addr int) <- get r, current-state +$check-state: { + compare *state, 0 # normal + { + break-if-!= + compare c, 0x2a # '*' + { + break-if-!= + # r->current-state == 0 && c == '*' => bold text + start-bold + copy-to *state, 1 + } + break $check-state + } + { + break-if-= + compare c, 0x2a # '*' + { + break-if-!= + # r->current-state == 1 && c == '*' => normal text + reset-formatting + copy-to *state, 0 + } + } + } # $check-state +} + +fn clear toprow: int, leftcol: int, botrow: int, rightcol: int { + var row/ecx: int <- copy toprow + { + compare row, botrow + break-if->= + var col/edx: int <- copy leftcol + move-cursor row, col + { + compare col, rightcol + break-if->= + print-string " " + col <- increment + loop + } + row <- increment + loop + } +} + +fn first-arg args-on-stack: (addr array (addr array byte)) -> out/eax: (addr array byte) { + var args/eax: (addr array (addr array byte)) <- copy args-on-stack + var result/eax: (addr addr array byte) <- index args, 1 + out <- copy *result +} + +fn load-file filename: (addr array byte) -> out/esi: (addr buffered-file) { + var result: (handle buffered-file) + { + var tmp1/eax: (addr handle buffered-file) <- address result + open filename, 0, tmp1 + } + var tmp2/eax: (addr buffered-file) <- lookup result + out <- copy tmp2 +} + +fn dump in: (addr buffered-file) { + var c/eax: byte <- read-byte-buffered in + compare c, 0xffffffff # EOF marker + break-if-= + print-byte c + loop +} diff --git a/prototypes/browse/README.md b/prototypes/browse/README.md new file mode 100644 index 00000000..3977dfb2 --- /dev/null +++ b/prototypes/browse/README.md @@ -0,0 +1,8 @@ +# Render text with word-wrap. + +This directory contains a series of prototypes. + +If you need to quit, press 'q'. + +For more details on the organization of this directory, see the parent +directory. |