From ef6116cbaf9368e490bfdec1c6404396ac161026 Mon Sep 17 00:00:00 2001 From: "Kartik K. Agaram" Date: Sat, 13 May 2017 12:50:07 -0700 Subject: 3855 --- html/edit/004-programming-environment.mu.html | 942 +++++++++++++------------- 1 file changed, 484 insertions(+), 458 deletions(-) (limited to 'html/edit/004-programming-environment.mu.html') diff --git a/html/edit/004-programming-environment.mu.html b/html/edit/004-programming-environment.mu.html index bc4394cd..87f2586b 100644 --- a/html/edit/004-programming-environment.mu.html +++ b/html/edit/004-programming-environment.mu.html @@ -70,7 +70,7 @@ if ('onhashchange' in window) { 7 local-scope 8 open-console 9 env:&:environment <- new-programming-environment 0/filesystem, 0/screen - 10 render-all 0/screen, env, render + 10 render-all 0/screen, env, render 11 event-loop 0/screen, 0/console, env, 0/filesystem 12 # never gets here 13 ] @@ -84,15 +84,15 @@ if ('onhashchange' in window) { 21 def new-programming-environment resources:&:resources, screen:&:screen, test-sandbox-editor-contents:text -> result:&:environment [ 22 local-scope 23 load-ingredients - 24 width:num <- screen-width screen + 24 width:num <- screen-width screen 25 result <- new environment:type 26 # recipe editor on the left 27 initial-recipe-contents:text <- slurp resources, [lesson/recipes.mu] # ignore errors 28 divider:num, _ <- divide-with-remainder width, 2 - 29 recipes:&:editor <- new-editor initial-recipe-contents, 0/left, divider/right + 29 recipes:&:editor <- new-editor initial-recipe-contents, 0/left, divider/right 30 # sandbox editor on the right 31 sandbox-left:num <- add divider, 1 - 32 current-sandbox:&:editor <- new-editor test-sandbox-editor-contents, sandbox-left, width/right + 32 current-sandbox:&:editor <- new-editor test-sandbox-editor-contents, sandbox-left, width/right 33 *result <- put *result, recipes:offset, recipes 34 *result <- put *result, current-sandbox:offset, current-sandbox 35 *result <- put *result, sandbox-in-focus?:offset, 0/false @@ -105,464 +105,490 @@ if ('onhashchange' in window) { 42 recipes:&:editor <- get *env, recipes:offset 43 current-sandbox:&:editor <- get *env, current-sandbox:offset 44 sandbox-in-focus?:bool <- get *env, sandbox-in-focus?:offset - 45 { - 46 ¦ # looping over each (keyboard or touch) event as it occurs - 47 ¦ +next-event - 48 ¦ e:event, found?:bool, quit?:bool, console <- read-event console - 49 ¦ loop-unless found? - 50 ¦ break-if quit? # only in tests - 51 ¦ trace 10, [app], [next-event] - 52 ¦ <handle-event> - 53 ¦ # check for global events that will trigger regardless of which editor has focus - 54 ¦ { - 55 ¦ ¦ k:num, is-keycode?:bool <- maybe-convert e:event, keycode:variant - 56 ¦ ¦ break-unless is-keycode? - 57 ¦ ¦ <global-keypress> - 58 ¦ } - 59 ¦ { - 60 ¦ ¦ c:char, is-unicode?:bool <- maybe-convert e:event, text:variant - 61 ¦ ¦ break-unless is-unicode? - 62 ¦ ¦ <global-type> - 63 ¦ } - 64 ¦ # 'touch' event - send to both sides, see what picks it up - 65 ¦ { - 66 ¦ ¦ t:touch-event, is-touch?:bool <- maybe-convert e:event, touch:variant - 67 ¦ ¦ break-unless is-touch? - 68 ¦ ¦ # ignore all but 'left-click' events for now - 69 ¦ ¦ # todo: test this - 70 ¦ ¦ touch-type:num <- get t, type:offset - 71 ¦ ¦ is-left-click?:bool <- equal touch-type, 65513/mouse-left - 72 ¦ ¦ loop-unless is-left-click?, +next-event - 73 ¦ ¦ click-row:num <- get t, row:offset - 74 ¦ ¦ click-column:num <- get t, column:offset - 75 ¦ ¦ # later exceptions for non-editor touches will go here - 76 ¦ ¦ <global-touch> - 77 ¦ ¦ # send to both editors - 78 ¦ ¦ _ <- move-cursor-in-editor screen, recipes, t - 79 ¦ ¦ sandbox-in-focus?:bool <- move-cursor-in-editor screen, current-sandbox, t - 80 ¦ ¦ *env <- put *env, sandbox-in-focus?:offset, sandbox-in-focus? - 81 ¦ ¦ screen <- update-cursor screen, recipes, current-sandbox, sandbox-in-focus?, env - 82 ¦ ¦ loop +next-event - 83 ¦ } - 84 ¦ # 'resize' event - redraw editor - 85 ¦ # todo: test this after supporting resize in assume-console - 86 ¦ { - 87 ¦ ¦ r:resize-event, is-resize?:bool <- maybe-convert e:event, resize:variant - 88 ¦ ¦ break-unless is-resize? - 89 ¦ ¦ env, screen <- resize screen, env - 90 ¦ ¦ screen <- render-all screen, env, render-without-moving-cursor - 91 ¦ ¦ loop +next-event - 92 ¦ } - 93 ¦ # if it's not global and not a touch event, send to appropriate editor - 94 ¦ { - 95 ¦ ¦ sandbox-in-focus?:bool <- get *env, sandbox-in-focus?:offset - 96 ¦ ¦ { - 97 ¦ ¦ ¦ break-if sandbox-in-focus? - 98 ¦ ¦ ¦ render?:bool <- handle-keyboard-event screen, recipes, e:event - 99 ¦ ¦ ¦ break-unless render? -100 ¦ ¦ ¦ screen <- render-all screen, env, render -101 ¦ ¦ } -102 ¦ ¦ { -103 ¦ ¦ ¦ break-unless sandbox-in-focus? -104 ¦ ¦ ¦ render?:bool <- handle-keyboard-event screen, current-sandbox, e:event -105 ¦ ¦ ¦ break-unless render? -106 ¦ ¦ ¦ screen <- render-sandbox-side screen, env, render -107 ¦ ¦ } -108 ¦ ¦ screen <- update-cursor screen, recipes, current-sandbox, sandbox-in-focus?, env -109 ¦ } -110 ¦ loop -111 } -112 ] -113 -114 def resize screen:&:screen, env:&:environment -> env:&:environment, screen:&:screen [ -115 local-scope -116 load-ingredients -117 clear-screen screen # update screen dimensions -118 width:num <- screen-width screen -119 divider:num, _ <- divide-with-remainder width, 2 -120 # update recipe editor -121 recipes:&:editor <- get *env, recipes:offset -122 right:num <- subtract divider, 1 -123 *recipes <- put *recipes, right:offset, right -124 # reset cursor (later we'll try to preserve its position) -125 *recipes <- put *recipes, cursor-row:offset, 1 -126 *recipes <- put *recipes, cursor-column:offset, 0 -127 # update sandbox editor -128 current-sandbox:&:editor <- get *env, current-sandbox:offset -129 left:num <- add divider, 1 -130 *current-sandbox <- put *current-sandbox, left:offset, left -131 right:num <- subtract width, 1 -132 *current-sandbox <- put *current-sandbox, right:offset, right -133 # reset cursor (later we'll try to preserve its position) -134 *current-sandbox <- put *current-sandbox, cursor-row:offset, 1 -135 *current-sandbox <- put *current-sandbox, cursor-column:offset, left -136 ] -137 -138 # Variant of 'render' that updates cursor-row and cursor-column based on -139 # before-cursor (rather than the other way around). If before-cursor moves -140 # off-screen, it resets cursor-row and cursor-column. -141 def render-without-moving-cursor screen:&:screen, editor:&:editor -> last-row:num, last-column:num, screen:&:screen, editor:&:editor [ -142 local-scope -143 load-ingredients -144 return-unless editor, 1/top, 0/left -145 left:num <- get *editor, left:offset -146 screen-height:num <- screen-height screen -147 right:num <- get *editor, right:offset -148 curr:&:duplex-list:char <- get *editor, top-of-screen:offset -149 prev:&:duplex-list:char <- copy curr # just in case curr becomes null and we can't compute prev -150 curr <- next curr -151 color:num <- copy 7/white -152 row:num <- copy 1/top -153 column:num <- copy left -154 # save before-cursor -155 old-before-cursor:&:duplex-list:char <- get *editor, before-cursor:offset -156 # initialze cursor-row/cursor-column/before-cursor to the top of the screen -157 # by default -158 *editor <- put *editor, cursor-row:offset, row -159 *editor <- put *editor, cursor-column:offset, column -160 top-of-screen:&:duplex-list:char <- get *editor, top-of-screen:offset -161 *editor <- put *editor, before-cursor:offset, top-of-screen -162 screen <- move-cursor screen, row, column -163 { -164 ¦ +next-character -165 ¦ break-unless curr -166 ¦ off-screen?:bool <- greater-or-equal row, screen-height -167 ¦ break-if off-screen? -168 ¦ # if we find old-before-cursor still on the new resized screen, update -169 ¦ # editor.cursor-row and editor.cursor-column based on -170 ¦ # old-before-cursor -171 ¦ { -172 ¦ ¦ at-cursor?:bool <- equal old-before-cursor, prev -173 ¦ ¦ break-unless at-cursor? -174 ¦ ¦ *editor <- put *editor, cursor-row:offset, row -175 ¦ ¦ *editor <- put *editor, cursor-column:offset, column -176 ¦ ¦ *editor <- put *editor, before-cursor:offset, old-before-cursor -177 ¦ } -178 ¦ c:char <- get *curr, value:offset -179 ¦ <character-c-received> -180 ¦ { -181 ¦ ¦ # newline? move to left rather than 0 -182 ¦ ¦ newline?:bool <- equal c, 10/newline -183 ¦ ¦ break-unless newline? -184 ¦ ¦ # clear rest of line in this window -185 ¦ ¦ clear-line-until screen, right -186 ¦ ¦ # skip to next line -187 ¦ ¦ row <- add row, 1 -188 ¦ ¦ column <- copy left -189 ¦ ¦ screen <- move-cursor screen, row, column -190 ¦ ¦ curr <- next curr -191 ¦ ¦ prev <- next prev -192 ¦ ¦ loop +next-character -193 ¦ } -194 ¦ { -195 ¦ ¦ # at right? wrap. even if there's only one more letter left; we need -196 ¦ ¦ # room for clicking on the cursor after it. -197 ¦ ¦ at-right?:bool <- equal column, right -198 ¦ ¦ break-unless at-right? -199 ¦ ¦ # print wrap icon -200 ¦ ¦ wrap-icon:char <- copy 8617/loop-back-to-left -201 ¦ ¦ print screen, wrap-icon, 245/grey -202 ¦ ¦ column <- copy left -203 ¦ ¦ row <- add row, 1 -204 ¦ ¦ screen <- move-cursor screen, row, column -205 ¦ ¦ # don't increment curr -206 ¦ ¦ loop +next-character -207 ¦ } -208 ¦ print screen, c, color -209 ¦ curr <- next curr -210 ¦ prev <- next prev -211 ¦ column <- add column, 1 -212 ¦ loop -213 } -214 # save first character off-screen -215 *editor <- put *editor, bottom-of-screen:offset, curr -216 *editor <- put *editor, bottom:offset, row -217 return row, column -218 ] -219 -220 scenario point-at-multiple-editors [ -221 local-scope -222 trace-until 100/app # trace too long -223 assume-screen 30/width, 5/height -224 # initialize both halves of screen -225 assume-resources [ -226 ¦ [lesson/recipes.mu] <- [ -227 ¦ ¦ |abc| -228 ¦ ] -229 ] -230 env:&:environment <- new-programming-environment resources, screen, [def] # contents of sandbox editor -231 # focus on both sides -232 assume-console [ -233 ¦ left-click 1, 1 -234 ¦ left-click 1, 17 -235 ] -236 # check cursor column in each -237 run [ -238 ¦ event-loop screen, console, env, resources -239 ¦ recipes:&:editor <- get *env, recipes:offset -240 ¦ 5:num/raw <- get *recipes, cursor-column:offset -241 ¦ sandbox:&:editor <- get *env, current-sandbox:offset -242 ¦ 7:num/raw <- get *sandbox, cursor-column:offset -243 ] -244 memory-should-contain [ -245 ¦ 5 <- 1 -246 ¦ 7 <- 17 -247 ] -248 ] -249 -250 scenario edit-multiple-editors [ -251 local-scope -252 trace-until 100/app # trace too long -253 assume-screen 30/width, 5/height -254 # initialize both halves of screen -255 assume-resources [ -256 ¦ [lesson/recipes.mu] <- [ -257 ¦ ¦ |abc| -258 ¦ ] -259 ] -260 env:&:environment <- new-programming-environment resources, screen, [def] # contents of sandbox -261 render-all screen, env, render -262 # type one letter in each of them -263 assume-console [ -264 ¦ left-click 1, 1 -265 ¦ type [0] -266 ¦ left-click 1, 17 -267 ¦ type [1] -268 ] -269 run [ -270 ¦ event-loop screen, console, env, resources -271 ¦ recipes:&:editor <- get *env, recipes:offset -272 ¦ 5:num/raw <- get *recipes, cursor-column:offset -273 ¦ sandbox:&:editor <- get *env, current-sandbox:offset -274 ¦ 7:num/raw <- get *sandbox, cursor-column:offset -275 ] -276 screen-should-contain [ -277 ¦ . run (F4) . # this line has a different background, but we don't test that yet -278 ¦ .a0bc ╎d1ef . -279 ¦ . ╎──────────────. -280 ¦ .╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╎ . -281 ¦ . ╎ . -282 ] -283 memory-should-contain [ -284 ¦ 5 <- 2 # cursor column of recipe editor -285 ¦ 7 <- 18 # cursor column of sandbox editor + 45 # if we fall behind we'll stop updating the screen, but then we have to + 46 # render the entire screen when we catch up. + 47 # todo: test this + 48 render-all-on-no-more-events?:bool <- copy 0/false + 49 { + 50 ¦ # looping over each (keyboard or touch) event as it occurs + 51 ¦ +next-event + 52 ¦ e:event, found?:bool, quit?:bool, console <- read-event console + 53 ¦ loop-unless found? + 54 ¦ break-if quit? # only in tests + 55 ¦ trace 10, [app], [next-event] + 56 ¦ <handle-event> + 57 ¦ # check for global events that will trigger regardless of which editor has focus + 58 ¦ { + 59 ¦ ¦ k:num, is-keycode?:bool <- maybe-convert e:event, keycode:variant + 60 ¦ ¦ break-unless is-keycode? + 61 ¦ ¦ <global-keypress> + 62 ¦ } + 63 ¦ { + 64 ¦ ¦ c:char, is-unicode?:bool <- maybe-convert e:event, text:variant + 65 ¦ ¦ break-unless is-unicode? + 66 ¦ ¦ <global-type> + 67 ¦ } + 68 ¦ # 'touch' event - send to both sides, see what picks it up + 69 ¦ { + 70 ¦ ¦ t:touch-event, is-touch?:bool <- maybe-convert e:event, touch:variant + 71 ¦ ¦ break-unless is-touch? + 72 ¦ ¦ # ignore all but 'left-click' events for now + 73 ¦ ¦ # todo: test this + 74 ¦ ¦ touch-type:num <- get t, type:offset + 75 ¦ ¦ is-left-click?:bool <- equal touch-type, 65513/mouse-left + 76 ¦ ¦ loop-unless is-left-click?, +next-event + 77 ¦ ¦ click-row:num <- get t, row:offset + 78 ¦ ¦ click-column:num <- get t, column:offset + 79 ¦ ¦ # later exceptions for non-editor touches will go here + 80 ¦ ¦ <global-touch> + 81 ¦ ¦ # send to both editors + 82 ¦ ¦ _ <- move-cursor-in-editor screen, recipes, t + 83 ¦ ¦ sandbox-in-focus?:bool <- move-cursor-in-editor screen, current-sandbox, t + 84 ¦ ¦ *env <- put *env, sandbox-in-focus?:offset, sandbox-in-focus? + 85 ¦ ¦ screen <- update-cursor screen, recipes, current-sandbox, sandbox-in-focus?, env + 86 ¦ ¦ loop +next-event + 87 ¦ } + 88 ¦ # 'resize' event - redraw editor + 89 ¦ # todo: test this after supporting resize in assume-console + 90 ¦ { + 91 ¦ ¦ r:resize-event, is-resize?:bool <- maybe-convert e:event, resize:variant + 92 ¦ ¦ break-unless is-resize? + 93 ¦ ¦ env, screen <- resize screen, env + 94 ¦ ¦ screen <- render-all screen, env, render-without-moving-cursor + 95 ¦ ¦ loop +next-event + 96 ¦ } + 97 ¦ # if it's not global and not a touch event, send to appropriate editor + 98 ¦ { + 99 ¦ ¦ hide-screen screen +100 ¦ ¦ sandbox-in-focus?:bool <- get *env, sandbox-in-focus?:offset +101 ¦ ¦ { +102 ¦ ¦ ¦ break-if sandbox-in-focus? +103 ¦ ¦ ¦ render?:bool <- handle-keyboard-event screen, recipes, e:event +104 ¦ ¦ } +105 ¦ ¦ { +106 ¦ ¦ ¦ break-unless sandbox-in-focus? +107 ¦ ¦ ¦ render?:bool <- handle-keyboard-event screen, current-sandbox, e:event +108 ¦ ¦ } +109 ¦ ¦ # try to batch up rendering if there are more events queued up +110 ¦ ¦ # to compensate for this additional code complexity, we always render both sides when we do render +111 ¦ ¦ render-all-on-no-more-events? <- or render-all-on-no-more-events?, render? +112 ¦ ¦ more-events?:bool <- has-more-events? console +113 ¦ ¦ { +114 ¦ ¦ ¦ break-if more-events? +115 ¦ ¦ ¦ break-unless render-all-on-no-more-events? +116 ¦ ¦ ¦ screen <- render-all screen, env, render +117 ¦ ¦ } +118 ¦ ¦ screen <- update-cursor screen, recipes, current-sandbox, sandbox-in-focus?, env +119 ¦ ¦ show-screen screen +120 ¦ } +121 ¦ loop +122 } +123 ] +124 +125 def resize screen:&:screen, env:&:environment -> env:&:environment, screen:&:screen [ +126 local-scope +127 load-ingredients +128 clear-screen screen # update screen dimensions +129 width:num <- screen-width screen +130 divider:num, _ <- divide-with-remainder width, 2 +131 # update recipe editor +132 recipes:&:editor <- get *env, recipes:offset +133 right:num <- subtract divider, 1 +134 *recipes <- put *recipes, right:offset, right +135 # reset cursor (later we'll try to preserve its position) +136 *recipes <- put *recipes, cursor-row:offset, 1 +137 *recipes <- put *recipes, cursor-column:offset, 0 +138 # update sandbox editor +139 current-sandbox:&:editor <- get *env, current-sandbox:offset +140 left:num <- add divider, 1 +141 *current-sandbox <- put *current-sandbox, left:offset, left +142 right:num <- subtract width, 1 +143 *current-sandbox <- put *current-sandbox, right:offset, right +144 # reset cursor (later we'll try to preserve its position) +145 *current-sandbox <- put *current-sandbox, cursor-row:offset, 1 +146 *current-sandbox <- put *current-sandbox, cursor-column:offset, left +147 ] +148 +149 # Variant of 'render' that updates cursor-row and cursor-column based on +150 # before-cursor (rather than the other way around). If before-cursor moves +151 # off-screen, it resets cursor-row and cursor-column. +152 def render-without-moving-cursor screen:&:screen, editor:&:editor -> last-row:num, last-column:num, screen:&:screen, editor:&:editor [ +153 local-scope +154 load-ingredients +155 return-unless editor, 1/top, 0/left +156 left:num <- get *editor, left:offset +157 screen-height:num <- screen-height screen +158 right:num <- get *editor, right:offset +159 curr:&:duplex-list:char <- get *editor, top-of-screen:offset +160 prev:&:duplex-list:char <- copy curr # just in case curr becomes null and we can't compute prev +161 curr <- next curr +162 color:num <- copy 7/white +163 row:num <- copy 1/top +164 column:num <- copy left +165 # save before-cursor +166 old-before-cursor:&:duplex-list:char <- get *editor, before-cursor:offset +167 # initialze cursor-row/cursor-column/before-cursor to the top of the screen +168 # by default +169 *editor <- put *editor, cursor-row:offset, row +170 *editor <- put *editor, cursor-column:offset, column +171 top-of-screen:&:duplex-list:char <- get *editor, top-of-screen:offset +172 *editor <- put *editor, before-cursor:offset, top-of-screen +173 screen <- move-cursor screen, row, column +174 { +175 ¦ +next-character +176 ¦ break-unless curr +177 ¦ off-screen?:bool <- greater-or-equal row, screen-height +178 ¦ break-if off-screen? +179 ¦ # if we find old-before-cursor still on the new resized screen, update +180 ¦ # editor.cursor-row and editor.cursor-column based on +181 ¦ # old-before-cursor +182 ¦ { +183 ¦ ¦ at-cursor?:bool <- equal old-before-cursor, prev +184 ¦ ¦ break-unless at-cursor? +185 ¦ ¦ *editor <- put *editor, cursor-row:offset, row +186 ¦ ¦ *editor <- put *editor, cursor-column:offset, column +187 ¦ ¦ *editor <- put *editor, before-cursor:offset, old-before-cursor +188 ¦ } +189 ¦ c:char <- get *curr, value:offset +190 ¦ <character-c-received> +191 ¦ { +192 ¦ ¦ # newline? move to left rather than 0 +193 ¦ ¦ newline?:bool <- equal c, 10/newline +194 ¦ ¦ break-unless newline? +195 ¦ ¦ # clear rest of line in this window +196 ¦ ¦ clear-line-until screen, right +197 ¦ ¦ # skip to next line +198 ¦ ¦ row <- add row, 1 +199 ¦ ¦ column <- copy left +200 ¦ ¦ screen <- move-cursor screen, row, column +201 ¦ ¦ curr <- next curr +202 ¦ ¦ prev <- next prev +203 ¦ ¦ loop +next-character +204 ¦ } +205 ¦ { +206 ¦ ¦ # at right? wrap. even if there's only one more letter left; we need +207 ¦ ¦ # room for clicking on the cursor after it. +208 ¦ ¦ at-right?:bool <- equal column, right +209 ¦ ¦ break-unless at-right? +210 ¦ ¦ # print wrap icon +211 ¦ ¦ wrap-icon:char <- copy 8617/loop-back-to-left +212 ¦ ¦ print screen, wrap-icon, 245/grey +213 ¦ ¦ column <- copy left +214 ¦ ¦ row <- add row, 1 +215 ¦ ¦ screen <- move-cursor screen, row, column +216 ¦ ¦ # don't increment curr +217 ¦ ¦ loop +next-character +218 ¦ } +219 ¦ print screen, c, color +220 ¦ curr <- next curr +221 ¦ prev <- next prev +222 ¦ column <- add column, 1 +223 ¦ loop +224 } +225 # save first character off-screen +226 *editor <- put *editor, bottom-of-screen:offset, curr +227 *editor <- put *editor, bottom:offset, row +228 return row, column +229 ] +230 +231 scenario point-at-multiple-editors [ +232 local-scope +233 trace-until 100/app # trace too long +234 assume-screen 30/width, 5/height +235 # initialize both halves of screen +236 assume-resources [ +237 ¦ [lesson/recipes.mu] <- [ +238 ¦ ¦ |abc| +239 ¦ ] +240 ] +241 env:&:environment <- new-programming-environment resources, screen, [def] # contents of sandbox editor +242 # focus on both sides +243 assume-console [ +244 ¦ left-click 1, 1 +245 ¦ left-click 1, 17 +246 ] +247 # check cursor column in each +248 run [ +249 ¦ event-loop screen, console, env, resources +250 ¦ recipes:&:editor <- get *env, recipes:offset +251 ¦ 5:num/raw <- get *recipes, cursor-column:offset +252 ¦ sandbox:&:editor <- get *env, current-sandbox:offset +253 ¦ 7:num/raw <- get *sandbox, cursor-column:offset +254 ] +255 memory-should-contain [ +256 ¦ 5 <- 1 +257 ¦ 7 <- 17 +258 ] +259 ] +260 +261 scenario edit-multiple-editors [ +262 local-scope +263 trace-until 100/app # trace too long +264 assume-screen 30/width, 5/height +265 # initialize both halves of screen +266 assume-resources [ +267 ¦ [lesson/recipes.mu] <- [ +268 ¦ ¦ |abc| +269 ¦ ] +270 ] +271 env:&:environment <- new-programming-environment resources, screen, [def] # contents of sandbox +272 render-all screen, env, render +273 # type one letter in each of them +274 assume-console [ +275 ¦ left-click 1, 1 +276 ¦ type [0] +277 ¦ left-click 1, 17 +278 ¦ type [1] +279 ] +280 run [ +281 ¦ event-loop screen, console, env, resources +282 ¦ recipes:&:editor <- get *env, recipes:offset +283 ¦ 5:num/raw <- get *recipes, cursor-column:offset +284 ¦ sandbox:&:editor <- get *env, current-sandbox:offset +285 ¦ 7:num/raw <- get *sandbox, cursor-column:offset 286 ] -287 # show the cursor at the right window -288 run [ -289 ¦ cursor:char <- copy 9251/␣ -290 ¦ print screen, cursor -291 ] -292 screen-should-contain [ -293 ¦ . run (F4) . -294 ¦ .a0bc ╎d1␣f . -295 ¦ . ╎──────────────. -296 ¦ .╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╎ . -297 ¦ . ╎ . -298 ] -299 ] -300 -301 scenario editor-in-focus-keeps-cursor [ -302 local-scope -303 trace-until 100/app # trace too long -304 assume-screen 30/width, 5/height -305 assume-resources [ -306 ¦ [lesson/recipes.mu] <- [ -307 ¦ ¦ |abc| -308 ¦ ] +287 screen-should-contain [ +288 ¦ . run (F4) . # this line has a different background, but we don't test that yet +289 ¦ .a0bc ╎d1ef . +290 ¦ . ╎──────────────. +291 ¦ .╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╎ . +292 ¦ . ╎ . +293 ] +294 memory-should-contain [ +295 ¦ 5 <- 2 # cursor column of recipe editor +296 ¦ 7 <- 18 # cursor column of sandbox editor +297 ] +298 # show the cursor at the right window +299 run [ +300 ¦ cursor:char <- copy 9251/␣ +301 ¦ print screen, cursor +302 ] +303 screen-should-contain [ +304 ¦ . run (F4) . +305 ¦ .a0bc ╎d1␣f . +306 ¦ . ╎──────────────. +307 ¦ .╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╎ . +308 ¦ . ╎ . 309 ] -310 env:&:environment <- new-programming-environment resources, screen, [def] -311 render-all screen, env, render -312 # initialize programming environment and highlight cursor -313 assume-console [] -314 run [ -315 ¦ event-loop screen, console, env, resources -316 ¦ cursor:char <- copy 9251/␣ -317 ¦ print screen, cursor -318 ] -319 # is cursor at the right place? -320 screen-should-contain [ -321 ¦ . run (F4) . -322 ¦ .␣bc ╎def . -323 ¦ . ╎──────────────. -324 ¦ .╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╎ . -325 ¦ . ╎ . -326 ] -327 # now try typing a letter -328 assume-console [ -329 ¦ type [z] -330 ] -331 run [ -332 ¦ event-loop screen, console, env, resources -333 ¦ cursor:char <- copy 9251/␣ -334 ¦ print screen, cursor -335 ] -336 # cursor should still be right -337 screen-should-contain [ -338 ¦ . run (F4) . -339 ¦ .z␣bc ╎def . -340 ¦ . ╎──────────────. -341 ¦ .╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╎ . -342 ¦ . ╎ . -343 ] -344 ] -345 -346 scenario backspace-in-sandbox-editor-joins-lines [ -347 local-scope -348 trace-until 100/app # trace too long -349 assume-screen 30/width, 5/height -350 assume-resources [ -351 ] -352 # initialize sandbox side with two lines -353 test-sandbox-editor-contents:text <- new [abc -354 def] -355 env:&:environment <- new-programming-environment resources, screen, test-sandbox-editor-contents -356 render-all screen, env, render -357 screen-should-contain [ -358 ¦ . run (F4) . -359 ¦ . ╎abc . -360 ¦ .╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╎def . -361 ¦ . ╎──────────────. -362 ¦ . ╎ . -363 ] -364 # position cursor at start of second line and hit backspace -365 assume-console [ -366 ¦ left-click 2, 16 -367 ¦ press backspace -368 ] -369 run [ -370 ¦ event-loop screen, console, env, resources -371 ¦ cursor:char <- copy 9251/␣ -372 ¦ print screen, cursor -373 ] -374 # cursor moves to end of old line -375 screen-should-contain [ -376 ¦ . run (F4) . -377 ¦ . ╎abc␣ef . -378 ¦ .╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╎──────────────. -379 ¦ . ╎ . -380 ] -381 ] -382 -383 def render-all screen:&:screen, env:&:environment, {render-editor: (recipe (address screen) (address editor) -> number number (address screen) (address editor))} -> screen:&:screen, env:&:environment [ -384 local-scope -385 load-ingredients -386 trace 10, [app], [render all] -387 # top menu -388 trace 11, [app], [render top menu] -389 width:num <- screen-width screen -390 draw-horizontal screen, 0, 0/left, width, 32/space, 0/black, 238/grey -391 button-start:num <- subtract width, 20 -392 button-on-screen?:bool <- greater-or-equal button-start, 0 -393 assert button-on-screen?, [screen too narrow for menu] -394 screen <- move-cursor screen, 0/row, button-start -395 print screen, [ run (F4) ], 255/white, 161/reddish -396 # dotted line down the middle -397 trace 11, [app], [render divider] -398 divider:num, _ <- divide-with-remainder width, 2 -399 height:num <- screen-height screen -400 draw-vertical screen, divider, 1/top, height, 9482/vertical-dotted -401 # -402 screen <- render-recipes screen, env, render-editor -403 screen <- render-sandbox-side screen, env, render-editor -404 <render-components-end> -405 # -406 recipes:&:editor <- get *env, recipes:offset -407 current-sandbox:&:editor <- get *env, current-sandbox:offset -408 sandbox-in-focus?:bool <- get *env, sandbox-in-focus?:offset -409 screen <- update-cursor screen, recipes, current-sandbox, sandbox-in-focus?, env -410 ] -411 -412 def render-recipes screen:&:screen, env:&:environment, {render-editor: (recipe (address screen) (address editor) -> number number (address screen) (address editor))} -> screen:&:screen, env:&:environment [ -413 local-scope -414 load-ingredients -415 trace 11, [app], [render recipes] -416 recipes:&:editor <- get *env, recipes:offset -417 # render recipes -418 left:num <- get *recipes, left:offset -419 right:num <- get *recipes, right:offset -420 row:num, column:num, screen <- call render-editor, screen, recipes -421 clear-line-until screen, right -422 row <- add row, 1 -423 <render-recipe-components-end> -424 # draw dotted line after recipes -425 draw-horizontal screen, row, left, right, 9480/horizontal-dotted -426 row <- add row, 1 -427 clear-screen-from screen, row, left, left, right -428 ] -429 -430 # replaced in a later layer -431 def render-sandbox-side screen:&:screen, env:&:environment, {render-editor: (recipe (address screen) (address editor) -> number number (address screen) (address editor))} -> screen:&:screen, env:&:environment [ -432 local-scope -433 load-ingredients -434 current-sandbox:&:editor <- get *env, current-sandbox:offset -435 left:num <- get *current-sandbox, left:offset -436 right:num <- get *current-sandbox, right:offset -437 row:num, column:num, screen, current-sandbox <- call render-editor, screen, current-sandbox -438 clear-line-until screen, right -439 row <- add row, 1 -440 # draw solid line after code (you'll see why in later layers) -441 draw-horizontal screen, row, left, right -442 row <- add row, 1 -443 clear-screen-from screen, row, left, left, right -444 ] -445 -446 def update-cursor screen:&:screen, recipes:&:editor, current-sandbox:&:editor, sandbox-in-focus?:bool, env:&:environment -> screen:&:screen [ -447 local-scope -448 load-ingredients -449 <update-cursor-special-cases> -450 { -451 ¦ break-if sandbox-in-focus? -452 ¦ cursor-row:num <- get *recipes, cursor-row:offset -453 ¦ cursor-column:num <- get *recipes, cursor-column:offset -454 } -455 { -456 ¦ break-unless sandbox-in-focus? -457 ¦ cursor-row:num <- get *current-sandbox, cursor-row:offset -458 ¦ cursor-column:num <- get *current-sandbox, cursor-column:offset -459 } -460 screen <- move-cursor screen, cursor-row, cursor-column -461 ] -462 -463 # ctrl-n - switch focus -464 # todo: test this -465 -466 after <global-type> [ -467 { -468 ¦ switch-side?:bool <- equal c, 14/ctrl-n -469 ¦ break-unless switch-side? -470 ¦ sandbox-in-focus?:bool <- get *env, sandbox-in-focus?:offset -471 ¦ sandbox-in-focus? <- not sandbox-in-focus? -472 ¦ *env <- put *env, sandbox-in-focus?:offset, sandbox-in-focus? -473 ¦ screen <- update-cursor screen, recipes, current-sandbox, sandbox-in-focus?, env -474 ¦ loop +next-event -475 } -476 ] -477 -478 ## helpers -479 -480 def draw-vertical screen:&:screen, col:num, y:num, bottom:num -> screen:&:screen [ -481 local-scope -482 load-ingredients -483 style:char, style-found?:bool <- next-ingredient -484 { -485 ¦ break-if style-found? -486 ¦ style <- copy 9474/vertical -487 } -488 color:num, color-found?:bool <- next-ingredient -489 { -490 ¦ # default color to white -491 ¦ break-if color-found? -492 ¦ color <- copy 245/grey -493 } -494 { -495 ¦ continue?:bool <- lesser-than y, bottom -496 ¦ break-unless continue? -497 ¦ screen <- move-cursor screen, y, col -498 ¦ print screen, style, color -499 ¦ y <- add y, 1 -500 ¦ loop +310 ] +311 +312 scenario editor-in-focus-keeps-cursor [ +313 local-scope +314 trace-until 100/app # trace too long +315 assume-screen 30/width, 5/height +316 assume-resources [ +317 ¦ [lesson/recipes.mu] <- [ +318 ¦ ¦ |abc| +319 ¦ ] +320 ] +321 env:&:environment <- new-programming-environment resources, screen, [def] +322 render-all screen, env, render +323 # initialize programming environment and highlight cursor +324 assume-console [] +325 run [ +326 ¦ event-loop screen, console, env, resources +327 ¦ cursor:char <- copy 9251/␣ +328 ¦ print screen, cursor +329 ] +330 # is cursor at the right place? +331 screen-should-contain [ +332 ¦ . run (F4) . +333 ¦ .␣bc ╎def . +334 ¦ . ╎──────────────. +335 ¦ .╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╎ . +336 ¦ . ╎ . +337 ] +338 # now try typing a letter +339 assume-console [ +340 ¦ type [z] +341 ] +342 run [ +343 ¦ event-loop screen, console, env, resources +344 ¦ cursor:char <- copy 9251/␣ +345 ¦ print screen, cursor +346 ] +347 # cursor should still be right +348 screen-should-contain [ +349 ¦ . run (F4) . +350 ¦ .z␣bc ╎def . +351 ¦ . ╎──────────────. +352 ¦ .╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╎ . +353 ¦ . ╎ . +354 ] +355 ] +356 +357 scenario backspace-in-sandbox-editor-joins-lines [ +358 local-scope +359 trace-until 100/app # trace too long +360 assume-screen 30/width, 5/height +361 assume-resources [ +362 ] +363 # initialize sandbox side with two lines +364 test-sandbox-editor-contents:text <- new [abc +365 def] +366 env:&:environment <- new-programming-environment resources, screen, test-sandbox-editor-contents +367 render-all screen, env, render +368 screen-should-contain [ +369 ¦ . run (F4) . +370 ¦ . ╎abc . +371 ¦ .╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╎def . +372 ¦ . ╎──────────────. +373 ¦ . ╎ . +374 ] +375 # position cursor at start of second line and hit backspace +376 assume-console [ +377 ¦ left-click 2, 16 +378 ¦ press backspace +379 ] +380 run [ +381 ¦ event-loop screen, console, env, resources +382 ¦ cursor:char <- copy 9251/␣ +383 ¦ print screen, cursor +384 ] +385 # cursor moves to end of old line +386 screen-should-contain [ +387 ¦ . run (F4) . +388 ¦ . ╎abc␣ef . +389 ¦ .╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╎──────────────. +390 ¦ . ╎ . +391 ] +392 ] +393 +394 def render-all screen:&:screen, env:&:environment, {render-editor: (recipe (address screen) (address editor) -> number number (address screen) (address editor))} -> screen:&:screen, env:&:environment [ +395 local-scope +396 load-ingredients +397 trace 10, [app], [render all] +398 hide-screen screen +399 # top menu +400 trace 11, [app], [render top menu] +401 width:num <- screen-width screen +402 draw-horizontal screen, 0, 0/left, width, 32/space, 0/black, 238/grey +403 button-start:num <- subtract width, 20 +404 button-on-screen?:bool <- greater-or-equal button-start, 0 +405 assert button-on-screen?, [screen too narrow for menu] +406 screen <- move-cursor screen, 0/row, button-start +407 print screen, [ run (F4) ], 255/white, 161/reddish +408 # dotted line down the middle +409 trace 11, [app], [render divider] +410 divider:num, _ <- divide-with-remainder width, 2 +411 height:num <- screen-height screen +412 draw-vertical screen, divider, 1/top, height, 9482/vertical-dotted +413 # +414 screen <- render-recipes screen, env, render-editor +415 screen <- render-sandbox-side screen, env, render-editor +416 <render-components-end> +417 # +418 recipes:&:editor <- get *env, recipes:offset +419 current-sandbox:&:editor <- get *env, current-sandbox:offset +420 sandbox-in-focus?:bool <- get *env, sandbox-in-focus?:offset +421 screen <- update-cursor screen, recipes, current-sandbox, sandbox-in-focus?, env +422 # +423 show-screen screen +424 ] +425 +426 def render-recipes screen:&:screen, env:&:environment, {render-editor: (recipe (address screen) (address editor) -> number number (address screen) (address editor))} -> screen:&:screen, env:&:environment [ +427 local-scope +428 load-ingredients +429 trace 11, [app], [render recipes] +430 recipes:&:editor <- get *env, recipes:offset +431 # render recipes +432 left:num <- get *recipes, left:offset +433 right:num <- get *recipes, right:offset +434 row:num, column:num, screen <- call render-editor, screen, recipes +435 clear-line-until screen, right +436 row <- add row, 1 +437 <render-recipe-components-end> +438 # draw dotted line after recipes +439 draw-horizontal screen, row, left, right, 9480/horizontal-dotted +440 row <- add row, 1 +441 clear-screen-from screen, row, left, left, right +442 ] +443 +444 # replaced in a later layer +445 def render-sandbox-side screen:&:screen, env:&:environment, {render-editor: (recipe (address screen) (address editor) -> number number (address screen) (address editor))} -> screen:&:screen, env:&:environment [ +446 local-scope +447 load-ingredients +448 current-sandbox:&:editor <- get *env, current-sandbox:offset +449 left:num <- get *current-sandbox, left:offset +450 right:num <- get *current-sandbox, right:offset +451 row:num, column:num, screen, current-sandbox <- call render-editor, screen, current-sandbox +452 clear-line-until screen, right +453 row <- add row, 1 +454 # draw solid line after code (you'll see why in later layers) +455 draw-horizontal screen, row, left, right +456 row <- add row, 1 +457 clear-screen-from screen, row, left, left, right +458 ] +459 +460 def update-cursor screen:&:screen, recipes:&:editor, current-sandbox:&:editor, sandbox-in-focus?:bool, env:&:environment -> screen:&:screen [ +461 local-scope +462 load-ingredients +463 <update-cursor-special-cases> +464 { +465 ¦ break-if sandbox-in-focus? +466 ¦ cursor-row:num <- get *recipes, cursor-row:offset +467 ¦ cursor-column:num <- get *recipes, cursor-column:offset +468 } +469 { +470 ¦ break-unless sandbox-in-focus? +471 ¦ cursor-row:num <- get *current-sandbox, cursor-row:offset +472 ¦ cursor-column:num <- get *current-sandbox, cursor-column:offset +473 } +474 screen <- move-cursor screen, cursor-row, cursor-column +475 ] +476 +477 # ctrl-l - redraw screen (just in case it printed junk somehow) +478 +479 after <global-type> [ +480 { +481 ¦ redraw-screen?:bool <- equal c, 12/ctrl-l +482 ¦ break-unless redraw-screen? +483 ¦ screen <- render-all screen, env:&:environment, render +484 ¦ sync-screen screen +485 ¦ loop +next-event +486 } +487 ] +488 +489 # ctrl-n - switch focus +490 # todo: test this +491 +492 after <global-type> [ +493 { +494 ¦ switch-side?:bool <- equal c, 14/ctrl-n +495 ¦ break-unless switch-side? +496 ¦ sandbox-in-focus?:bool <- get *env, sandbox-in-focus?:offset +497 ¦ sandbox-in-focus? <- not sandbox-in-focus? +498 ¦ *env <- put *env, sandbox-in-focus?:offset, sandbox-in-focus? +499 ¦ screen <- update-cursor screen, recipes, current-sandbox, sandbox-in-focus?, env +500 ¦ loop +next-event 501 } 502 ] +503 +504 ## helpers +505 +506 def draw-vertical screen:&:screen, col:num, y:num, bottom:num -> screen:&:screen [ +507 local-scope +508 load-ingredients +509 style:char, style-found?:bool <- next-ingredient +510 { +511 ¦ break-if style-found? +512 ¦ style <- copy 9474/vertical +513 } +514 color:num, color-found?:bool <- next-ingredient +515 { +516 ¦ # default color to white +517 ¦ break-if color-found? +518 ¦ color <- copy 245/grey +519 } +520 { +521 ¦ continue?:bool <- lesser-than y, bottom +522 ¦ break-unless continue? +523 ¦ screen <- move-cursor screen, y, col +524 ¦ print screen, style, color +525 ¦ y <- add y, 1 +526 ¦ loop +527 } +528 ] -- cgit 1.4.1-2-gfad0