From 1156971774b307bec29fab34a523eb39a7904174 Mon Sep 17 00:00:00 2001 From: "Kartik K. Agaram" Date: Wed, 11 May 2016 18:00:11 -0700 Subject: 2953 - use pgup/pgdn to scroll through sandboxes In the process I've also simplified the sandbox/ app. Since it's impossible for sandbox editors to span multiple pages, we can drop all scroll support altogether. --- sandbox/003-shortcuts.mu | 1344 ++-------------------------------------------- 1 file changed, 35 insertions(+), 1309 deletions(-) (limited to 'sandbox/003-shortcuts.mu') diff --git a/sandbox/003-shortcuts.mu b/sandbox/003-shortcuts.mu index 40956cb3..46ab636e 100644 --- a/sandbox/003-shortcuts.mu +++ b/sandbox/003-shortcuts.mu @@ -89,21 +89,19 @@ def delete-before-cursor editor:address:editor-data, screen:address:screen -> ed prev:address:duplex-list:character <- prev before-cursor go-render?, backspaced-cell <- copy 0/no-more-render, 0/nothing-deleted return-unless prev + go-render? <- copy 1/true trace 10, [app], [delete-before-cursor] original-row:number <- get *editor, cursor-row:offset - editor, scroll?:boolean <- move-cursor-coordinates-left editor + editor <- move-cursor-coordinates-left editor backspaced-cell:address:duplex-list:character <- copy before-cursor data <- remove before-cursor, data # will also neatly trim next/prev pointers in backspaced-cell/before-cursor before-cursor <- copy prev *editor <- put *editor, before-cursor:offset, before-cursor - go-render? <- copy 1/true - return-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 - go-render? <- copy 1/true return-unless same-row? left:number <- get *editor, left:offset right:number <- get *editor, right:offset @@ -113,7 +111,6 @@ def delete-before-cursor editor:address:editor-data, screen:address:screen -> ed { # hit right margin? give up and let caller render at-right?:boolean <- greater-or-equal curr-column, right - go-render? <- copy 1/true return-if at-right? break-unless curr # newline? done. @@ -131,7 +128,7 @@ def delete-before-cursor editor:address:editor-data, screen:address:screen -> ed go-render? <- copy 0/false ] -def move-cursor-coordinates-left editor:address:editor-data -> editor:address:editor-data, go-render?:boolean [ +def move-cursor-coordinates-left editor:address:editor-data -> editor:address:editor-data [ local-scope load-ingredients before-cursor:address:duplex-list:character <- get *editor, before-cursor:offset @@ -145,12 +142,10 @@ def move-cursor-coordinates-left editor:address:editor-data -> editor:address:ed trace 10, [app], [decrementing cursor column] cursor-column <- subtract cursor-column, 1 *editor <- put *editor, cursor-column:offset, cursor-column - go-render? <- copy 0/false return } # if at left margin, we must move to previous row: top-of-screen?:boolean <- equal cursor-row, 1 # exclude menu bar - go-render?:boolean <- copy 0/false { break-if top-of-screen? cursor-row <- subtract cursor-row, 1 @@ -158,8 +153,7 @@ def move-cursor-coordinates-left editor:address:editor-data -> editor:address:ed } { break-unless top-of-screen? - - go-render? <- copy 1/true + # no scroll, so do nothing } { # case 1: if previous character was newline, figure out how long the previous line is @@ -452,7 +446,6 @@ def move-cursor-coordinates-right editor:address:editor-data, screen-height:numb below-screen?:boolean <- greater-or-equal cursor-row, screen-height # must be equal go-render? <- copy 0/false return-unless below-screen? - cursor-row <- subtract cursor-row, 1 # bring back into screen range *editor <- put *editor, cursor-row:offset, cursor-row go-render? <- copy 1/true @@ -476,7 +469,6 @@ def move-cursor-coordinates-right editor:address:editor-data, screen-height:numb *editor <- put *editor, cursor-column:offset, cursor-column below-screen?:boolean <- greater-or-equal cursor-row, screen-height # must be equal return-unless below-screen?, editor/same-as-ingredient:0, 0/no-more-render - cursor-row <- subtract cursor-row, 1 # bring back into screen range *editor <- put *editor, cursor-row:offset, cursor-row go-render? <- copy 1/true @@ -707,7 +699,7 @@ after [ go-render? <- copy 0/false return-unless prev - editor, go-render? <- move-cursor-coordinates-left editor + editor <- move-cursor-coordinates-left editor before-cursor <- copy prev *editor <- put *editor, before-cursor:offset, before-cursor undo-coalesce-tag:number <- copy 1/left-arrow @@ -1033,10 +1025,9 @@ def move-to-previous-line editor:address:editor-data -> editor:address:editor-da return } { - # if cursor already at top, scroll up + # if cursor already at top, do nothing break-unless already-at-top? - - go-render? <- copy 1/true + go-render? <- copy 0/true return } ] @@ -1196,14 +1187,14 @@ after [ move-to-next-line?:boolean <- equal k, 65516/down-arrow break-unless move-to-next-line? - editor, go-render? <- move-to-next-line editor, screen-height + editor <- move-to-next-line editor, screen-height undo-coalesce-tag:number <- copy 4/down-arrow return } ] -def move-to-next-line editor:address:editor-data, screen-height:number -> editor:address:editor-data, go-render?:boolean [ +def move-to-next-line editor:address:editor-data, screen-height:number -> editor:address:editor-data [ local-scope load-ingredients cursor-row:number <- get *editor, cursor-row:offset @@ -1213,50 +1204,36 @@ def move-to-next-line editor:address:editor-data, screen-height:number -> editor right:number <- get *editor, right:offset last-line:number <- subtract screen-height, 1 already-at-bottom?:boolean <- greater-or-equal cursor-row, last-line + # if cursor not at bottom + return-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:character <- before-start-of-next-line before-cursor, max + # already at end of buffer? do nothing + no-motion?:boolean <- equal next-line, before-cursor + return-if no-motion? + cursor-row <- add cursor-row, 1 + *editor <- put *editor, cursor-row:offset, cursor-row + before-cursor <- copy next-line + *editor <- put *editor, before-cursor:offset, before-cursor + target-column:number <- copy cursor-column + cursor-column <- copy left + *editor <- put *editor, cursor-column:offset, cursor-column { - # if cursor not at bottom, move it - 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: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) - no-motion?:boolean <- equal next-line, before-cursor - break-unless no-motion? - scroll?:boolean <- greater-than cursor-row, 1 - break-if scroll?, +try-to-scroll:label - go-render? <- copy 0/false - return - } - cursor-row <- add cursor-row, 1 - *editor <- put *editor, cursor-row:offset, cursor-row - before-cursor <- copy next-line + done?:boolean <- greater-or-equal cursor-column, target-column + break-if done? + curr:address:duplex-list:character <- next before-cursor + break-unless curr + currc:character <- get *curr, value:offset + at-newline?:boolean <- equal currc, 10/newline + break-if at-newline? + # + before-cursor <- copy curr *editor <- put *editor, before-cursor:offset, before-cursor - target-column:number <- copy cursor-column - cursor-column <- copy left + cursor-column <- add cursor-column, 1 *editor <- put *editor, cursor-column:offset, cursor-column - { - done?:boolean <- greater-or-equal cursor-column, target-column - break-if done? - curr:address:duplex-list:character <- next before-cursor - break-unless curr - currc:character <- get *curr, value:offset - at-newline?:boolean <- equal currc, 10/newline - break-if at-newline? - # - before-cursor <- copy curr - *editor <- put *editor, before-cursor:offset, before-cursor - cursor-column <- add cursor-column, 1 - *editor <- put *editor, cursor-column:offset, cursor-column - loop - } - go-render? <- copy 0/false - return + loop } - +try-to-scroll - - go-render? <- copy 1/true ] scenario editor-adjusts-column-at-next-line [ @@ -1921,54 +1898,6 @@ scenario editor-deletes-to-end-of-line-with-ctrl-k-6 [ ] ] -# cursor-down can scroll if necessary - -scenario editor-can-scroll-down-using-arrow-keys [ - # screen has 1 line for menu + 3 lines - assume-screen 10/width, 4/height - # initialize editor with >3 lines - 1:address:array:character <- new [a -b -c -d] - 2:address:editor-data <- new-editor 1:address:array:character, screen:address:screen, 0/left, 10/right - screen-should-contain [ - . . - .a . - .b . - .c . - ] - # position cursor at last line, then try to move further down - assume-console [ - left-click 3, 0 - press down-arrow - ] - run [ - editor-event-loop screen:address:screen, console:address:console, 2:address:editor-data - ] - # screen slides by one line - screen-should-contain [ - . . - .b . - .c . - .d . - ] -] - -after [ - trace 10, [app], [scroll down] - top-of-screen:address:duplex-list:character <- get *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:character <- copy top-of-screen - top-of-screen <- before-start-of-next-line top-of-screen, max - *editor <- put *editor, top-of-screen:offset, top-of-screen - no-movement?:boolean <- equal old-top, top-of-screen - go-render? <- copy 0/false - return-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. @@ -2000,343 +1929,6 @@ def before-start-of-next-line original:address:duplex-list:character, max:number return curr ] -scenario editor-scrolls-down-past-wrapped-line-using-arrow-keys [ - # screen has 1 line for menu + 3 lines - assume-screen 10/width, 4/height - # initialize editor with a long, wrapped line and more than a screen of - # other lines - 1:address:array:character <- new [abcdef -g -h -i] - 2:address:editor-data <- new-editor 1:address:array:character, screen:address:screen, 0/left, 5/right - screen-should-contain [ - . . - .abcd↩ . - .ef . - .g . - ] - # position cursor at last line, then try to move further down - assume-console [ - left-click 3, 0 - press down-arrow - ] - run [ - editor-event-loop screen:address:screen, console:address:console, 2:address:editor-data - ] - # screen shows partial wrapped line - screen-should-contain [ - . . - .ef . - .g . - .h . - ] -] - -scenario editor-scrolls-down-past-wrapped-line-using-arrow-keys-2 [ - # screen has 1 line for menu + 3 lines - assume-screen 10/width, 4/height - # editor starts with a long line wrapping twice - 1:address:array:character <- new [abcdefghij -k -l -m] - 2:address:editor-data <- new-editor 1:address:array:character, screen:address:screen, 0/left, 5/right - # position cursor at last line, then try to move further down - assume-console [ - left-click 3, 0 - press down-arrow - ] - run [ - editor-event-loop screen:address:screen, console:address:console, 2:address:editor-data - ] - # screen shows partial wrapped line containing a wrap icon - screen-should-contain [ - . . - .efgh↩ . - .ij . - .k . - ] - # scroll down again - assume-console [ - press down-arrow - ] - run [ - editor-event-loop screen:address:screen, console:address:console, 2:address:editor-data - ] - # screen shows partial wrapped line - screen-should-contain [ - . . - .ij . - .k . - .l . - ] -] - -scenario editor-scrolls-down-when-line-wraps [ - # screen has 1 line for menu + 3 lines - assume-screen 5/width, 4/height - # editor contains a long line in the third line - 1:address:array:character <- new [a -b -cdef] - 2:address:editor-data <- new-editor 1:address:array:character, screen:address:screen, 0/left, 5/right - # position cursor at end, type a character - assume-console [ - left-click 3, 4 - type [g] - ] - 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 scrolls - screen-should-contain [ - . . - .b . - .cdef↩. - .g . - ] - memory-should-contain [ - 3 <- 3 - 4 <- 1 - ] -] - -scenario editor-scrolls-down-on-newline [ - assume-screen 5/width, 4/height - # position cursor after last line and type newline - 1:address:array:character <- new [a -b -c] - 2:address:editor-data <- new-editor 1:address:array:character, screen:address:screen, 0/left, 5/right - assume-console [ - left-click 3, 4 - type [ -] - ] - 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 scrolls - screen-should-contain [ - . . - .b . - .c . - . . - ] - memory-should-contain [ - 3 <- 3 - 4 <- 0 - ] -] - -scenario editor-scrolls-down-on-right-arrow [ - # screen has 1 line for menu + 3 lines - assume-screen 5/width, 4/height - # editor contains a wrapped line - 1:address:array:character <- new [a -b -cdefgh] - 2:address:editor-data <- new-editor 1:address:array:character, screen:address:screen, 0/left, 5/right - # position cursor at end of screen and try to move right - assume-console [ - left-click 3, 3 - press right-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 scrolls - screen-should-contain [ - . . - .b . - .cdef↩. - .gh . - ] - memory-should-contain [ - 3 <- 3 - 4 <- 0 - ] -] - -scenario editor-scrolls-down-on-right-arrow-2 [ - # screen has 1 line for menu + 3 lines - assume-screen 5/width, 4/height - # editor contains more lines than can fit on screen - 1:address:array:character <- new [a -b -c -d] - 2:address:editor-data <- new-editor 1:address:array:character, screen:address:screen, 0/left, 5/right - # position cursor at end of screen and try to move right - assume-console [ - left-click 3, 3 - press right-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 scrolls - screen-should-contain [ - . . - .b . - .c . - .d . - ] - memory-should-contain [ - 3 <- 3 - 4 <- 0 - ] -] - -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 - # initialize editor with a few pages of lines - 1:address:array:character <- new [a -b -c -d -e -f -g] - 2:address:editor-data <- new-editor 1:address:array:character, screen:address:screen, 0/left, 5/right - # scroll down one page and one line - assume-console [ - press page-down - left-click 3, 0 - press down-arrow - ] - run [ - editor-event-loop screen:address:screen, console:address:console, 2:address:editor-data - ] - # screen scrolls down 3 lines - screen-should-contain [ - . . - .d . - .e . - .f . - ] -] - -# cursor-up can scroll if necessary - -scenario editor-can-scroll-up-using-arrow-keys [ - # screen has 1 line for menu + 3 lines - assume-screen 10/width, 4/height - # initialize editor with >3 lines - 1:address:array:character <- new [a -b -c -d] - 2:address:editor-data <- new-editor 1:address:array:character, screen:address:screen, 0/left, 10/right - screen-should-contain [ - . . - .a . - .b . - .c . - ] - # position cursor at top of second page, then try to move up - assume-console [ - press page-down - press up-arrow - ] - run [ - editor-event-loop screen:address:screen, console:address:console, 2:address:editor-data - ] - # screen slides by one line - screen-should-contain [ - . . - .b . - .c . - .d . - ] -] - -after [ - trace 10, [app], [scroll up] - top-of-screen:address:duplex-list:character <- get *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 - *editor <- put *editor, top-of-screen:offset, top-of-screen - no-movement?:boolean <- equal old-top, top-of-screen - go-render? <- copy 0/false - return-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 @@ -2380,869 +1972,3 @@ def before-previous-line in:address:duplex-list:character, editor:address:editor } return curr ] - -scenario editor-scrolls-up-past-wrapped-line-using-arrow-keys [ - # screen has 1 line for menu + 3 lines - assume-screen 10/width, 4/height - # initialize editor with a long, wrapped line and more than a screen of - # other lines - 1:address:array:character <- new [abcdef -g -h -i] - 2:address:editor-data <- new-editor 1:address:array:character, screen:address:screen, 0/left, 5/right - screen-should-contain [ - . . - .abcd↩ . - .ef . - .g . - ] - # position cursor at top of second page, just below wrapped line - assume-console [ - press page-down - ] - run [ - editor-event-loop screen:address:screen, console:address:console, 2:address:editor-data - ] - screen-should-contain [ - . . - .g . - .h . - .i . - ] - # now move up one line - assume-console [ - press up-arrow - ] - run [ - editor-event-loop screen:address:screen, console:address:console, 2:address:editor-data - ] - # screen shows partial wrapped line - screen-should-contain [ - . . - .ef . - .g . - .h . - ] -] - -scenario editor-scrolls-up-past-wrapped-line-using-arrow-keys-2 [ - # screen has 1 line for menu + 4 lines - assume-screen 10/width, 5/height - # editor starts with a long line wrapping twice, occupying 3 of the 4 lines - 1:address:array:character <- new [abcdefghij -k -l -m] - 2:address:editor-data <- new-editor 1:address:array:character, screen:address:screen, 0/left, 5/right - # position cursor at top of second page - assume-console [ - press page-down - ] - run [ - editor-event-loop screen:address:screen, console:address:console, 2:address:editor-data - ] - screen-should-contain [ - . . - .k . - .l . - .m . - .┈┈┈┈┈ . - ] - # move up one line - assume-console [ - press up-arrow - ] - run [ - editor-event-loop screen:address:screen, console:address:console, 2:address:editor-data - ] - # screen shows partial wrapped line - screen-should-contain [ - . . - .ij . - .k . - .l . - .m . - ] - # move up a second line - assume-console [ - press up-arrow - ] - run [ - editor-event-loop screen:address:screen, console:address:console, 2:address:editor-data - ] - # screen shows partial wrapped line - screen-should-contain [ - . . - .efgh↩ . - .ij . - .k . - .l . - ] - # move up a third line - assume-console [ - press up-arrow - ] - run [ - editor-event-loop screen:address:screen, console:address:console, 2:address:editor-data - ] - # screen shows partial wrapped line - screen-should-contain [ - . . - .abcd↩ . - .efgh↩ . - .ij . - .k . - ] -] - -# same as editor-scrolls-up-past-wrapped-line-using-arrow-keys but length -# slightly off, just to prevent over-training -scenario editor-scrolls-up-past-wrapped-line-using-arrow-keys-3 [ - # screen has 1 line for menu + 3 lines - assume-screen 10/width, 4/height - # initialize editor with a long, wrapped line and more than a screen of - # other lines - 1:address:array:character <- new [abcdef -g -h -i] - 2:address:editor-data <- new-editor 1:address:array:character, screen:address:screen, 0/left, 6/right - screen-should-contain [ - . . - .abcde↩ . - .f . - .g . - ] - # position cursor at top of second page, just below wrapped line - assume-console [ - press page-down - ] - run [ - editor-event-loop screen:address:screen, console:address:console, 2:address:editor-data - ] - screen-should-contain [ - . . - .g . - .h . - .i . - ] - # now move up one line - assume-console [ - press up-arrow - ] - run [ - editor-event-loop screen:address:screen, console:address:console, 2:address:editor-data - ] - # screen shows partial wrapped line - screen-should-contain [ - . . - .f . - .g . - .h . - ] -] - -# check empty lines -scenario editor-scrolls-up-past-wrapped-line-using-arrow-keys-4 [ - assume-screen 10/width, 4/height - # initialize editor with some lines around an empty line - 1:address:array:character <- new [a -b - -c -d -e] - 2:address:editor-data <- new-editor 1:address:array:character, screen:address:screen, 0/left, 6/right - assume-console [ - press page-down - ] - run [ - editor-event-loop screen:address:screen, console:address:console, 2:address:editor-data - ] - screen-should-contain [ - . . - . . - .c . - .d . - ] - assume-console [ - press page-down - ] - run [ - editor-event-loop screen:address:screen, console:address:console, 2:address:editor-data - ] - screen-should-contain [ - . . - .d . - .e . - .┈┈┈┈┈┈ . - ] - assume-console [ - press page-up - ] - run [ - editor-event-loop screen:address:screen, console:address:console, 2:address:editor-data - ] - screen-should-contain [ - . . - . . - .c . - .d . - ] -] - -scenario editor-scrolls-up-on-left-arrow [ - # screen has 1 line for menu + 3 lines - assume-screen 5/width, 4/height - # editor contains >3 lines - 1:address:array:character <- new [a -b -c -d -e] - 2:address:editor-data <- new-editor 1:address:array:character, screen:address:screen, 0/left, 5/right - # position cursor at top of second page - assume-console [ - press page-down - ] - run [ - editor-event-loop screen:address:screen, console:address:console, 2:address:editor-data - ] - screen-should-contain [ - . . - .c . - .d . - .e . - ] - # now try to move left - assume-console [ - press left-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 scrolls - screen-should-contain [ - . . - .b . - .c . - .d . - ] - memory-should-contain [ - 3 <- 1 - 4 <- 1 - ] -] - -scenario editor-can-scroll-up-to-start-of-file [ - # screen has 1 line for menu + 3 lines - assume-screen 10/width, 4/height - # initialize editor with >3 lines - 1:address:array:character <- new [a -b -c -d] - 2:address:editor-data <- new-editor 1:address:array:character, screen:address:screen, 0/left, 10/right - screen-should-contain [ - . . - .a . - .b . - .c . - ] - # position cursor at top of second page, then try to move up to start of - # text - assume-console [ - press page-down - press up-arrow - press up-arrow - ] - run [ - editor-event-loop screen:address:screen, console:address:console, 2:address:editor-data - ] - # screen slides by one line - screen-should-contain [ - . . - .a . - .b . - .c . - ] - # try to move up again - assume-console [ - press up-arrow - ] - run [ - editor-event-loop screen:address:screen, console:address:console, 2:address:editor-data - ] - # screen remains unchanged - screen-should-contain [ - . . - .a . - .b . - .c . - ] -] - -# ctrl-f/page-down - render next page if it exists - -scenario editor-can-scroll [ - assume-screen 10/width, 4/height - 1:address:array:character <- new [a -b -c -d] - 2:address:editor-data <- new-editor 1:address:array:character, screen:address:screen, 0/left, 10/right - screen-should-contain [ - . . - .a . - .b . - .c . - ] - # scroll down - assume-console [ - press page-down - ] - run [ - editor-event-loop screen:address:screen, console:address:console, 2:address:editor-data - ] - # screen shows next page - screen-should-contain [ - . . - .c . - .d . - .┈┈┈┈┈┈┈┈┈┈. - ] -] - -after [ - { - page-down?:boolean <- equal c, 6/ctrl-f - break-unless page-down? - old-top:address:duplex-list:character <- get *editor, top-of-screen:offset - - page-down editor - undo-coalesce-tag:number <- copy 0/never - - top-of-screen:address:duplex-list:character <- get *editor, top-of-screen:offset - no-movement?:boolean <- equal top-of-screen, old-top - go-render? <- not no-movement? - return - } -] - -after [ - { - page-down?:boolean <- equal k, 65518/page-down - break-unless page-down? - old-top:address:duplex-list:character <- get *editor, top-of-screen:offset - - page-down editor - undo-coalesce-tag:number <- copy 0/never - - top-of-screen:address:duplex-list:character <- get *editor, top-of-screen:offset - no-movement?:boolean <- equal top-of-screen, old-top - go-render? <- not no-movement? - return - } -] - -# page-down skips entire wrapped lines, so it can't scroll past lines -# taking up the entire screen -def page-down editor:address:editor-data -> editor:address:editor-data [ - local-scope - load-ingredients - # if editor contents don't overflow screen, do nothing - bottom-of-screen:address:duplex-list:character <- get *editor, bottom-of-screen:offset - return-unless bottom-of-screen - # if not, position cursor at final character - before-cursor:address:duplex-list:character <- get *editor, before-cursor:offset - before-cursor:address:duplex-list:character <- prev bottom-of-screen - *editor <- put *editor, before-cursor:offset, before-cursor - # keep one line in common with previous page - { - last:character <- get *before-cursor, value:offset - newline?:boolean <- equal last, 10/newline - break-unless newline?:boolean - before-cursor <- prev before-cursor - *editor <- put *editor, before-cursor:offset, before-cursor - } - # move cursor and top-of-screen to start of that line - move-to-start-of-line editor - before-cursor <- get *editor, before-cursor:offset - *editor <- put *editor, top-of-screen:offset, before-cursor -] - -scenario editor-does-not-scroll-past-end [ - assume-screen 10/width, 4/height - 1:address:array:character <- new [a -b] - 2:address:editor-data <- new-editor 1:address:array:character, screen:address:screen, 0/left, 10/right - editor-render screen, 2:address:editor-data - screen-should-contain [ - . . - .a . - .b . - .┈┈┈┈┈┈┈┈┈┈. - ] - # scroll down - assume-console [ - press page-down - ] - run [ - editor-event-loop screen:address:screen, console:address:console, 2:address:editor-data - ] - # screen remains unmodified - screen-should-contain [ - . . - .a . - .b . - .┈┈┈┈┈┈┈┈┈┈. - ] -] - -scenario editor-starts-next-page-at-start-of-wrapped-line [ - # screen has 1 line for menu + 3 lines for text - assume-screen 10/width, 4/height - # editor contains a long last line - 1:address:array:character <- new [a -b -cdefgh] - # editor screen triggers wrap of last line - 2:address:editor-data <- new-editor 1:address:array:character, screen:address:screen, 0/left, 4/right - # some part of last line is not displayed - screen-should-contain [ - . . - .a . - .b . - .cde↩ . - ] - # scroll down - assume-console [ - press page-down - ] - run [ - editor-event-loop screen:address:screen, console:address:console, 2:address:editor-data - ] - # screen shows entire wrapped line - screen-should-contain [ - . . - .cde↩ . - .fgh . - .┈┈┈┈ . - ] -] - -scenario editor-starts-next-page-at-start-of-wrapped-line-2 [ - # screen has 1 line for menu + 3 lines for text - assume-screen 10/width, 4/height - # editor contains a very long line that occupies last two lines of screen - # and still has something left over - 1:address:array:character <- new [a -bcdefgh] - 2:address:editor-data <- new-editor 1:address:array:character, screen:address:screen, 0/left, 4/right - # some part of last line is not displayed - screen-should-contain [ - . . - .a . - .bcd↩ . - .efg↩ . - ] - # scroll down - assume-console [ - press page-down - ] - run [ - editor-event-loop screen:address:screen, console:address:console, 2:address:editor-data - ] - # screen shows entire wrapped line - screen-should-contain [ - . . - .bcd↩ . - .efg↩ . - .h . - ] -] - -# ctrl-b/page-up - render previous page if it exists - -scenario editor-can-scroll-up [ - assume-screen 10/width, 4/height - 1:address:array:character <- new [a -b -c -d] - 2:address:editor-data <- new-editor 1:address:array:character, screen:address:screen, 0/left, 10/right - screen-should-contain [ - . . - .a . - .b . - .c . - ] - # scroll down - assume-console [ - press page-down - ] - run [ - editor-event-loop screen:address:screen, console:address:console, 2:address:editor-data - ] - # screen shows next page - screen-should-contain [ - . . - .c . - .d . - .┈┈┈┈┈┈┈┈┈┈. - ] - # scroll back up - assume-console [ - press page-up - ] - run [ - editor-event-loop screen:address:screen, console:address:console, 2:address:editor-data - ] - # screen shows original page again - screen-should-contain [ - . . - .a . - .b . - .c . - ] -] - -after [ - { - page-up?:boolean <- equal c, 2/ctrl-b - break-unless page-up? - old-top:address:duplex-list:character <- get *editor, top-of-screen:offset - - editor <- page-up editor, screen-height - undo-coalesce-tag:number <- copy 0/never - - top-of-screen:address:duplex-list:character <- get *editor, top-of-screen:offset - no-movement?:boolean <- equal top-of-screen, old-top - go-render? <- not no-movement? - return - } -] - -after [ - { - page-up?:boolean <- equal k, 65519/page-up - break-unless page-up? - old-top:address:duplex-list:character <- get *editor, top-of-screen:offset - - editor <- page-up editor, screen-height - undo-coalesce-tag:number <- copy 0/never - - top-of-screen:address:duplex-list:character <- get *editor, top-of-screen:offset - no-movement?:boolean <- equal top-of-screen, old-top - # don't bother re-rendering if nothing changed. todo: test this - go-render? <- not no-movement? - return - } -] - -def page-up editor:address:editor-data, screen-height:number -> editor:address:editor-data [ - local-scope - load-ingredients - max:number <- subtract screen-height, 1/menu-bar, 1/overlapping-line - count:number <- copy 0 - top-of-screen:address:duplex-list:character <- get *editor, top-of-screen:offset - { - done?:boolean <- greater-or-equal count, max - break-if done? - prev:address:duplex-list:character <- before-previous-line top-of-screen, editor - break-unless prev - top-of-screen <- copy prev - *editor <- put *editor, top-of-screen:offset, top-of-screen - count <- add count, 1 - loop - } -] - -scenario editor-can-scroll-up-multiple-pages [ - # screen has 1 line for menu + 3 lines - assume-screen 10/width, 4/height - # initialize editor with 8 lines - 1:address:array:character <- new [a -b -c -d -e -f -g -h] - 2:address:editor-data <- new-editor 1:address:array:character, screen:address:screen, 0/left, 10/right - screen-should-contain [ - . . - .a . - .b . - .c . - ] - # scroll down two pages - assume-console [ - press page-down - press page-down - ] - run [ - editor-event-loop screen:address:screen, console:address:console, 2:address:editor-data - ] - # screen shows third page - screen-should-contain [ - . . - .e . - .f . - .g . - ] - # scroll up - assume-console [ - press page-up - ] - run [ - editor-event-loop screen:address:screen, console:address:console, 2:address:editor-data - ] - # screen shows second page - screen-should-contain [ - . . - .c . - .d . - .e . - ] - # scroll up again - assume-console [ - press page-up - ] - run [ - editor-event-loop screen:address:screen, console:address:console, 2:address:editor-data - ] - # screen shows original page again - screen-should-contain [ - . . - .a . - .b . - .c . - ] -] - -scenario editor-can-scroll-up-wrapped-lines [ - # screen has 1 line for menu + 5 lines for text - assume-screen 10/width, 6/height - # editor contains a long line in the first page - 1:address:array:character <- new [a -b -cdefgh -i -j -k -l -m -n -o] - # editor screen triggers wrap of last line - 2:address:editor-data <- new-editor 1:address:array:character, screen:address:screen, 0/left, 4/right - # some part of last line is not displayed - screen-should-contain [ - . . - .a . - .b . - .cde↩ . - .fgh . - .i . - ] - # scroll down a page and a line - assume-console [ - press page-down - left-click 5, 0 - press down-arrow - ] - run [ - editor-event-loop screen:address:screen, console:address:console, 2:address:editor-data - ] - # screen shows entire wrapped line - screen-should-contain [ - . . - .j . - .k . - .l . - .m . - .n . - ] - # now scroll up one page - assume-console [ - press page-up - ] - run [ - editor-event-loop screen:address:screen, console:address:console, 2:address:editor-data - ] - # screen resets - screen-should-contain [ - . . - .b . - .cde↩ . - .fgh . - .i . - .j . - ] -] - -scenario editor-can-scroll-up-wrapped-lines-2 [ - # screen has 1 line for menu + 3 lines for text - assume-screen 10/width, 4/height - # editor contains a very long line that occupies last two lines of screen - # and still has something left over - 1:address:array:character <- new [a -bcdefgh] - 2:address:editor-data <- new-editor 1:address:array:character, screen:address:screen, 0/left, 4/right - # some part of last line is not displayed - screen-should-contain [ - . . - .a . - .bcd↩ . - .efg↩ . - ] - # scroll down - assume-console [ - press page-down - ] - run [ - editor-event-loop screen:address:screen, console:address:console, 2:address:editor-data - ] - # screen shows entire wrapped line - screen-should-contain [ - . . - .bcd↩ . - .efg↩ . - .h . - ] - # scroll back up - assume-console [ - press page-up - ] - run [ - editor-event-loop screen:address:screen, console:address:console, 2:address:editor-data - ] - # screen resets - screen-should-contain [ - . . - .a . - .bcd↩ . - .efg↩ . - ] -] - -scenario editor-can-scroll-up-past-nonempty-lines [ - assume-screen 10/width, 4/height - # text with empty line in second screen - 1:address:array:character <- new [axx -bxx -cxx -dxx -exx -fxx -gxx -hxx -] - 2:address:editor-data <- new-editor 1:address:array:character, screen:address:screen, 0/left, 4/right - screen-should-contain [ - . . - .axx . - .bxx . - .cxx . - ] - assume-console [ - press page-down - ] - run [ - editor-event-loop screen:address:screen, console:address:console, 2:address:editor-data - ] - screen-should-contain [ - . . - .cxx . - .dxx . - .exx . - ] - assume-console [ - press page-down - ] - run [ - editor-event-loop screen:address:screen, console:address:console, 2:address:editor-data - ] - screen-should-contain [ - . . - .exx . - .fxx . - .gxx . - ] - # scroll back up past empty line - assume-console [ - press page-up - ] - run [ - editor-event-loop screen:address:screen, console:address:console, 2:address:editor-data - ] - screen-should-contain [ - . . - .cxx . - .dxx . - .exx . - ] -] - -scenario editor-can-scroll-up-past-empty-lines [ - assume-screen 10/width, 4/height - # text with empty line in second screen - 1:address:array:character <- new [axy -bxy -cxy - -dxy -exy -fxy -gxy -] - 2:address:editor-data <- new-editor 1:address:array:character, screen:address:screen, 0/left, 4/right - screen-should-contain [ - . . - .axy . - .bxy . - .cxy . - ] - assume-console [ - press page-down - ] - run [ - editor-event-loop screen:address:screen, console:address:console, 2:address:editor-data - ] - screen-should-contain [ - . . - .cxy . - . . - .dxy . - ] - assume-console [ - press page-down - ] - run [ - editor-event-loop screen:address:screen, console:address:console, 2:address:editor-data - ] - screen-should-contain [ - . . - .dxy . - .exy . - .fxy . - ] - # scroll back up past empty line - assume-console [ - press page-up - ] - run [ - editor-event-loop screen:address:screen, console:address:console, 2:address:editor-data - ] - screen-should-contain [ - . . - .cxy . - . . - .dxy . - ] -] -- cgit 1.4.1-2-gfad0