diff options
author | Kartik K. Agaram <vc@akkartik.com> | 2015-11-05 09:03:00 -0800 |
---|---|---|
committer | Kartik K. Agaram <vc@akkartik.com> | 2015-11-05 09:18:09 -0800 |
commit | f7e7582507e42054c478724ac630d6e716a926ee (patch) | |
tree | b48699c613a1936d11a648ae8fabad7ad0f33567 /edit | |
parent | 805a476150590ecf5c9eeca791db1f6aa1b4787a (diff) | |
download | mu-f7e7582507e42054c478724ac630d6e716a926ee.tar.gz |
2370 - layers 1-4 of edit are back
One nice consequence of all my deduction of reply ingredients is that I can insert the same fragment into recipes with different headers, and everything works as long as reply instructions are implicitly deduced. One thing I had to fix to make this work was to move reply-deduction out of rewrite rules and turn it into a first-class transform, so that it happens after tangling. I'm glad to see the back of that hack inside <scroll-down>.
Diffstat (limited to 'edit')
-rw-r--r-- | edit/001-editor.mu | 3 | ||||
-rw-r--r-- | edit/002-typing.mu | 127 | ||||
-rw-r--r-- | edit/003-shortcuts.mu | 448 | ||||
-rw-r--r-- | edit/004-programming-environment.mu | 87 |
4 files changed, 312 insertions, 353 deletions
diff --git a/edit/001-editor.mu b/edit/001-editor.mu index e7596c7f..b74b3ecf 100644 --- a/edit/001-editor.mu +++ b/edit/001-editor.mu @@ -125,8 +125,6 @@ scenario editor-initializes-without-data [ ] ] -# last-row:number, last-column:number, screen, editor <- render screen:address:screen, editor:address:editor-data -# # Assumes cursor should be at coordinates (cursor-row, cursor-column) and # updates before-cursor to match. Might also move coordinates if they're # outside text. @@ -412,7 +410,6 @@ after <character-c-received> [ color <- get-color color, c ] -# color <- get-color color:number, c:character # so far the previous color is all the information we need; that may change recipe get-color color:number, c:character -> color:number [ local-scope diff --git a/edit/002-typing.mu b/edit/002-typing.mu index 45eaaa89..bd69ae16 100644 --- a/edit/002-typing.mu +++ b/edit/002-typing.mu @@ -2,20 +2,18 @@ # temporary main: interactive editor # hit ctrl-c to exit -recipe! main [ +recipe! main text:address:array:character [ local-scope - text:address:array:character <- next-ingredient + load-ingredients open-console editor:address:editor-data <- new-editor text, 0/screen, 5/left, 45/right editor-event-loop 0/screen, 0/console, editor close-console ] -recipe editor-event-loop [ +recipe editor-event-loop screen:address:screen, console:address:console, editor:address:editor-data [ local-scope - screen:address:screen <- next-ingredient - console:address:console <- next-ingredient - editor:address:editor-data <- next-ingredient + load-ingredients { # looping over each (keyboard or touch) event as it occurs +next-event @@ -47,11 +45,9 @@ recipe editor-event-loop [ ] # process click, return if it was on current editor -recipe move-cursor-in-editor [ +recipe move-cursor-in-editor screen:address:screen, editor:address:editor-data, t:touch-event -> in-focus?:boolean [ local-scope - screen:address:screen <- next-ingredient - editor:address:editor-data <- next-ingredient - t:touch-event <- next-ingredient + load-ingredients reply-unless editor, 0/false click-row:number <- get t, row:offset reply-unless click-row, 0/false # ignore clicks on 'menu' @@ -71,24 +67,19 @@ recipe move-cursor-in-editor [ reply 1/true ] -# editor <- snap-cursor screen:address:screen, editor:address:editor-data, target-row:number, target-column:number -# # Variant of 'render' that only moves the cursor (coordinates and # before-cursor). If it's past the end of a line, it 'slides' it left. If it's # past the last line it positions at end of last line. -recipe snap-cursor [ +recipe snap-cursor screen:address:screen, editor:address:editor-data, target-row:number, target-column:number -> editor:address:editor-data [ local-scope - screen:address:screen <- next-ingredient - editor:address:editor-data <- next-ingredient - target-row:number <- next-ingredient - target-column:number <- next-ingredient - reply-unless editor, 1/top, editor/same-as-ingredient:1 + load-ingredients + reply-unless editor left:number <- get *editor, left:offset right:number <- get *editor, right:offset screen-height:number <- screen-height screen # count newlines until screen row - curr:address:duplex-list <- get *editor, top-of-screen:offset - prev:address:duplex-list <- copy curr # just in case curr becomes null and we can't compute prev-duplex + curr:address:duplex-list:character <- get *editor, top-of-screen:offset + prev:address:duplex-list:character <- copy curr # just in case curr becomes null and we can't compute prev-duplex curr <- next-duplex curr row:number <- copy 1/top column:number <- copy left @@ -96,7 +87,7 @@ recipe snap-cursor [ *cursor-row <- copy target-row cursor-column:address:number <- get-address *editor, cursor-column:offset *cursor-column <- copy target-column - before-cursor:address:address:duplex-list <- get-address *editor, before-cursor:offset + before-cursor:address:address:duplex-list:character <- get-address *editor, before-cursor:offset { +next-character break-unless curr @@ -160,23 +151,20 @@ recipe snap-cursor [ *cursor-column <- copy column *before-cursor <- copy prev } - reply editor/same-as-ingredient:1 ] -# screen, editor, go-render?:boolean <- handle-keyboard-event screen:address:screen, editor:address:editor-data, e:event # Process an event 'e' and try to minimally update the screen. # Set 'go-render?' to true to indicate the caller must perform a non-minimal update. -recipe handle-keyboard-event [ +recipe handle-keyboard-event screen:address:screen, editor:address:editor-data, e:event -> screen:address:screen, editor:address:editor-data, go-render?:boolean [ local-scope - screen:address:screen <- next-ingredient - editor:address:editor-data <- next-ingredient - e:event <- next-ingredient - reply-unless editor, screen/same-as-ingredient:0, editor/same-as-ingredient:1, 0/no-more-render + load-ingredients + go-render? <- copy 0/false + reply-unless editor screen-width:number <- screen-width screen screen-height:number <- screen-height screen left:number <- get *editor, left:offset right:number <- get *editor, right:offset - before-cursor:address:address:duplex-list <- get-address *editor, before-cursor:offset + before-cursor:address:address:duplex-list:character <- get-address *editor, before-cursor:offset cursor-row:address:number <- get-address *editor, cursor-row:offset cursor-column:address:number <- get-address *editor, cursor-column:offset save-row:number <- copy *cursor-row @@ -190,27 +178,27 @@ recipe handle-keyboard-event [ <handle-special-character> # ignore any other special characters regular-character?:boolean <- greater-or-equal *c, 32/space - reply-unless regular-character?, screen/same-as-ingredient:0, editor/same-as-ingredient:1, 0/no-more-render + go-render? <- copy 0/false + reply-unless regular-character? # otherwise type it in <insert-character-begin> editor, screen, go-render?:boolean <- insert-at-cursor editor, *c, screen <insert-character-end> - reply screen/same-as-ingredient:0, editor/same-as-ingredient:1, go-render? + reply } # special key to modify the text or move the cursor k:address:number <- maybe-convert e:event, keycode:variant assert k, [event was of unknown type; neither keyboard nor mouse] # handlers for each special key will go here <handle-special-key> - reply screen/same-as-ingredient:0, editor/same-as-ingredient:1, 1/go-render + go-render? <- copy 1/true + reply ] -recipe insert-at-cursor [ +recipe insert-at-cursor editor:address:editor-data, c:character, screen:address:screen -> editor:address:editor-data, screen:address:screen, go-render?:boolean [ local-scope - editor:address:editor-data <- next-ingredient - c:character <- next-ingredient - screen:address:screen <- next-ingredient - before-cursor:address:address:duplex-list <- get-address *editor, before-cursor:offset + load-ingredients + before-cursor:address:address:duplex-list:character <- get-address *editor, before-cursor:offset insert-duplex c, *before-cursor *before-cursor <- next-duplex *before-cursor cursor-row:address:number <- get-address *editor, cursor-row:offset @@ -225,7 +213,7 @@ recipe insert-at-cursor [ <insert-character-special-case> # but mostly we'll just move the cursor right *cursor-column <- add *cursor-column, 1 - next:address:duplex-list <- next-duplex *before-cursor + next:address:duplex-list:character <- next-duplex *before-cursor { # at end of all text? no need to scroll? just print the character and leave at-end?:boolean <- equal next, 0/null @@ -237,20 +225,22 @@ recipe insert-at-cursor [ break-if overflow? move-cursor screen, save-row, save-column print-character screen, c - reply editor/same-as-ingredient:0, screen/same-as-ingredient:2, 0/no-more-render + go-render? <- copy 0/false + reply } { # not at right margin? print the character and rest of line break-unless next at-right?:boolean <- greater-or-equal *cursor-column, screen-width break-if at-right? - curr:address:duplex-list <- copy *before-cursor + curr:address:duplex-list:character <- copy *before-cursor move-cursor screen, save-row, save-column curr-column:number <- copy save-column { # hit right margin? give up and let caller render + go-render? <- copy 1/true at-right?:boolean <- greater-than curr-column, right - reply-if at-right?, editor/same-as-ingredient:0, screen/same-as-ingredient:2, 1/go-render + reply-if at-right? break-unless curr # newline? done. currc:character <- get *curr, value:offset @@ -261,16 +251,17 @@ recipe insert-at-cursor [ curr <- next-duplex curr loop } - reply editor/same-as-ingredient:0, screen/same-as-ingredient:2, 0/no-more-render + go-render? <- copy 0/false + reply } - reply editor/same-as-ingredient:0, screen/same-as-ingredient:2, 1/go-render + go-render? <- copy 1/true + reply ] # helper for tests -recipe editor-render [ +recipe editor-render screen:address:screen, editor:address:editor-data [ local-scope - screen:address:screen <- next-ingredient - editor:address:editor-data <- next-ingredient + load-ingredients left:number <- get *editor, left:offset right:number <- get *editor, right:offset row:number, column:number <- render screen, editor @@ -705,7 +696,8 @@ after <insert-character-special-case> [ break-unless below-screen? <scroll-down> } - reply editor/same-as-ingredient:0, screen/same-as-ingredient:2, 1/go-render + go-render? <- copy 1/true + reply } ] @@ -825,17 +817,17 @@ after <handle-special-character> [ <insert-enter-begin> editor <- insert-new-line-and-indent editor, screen <insert-enter-end> - reply screen/same-as-ingredient:0, editor/same-as-ingredient:1, 1/go-render + go-render? <- copy 1/true + reply } ] -recipe insert-new-line-and-indent [ +recipe insert-new-line-and-indent editor:address:editor-data, screen:address:screen -> editor:address:editor-data, screen:address:screen, go-render?:boolean [ local-scope - editor:address:editor-data <- next-ingredient - screen:address:screen <- next-ingredient + load-ingredients cursor-row:address:number <- get-address *editor, cursor-row:offset cursor-column:address:number <- get-address *editor, cursor-column:offset - before-cursor:address:address:duplex-list <- get-address *editor, before-cursor:offset + before-cursor:address:address:duplex-list:character <- get-address *editor, before-cursor:offset left:number <- get *editor, left:offset right:number <- get *editor, right:offset screen-height:number <- screen-height screen @@ -849,13 +841,14 @@ recipe insert-new-line-and-indent [ below-screen?:boolean <- greater-or-equal *cursor-row, screen-height # must be equal, never greater break-unless below-screen? <scroll-down> + go-render? <- copy 1/true *cursor-row <- subtract *cursor-row, 1 # bring back into screen range } # indent if necessary indent?:boolean <- get *editor, indent?:offset - reply-unless indent?, editor/same-as-ingredient:0, screen/same-as-ingredient:1 - d:address:duplex-list <- get *editor, data:offset - end-of-previous-line:address:duplex-list <- prev-duplex *before-cursor + reply-unless indent? + d:address:duplex-list:character <- get *editor, data:offset + end-of-previous-line:address:duplex-list:character <- prev-duplex *before-cursor indent:number <- line-indent end-of-previous-line, d i:number <- copy 0 { @@ -865,19 +858,17 @@ recipe insert-new-line-and-indent [ i <- add i, 1 loop } - reply editor/same-as-ingredient:0, screen/same-as-ingredient:1 ] # takes a pointer 'curr' into the doubly-linked list and its sentinel, counts # the number of spaces at the start of the line containing 'curr'. -recipe line-indent [ +recipe line-indent curr:address:duplex-list:character, start:address:duplex-list:character -> result:number [ local-scope - curr:address:duplex-list <- next-ingredient - start:address:duplex-list <- next-ingredient + load-ingredients result:number <- copy 0 - reply-unless curr, result + reply-unless curr at-start?:boolean <- equal curr, start - reply-if at-start?, result + reply-if at-start? { curr <- prev-duplex curr break-unless curr @@ -899,7 +890,6 @@ recipe line-indent [ } loop } - reply result ] scenario editor-moves-cursor-down-after-inserting-newline-2 [ @@ -1004,7 +994,8 @@ after <handle-special-key> [ break-unless paste-start? indent?:address:boolean <- get-address *editor, indent?:offset *indent? <- copy 0/false - reply screen/same-as-ingredient:0, editor/same-as-ingredient:1, 1/go-render + go-render? <- copy 1/true + reply } ] @@ -1014,18 +1005,16 @@ after <handle-special-key> [ break-unless paste-end? indent?:address:boolean <- get-address *editor, indent?:offset *indent? <- copy 1/true - reply screen/same-as-ingredient:0, editor/same-as-ingredient:1, 1/go-render + go-render? <- copy 1/true + reply } ] ## helpers -recipe draw-horizontal [ +recipe draw-horizontal screen:address:screen, row:number, x:number, right:number [ local-scope - screen:address:screen <- next-ingredient - row:number <- next-ingredient - x:number <- next-ingredient - right:number <- next-ingredient + load-ingredients style:character, style-found?:boolean <- next-ingredient { break-if style-found? diff --git a/edit/003-shortcuts.mu b/edit/003-shortcuts.mu index ac5b468e..10f46357 100644 --- a/edit/003-shortcuts.mu +++ b/edit/003-shortcuts.mu @@ -31,7 +31,8 @@ after <handle-special-character> [ editor, screen, go-render?:boolean <- insert-at-cursor editor, 32/space, screen editor, screen, go-render?:boolean <- insert-at-cursor editor, 32/space, screen <insert-character-end> - reply screen/same-as-ingredient:0, editor/same-as-ingredient:1, 1/go-render + go-render? <- copy 1/true + reply } ] @@ -70,46 +71,48 @@ after <handle-special-character> [ delete-previous-character?:boolean <- equal *c, 8/backspace break-unless delete-previous-character? <backspace-character-begin> - editor, screen, go-render?:boolean, backspaced-cell:address:duplex-list <- delete-before-cursor editor, screen + editor, screen, go-render?:boolean, backspaced-cell:address:duplex-list:character <- delete-before-cursor editor, screen <backspace-character-end> - reply screen/same-as-ingredient:0, editor/same-as-ingredient:1, go-render? + reply } ] -# editor, screen, go-render?:boolean, backspaced-cell:address:duplex-list <- delete-before-cursor editor:address:editor-data, screen # return values: # go-render? - whether caller needs to update the screen # backspaced-cell - value deleted (or 0 if nothing was deleted) so we can save it for undo, etc. -recipe delete-before-cursor [ +recipe delete-before-cursor editor:address:editor-data, screen:address:screen -> editor:address:editor-data, screen:address:screen, go-render?:boolean, backspaced-cell:address:duplex-list:character [ local-scope - editor:address:editor-data <- next-ingredient - screen:address:screen <- next-ingredient - before-cursor:address:address:duplex-list <- get-address *editor, before-cursor:offset + load-ingredients + before-cursor:address:address:duplex-list:character <- get-address *editor, before-cursor:offset # if at start of text (before-cursor at § sentinel), return - prev:address:duplex-list <- prev-duplex *before-cursor - reply-unless prev, editor/same-as-ingredient:0, screen/same-as-ingredient:1, 0/no-more-render, 0/nothing-deleted + prev:address:duplex-list:character <- prev-duplex *before-cursor + go-render?, backspaced-cell <- copy 0/no-more-render, 0/nothing-deleted + reply-unless prev trace 10, [app], [delete-before-cursor] original-row:number <- get *editor, cursor-row:offset editor, scroll?:boolean <- move-cursor-coordinates-left editor - backspaced-cell:address:duplex-list <- copy *before-cursor + backspaced-cell:address:duplex-list:character <- copy *before-cursor remove-duplex *before-cursor # will also neatly trim next/prev pointers in backspaced-cell/*before-cursor *before-cursor <- copy prev - reply-if scroll?, editor/same-as-ingredient:0, 1/go-render, backspaced-cell + go-render? <- copy 1/true + reply-if scroll? screen-width:number <- screen-width screen cursor-row:number <- get *editor, cursor-row:offset cursor-column:number <- get *editor, cursor-column:offset # did we just backspace over a newline? same-row?:boolean <- equal cursor-row, original-row - reply-unless same-row?, editor/same-as-ingredient:0, screen/same-as-ingredient:1, 1/go-render, backspaced-cell + go-render? <- copy 1/true + reply-unless same-row? left:number <- get *editor, left:offset right:number <- get *editor, right:offset - curr:address:duplex-list <- next-duplex *before-cursor + curr:address:duplex-list:character <- next-duplex *before-cursor screen <- move-cursor screen, cursor-row, cursor-column curr-column:number <- copy cursor-column { # hit right margin? give up and let caller render at-right?:boolean <- greater-or-equal curr-column, screen-width - reply-if at-right?, editor/same-as-ingredient:0, screen/same-as-ingredient:1, 1/go-render, backspaced-cell + go-render? <- copy 1/true + reply-if at-right? break-unless curr # newline? done. currc:character <- get *curr, value:offset @@ -122,13 +125,13 @@ recipe delete-before-cursor [ } # we're guaranteed not to be at the right margin screen <- print-character screen, 32/space - reply editor/same-as-ingredient:0, screen/same-as-ingredient:1, 0/no-more-render, backspaced-cell + go-render? <- copy 0/false ] -recipe move-cursor-coordinates-left [ +recipe move-cursor-coordinates-left editor:address:editor-data -> editor:address:editor-data, go-render?:boolean [ local-scope - editor:address:editor-data <- next-ingredient - before-cursor:address:duplex-list <- get *editor, before-cursor:offset + load-ingredients + before-cursor:address:duplex-list:character <- get *editor, before-cursor:offset cursor-row:address:number <- get-address *editor, cursor-row:offset cursor-column:address:number <- get-address *editor, cursor-column:offset left:number <- get *editor, left:offset @@ -138,7 +141,8 @@ recipe move-cursor-coordinates-left [ break-if at-left-margin? trace 10, [app], [decrementing cursor column] *cursor-column <- subtract *cursor-column, 1 - reply editor/same-as-ingredient:0, 0/no-more-render + go-render? <- copy 0/false + reply } # if at left margin, we must move to previous row: top-of-screen?:boolean <- equal *cursor-row, 1 # exclude menu bar @@ -159,28 +163,26 @@ recipe move-cursor-coordinates-left [ break-unless previous-character-is-newline? # compute length of previous line trace 10, [app], [switching to previous line] - d:address:duplex-list <- get *editor, data:offset + d:address:duplex-list:character <- get *editor, data:offset end-of-line:number <- previous-line-length before-cursor, d *cursor-column <- add left, end-of-line - reply editor/same-as-ingredient:0, go-render? + reply } # case 2: if previous-character was not newline, we're just at a wrapped line trace 10, [app], [wrapping to previous line] right:number <- get *editor, right:offset *cursor-column <- subtract right, 1 # leave room for wrap icon - reply editor/same-as-ingredient:0, go-render? ] # takes a pointer 'curr' into the doubly-linked list and its sentinel, counts # the length of the previous line before the 'curr' pointer. -recipe previous-line-length [ +recipe previous-line-length curr:address:duplex-list:character, start:address:duplex-list:character -> result:number [ local-scope - curr:address:duplex-list <- next-ingredient - start:address:duplex-list <- next-ingredient + load-ingredients result:number <- copy 0 - reply-unless curr, result + reply-unless curr at-start?:boolean <- equal curr, start - reply-if at-start?, result + reply-if at-start? { curr <- prev-duplex curr break-unless curr @@ -192,7 +194,6 @@ recipe previous-line-length [ result <- add result, 1 loop } - reply result ] scenario editor-clears-last-line-on-backspace [ @@ -264,25 +265,26 @@ after <handle-special-key> [ delete-next-character?:boolean <- equal *k, 65522/delete break-unless delete-next-character? <delete-character-begin> - editor, screen, go-render?:boolean, deleted-cell:address:duplex-list <- delete-at-cursor editor, screen + editor, screen, go-render?:boolean, deleted-cell:address:duplex-list:character <- delete-at-cursor editor, screen <delete-character-end> - reply screen/same-as-ingredient:0, editor/same-as-ingredient:1, go-render? + reply } ] -recipe delete-at-cursor [ +recipe delete-at-cursor editor:address:editor-data, screen:address:screen -> editor:address:editor-data, screen:address:screen, go-render?:boolean, deleted-cell:address:duplex-list:character [ local-scope - editor:address:editor-data <- next-ingredient - screen:address:screen <- next-ingredient - before-cursor:address:address:duplex-list <- get-address *editor, before-cursor:offset - candidate:address:duplex-list <- next-duplex *before-cursor - reply-unless candidate, editor/same-as-ingredient:0, screen/same-as-ingredient:1, 0/no-more-render, 0/nothing-deleted - currc:character <- get *candidate, value:offset - remove-duplex candidate + load-ingredients + before-cursor:address:address:duplex-list:character <- get-address *editor, before-cursor:offset + deleted-cell:address:duplex-list:character <- next-duplex *before-cursor + go-render? <- copy 0/false + reply-unless deleted-cell + currc:character <- get *deleted-cell, value:offset + remove-duplex deleted-cell deleted-newline?:boolean <- equal currc, 10/newline - reply-if deleted-newline?, editor/same-as-ingredient:0, screen/same-as-ingredient:1, 1/go-render, candidate/deleted-cell + go-render? <- copy 1/true + reply-if deleted-newline? # wasn't a newline? render rest of line - curr:address:duplex-list <- next-duplex *before-cursor # refresh after remove-duplex above + curr:address:duplex-list:character <- next-duplex *before-cursor # refresh after remove-duplex above cursor-row:address:number <- get-address *editor, cursor-row:offset cursor-column:address:number <- get-address *editor, cursor-column:offset screen <- move-cursor screen, *cursor-row, *cursor-column @@ -291,7 +293,8 @@ recipe delete-at-cursor [ { # hit right margin? give up and let caller render at-right?:boolean <- greater-or-equal curr-column, screen-width - reply-if at-right?, editor/same-as-ingredient:0, screen/same-as-ingredient:1, 1/go-render, candidate/deleted-cell + go-render? <- copy 1/true + reply-if at-right? break-unless curr # newline? done. currc:character <- get *curr, value:offset @@ -304,7 +307,7 @@ recipe delete-at-cursor [ } # we're guaranteed not to be at the right margin screen <- print-character screen, 32/space - reply editor/same-as-ingredient:0, screen/same-as-ingredient:1, 0/no-more-render, candidate/deleted-cell + go-render? <- copy 0/false ] # right arrow @@ -336,7 +339,7 @@ after <handle-special-key> [ move-to-next-character?:boolean <- equal *k, 65514/right-arrow break-unless move-to-next-character? # if not at end of text - next-cursor:address:duplex-list <- next-duplex *before-cursor + next-cursor:address:duplex-list:character <- next-duplex *before-cursor break-unless next-cursor # scan to next character <move-cursor-begin> @@ -345,15 +348,14 @@ after <handle-special-key> [ screen <- move-cursor screen, *cursor-row, *cursor-column undo-coalesce-tag:number <- copy 2/right-arrow <move-cursor-end> - reply screen/same-as-ingredient:0, editor/same-as-ingredient:1, go-render? + reply } ] -recipe move-cursor-coordinates-right [ +recipe move-cursor-coordinates-right editor:address:editor-data, screen-height:number -> editor:address:editor-data, go-render?:boolean [ local-scope - editor:address:editor-data <- next-ingredient - screen-height:number <- next-ingredient - before-cursor:address:duplex-list <- get *editor before-cursor:offset + load-ingredients + before-cursor:address:duplex-list:character <- get *editor before-cursor:offset cursor-row:address:number <- get-address *editor, cursor-row:offset cursor-column:address:number <- get-address *editor, cursor-column:offset left:number <- get *editor, left:offset @@ -366,10 +368,12 @@ recipe move-cursor-coordinates-right [ *cursor-row <- add *cursor-row, 1 *cursor-column <- copy left below-screen?:boolean <- greater-or-equal *cursor-row, screen-height # must be equal - reply-unless below-screen?, editor/same-as-ingredient:0, 0/no-more-render + go-render? <- copy 0/false + reply-unless below-screen? <scroll-down> *cursor-row <- subtract *cursor-row, 1 # bring back into screen range - reply editor/same-as-ingredient:0, 1/go-render + go-render? <- copy 1/true + reply } # if the line wraps, move cursor to start of next row { @@ -378,7 +382,7 @@ recipe move-cursor-coordinates-right [ at-wrap?:boolean <- equal *cursor-column, wrap-column break-unless at-wrap? # and if next character isn't newline - next:address:duplex-list <- next-duplex before-cursor + next:address:duplex-list:character <- next-duplex before-cursor break-unless next next-character:character <- get *next, value:offset newline?:boolean <- equal next-character, 10/newline @@ -389,11 +393,12 @@ recipe move-cursor-coordinates-right [ reply-unless below-screen?, editor/same-as-ingredient:0, 0/no-more-render <scroll-down> *cursor-row <- subtract *cursor-row, 1 # bring back into screen range - reply editor/same-as-ingredient:0, 1/go-render + go-render? <- copy 1/true + reply } # otherwise move cursor one character right *cursor-column <- add *cursor-column, 1 - reply editor/same-as-ingredient:0, 0/no-more-render + go-render? <- copy 0/false ] scenario editor-moves-cursor-to-next-line-with-right-arrow [ @@ -611,14 +616,15 @@ after <handle-special-key> [ break-unless move-to-previous-character? trace 10, [app], [left arrow] # if not at start of text (before-cursor at § sentinel) - prev:address:duplex-list <- prev-duplex *before-cursor - reply-unless prev, screen/same-as-ingredient:0, editor/same-as-ingredient:1, 0/no-more-render + prev:address:duplex-list:character <- prev-duplex *before-cursor + go-render? <- copy 0/false + reply-unless prev <move-cursor-begin> editor, go-render? <- move-cursor-coordinates-left editor *before-cursor <- copy prev undo-coalesce-tag:number <- copy 1/left-arrow <move-cursor-end> - reply screen/same-as-ingredient:0, editor/same-as-ingredient:1, go-render? + reply } ] @@ -811,16 +817,16 @@ after <handle-special-key> [ editor, go-render? <- move-to-previous-line editor undo-coalesce-tag:number <- copy 3/up-arrow <move-cursor-end> - reply screen/same-as-ingredient:0, editor/same-as-ingredient:1, go-render? + reply } ] -recipe move-to-previous-line [ +recipe move-to-previous-line editor:address:editor-data -> editor:address:editor-data, go-render?:boolean [ local-scope - editor:address:editor-data <- next-ingredient + load-ingredients cursor-row:address:number <- get-address *editor, cursor-row:offset cursor-column:address:number <- get-address *editor, cursor-column:offset - before-cursor:address:address:duplex-list <- get-address *editor, before-cursor:offset + before-cursor:address:address:duplex-list:character <- get-address *editor, before-cursor:offset left:number <- get *editor, left:offset right:number <- get *editor, right:offset already-at-top?:boolean <- lesser-or-equal *cursor-row, 1/top @@ -830,21 +836,23 @@ recipe move-to-previous-line [ # if not at newline, move to start of line (previous newline) # then scan back another line # if either step fails, give up without modifying cursor or coordinates - curr:address:duplex-list <- copy *before-cursor + curr:address:duplex-list:character <- copy *before-cursor { - old:address:duplex-list <- copy curr + old:address:duplex-list:character <- copy curr c2:character <- get *curr, value:offset at-newline?:boolean <- equal c2, 10/newline break-if at-newline? - curr:address:duplex-list <- before-previous-line curr, editor + curr:address:duplex-list:character <- before-previous-line curr, editor no-motion?:boolean <- equal curr, old - reply-if no-motion?, editor/same-as-ingredient:0, 0/no-more-render + go-render? <- copy 0/false + reply-if no-motion? } { old <- copy curr curr <- before-previous-line curr, editor no-motion?:boolean <- equal curr, old - reply-if no-motion?, editor/same-as-ingredient:0, 0/no-more-render + go-render? <- copy 0/false + reply-if no-motion? } *before-cursor <- copy curr *cursor-row <- subtract *cursor-row, 1 @@ -854,7 +862,7 @@ recipe move-to-previous-line [ { done?:boolean <- greater-or-equal *cursor-column, target-column break-if done? - curr:address:duplex-list <- next-duplex *before-cursor + curr:address:duplex-list:character <- next-duplex *before-cursor break-unless curr currc:character <- get *curr, value:offset at-newline?:boolean <- equal currc, 10/newline @@ -864,13 +872,15 @@ recipe move-to-previous-line [ *cursor-column <- add *cursor-column, 1 loop } - reply editor/same-as-ingredient:0, 0/no-more-render + go-render? <- copy 0/false + reply } { # if cursor already at top, scroll up break-unless already-at-top? <scroll-up> - reply editor/same-as-ingredient:0, 1/go-render + go-render? <- copy 1/true + reply } ] @@ -1032,17 +1042,16 @@ after <handle-special-key> [ editor, go-render? <- move-to-next-line editor, screen-height undo-coalesce-tag:number <- copy 4/down-arrow <move-cursor-end> - reply screen/same-as-ingredient:0, editor/same-as-ingredient:1, go-render? + reply } ] -recipe move-to-next-line [ +recipe move-to-next-line editor:address:editor-data, screen-height:number -> editor:address:editor-data, go-render?:boolean [ local-scope - editor:address:editor-data <- next-ingredient - screen-height:number <- next-ingredient + load-ingredients cursor-row:address:number <- get-address *editor, cursor-row:offset cursor-column:address:number <- get-address *editor, cursor-column:offset - before-cursor:address:address:duplex-list <- get-address *editor, before-cursor:offset + before-cursor:address:address:duplex-list:character <- get-address *editor, before-cursor:offset left:number <- get *editor, left:offset right:number <- get *editor, right:offset last-line:number <- subtract screen-height, 1 @@ -1052,7 +1061,7 @@ recipe move-to-next-line [ break-if already-at-bottom? # scan to start of next line, then to right column or until end of line max:number <- subtract right, left - next-line:address:duplex-list <- before-start-of-next-line *before-cursor, max + next-line:address:duplex-list:character <- before-start-of-next-line *before-cursor, max { # already at end of buffer? try to scroll up (so we can see more # warnings or sandboxes below) @@ -1060,7 +1069,8 @@ recipe move-to-next-line [ break-unless no-motion? scroll?:boolean <- greater-than *cursor-row, 1 break-if scroll?, +try-to-scroll:label - reply editor/same-as-ingredient:0, 0/no-more-render + go-render? <- copy 0/false + reply } *cursor-row <- add *cursor-row, 1 *before-cursor <- copy next-line @@ -1069,7 +1079,7 @@ recipe move-to-next-line [ { done?:boolean <- greater-or-equal *cursor-column, target-column break-if done? - curr:address:duplex-list <- next-duplex *before-cursor + curr:address:duplex-list:character <- next-duplex *before-cursor break-unless curr currc:character <- get *curr, value:offset at-newline?:boolean <- equal currc, 10/newline @@ -1079,11 +1089,12 @@ recipe move-to-next-line [ *cursor-column <- add *cursor-column, 1 loop } - reply editor/same-as-ingredient:0, 0/no-more-render + go-render? <- copy 0/false + reply } +try-to-scroll <scroll-down> - reply editor/same-as-ingredient:0, 1/go-render + go-render? <- copy 1/true ] scenario editor-adjusts-column-at-next-line [ @@ -1122,71 +1133,6 @@ de] ] ] -scenario editor-scrolls-at-end-on-down-arrow [ - assume-screen 10/width, 5/height - 1:address:array:character <- new [abc -de] - 2:address:editor-data <- new-editor 1:address:array:character, screen:address:screen, 0/left, 10/right - editor-render screen, 2:address:editor-data - $clear-trace - # try to move down past end of text - assume-console [ - left-click 2, 0 - press down-arrow - ] - 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 scroll, moving cursor to end of text - memory-should-contain [ - 3 <- 1 - 4 <- 2 - ] - assume-console [ - type [0] - ] - run [ - editor-event-loop screen:address:screen, console:address:console, 2:address:editor-data - ] - screen-should-contain [ - . . - .de0 . - .┈┈┈┈┈┈┈┈┈┈. - . . - ] - # try to move down again - $clear-trace - assume-console [ - left-click 2, 0 - press down-arrow - ] - 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 stops scrolling because cursor is already at top - memory-should-contain [ - 3 <- 1 - 4 <- 3 - ] - check-trace-count-for-label 0, [print-character] - assume-console [ - type [1] - ] - run [ - editor-event-loop screen:address:screen, console:address:console, 2:address:editor-data - ] - screen-should-contain [ - . . - .de01 . - .┈┈┈┈┈┈┈┈┈┈. - . . - ] -] - # ctrl-a/home - move cursor to start of line scenario editor-moves-to-start-of-line-with-ctrl-a [ @@ -1222,7 +1168,8 @@ after <handle-special-character> [ move-to-start-of-line editor undo-coalesce-tag:number <- copy 0/never <move-cursor-end> - reply screen/same-as-ingredient:0, editor/same-as-ingredient:1, 0/no-more-render + go-render? <- copy 0/false + reply } ] @@ -1234,20 +1181,21 @@ after <handle-special-key> [ move-to-start-of-line editor undo-coalesce-tag:number <- copy 0/never <move-cursor-end> - reply screen/same-as-ingredient:0, editor/same-as-ingredient:1, 0/no-more-render + go-render? <- copy 0/false + reply } ] -recipe move-to-start-of-line [ +recipe move-to-start-of-line editor:address:editor-data [ local-scope - editor:address:editor-data <- next-ingredient + load-ingredients # update cursor column left:number <- get *editor, left:offset cursor-column:address:number <- get-address *editor, cursor-column:offset *cursor-column <- copy left # update before-cursor - before-cursor:address:address:duplex-list <- get-address *editor, before-cursor:offset - init:address:duplex-list <- get *editor, data:offset + before-cursor:address:address:duplex-list:character <- get-address *editor, before-cursor:offset + init:address:duplex-list:character <- get *editor, data:offset # while not at start of line, move { at-start-of-text?:boolean <- equal *before-cursor, init @@ -1391,7 +1339,8 @@ after <handle-special-character> [ move-to-end-of-line editor undo-coalesce-tag:number <- copy 0/never <move-cursor-end> - reply screen/same-as-ingredient:0, editor/same-as-ingredient:1, 0/no-more-render + go-render? <- copy 0/false + reply } ] @@ -1403,18 +1352,19 @@ after <handle-special-key> [ move-to-end-of-line editor undo-coalesce-tag:number <- copy 0/never <move-cursor-end> - reply screen/same-as-ingredient:0, editor/same-as-ingredient:1, 0/no-more-render + go-render? <- copy 0/false + reply } ] -recipe move-to-end-of-line [ +recipe move-to-end-of-line editor:address:editor-data [ local-scope editor:address:editor-data <- next-ingredient - before-cursor:address:address:duplex-list <- get-address *editor, before-cursor:offset + before-cursor:address:address:duplex-list:character <- get-address *editor, before-cursor:offset cursor-column:address:number <- get-address *editor, cursor-column:offset # while not at start of line, move { - next:address:duplex-list <- next-duplex *before-cursor + next:address:duplex-list:character <- next-duplex *before-cursor break-unless next # end of text nextc:character <- get *next, value:offset at-end-of-line?:boolean <- equal nextc, 10/newline @@ -1530,20 +1480,21 @@ after <handle-special-character> [ delete-to-start-of-line?:boolean <- equal *c, 21/ctrl-u break-unless delete-to-start-of-line? <delete-to-start-of-line-begin> - deleted-cells:address:duplex-list <- delete-to-start-of-line editor + deleted-cells:address:duplex-list:character <- delete-to-start-of-line editor <delete-to-start-of-line-end> - reply screen/same-as-ingredient:0, editor/same-as-ingredient:1, 1/go-render + go-render? <- copy 1/true + reply } ] -recipe delete-to-start-of-line [ +recipe delete-to-start-of-line editor:address:editor-data -> result:address:duplex-list:character [ local-scope - editor:address:editor-data <- next-ingredient + load-ingredients # compute range to delete - init:address:duplex-list <- get *editor, data:offset - before-cursor:address:address:duplex-list <- get-address *editor, before-cursor:offset - start:address:duplex-list <- copy *before-cursor - end:address:duplex-list <- next-duplex *before-cursor + init:address:duplex-list:character <- get *editor, data:offset + before-cursor:address:address:duplex-list:character <- get-address *editor, before-cursor:offset + start:address:duplex-list:character <- copy *before-cursor + end:address:duplex-list:character <- next-duplex *before-cursor { at-start-of-text?:boolean <- equal start, init break-if at-start-of-text? @@ -1555,14 +1506,13 @@ recipe delete-to-start-of-line [ loop } # snip it out - result:address:duplex-list <- next-duplex start + result:address:duplex-list:character <- next-duplex start remove-duplex-between start, end # adjust cursor *before-cursor <- copy start left:number <- get *editor, left:offset cursor-column:address:number <- get-address *editor, cursor-column:offset *cursor-column <- copy left - reply result ] scenario editor-deletes-to-start-of-line-with-ctrl-u-2 [ @@ -1664,18 +1614,19 @@ after <handle-special-character> [ delete-to-end-of-line?:boolean <- equal *c, 11/ctrl-k break-unless delete-to-end-of-line? <delete-to-end-of-line-begin> - deleted-cells:address:duplex-list <- delete-to-end-of-line editor + deleted-cells:address:duplex-list:character <- delete-to-end-of-line editor <delete-to-end-of-line-end> - reply screen/same-as-ingredient:0, editor/same-as-ingredient:1, 1/go-render + go-render? <- copy 1/true + reply } ] -recipe delete-to-end-of-line [ +recipe delete-to-end-of-line editor:address:editor-data -> result:address:duplex-list:character [ local-scope - editor:address:editor-data <- next-ingredient + load-ingredients # compute range to delete - start:address:duplex-list <- get *editor, before-cursor:offset - end:address:duplex-list <- next-duplex start + start:address:duplex-list:character <- get *editor, before-cursor:offset + end:address:duplex-list:character <- next-duplex start { at-end-of-text?:boolean <- equal end, 0/null break-if at-end-of-text? @@ -1686,9 +1637,8 @@ recipe delete-to-end-of-line [ loop } # snip it out - result:address:duplex-list <- next-duplex start + result:address:duplex-list:character <- next-duplex start # XXX: segfault on deleting this type remove-duplex-between start, end - reply result ] scenario editor-deletes-to-end-of-line-with-ctrl-k-2 [ @@ -1842,29 +1792,25 @@ d] after <scroll-down> [ trace 10, [app], [scroll down] - top-of-screen:address:address:duplex-list <- get-address *editor, top-of-screen:offset + top-of-screen:address:address:duplex-list:character <- get-address *editor, top-of-screen:offset left:number <- get *editor, left:offset right:number <- get *editor, right:offset max:number <- subtract right, left - old-top:address:duplex-list <- copy *top-of-screen + old-top:address:duplex-list:character <- copy *top-of-screen *top-of-screen <- before-start-of-next-line *top-of-screen, max no-movement?:boolean <- equal old-top, *top-of-screen - # Hack: this reply doesn't match one of the locations of <scroll-down>, - # directly within insert-at-cursor. However, I'm unable to trigger the - # error.. If necessary create a duplicate copy of <scroll-down> with the - # right 'reply-if'. - reply-if no-movement?, editor/same-as-ingredient:0, 0/no-more-render + go-render? <- copy 0/false + reply-if no-movement? ] # takes a pointer into the doubly-linked list, scans ahead at most 'max' # positions until the next newline # beware: never return null pointer. -recipe before-start-of-next-line [ +recipe before-start-of-next-line original:address:duplex-list:character, max:number -> curr:address:duplex-list:character [ local-scope - original:address:duplex-list <- next-ingredient - max:number <- next-ingredient + load-ingredients count:number <- copy 0 - curr:address:duplex-list <- copy original + curr:address:duplex-list:character <- copy original # skip the initial newline if it exists { c:character <- get *curr, value:offset @@ -2085,6 +2031,71 @@ d] ] ] +scenario editor-scrolls-at-end-on-down-arrow [ + assume-screen 10/width, 5/height + 1:address:array:character <- new [abc +de] + 2:address:editor-data <- new-editor 1:address:array:character, screen:address:screen, 0/left, 10/right + editor-render screen, 2:address:editor-data + $clear-trace + # try to move down past end of text + assume-console [ + left-click 2, 0 + press down-arrow + ] + 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 scroll, moving cursor to end of text + memory-should-contain [ + 3 <- 1 + 4 <- 2 + ] + assume-console [ + type [0] + ] + run [ + editor-event-loop screen:address:screen, console:address:console, 2:address:editor-data + ] + screen-should-contain [ + . . + .de0 . + .┈┈┈┈┈┈┈┈┈┈. + . . + ] + # try to move down again + $clear-trace + assume-console [ + left-click 2, 0 + press down-arrow + ] + 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 stops scrolling because cursor is already at top + memory-should-contain [ + 3 <- 1 + 4 <- 3 + ] + check-trace-count-for-label 0, [print-character] + assume-console [ + type [1] + ] + run [ + editor-event-loop screen:address:screen, console:address:console, 2:address:editor-data + ] + screen-should-contain [ + . . + .de01 . + .┈┈┈┈┈┈┈┈┈┈. + . . + ] +] + scenario editor-combines-page-and-line-scroll [ # screen has 1 line for menu + 3 lines assume-screen 10/width, 4/height @@ -2151,19 +2162,20 @@ d] after <scroll-up> [ trace 10, [app], [scroll up] - top-of-screen:address:address:duplex-list <- get-address *editor, top-of-screen:offset - old-top:address:duplex-list <- copy *top-of-screen + top-of-screen:address:address:duplex-list:character <- get-address *editor, top-of-screen:offset + old-top:address:duplex-list:character <- copy *top-of-screen *top-of-screen <- before-previous-line *top-of-screen, editor no-movement?:boolean <- equal old-top, *top-of-screen - reply-if no-movement?, editor/same-as-ingredient:0, 0/no-more-render + go-render? <- copy 0/false + reply-if no-movement? ] # takes a pointer into the doubly-linked list, scans back to before start of # previous *wrapped* line # beware: never return null pointer -recipe before-previous-line [ +recipe before-previous-line curr:address:duplex-list:character -> curr:address:duplex-list:character [ local-scope - curr:address:duplex-list <- next-ingredient + curr:address:duplex-list:character <- next-ingredient c:character <- get *curr, value:offset # compute max, number of characters to skip # 1 + len%(width-1) @@ -2172,12 +2184,12 @@ recipe before-previous-line [ left:number <- get *editor, left:offset right:number <- get *editor, right:offset max-line-length:number <- subtract right, left, -1/exclusive-right, 1/wrap-icon - sentinel:address:duplex-list <- get *editor, data:offset + sentinel:address:duplex-list:character <- get *editor, data:offset len:number <- previous-line-length curr, sentinel { break-if len # empty line; just skip this newline - prev:address:duplex-list <- prev-duplex curr + prev:address:duplex-list:character <- prev-duplex curr reply-unless prev, curr reply prev } @@ -2193,7 +2205,7 @@ recipe before-previous-line [ { done?:boolean <- greater-or-equal count, max break-if done? - prev:address:duplex-list <- prev-duplex curr + prev:address:duplex-list:character <- prev-duplex curr break-unless prev curr <- copy prev count <- add count, 1 @@ -2541,15 +2553,15 @@ after <handle-special-character> [ { page-down?:boolean <- equal *c, 6/ctrl-f break-unless page-down? - top-of-screen:address:address:duplex-list <- get-address *editor, top-of-screen:offset - old-top:address:duplex-list <- copy *top-of-screen + top-of-screen:address:address:duplex-list:character <- get-address *editor, top-of-screen:offset + old-top:address:duplex-list:character <- copy *top-of-screen <move-cursor-begin> page-down editor undo-coalesce-tag:number <- copy 0/never <move-cursor-end> no-movement?:boolean <- equal *top-of-screen, old-top - reply-if no-movement?, screen/same-as-ingredient:0, editor/same-as-ingredient:1, 0/no-more-render - reply screen/same-as-ingredient:0, editor/same-as-ingredient:1, 1/go-render + go-render? <- not no-movement? + reply } ] @@ -2557,28 +2569,28 @@ after <handle-special-key> [ { page-down?:boolean <- equal *k, 65518/page-down break-unless page-down? - top-of-screen:address:address:duplex-list <- get-address *editor, top-of-screen:offset - old-top:address:duplex-list <- copy *top-of-screen + top-of-screen:address:address:duplex-list:character <- get-address *editor, top-of-screen:offset + old-top:address:duplex-list:character <- copy *top-of-screen <move-cursor-begin> page-down editor undo-coalesce-tag:number <- copy 0/never <move-cursor-end> no-movement?:boolean <- equal *top-of-screen, old-top - reply-if no-movement?, screen/same-as-ingredient:0, editor/same-as-ingredient:1, 0/no-more-render - reply screen/same-as-ingredient:0, editor/same-as-ingredient:1, 1/go-render + go-render? <- not no-movement? + reply } ] # page-down skips entire wrapped lines, so it can't scroll past lines # taking up the entire screen -recipe page-down [ +recipe page-down editor:address:editor-data -> editor:address:editor-data [ local-scope - editor:address:editor-data <- next-ingredient + load-ingredients # if editor contents don't overflow screen, do nothing - bottom-of-screen:address:duplex-list <- get *editor, bottom-of-screen:offset - reply-unless bottom-of-screen, editor/same-as-ingredient:0 + bottom-of-screen:address:duplex-list:character <- get *editor, bottom-of-screen:offset + reply-unless bottom-of-screen # if not, position cursor at final character - before-cursor:address:address:duplex-list <- get-address *editor, before-cursor:offset + before-cursor:address:address:duplex-list:character <- get-address *editor, before-cursor:offset *before-cursor <- prev-duplex bottom-of-screen # keep one line in common with previous page { @@ -2589,9 +2601,8 @@ recipe page-down [ } # move cursor and top-of-screen to start of that line move-to-start-of-line editor - top-of-screen:address:address:duplex-list <- get-address *editor, top-of-screen:offset + top-of-screen:address:address:duplex-list:character <- get-address *editor, top-of-screen:offset *top-of-screen <- copy *before-cursor - reply editor/same-as-ingredient:0 ] scenario editor-does-not-scroll-past-end [ @@ -2734,15 +2745,15 @@ after <handle-special-character> [ { page-up?:boolean <- equal *c, 2/ctrl-b break-unless page-up? - top-of-screen:address:address:duplex-list <- get-address *editor, top-of-screen:offset - old-top:address:duplex-list <- copy *top-of-screen + top-of-screen:address:address:duplex-list:character <- get-address *editor, top-of-screen:offset + old-top:address:duplex-list:character <- copy *top-of-screen <move-cursor-begin> editor <- page-up editor, screen-height undo-coalesce-tag:number <- copy 0/never <move-cursor-end> no-movement?:boolean <- equal *top-of-screen, old-top - reply-if no-movement?, screen/same-as-ingredient:0, editor/same-as-ingredient:1, 0/no-more-render - reply screen/same-as-ingredient:0, editor/same-as-ingredient:1, 1/go-render + go-render? <- not no-movement? + reply } ] @@ -2750,36 +2761,35 @@ after <handle-special-key> [ { page-up?:boolean <- equal *k, 65519/page-up break-unless page-up? - top-of-screen:address:address:duplex-list <- get-address *editor, top-of-screen:offset - old-top:address:duplex-list <- copy *top-of-screen + top-of-screen:address:address:duplex-list:character <- get-address *editor, top-of-screen:offset + old-top:address:duplex-list:character <- copy *top-of-screen <move-cursor-begin> editor <- page-up editor, screen-height undo-coalesce-tag:number <- copy 0/never <move-cursor-end> no-movement?:boolean <- equal *top-of-screen, old-top # don't bother re-rendering if nothing changed. todo: test this - reply-if no-movement?, screen/same-as-ingredient:0, editor/same-as-ingredient:1, 0/no-more-render - reply screen/same-as-ingredient:0, editor/same-as-ingredient:1, 1/go-render + go-render? <- not no-movement? + reply } ] -recipe page-up [ +recipe page-up editor:address:editor-data, screen-height:number -> editor:address:editor-data [ local-scope editor:address:editor-data <- next-ingredient screen-height:number <- next-ingredient max:number <- subtract screen-height, 1/menu-bar, 1/overlapping-line count:number <- copy 0 - top-of-screen:address:address:duplex-list <- get-address *editor, top-of-screen:offset + top-of-screen:address:address:duplex-list:character <- get-address *editor, top-of-screen:offset { done?:boolean <- greater-or-equal count, max break-if done? - prev:address:duplex-list <- before-previous-line *top-of-screen, editor + prev:address:duplex-list:character <- before-previous-line *top-of-screen, editor break-unless prev *top-of-screen <- copy prev count <- add count, 1 loop } - reply editor/same-as-ingredient:0 ] scenario editor-can-scroll-up-multiple-pages [ diff --git a/edit/004-programming-environment.mu b/edit/004-programming-environment.mu index e06f9f72..d5c6d093 100644 --- a/edit/004-programming-environment.mu +++ b/edit/004-programming-environment.mu @@ -21,15 +21,13 @@ container programming-environment-data [ sandbox-in-focus?:boolean # false => cursor in recipes; true => cursor in current-sandbox ] -recipe new-programming-environment [ +recipe new-programming-environment screen:address:screen, initial-recipe-contents:address:array:character, initial-sandbox-contents:address:array:character -> result:address:programming-environment-data [ local-scope - screen:address:screen <- next-ingredient - initial-recipe-contents:address:array:character <- next-ingredient - initial-sandbox-contents:address:array:character <- next-ingredient + load-ingredients width:number <- screen-width screen height:number <- screen-height screen # top menu - result:address:programming-environment-data <- new programming-environment-data:type + result <- new programming-environment-data:type draw-horizontal screen, 0, 0/left, width, 32/space, 0/black, 238/grey button-start:number <- subtract width, 20 button-on-screen?:boolean <- greater-or-equal button-start, 0 @@ -47,15 +45,11 @@ recipe new-programming-environment [ new-left:number <- add divider, 1 current-sandbox:address:address:editor-data <- get-address *result, current-sandbox:offset *current-sandbox <- new-editor initial-sandbox-contents, screen, new-left, width/right - +programming-environment-initialization - reply result ] -recipe event-loop [ +recipe event-loop screen:address:screen, console:address:console, env:address:programming-environment-data [ local-scope - screen:address:screen <- next-ingredient - console:address:console <- next-ingredient - env:address:programming-environment-data <- next-ingredient + load-ingredients recipes:address:editor-data <- get *env, recipes:offset current-sandbox:address:editor-data <- get *env, current-sandbox:offset sandbox-in-focus?:address:boolean <- get-address *env, sandbox-in-focus?:offset @@ -185,10 +179,9 @@ recipe event-loop [ } ] -recipe resize [ +recipe resize screen:address:screen, env:address:programming-environment-data -> env:address:programming-environment-data [ local-scope - screen:address:screen <- next-ingredient - env:address:programming-environment-data <- next-ingredient + load-ingredients clear-screen screen # update screen dimensions width:number <- screen-width screen divider:number, _ <- divide-with-remainder width, 2 @@ -212,7 +205,6 @@ recipe resize [ *cursor-row <- copy 1 cursor-column:address:number <- get-address *current-sandbox, cursor-column:offset *cursor-column <- copy *left - reply env/same-as-ingredient:1 ] scenario point-at-multiple-editors [ @@ -375,10 +367,9 @@ def] ] ] -recipe render-all [ +recipe render-all screen:address:screen, env:address:programming-environment-data -> screen:address:screen [ local-scope - screen:address:screen <- next-ingredient - env:address:programming-environment-data <- next-ingredient + load-ingredients trace 10, [app], [render all] hide-screen screen # top menu @@ -407,13 +398,11 @@ recipe render-all [ screen <- update-cursor screen, recipes, current-sandbox, sandbox-in-focus? # show-screen screen - reply screen/same-as-ingredient:0 ] -recipe render-recipes [ +recipe render-recipes screen:address:screen, env:address:programming-environment-data -> screen:address:screen [ local-scope - screen:address:screen <- next-ingredient - env:address:programming-environment-data <- next-ingredient + load-ingredients trace 11, [app], [render recipes] recipes:address:editor-data <- get *env, recipes:offset # render recipes @@ -427,14 +416,12 @@ recipe render-recipes [ draw-horizontal screen, row, left, right, 9480/horizontal-dotted row <- add row, 1 clear-screen-from screen, row, left, left, right - reply screen/same-as-ingredient:0 ] # replaced in a later layer -recipe render-sandbox-side [ +recipe render-sandbox-side screen:address:screen, env:address:programming-environment-data -> screen:address:screen [ local-scope - screen:address:screen <- next-ingredient - env:address:programming-environment-data <- next-ingredient + load-ingredients current-sandbox:address:editor-data <- get *env, current-sandbox:offset left:number <- get *current-sandbox, left:offset right:number <- get *current-sandbox, right:offset @@ -445,15 +432,11 @@ recipe render-sandbox-side [ draw-horizontal screen, row, left, right, 9473/horizontal row <- add row, 1 clear-screen-from screen, row, left, left, right - reply screen/same-as-ingredient:0 ] -recipe update-cursor [ +recipe update-cursor screen:address:screen, recipes:address:editor-data, current-sandbox:address:editor-data, sandbox-in-focus?:boolean -> screen:address:screen [ local-scope - screen:address:screen <- next-ingredient - recipes:address:editor-data <- next-ingredient - current-sandbox:address:editor-data <- next-ingredient - sandbox-in-focus?:boolean <- next-ingredient + load-ingredients { break-if sandbox-in-focus? cursor-row:number <- get *recipes, cursor-row:offset @@ -465,21 +448,14 @@ recipe update-cursor [ cursor-column:number <- get *current-sandbox, cursor-column:offset } screen <- move-cursor screen, cursor-row, cursor-column - reply screen/same-as-ingredient:0 ] -# row, screen <- render-string screen:address:screen, s:address:array:character, left:number, right:number, color:number, row:number # print a string 's' to 'editor' in 'color' starting at 'row' # clear rest of last line, move cursor to next line -recipe render-string [ +recipe render-string screen:address:screen, s:address:array:character, left:number, right:number, color:number, row:number -> row:number, screen:address:screen [ local-scope - screen:address:screen <- next-ingredient - s:address:array:character <- next-ingredient - left:number <- next-ingredient - right:number <- next-ingredient - color:number <- next-ingredient - row:number <- next-ingredient - reply-unless s, row/same-as-ingredient:5, screen/same-as-ingredient:0 + load-ingredients + reply-unless s column:number <- copy left screen <- move-cursor screen, row, column screen-height:number <- screen-height screen @@ -532,19 +508,13 @@ recipe render-string [ row <- add row, 1 } move-cursor screen, row, left - reply row/same-as-ingredient:5, screen/same-as-ingredient:0 ] -# row, screen <- render-code-string screen:address:screen, s:address:array:character, left:number, right:number, row:number # like 'render-string' but with colorization for comments like in the editor -recipe render-code-string [ +recipe render-code-string screen:address:screen, s:address:array:character, left:number, right:number, color:number, row:number -> row:number, screen:address:screen [ local-scope - screen:address:screen <- next-ingredient - s:address:array:character <- next-ingredient - left:number <- next-ingredient - right:number <- next-ingredient - row:number <- next-ingredient - reply-unless s, row/same-as-ingredient:4, screen/same-as-ingredient:0 + load-ingredients + reply-unless s color:number <- copy 7/white column:number <- copy left screen <- move-cursor screen, row, column @@ -599,7 +569,6 @@ recipe render-code-string [ row <- add row, 1 } move-cursor screen, row, left - reply row/same-as-ingredient:4, screen/same-as-ingredient:0 ] # ctrl-l - redraw screen (just in case it printed junk somehow) @@ -696,11 +665,9 @@ after <global-type> [ } ] -recipe maximize [ +recipe maximize screen:address:screen, console:address:console, env:address:programming-environment-data -> screen:address:screen, console:address:console [ local-scope - screen:address:screen <- next-ingredient - console:address:console <- next-ingredient - env:address:programming-environment-data <- next-ingredient + load-ingredients hide-screen screen # maximize one of the sides maximized?:address:boolean <- get-address *env, maximized?:offset @@ -723,7 +690,6 @@ recipe maximize [ screen <- render-sandbox-side screen, env } show-screen screen - reply screen/same-as-ingredient:0, console/same-as-ingredient:1 ] # when maximized, wait for any event and simply unmaximize @@ -757,12 +723,9 @@ after <handle-event> [ ## helpers -recipe draw-vertical [ +recipe draw-vertical screen:address:screen, col:number, y:number, bottom:number [ local-scope - screen:address:screen <- next-ingredient - col:number <- next-ingredient - y:number <- next-ingredient - bottom:number <- next-ingredient + load-ingredients style:character, style-found?:boolean <- next-ingredient { break-if style-found? |