diff options
author | Kartik K. Agaram <vc@akkartik.com> | 2016-01-23 13:32:00 -0800 |
---|---|---|
committer | Kartik K. Agaram <vc@akkartik.com> | 2016-01-23 13:32:00 -0800 |
commit | a01dd5959383a0dc7ffe2c9b3eee8d2c28e94c45 (patch) | |
tree | 487472df0fba86cc8c0219a8677b682fd825035c | |
parent | e0d69d3b3326081dda661d714cef97a13dabb7c8 (diff) | |
download | mu-a01dd5959383a0dc7ffe2c9b3eee8d2c28e94c45.tar.gz |
2594 - bugfixes: managing state when deleting
This required completely redesigning scrolling.
-rw-r--r-- | edit/005-sandbox.mu | 174 | ||||
-rw-r--r-- | edit/006-sandbox-edit.mu | 12 | ||||
-rw-r--r-- | edit/007-sandbox-delete.mu | 213 | ||||
-rw-r--r-- | sandbox/005-sandbox.mu | 174 | ||||
-rw-r--r-- | sandbox/006-sandbox-edit.mu | 14 | ||||
-rw-r--r-- | sandbox/007-sandbox-delete.mu | 215 |
6 files changed, 615 insertions, 187 deletions
diff --git a/edit/005-sandbox.mu b/edit/005-sandbox.mu index 10ec7817..160c4794 100644 --- a/edit/005-sandbox.mu +++ b/edit/005-sandbox.mu @@ -19,8 +19,13 @@ recipe! main [ container programming-environment-data [ sandbox:address:shared:sandbox-data # list of sandboxes, from top to bottom - first-sandbox-to-render:address:shared:sandbox-data # 0 = display current-sandbox editor - first-sandbox-index:number + render-from:number + number-of-sandboxes:number +] + +after <programming-environment-initialization> [ + render-from:address:number <- get-address *result, render-from:offset + *render-from <- copy -1 ] container sandbox-data [ @@ -28,6 +33,7 @@ container sandbox-data [ response:address:shared:array:character expected-response:address:shared:array:character # coordinates to track clicks + # constraint: will be 0 for sandboxes at positions before env.render-from starting-row-on-screen:number code-ending-row-on-screen:number # past end of code response-starting-row-on-screen:number @@ -162,6 +168,9 @@ recipe run-sandboxes env:address:shared:programming-environment-data, screen:add next:address:address:shared:sandbox-data <- get-address *new-sandbox, next-sandbox:offset *next <- copy *dest *dest <- copy new-sandbox + # update sandbox count + sandbox-count:address:number <- get-address *env, number-of-sandboxes:offset + *sandbox-count <- add *sandbox-count, 1 # clear sandbox editor init:address:address:shared:duplex-list:character <- get-address *current-sandbox, data:offset *init <- push 167/§, 0/tail @@ -244,19 +253,26 @@ recipe! render-sandbox-side screen:address:shared:screen, env:address:shared:pro #? $log [render sandbox side] trace 11, [app], [render sandbox side] current-sandbox:address:shared:editor-data <- get *env, current-sandbox:offset + row:number, column:number <- copy 1, 0 left:number <- get *current-sandbox, left:offset right:number <- get *current-sandbox, right:offset - <render-sandbox-side-special-cases> - row:number, column:number, screen, current-sandbox <- render screen, current-sandbox - clear-screen-from screen, row, column, left, right - row <- add row, 1 + # render sandbox editor + render-from:number <- get *env, render-from:offset + { + render-current-sandbox?:boolean <- equal render-from, -1 + break-unless render-current-sandbox? + row, column, screen, current-sandbox <- render screen, current-sandbox + clear-screen-from screen, row, column, left, right + row <- add row, 1 + } + # render sandboxes draw-horizontal screen, row, left, right, 9473/horizontal-double sandbox:address:shared:sandbox-data <- get *env, sandbox:offset - row, screen <- render-sandboxes screen, sandbox, left, right, row, 0 + row, screen <- render-sandboxes screen, sandbox, left, right, row, render-from clear-rest-of-screen screen, row, left, right ] -recipe render-sandboxes screen:address:shared:screen, sandbox:address:shared:sandbox-data, left:number, right:number, row:number, idx:number -> row:number, screen:address:shared:screen, sandbox:address:shared:sandbox-data [ +recipe render-sandboxes screen:address:shared:screen, sandbox:address:shared:sandbox-data, left:number, right:number, row:number, render-from:number, idx:number -> row:number, screen:address:shared:screen, sandbox:address:shared:sandbox-data [ local-scope load-ingredients #? $log [render sandbox] @@ -264,48 +280,62 @@ recipe render-sandboxes screen:address:shared:screen, sandbox:address:shared:san screen-height:number <- screen-height screen at-bottom?:boolean <- greater-or-equal row, screen-height reply-if at-bottom?:boolean - # render sandbox menu - row <- add row, 1 - screen <- move-cursor screen, row, left - print screen, idx, 240/dark-grey - clear-line-delimited screen, left, right - delete-icon:character <- copy 120/x - print screen, delete-icon, 245/grey - # save menu row so we can detect clicks to it later - starting-row:address:number <- get-address *sandbox, starting-row-on-screen:offset - *starting-row <- copy row - # render sandbox contents - row <- add row, 1 - screen <- move-cursor screen, row, left - sandbox-data:address:shared:array:character <- get *sandbox, data:offset - row, screen <- render-code screen, sandbox-data, left, right, row - code-ending-row:address:number <- get-address *sandbox, code-ending-row-on-screen:offset - *code-ending-row <- copy row - # render sandbox warnings, screen or response, in that order - response-starting-row:address:number <- get-address *sandbox, response-starting-row-on-screen:offset - sandbox-response:address:shared:array:character <- get *sandbox, response:offset - <render-sandbox-results> + hidden?:boolean <- lesser-than idx, render-from { - sandbox-screen:address:shared:screen <- get *sandbox, screen:offset - empty-screen?:boolean <- fake-screen-is-empty? sandbox-screen - break-if empty-screen? - row, screen <- render-screen screen, sandbox-screen, left, right, row + break-if hidden? + # render sandbox menu + row <- add row, 1 + screen <- move-cursor screen, row, left + print screen, idx, 240/dark-grey + clear-line-delimited screen, left, right + delete-icon:character <- copy 120/x + print screen, delete-icon, 245/grey + # save menu row so we can detect clicks to it later + starting-row:address:number <- get-address *sandbox, starting-row-on-screen:offset + *starting-row <- copy row + # render sandbox contents + row <- add row, 1 + screen <- move-cursor screen, row, left + sandbox-data:address:shared:array:character <- get *sandbox, data:offset + row, screen <- render-code screen, sandbox-data, left, right, row + code-ending-row:address:number <- get-address *sandbox, code-ending-row-on-screen:offset + *code-ending-row <- copy row + # render sandbox warnings, screen or response, in that order + response-starting-row:address:number <- get-address *sandbox, response-starting-row-on-screen:offset + sandbox-response:address:shared:array:character <- get *sandbox, response:offset + <render-sandbox-results> + { + sandbox-screen:address:shared:screen <- get *sandbox, screen:offset + empty-screen?:boolean <- fake-screen-is-empty? sandbox-screen + break-if empty-screen? + row, screen <- render-screen screen, sandbox-screen, left, right, row + } + { + break-unless empty-screen? + *response-starting-row <- copy row + <render-sandbox-response> + row, screen <- render screen, sandbox-response, left, right, 245/grey, row + } + +render-sandbox-end + at-bottom?:boolean <- greater-or-equal row, screen-height + reply-if at-bottom? + # draw solid line after sandbox + draw-horizontal screen, row, left, right, 9473/horizontal-double } + # if hidden, reset row attributes { - break-unless empty-screen? - *response-starting-row <- copy row - <render-sandbox-response> - row, screen <- render screen, sandbox-response, left, right, 245/grey, row + break-unless hidden? + tmp:address:number <- get-address *sandbox, starting-row-on-screen:offset + *tmp <- copy 0 + tmp:address:number <- get-address *sandbox, code-ending-row-on-screen:offset + *tmp <- copy 0 + tmp:address:number <- get-address *sandbox, response-starting-row-on-screen:offset + *tmp <- copy 0 } - +render-sandbox-end - at-bottom?:boolean <- greater-or-equal row, screen-height - reply-if at-bottom? - # draw solid line after sandbox - draw-horizontal screen, row, left, right, 9473/horizontal-double # draw next sandbox next-sandbox:address:shared:sandbox-data <- get *sandbox, next-sandbox:offset next-idx:number <- add idx, 1 - row, screen <- render-sandboxes screen, next-sandbox, left, right, row, next-idx + row, screen <- render-sandboxes screen, next-sandbox, left, right, row, render-from, next-idx ] # assumes programming environment has no sandboxes; restores them from previous session @@ -598,7 +628,7 @@ scenario scrolling-down-past-bottom-of-sandbox-editor [ ] ] -# down on sandbox side updates first-sandbox-to-render when sandbox editor has cursor at bottom +# down on sandbox side updates render-from when sandbox editor has cursor at bottom after <global-keypress> [ { break-unless *sandbox-in-focus? @@ -610,21 +640,14 @@ after <global-keypress> [ break-unless sandbox-cursor-on-last-line? sandbox:address:shared:sandbox-data <- get *env, sandbox:offset break-unless sandbox - first-sandbox-to-render:address:address:shared:sandbox-data <- get-address *env, first-sandbox-to-render:offset - first-sandbox-index:address:number <- get-address *env, first-sandbox-index:offset - # if first-sandbox-to-render is set, slide it down if possible + # slide down if possible { - break-unless *first-sandbox-to-render - next:address:shared:sandbox-data <- get **first-sandbox-to-render, next-sandbox:offset - break-unless next - *first-sandbox-to-render <- copy next - *first-sandbox-index <- add *first-sandbox-index, 1 - } - # if first-sandbox-to-render is not set, set it to first sandbox - { - break-if *first-sandbox-to-render - *first-sandbox-to-render <- copy sandbox - *first-sandbox-index <- copy 0 + render-from:address:number <- get-address *env, render-from:offset + number-of-sandboxes:number <- get *env, number-of-sandboxes:offset + max:number <- subtract number-of-sandboxes, 1 + at-end?:boolean <- greater-or-equal *render-from, max + break-if at-end? + *render-from <- add *render-from, 1 } hide-screen screen screen <- render-sandbox-side screen, env @@ -633,46 +656,29 @@ after <global-keypress> [ } ] -# render-sandbox-side takes first-sandbox-to-render into account -after <render-sandbox-side-special-cases> [ - { - first-sandbox-to-render:address:shared:sandbox-data <- get *env, first-sandbox-to-render:offset - break-unless first-sandbox-to-render - row:number <- copy 1 # skip menu - draw-horizontal screen, row, left, right, 9473/horizontal-double - first-sandbox-index:number <- get *env, first-sandbox-index:offset - row, screen <- render-sandboxes screen, first-sandbox-to-render, left, right, row, first-sandbox-index - clear-rest-of-screen screen, row, left, right - reply - } -] - -# update-cursor takes first-sandbox-to-render into account +# update-cursor takes render-from into account after <update-cursor-special-cases> [ { break-unless sandbox-in-focus? - first-sandbox-to-render:address:shared:sandbox-data <- get *env, first-sandbox-to-render:offset - break-unless first-sandbox-to-render + render-from:number <- get *env, render-from:offset + scrolling?:boolean <- greater-or-equal render-from, 0 + break-unless scrolling? cursor-column:number <- get *current-sandbox, left:offset screen <- move-cursor screen, 2/row, cursor-column # highlighted sandbox will always start at row 2 reply } ] -# 'up' on sandbox side is like 'down': updates first-sandbox-to-render when necessary +# 'up' on sandbox side is like 'down': updates render-from when necessary after <global-keypress> [ { break-unless *sandbox-in-focus? up?:boolean <- equal *k, 65517/up-arrow break-unless up? - first-sandbox-to-render:address:address:shared:sandbox-data <- get-address *env, first-sandbox-to-render:offset - break-unless *first-sandbox-to-render - { - break-unless *first-sandbox-to-render - *first-sandbox-to-render <- previous-sandbox env, *first-sandbox-to-render - first-sandbox-index:address:number <- get-address *env, first-sandbox-index:offset - *first-sandbox-index <- subtract *first-sandbox-index, 1 - } + render-from:address:number <- get-address *env, render-from:offset + at-beginning?:boolean <- equal *render-from, -1 + break-if at-beginning? + *render-from <- subtract *render-from, 1 hide-screen screen screen <- render-sandbox-side screen, env show-screen screen diff --git a/edit/006-sandbox-edit.mu b/edit/006-sandbox-edit.mu index db1ee324..600a5c4c 100644 --- a/edit/006-sandbox-edit.mu +++ b/edit/006-sandbox-edit.mu @@ -79,12 +79,11 @@ after <global-touch> [ break-unless empty-sandbox-editor? # don't clobber existing contents # identify the sandbox to edit and remove it from the sandbox list sandbox:address:shared:sandbox-data <- extract-sandbox env, click-row + break-unless sandbox text:address:shared:array:character <- get *sandbox, data:offset current-sandbox <- insert-text current-sandbox, text - first-sandbox-to-render:address:address:shared:sandbox-data <- get-address *env, first-sandbox-to-render:offset - *first-sandbox-to-render <- copy 0 - first-sandbox-index:address:number <- get-address *env, first-sandbox-index:offset - *first-sandbox-index <- copy 0 + render-from:address:number <- get-address *env, render-from:offset + *render-from <- copy -1 hide-screen screen screen <- render-sandbox-side screen, env screen <- update-cursor screen, recipes, current-sandbox, *sandbox-in-focus?, env @@ -104,11 +103,10 @@ recipe empty-editor? editor:address:shared:editor-data -> result:boolean [ recipe extract-sandbox env:address:shared:programming-environment-data, click-row:number -> result:address:shared:sandbox-data, env:address:shared:programming-environment-data [ local-scope load-ingredients - # assert click-row >= sandbox.starting-row-on-screen sandbox:address:address:shared:sandbox-data <- get-address *env, sandbox:offset start:number <- get **sandbox, starting-row-on-screen:offset - clicked-on-sandboxes?:boolean <- greater-or-equal click-row, start - assert clicked-on-sandboxes?, [extract-sandbox called on click to sandbox editor] + in-editor?:boolean <- lesser-than click-row, start + reply-if in-editor?, 0 { next-sandbox:address:shared:sandbox-data <- get **sandbox, next-sandbox:offset break-unless next-sandbox diff --git a/edit/007-sandbox-delete.mu b/edit/007-sandbox-delete.mu index e973d8a1..a478c93f 100644 --- a/edit/007-sandbox-delete.mu +++ b/edit/007-sandbox-delete.mu @@ -95,9 +95,20 @@ recipe delete-sandbox t:touch-event, env:address:shared:programming-environment- target-row:number <- get *curr, starting-row-on-screen:offset delete-curr?:boolean <- equal target-row, click-row break-unless delete-curr? - # delete this sandbox, rerender and stop + # delete this sandbox *prev <- get *curr, next-sandbox:offset - reply 1/true + # update sandbox count + sandbox-count:address:number <- get-address *env, number-of-sandboxes:offset + *sandbox-count <- subtract *sandbox-count, 1 + # if it's the last sandbox and if it was the only sandbox rendered, reset scroll + { + break-if *prev + render-from:address:number <- get-address *env, render-from:offset + reset-scroll?:boolean <- equal *render-from, *sandbox-count + break-unless reset-scroll? + *render-from <- copy -1 + } + reply 1/true # force rerender } prev <- get-address *curr, next-sandbox:offset curr <- get *curr, next-sandbox:offset @@ -105,3 +116,201 @@ recipe delete-sandbox t:touch-event, env:address:shared:programming-environment- } reply 0/false ] + +scenario deleting-sandbox-after-scroll [ + trace-until 100/app # trace too long + assume-screen 30/width, 10/height + # initialize environment + 1:address:shared:array:character <- new [] + 2:address:shared:array:character <- new [] + 3:address:shared:programming-environment-data <- new-programming-environment screen:address:shared:screen, 1:address:shared:array:character, 2:address:shared:array:character + render-all screen, 3:address:shared:programming-environment-data + # create 2 sandboxes and scroll to second + assume-console [ + press ctrl-n + type [add 2, 2] + press F4 + type [add 1, 1] + press F4 + press down-arrow + ] + run [ + event-loop screen:address:shared:screen, console:address:shared:console, 3:address:shared:programming-environment-data + ] + screen-should-contain [ + . . + . ┊━━━━━━━━━━━━━━. + .┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┊0 x. + . ┊add 1, 1 . + . ┊2 . + . ┊━━━━━━━━━━━━━━. + . ┊1 x. + ] + # delete the second sandbox + assume-console [ + left-click 6, 29 + ] + run [ + event-loop screen:address:shared:screen, console:address:shared:console, 3:address:shared:programming-environment-data + ] + # second sandbox shows in editor; scroll resets to display first sandbox + screen-should-contain [ + . . + . ┊━━━━━━━━━━━━━━. + .┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┊0 x. + . ┊add 1, 1 . + . ┊2 . + . ┊━━━━━━━━━━━━━━. + . ┊ . + ] +] + +scenario deleting-top-sandbox-after-scroll [ + trace-until 100/app # trace too long + assume-screen 30/width, 10/height + # initialize environment + 1:address:shared:array:character <- new [] + 2:address:shared:array:character <- new [] + 3:address:shared:programming-environment-data <- new-programming-environment screen:address:shared:screen, 1:address:shared:array:character, 2:address:shared:array:character + render-all screen, 3:address:shared:programming-environment-data + # create 2 sandboxes and scroll to second + assume-console [ + press ctrl-n + type [add 2, 2] + press F4 + type [add 1, 1] + press F4 + press down-arrow + ] + run [ + event-loop screen:address:shared:screen, console:address:shared:console, 3:address:shared:programming-environment-data + ] + screen-should-contain [ + . . + . ┊━━━━━━━━━━━━━━. + .┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┊0 x. + . ┊add 1, 1 . + . ┊2 . + . ┊━━━━━━━━━━━━━━. + . ┊1 x. + ] + # delete the second sandbox + assume-console [ + left-click 2, 29 + ] + run [ + event-loop screen:address:shared:screen, console:address:shared:console, 3:address:shared:programming-environment-data + ] + # second sandbox shows in editor; scroll resets to display first sandbox + screen-should-contain [ + . . + . ┊━━━━━━━━━━━━━━. + .┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┊0 x. + . ┊add 2, 2 . + . ┊4 . + . ┊━━━━━━━━━━━━━━. + . ┊ . + ] +] + +scenario deleting-final-sandbox-after-scroll [ + trace-until 100/app # trace too long + assume-screen 30/width, 10/height + # initialize environment + 1:address:shared:array:character <- new [] + 2:address:shared:array:character <- new [] + 3:address:shared:programming-environment-data <- new-programming-environment screen:address:shared:screen, 1:address:shared:array:character, 2:address:shared:array:character + render-all screen, 3:address:shared:programming-environment-data + # create 2 sandboxes and scroll to second + assume-console [ + press ctrl-n + type [add 2, 2] + press F4 + type [add 1, 1] + press F4 + press down-arrow + press down-arrow + ] + run [ + event-loop screen:address:shared:screen, console:address:shared:console, 3:address:shared:programming-environment-data + ] + screen-should-contain [ + . . + . ┊━━━━━━━━━━━━━━. + .┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┊1 x. + . ┊add 2, 2 . + . ┊4 . + . ┊━━━━━━━━━━━━━━. + . ┊ . + ] + # delete the second sandbox + assume-console [ + left-click 2, 29 + ] + run [ + event-loop screen:address:shared:screen, console:address:shared:console, 3:address:shared:programming-environment-data + ] + # implicitly scroll up to first sandbox + screen-should-contain [ + . . + . ┊ . + .┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┊━━━━━━━━━━━━━━. + . ┊0 x. + . ┊add 1, 1 . + . ┊2 . + . ┊━━━━━━━━━━━━━━. + . ┊ . + ] +] + +scenario deleting-updates-sandbox-count [ + trace-until 100/app # trace too long + assume-screen 30/width, 10/height + # initialize environment + 1:address:shared:array:character <- new [] + 2:address:shared:array:character <- new [] + 3:address:shared:programming-environment-data <- new-programming-environment screen:address:shared:screen, 1:address:shared:array:character, 2:address:shared:array:character + render-all screen, 3:address:shared:programming-environment-data + # create 2 sandboxes + assume-console [ + press ctrl-n + type [add 2, 2] + press F4 + type [add 1, 1] + press F4 + ] + run [ + event-loop screen:address:shared:screen, console:address:shared:console, 3:address:shared:programming-environment-data + ] + screen-should-contain [ + . . + . ┊ . + .┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┊━━━━━━━━━━━━━━. + . ┊0 x. + . ┊add 1, 1 . + . ┊2 . + . ┊━━━━━━━━━━━━━━. + . ┊1 x. + . ┊add 2, 2 . + . ┊4 . + ] + # delete the second sandbox, then try to scroll down twice + assume-console [ + left-click 3, 29 + press down-arrow + press down-arrow + ] + run [ + event-loop screen:address:shared:screen, console:address:shared:console, 3:address:shared:programming-environment-data + ] + # shouldn't go past last sandbox + screen-should-contain [ + . . + . ┊━━━━━━━━━━━━━━. + .┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┊0 x. + . ┊add 2, 2 . + . ┊4 . + . ┊━━━━━━━━━━━━━━. + . ┊ . + ] +] diff --git a/sandbox/005-sandbox.mu b/sandbox/005-sandbox.mu index 08617080..2821f2db 100644 --- a/sandbox/005-sandbox.mu +++ b/sandbox/005-sandbox.mu @@ -6,8 +6,13 @@ container programming-environment-data [ sandbox:address:shared:sandbox-data # list of sandboxes, from top to bottom - first-sandbox-to-render:address:shared:sandbox-data # 0 = display current-sandbox editor - first-sandbox-index:number + render-from:number + number-of-sandboxes:number +] + +after <programming-environment-initialization> [ + render-from:address:number <- get-address *result, render-from:offset + *render-from <- copy -1 ] container sandbox-data [ @@ -15,6 +20,7 @@ container sandbox-data [ response:address:shared:array:character expected-response:address:shared:array:character # coordinates to track clicks + # constraint: will be 0 for sandboxes at positions before env.render-from starting-row-on-screen:number code-ending-row-on-screen:number # past end of code response-starting-row-on-screen:number @@ -145,6 +151,9 @@ recipe run-sandboxes env:address:shared:programming-environment-data, screen:add next:address:address:shared:sandbox-data <- get-address *new-sandbox, next-sandbox:offset *next <- copy *dest *dest <- copy new-sandbox + # update sandbox count + sandbox-count:address:number <- get-address *env, number-of-sandboxes:offset + *sandbox-count <- add *sandbox-count, 1 # clear sandbox editor init:address:address:shared:duplex-list:character <- get-address *current-sandbox, data:offset *init <- push 167/§, 0/tail @@ -224,19 +233,26 @@ recipe! render-sandbox-side screen:address:shared:screen, env:address:shared:pro load-ingredients trace 11, [app], [render sandbox side] current-sandbox:address:shared:editor-data <- get *env, current-sandbox:offset + row:number, column:number <- copy 1, 0 left:number <- get *current-sandbox, left:offset right:number <- get *current-sandbox, right:offset - <render-sandbox-side-special-cases> - row:number, column:number, screen, current-sandbox <- render screen, current-sandbox - clear-screen-from screen, row, column, left, right - row <- add row, 1 + # render sandbox editor + render-from:number <- get *env, render-from:offset + { + render-current-sandbox?:boolean <- equal render-from, -1 + break-unless render-current-sandbox? + row, column, screen, current-sandbox <- render screen, current-sandbox + clear-screen-from screen, row, column, left, right + row <- add row, 1 + } + # render sandboxes draw-horizontal screen, row, left, right, 9473/horizontal-double sandbox:address:shared:sandbox-data <- get *env, sandbox:offset - row, screen <- render-sandboxes screen, sandbox, left, right, row, 0, env + row, screen <- render-sandboxes screen, sandbox, left, right, row, render-from, 0, env clear-rest-of-screen screen, row, left, right ] -recipe render-sandboxes screen:address:shared:screen, sandbox:address:shared:sandbox-data, left:number, right:number, row:number, idx:number -> row:number, screen:address:shared:screen, sandbox:address:shared:sandbox-data [ +recipe render-sandboxes screen:address:shared:screen, sandbox:address:shared:sandbox-data, left:number, right:number, row:number, render-from:number, idx:number -> row:number, screen:address:shared:screen, sandbox:address:shared:sandbox-data [ local-scope load-ingredients env:address:shared:programming-environment-data, _/optional <- next-ingredient @@ -244,48 +260,62 @@ recipe render-sandboxes screen:address:shared:screen, sandbox:address:shared:san screen-height:number <- screen-height screen at-bottom?:boolean <- greater-or-equal row, screen-height reply-if at-bottom?:boolean - # render sandbox menu - row <- add row, 1 - screen <- move-cursor screen, row, left - print screen, idx, 240/dark-grey - clear-line-delimited screen, left, right - delete-icon:character <- copy 120/x - print screen, delete-icon, 245/grey - # save menu row so we can detect clicks to it later - starting-row:address:number <- get-address *sandbox, starting-row-on-screen:offset - *starting-row <- copy row - # render sandbox contents - row <- add row, 1 - screen <- move-cursor screen, row, left - sandbox-data:address:shared:array:character <- get *sandbox, data:offset - row, screen <- render-code screen, sandbox-data, left, right, row - code-ending-row:address:number <- get-address *sandbox, code-ending-row-on-screen:offset - *code-ending-row <- copy row - # render sandbox warnings, screen or response, in that order - response-starting-row:address:number <- get-address *sandbox, response-starting-row-on-screen:offset - sandbox-response:address:shared:array:character <- get *sandbox, response:offset - <render-sandbox-results> + hidden?:boolean <- lesser-than idx, render-from { - sandbox-screen:address:shared:screen <- get *sandbox, screen:offset - empty-screen?:boolean <- fake-screen-is-empty? sandbox-screen - break-if empty-screen? - row, screen <- render-screen screen, sandbox-screen, left, right, row + break-if hidden? + # render sandbox menu + row <- add row, 1 + screen <- move-cursor screen, row, left + print screen, idx, 240/dark-grey + clear-line-delimited screen, left, right + delete-icon:character <- copy 120/x + print screen, delete-icon, 245/grey + # save menu row so we can detect clicks to it later + starting-row:address:number <- get-address *sandbox, starting-row-on-screen:offset + *starting-row <- copy row + # render sandbox contents + row <- add row, 1 + screen <- move-cursor screen, row, left + sandbox-data:address:shared:array:character <- get *sandbox, data:offset + row, screen <- render-code screen, sandbox-data, left, right, row + code-ending-row:address:number <- get-address *sandbox, code-ending-row-on-screen:offset + *code-ending-row <- copy row + # render sandbox warnings, screen or response, in that order + response-starting-row:address:number <- get-address *sandbox, response-starting-row-on-screen:offset + sandbox-response:address:shared:array:character <- get *sandbox, response:offset + <render-sandbox-results> + { + sandbox-screen:address:shared:screen <- get *sandbox, screen:offset + empty-screen?:boolean <- fake-screen-is-empty? sandbox-screen + break-if empty-screen? + row, screen <- render-screen screen, sandbox-screen, left, right, row + } + { + break-unless empty-screen? + *response-starting-row <- copy row + <render-sandbox-response> + row, screen <- render screen, sandbox-response, left, right, 245/grey, row + } + +render-sandbox-end + at-bottom?:boolean <- greater-or-equal row, screen-height + reply-if at-bottom?, row/same-as-ingredient:4, screen/same-as-ingredient:0 + # draw solid line after sandbox + draw-horizontal screen, row, left, right, 9473/horizontal-double } + # if hidden, reset row attributes { - break-unless empty-screen? - *response-starting-row <- copy row - <render-sandbox-response> - row, screen <- render screen, sandbox-response, left, right, 245/grey, row + break-unless hidden? + tmp:address:number <- get-address *sandbox, starting-row-on-screen:offset + *tmp <- copy 0 + tmp:address:number <- get-address *sandbox, code-ending-row-on-screen:offset + *tmp <- copy 0 + tmp:address:number <- get-address *sandbox, response-starting-row-on-screen:offset + *tmp <- copy 0 } - +render-sandbox-end - at-bottom?:boolean <- greater-or-equal row, screen-height - reply-if at-bottom?, row/same-as-ingredient:4, screen/same-as-ingredient:0 - # draw solid line after sandbox - draw-horizontal screen, row, left, right, 9473/horizontal-double # draw next sandbox next-sandbox:address:shared:sandbox-data <- get *sandbox, next-sandbox:offset next-idx:number <- add idx, 1 - row, screen <- render-sandboxes screen, next-sandbox, left, right, row, next-idx, env + row, screen <- render-sandboxes screen, next-sandbox, left, right, row, render-from, next-idx, env ] # assumes programming environment has no sandboxes; restores them from previous session @@ -530,7 +560,7 @@ scenario scrolling-down-past-bottom-of-sandbox-editor [ ] ] -# down on sandbox side updates first-sandbox-to-render when sandbox editor has cursor at bottom +# down on sandbox side updates render-from when sandbox editor has cursor at bottom after <global-keypress> [ { down?:boolean <- equal *k, 65516/down-arrow @@ -541,21 +571,14 @@ after <global-keypress> [ break-unless sandbox-cursor-on-last-line? sandbox:address:shared:sandbox-data <- get *env, sandbox:offset break-unless sandbox - first-sandbox-to-render:address:address:shared:sandbox-data <- get-address *env, first-sandbox-to-render:offset - first-sandbox-index:address:number <- get-address *env, first-sandbox-index:offset - # if first-sandbox-to-render is set, slide it down if possible + # slide down if possible { - break-unless *first-sandbox-to-render - next:address:shared:sandbox-data <- get **first-sandbox-to-render, next-sandbox:offset - break-unless next - *first-sandbox-to-render <- copy next - *first-sandbox-index <- add *first-sandbox-index, 1 - } - # if first-sandbox-to-render is not set, set it to first sandbox - { - break-if *first-sandbox-to-render - *first-sandbox-to-render <- copy sandbox - *first-sandbox-index <- copy 0 + render-from:address:number <- get-address *env, render-from:offset + number-of-sandboxes:number <- get *env, number-of-sandboxes:offset + max:number <- subtract number-of-sandboxes, 1 + at-end?:boolean <- greater-or-equal *render-from, max + break-if at-end? + *render-from <- add *render-from, 1 } hide-screen screen screen <- render-sandbox-side screen, env @@ -564,27 +587,14 @@ after <global-keypress> [ } ] -# render-sandbox-side takes first-sandbox-to-render into account -after <render-sandbox-side-special-cases> [ - { - first-sandbox-to-render:address:shared:sandbox-data <- get *env, first-sandbox-to-render:offset - break-unless first-sandbox-to-render - row:number <- copy 1 # skip menu - draw-horizontal screen, row, left, right, 9473/horizontal-double - first-sandbox-index:number <- get *env, first-sandbox-index:offset - row, screen <- render-sandboxes screen, first-sandbox-to-render, left, right, row, first-sandbox-index - clear-rest-of-screen screen, row, left, right - reply - } -] - -# update-cursor takes first-sandbox-to-render into account +# update-cursor takes render-from into account after <update-cursor-special-cases> [ { - first-sandbox-to-render:address:shared:sandbox-data <- get *env, first-sandbox-to-render:offset - break-unless first-sandbox-to-render + render-from:number <- get *env, render-from:offset + scrolling?:boolean <- greater-or-equal render-from, 0 + break-unless scrolling? cursor-column:number <- get *current-sandbox, left:offset - screen <- move-cursor screen, 2/row, cursor-column + screen <- move-cursor screen, 2/row, cursor-column # highlighted sandbox will always start at row 2 reply } ] @@ -594,14 +604,10 @@ after <global-keypress> [ { up?:boolean <- equal *k, 65517/up-arrow break-unless up? - first-sandbox-to-render:address:address:shared:sandbox-data <- get-address *env, first-sandbox-to-render:offset - break-unless *first-sandbox-to-render - { - break-unless *first-sandbox-to-render - *first-sandbox-to-render <- previous-sandbox env, *first-sandbox-to-render - first-sandbox-index:address:number <- get-address *env, first-sandbox-index:offset - *first-sandbox-index <- subtract *first-sandbox-index, 1 - } + render-from:address:number <- get-address *env, render-from:offset + at-beginning?:boolean <- equal *render-from, -1 + break-if at-beginning? + *render-from <- subtract *render-from, 1 hide-screen screen screen <- render-sandbox-side screen, env show-screen screen diff --git a/sandbox/006-sandbox-edit.mu b/sandbox/006-sandbox-edit.mu index 3885588d..6f3ac272 100644 --- a/sandbox/006-sandbox-edit.mu +++ b/sandbox/006-sandbox-edit.mu @@ -77,15 +77,14 @@ after <global-touch> [ below-sandbox-editor?:boolean <- greater-or-equal click-row, first-sandbox-begins break-unless below-sandbox-editor? empty-sandbox-editor?:boolean <- empty-editor? current-sandbox - break-unless empty-sandbox-editor? # make the user hit F4 before editing a new sandbox + break-unless empty-sandbox-editor? # don't clobber existing contents # identify the sandbox to edit and remove it from the sandbox list sandbox:address:shared:sandbox-data <- extract-sandbox env, click-row + break-unless sandbox text:address:shared:array:character <- get *sandbox, data:offset current-sandbox <- insert-text current-sandbox, text - first-sandbox-to-render:address:address:shared:sandbox-data <- get-address *env, first-sandbox-to-render:offset - *first-sandbox-to-render <- copy 0 - first-sandbox-index:address:number <- get-address *env, first-sandbox-index:offset - *first-sandbox-index <- copy 0 + render-from:address:number <- get-address *env, render-from:offset + *render-from <- copy -1 hide-screen screen screen <- render-sandbox-side screen, env screen <- update-cursor screen, current-sandbox, env @@ -105,11 +104,10 @@ recipe empty-editor? editor:address:shared:editor-data -> result:boolean [ recipe extract-sandbox env:address:shared:programming-environment-data, click-row:number -> result:address:shared:sandbox-data, env:address:shared:programming-environment-data [ local-scope load-ingredients - # assert click-row >= sandbox.starting-row-on-screen sandbox:address:address:shared:sandbox-data <- get-address *env, sandbox:offset start:number <- get **sandbox, starting-row-on-screen:offset - clicked-on-sandboxes?:boolean <- greater-or-equal click-row, start - assert clicked-on-sandboxes?, [extract-sandbox called on click to sandbox editor] + in-editor?:boolean <- lesser-than click-row, start + reply-if in-editor?, 0 { next-sandbox:address:shared:sandbox-data <- get **sandbox, next-sandbox:offset break-unless next-sandbox diff --git a/sandbox/007-sandbox-delete.mu b/sandbox/007-sandbox-delete.mu index f3c3ef10..af9db190 100644 --- a/sandbox/007-sandbox-delete.mu +++ b/sandbox/007-sandbox-delete.mu @@ -94,9 +94,20 @@ recipe delete-sandbox t:touch-event, env:address:shared:programming-environment- target-row:number <- get *curr, starting-row-on-screen:offset delete-curr?:boolean <- equal target-row, click-row break-unless delete-curr? - # delete this sandbox, rerender and stop + # delete this sandbox *prev <- get *curr, next-sandbox:offset - reply 1/true + # update sandbox count + sandbox-count:address:number <- get-address *env, number-of-sandboxes:offset + *sandbox-count <- subtract *sandbox-count, 1 + # if it's the last sandbox and if it was the only sandbox rendered, reset scroll + { + break-if *prev + render-from:address:number <- get-address *env, render-from:offset + reset-scroll?:boolean <- equal *render-from, *sandbox-count + break-unless reset-scroll? + *render-from <- copy -1 + } + reply 1/true # force rerender } prev <- get-address *curr, next-sandbox:offset curr <- get *curr, next-sandbox:offset @@ -104,3 +115,203 @@ recipe delete-sandbox t:touch-event, env:address:shared:programming-environment- } reply 0/false ] + +scenario deleting-sandbox-after-scroll [ + trace-until 100/app # trace too long + assume-screen 30/width, 10/height + # initialize environment + 1:address:shared:array:character <- new [] + 2:address:shared:programming-environment-data <- new-programming-environment screen:address:shared:screen, 1:address:shared:array:character + render-all screen, 2:address:shared:programming-environment-data + # create 2 sandboxes and scroll to second + assume-console [ + press ctrl-n + type [add 2, 2] + press F4 + type [add 1, 1] + press F4 + press down-arrow + ] + run [ + event-loop screen:address:shared:screen, console:address:shared:console, 2:address:shared:programming-environment-data + ] + screen-should-contain [ + . . # menu + .━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━. + .0 x. + .add 1, 1 . + .2 . + .━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━. + .1 x. + .add 2, 2 . + .4 . + .━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━. + ] + # delete the second sandbox + assume-console [ + left-click 6, 29 + ] + run [ + event-loop screen:address:shared:screen, console:address:shared:console, 2:address:shared:programming-environment-data + ] + # second sandbox shows in editor; scroll resets to display first sandbox + screen-should-contain [ + . . + .━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━. + .0 x. + .add 1, 1 . + .2 . + .━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━. + . . + ] +] + +scenario deleting-top-sandbox-after-scroll [ + trace-until 100/app # trace too long + assume-screen 30/width, 10/height + # initialize environment + 1:address:shared:array:character <- new [] + 2:address:shared:programming-environment-data <- new-programming-environment screen:address:shared:screen, 1:address:shared:array:character + render-all screen, 2:address:shared:programming-environment-data + # create 2 sandboxes and scroll to second + assume-console [ + press ctrl-n + type [add 2, 2] + press F4 + type [add 1, 1] + press F4 + press down-arrow + ] + run [ + event-loop screen:address:shared:screen, console:address:shared:console, 2:address:shared:programming-environment-data + ] + screen-should-contain [ + . . # menu + .━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━. + .0 x. + .add 1, 1 . + .2 . + .━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━. + .1 x. + .add 2, 2 . + .4 . + .━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━. + ] + # delete the second sandbox + assume-console [ + left-click 2, 29 + ] + run [ + event-loop screen:address:shared:screen, console:address:shared:console, 2:address:shared:programming-environment-data + ] + # second sandbox shows in editor; scroll resets to display first sandbox + screen-should-contain [ + . . + .━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━. + .0 x. + .add 2, 2 . + .4 . + .━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━. + . . + ] +] + +scenario deleting-final-sandbox-after-scroll [ + trace-until 100/app # trace too long + assume-screen 30/width, 10/height + # initialize environment + 1:address:shared:array:character <- new [] + 2:address:shared:programming-environment-data <- new-programming-environment screen:address:shared:screen, 1:address:shared:array:character + render-all screen, 2:address:shared:programming-environment-data + # create 2 sandboxes and scroll to second + assume-console [ + press ctrl-n + type [add 2, 2] + press F4 + type [add 1, 1] + press F4 + press down-arrow + press down-arrow + ] + run [ + event-loop screen:address:shared:screen, console:address:shared:console, 2:address:shared:programming-environment-data + ] + screen-should-contain [ + . . + .━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━. + .1 x. + .add 2, 2 . + .4 . + .━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━. + . . + ] + # delete the second sandbox + assume-console [ + left-click 2, 29 + ] + run [ + event-loop screen:address:shared:screen, console:address:shared:console, 2:address:shared:programming-environment-data + ] + # implicitly scroll up to first sandbox + screen-should-contain [ + . . + . . + .━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━. + .0 x. + .add 1, 1 . + .2 . + .━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━. + . . + ] +] + +scenario deleting-updates-sandbox-count [ + trace-until 100/app # trace too long + assume-screen 30/width, 10/height + # initialize environment + 1:address:shared:array:character <- new [] + 2:address:shared:programming-environment-data <- new-programming-environment screen:address:shared:screen, 1:address:shared:array:character + render-all screen, 2:address:shared:programming-environment-data + # create 2 sandboxes + assume-console [ + press ctrl-n + type [add 2, 2] + press F4 + type [add 1, 1] + press F4 + ] + run [ + event-loop screen:address:shared:screen, console:address:shared:console, 2:address:shared:programming-environment-data + ] + screen-should-contain [ + . . + . . + .━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━. + .0 x. + .add 1, 1 . + .2 . + .━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━. + .1 x. + .add 2, 2 . + .4 . + ] + # delete the second sandbox, then try to scroll down twice + assume-console [ + left-click 3, 29 + press down-arrow + press down-arrow + ] + run [ + event-loop screen:address:shared:screen, console:address:shared:console, 2:address:shared:programming-environment-data + ] + # shouldn't go past last sandbox + screen-should-contain [ + . . + .━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━. + .0 x. + .add 2, 2 . + .4 . + .━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━. + . . + ] +] |