From 05a22c024d0ffe3382f94ccacec6718cb10ef78f Mon Sep 17 00:00:00 2001 From: "Kartik K. Agaram" Date: Sat, 13 May 2017 17:21:47 -0700 Subject: 3856 Bugfix on commit 3853: clear `render-all-on-no-more-events` once you've actually run the `render-all`. --- html/edit/004-programming-environment.mu.html | 837 +++++++++++++------------- html/edit/005-sandbox.mu.html | 30 +- html/edit/006-sandbox-copy.mu.html | 2 +- html/edit/007-sandbox-delete.mu.html | 10 +- html/edit/008-sandbox-edit.mu.html | 6 +- html/edit/009-sandbox-test.mu.html | 2 +- html/edit/010-sandbox-trace.mu.html | 2 +- html/edit/011-errors.mu.html | 8 +- 8 files changed, 449 insertions(+), 448 deletions(-) (limited to 'html/edit') diff --git a/html/edit/004-programming-environment.mu.html b/html/edit/004-programming-environment.mu.html index 87f2586b..1dd841ac 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 ] @@ -145,16 +145,16 @@ if ('onhashchange' in window) { 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 + 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 + 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 + 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 @@ -176,419 +176,420 @@ if ('onhashchange' in window) { 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 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 ] -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 ] +116 ¦ ¦ ¦ render-all-on-no-more-events? <- copy 0/false +117 ¦ ¦ ¦ screen <- render-all screen, env, render +118 ¦ ¦ } +119 ¦ ¦ screen <- update-cursor screen, recipes, current-sandbox, sandbox-in-focus?, env +120 ¦ ¦ show-screen screen +121 ¦ } +122 ¦ loop +123 } +124 ] +125 +126 def resize screen:&:screen, env:&:environment -> env:&:environment, screen:&:screen [ +127 local-scope +128 load-ingredients +129 clear-screen screen # update screen dimensions +130 width:num <- screen-width screen +131 divider:num, _ <- divide-with-remainder width, 2 +132 # update recipe editor +133 recipes:&:editor <- get *env, recipes:offset +134 right:num <- subtract divider, 1 +135 *recipes <- put *recipes, right:offset, right +136 # reset cursor (later we'll try to preserve its position) +137 *recipes <- put *recipes, cursor-row:offset, 1 +138 *recipes <- put *recipes, cursor-column:offset, 0 +139 # update sandbox editor +140 current-sandbox:&:editor <- get *env, current-sandbox:offset +141 left:num <- add divider, 1 +142 *current-sandbox <- put *current-sandbox, left:offset, left +143 right:num <- subtract width, 1 +144 *current-sandbox <- put *current-sandbox, right:offset, right +145 # reset cursor (later we'll try to preserve its position) +146 *current-sandbox <- put *current-sandbox, cursor-row:offset, 1 +147 *current-sandbox <- put *current-sandbox, cursor-column:offset, left +148 ] +149 +150 # Variant of 'render' that updates cursor-row and cursor-column based on +151 # before-cursor (rather than the other way around). If before-cursor moves +152 # off-screen, it resets cursor-row and cursor-column. +153 def render-without-moving-cursor screen:&:screen, editor:&:editor -> last-row:num, last-column:num, screen:&:screen, editor:&:editor [ +154 local-scope +155 load-ingredients +156 return-unless editor, 1/top, 0/left +157 left:num <- get *editor, left:offset +158 screen-height:num <- screen-height screen +159 right:num <- get *editor, right:offset +160 curr:&:duplex-list:char <- get *editor, top-of-screen:offset +161 prev:&:duplex-list:char <- copy curr # just in case curr becomes null and we can't compute prev +162 curr <- next curr +163 color:num <- copy 7/white +164 row:num <- copy 1/top +165 column:num <- copy left +166 # save before-cursor +167 old-before-cursor:&:duplex-list:char <- get *editor, before-cursor:offset +168 # initialze cursor-row/cursor-column/before-cursor to the top of the screen +169 # by default +170 *editor <- put *editor, cursor-row:offset, row +171 *editor <- put *editor, cursor-column:offset, column +172 top-of-screen:&:duplex-list:char <- get *editor, top-of-screen:offset +173 *editor <- put *editor, before-cursor:offset, top-of-screen +174 screen <- move-cursor screen, row, column +175 { +176 ¦ +next-character +177 ¦ break-unless curr +178 ¦ off-screen?:bool <- greater-or-equal row, screen-height +179 ¦ break-if off-screen? +180 ¦ # if we find old-before-cursor still on the new resized screen, update +181 ¦ # editor.cursor-row and editor.cursor-column based on +182 ¦ # old-before-cursor +183 ¦ { +184 ¦ ¦ at-cursor?:bool <- equal old-before-cursor, prev +185 ¦ ¦ break-unless at-cursor? +186 ¦ ¦ *editor <- put *editor, cursor-row:offset, row +187 ¦ ¦ *editor <- put *editor, cursor-column:offset, column +188 ¦ ¦ *editor <- put *editor, before-cursor:offset, old-before-cursor +189 ¦ } +190 ¦ c:char <- get *curr, value:offset +191 ¦ <character-c-received> +192 ¦ { +193 ¦ ¦ # newline? move to left rather than 0 +194 ¦ ¦ newline?:bool <- equal c, 10/newline +195 ¦ ¦ break-unless newline? +196 ¦ ¦ # clear rest of line in this window +197 ¦ ¦ clear-line-until screen, right +198 ¦ ¦ # skip to next line +199 ¦ ¦ row <- add row, 1 +200 ¦ ¦ column <- copy left +201 ¦ ¦ screen <- move-cursor screen, row, column +202 ¦ ¦ curr <- next curr +203 ¦ ¦ prev <- next prev +204 ¦ ¦ loop +next-character +205 ¦ } +206 ¦ { +207 ¦ ¦ # at right? wrap. even if there's only one more letter left; we need +208 ¦ ¦ # room for clicking on the cursor after it. +209 ¦ ¦ at-right?:bool <- equal column, right +210 ¦ ¦ break-unless at-right? +211 ¦ ¦ # print wrap icon +212 ¦ ¦ wrap-icon:char <- copy 8617/loop-back-to-left +213 ¦ ¦ print screen, wrap-icon, 245/grey +214 ¦ ¦ column <- copy left +215 ¦ ¦ row <- add row, 1 +216 ¦ ¦ screen <- move-cursor screen, row, column +217 ¦ ¦ # don't increment curr +218 ¦ ¦ loop +next-character +219 ¦ } +220 ¦ print screen, c, color +221 ¦ curr <- next curr +222 ¦ prev <- next prev +223 ¦ column <- add column, 1 +224 ¦ loop +225 } +226 # save first character off-screen +227 *editor <- put *editor, bottom-of-screen:offset, curr +228 *editor <- put *editor, bottom:offset, row +229 return row, column +230 ] +231 +232 scenario point-at-multiple-editors [ +233 local-scope +234 trace-until 100/app # trace too long +235 assume-screen 30/width, 5/height +236 # initialize both halves of screen +237 assume-resources [ +238 ¦ [lesson/recipes.mu] <- [ +239 ¦ ¦ |abc| +240 ¦ ] +241 ] +242 env:&:environment <- new-programming-environment resources, screen, [def] # contents of sandbox editor +243 # focus on both sides +244 assume-console [ +245 ¦ left-click 1, 1 +246 ¦ left-click 1, 17 +247 ] +248 # check cursor column in each +249 run [ +250 ¦ event-loop screen, console, env, resources +251 ¦ recipes:&:editor <- get *env, recipes:offset +252 ¦ 5:num/raw <- get *recipes, cursor-column:offset +253 ¦ sandbox:&:editor <- get *env, current-sandbox:offset +254 ¦ 7:num/raw <- get *sandbox, cursor-column:offset +255 ] +256 memory-should-contain [ +257 ¦ 5 <- 1 +258 ¦ 7 <- 17 +259 ] +260 ] +261 +262 scenario edit-multiple-editors [ +263 local-scope +264 trace-until 100/app # trace too long +265 assume-screen 30/width, 5/height +266 # initialize both halves of screen +267 assume-resources [ +268 ¦ [lesson/recipes.mu] <- [ +269 ¦ ¦ |abc| +270 ¦ ] +271 ] +272 env:&:environment <- new-programming-environment resources, screen, [def] # contents of sandbox +273 render-all screen, env, render +274 # type one letter in each of them +275 assume-console [ +276 ¦ left-click 1, 1 +277 ¦ type [0] +278 ¦ left-click 1, 17 +279 ¦ type [1] +280 ] +281 run [ +282 ¦ event-loop screen, console, env, resources +283 ¦ recipes:&:editor <- get *env, recipes:offset +284 ¦ 5:num/raw <- get *recipes, cursor-column:offset +285 ¦ sandbox:&:editor <- get *env, current-sandbox:offset +286 ¦ 7:num/raw <- get *sandbox, cursor-column:offset +287 ] +288 screen-should-contain [ +289 ¦ . run (F4) . # this line has a different background, but we don't test that yet +290 ¦ .a0bc ╎d1ef . +291 ¦ . ╎──────────────. +292 ¦ .╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╎ . +293 ¦ . ╎ . +294 ] +295 memory-should-contain [ +296 ¦ 5 <- 2 # cursor column of recipe editor +297 ¦ 7 <- 18 # cursor column of sandbox editor +298 ] +299 # show the cursor at the right window +300 run [ +301 ¦ cursor:char <- copy 9251/␣ +302 ¦ print screen, cursor +303 ] +304 screen-should-contain [ +305 ¦ . run (F4) . +306 ¦ .a0bc ╎d1␣f . +307 ¦ . ╎──────────────. +308 ¦ .╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╎ . +309 ¦ . ╎ . +310 ] +311 ] +312 +313 scenario editor-in-focus-keeps-cursor [ +314 local-scope +315 trace-until 100/app # trace too long +316 assume-screen 30/width, 5/height +317 assume-resources [ +318 ¦ [lesson/recipes.mu] <- [ +319 ¦ ¦ |abc| +320 ¦ ] +321 ] +322 env:&:environment <- new-programming-environment resources, screen, [def] +323 render-all screen, env, render +324 # initialize programming environment and highlight cursor +325 assume-console [] +326 run [ +327 ¦ event-loop screen, console, env, resources +328 ¦ cursor:char <- copy 9251/␣ +329 ¦ print screen, cursor +330 ] +331 # is cursor at the right place? +332 screen-should-contain [ +333 ¦ . run (F4) . +334 ¦ .␣bc ╎def . +335 ¦ . ╎──────────────. +336 ¦ .╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╎ . +337 ¦ . ╎ . +338 ] +339 # now try typing a letter +340 assume-console [ +341 ¦ type [z] +342 ] +343 run [ +344 ¦ event-loop screen, console, env, resources +345 ¦ cursor:char <- copy 9251/␣ +346 ¦ print screen, cursor +347 ] +348 # cursor should still be right +349 screen-should-contain [ +350 ¦ . run (F4) . +351 ¦ .z␣bc ╎def . +352 ¦ . ╎──────────────. +353 ¦ .╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╎ . +354 ¦ . ╎ . +355 ] +356 ] +357 +358 scenario backspace-in-sandbox-editor-joins-lines [ +359 local-scope +360 trace-until 100/app # trace too long +361 assume-screen 30/width, 5/height +362 assume-resources [ +363 ] +364 # initialize sandbox side with two lines +365 test-sandbox-editor-contents:text <- new [abc +366 def] +367 env:&:environment <- new-programming-environment resources, screen, test-sandbox-editor-contents +368 render-all screen, env, render +369 screen-should-contain [ +370 ¦ . run (F4) . +371 ¦ . ╎abc . +372 ¦ .╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╎def . +373 ¦ . ╎──────────────. +374 ¦ . ╎ . +375 ] +376 # position cursor at start of second line and hit backspace +377 assume-console [ +378 ¦ left-click 2, 16 +379 ¦ press backspace +380 ] +381 run [ +382 ¦ event-loop screen, console, env, resources +383 ¦ cursor:char <- copy 9251/␣ +384 ¦ print screen, cursor +385 ] +386 # cursor moves to end of old line +387 screen-should-contain [ +388 ¦ . run (F4) . +389 ¦ . ╎abc␣ef . +390 ¦ .╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╎──────────────. +391 ¦ . ╎ . +392 ] +393 ] +394 +395 def render-all screen:&:screen, env:&:environment, {render-editor: (recipe (address screen) (address editor) -> number number (address screen) (address editor))} -> screen:&:screen, env:&:environment [ +396 local-scope +397 load-ingredients +398 trace 10, [app], [render all] +399 hide-screen screen +400 # top menu +401 trace 11, [app], [render top menu] +402 width:num <- screen-width screen +403 draw-horizontal screen, 0, 0/left, width, 32/space, 0/black, 238/grey +404 button-start:num <- subtract width, 20 +405 button-on-screen?:bool <- greater-or-equal button-start, 0 +406 assert button-on-screen?, [screen too narrow for menu] +407 screen <- move-cursor screen, 0/row, button-start +408 print screen, [ run (F4) ], 255/white, 161/reddish +409 # dotted line down the middle +410 trace 11, [app], [render divider] +411 divider:num, _ <- divide-with-remainder width, 2 +412 height:num <- screen-height screen +413 draw-vertical screen, divider, 1/top, height, 9482/vertical-dotted +414 # +415 screen <- render-recipes screen, env, render-editor +416 screen <- render-sandbox-side screen, env, render-editor +417 <render-components-end> +418 # +419 recipes:&:editor <- get *env, recipes:offset +420 current-sandbox:&:editor <- get *env, current-sandbox:offset +421 sandbox-in-focus?:bool <- get *env, sandbox-in-focus?:offset +422 screen <- update-cursor screen, recipes, current-sandbox, sandbox-in-focus?, env +423 # +424 show-screen screen +425 ] +426 +427 def render-recipes screen:&:screen, env:&:environment, {render-editor: (recipe (address screen) (address editor) -> number number (address screen) (address editor))} -> screen:&:screen, env:&:environment [ +428 local-scope +429 load-ingredients +430 trace 11, [app], [render recipes] +431 recipes:&:editor <- get *env, recipes:offset +432 # render recipes +433 left:num <- get *recipes, left:offset +434 right:num <- get *recipes, right:offset +435 row:num, column:num, screen <- call render-editor, screen, recipes +436 clear-line-until screen, right +437 row <- add row, 1 +438 <render-recipe-components-end> +439 # draw dotted line after recipes +440 draw-horizontal screen, row, left, right, 9480/horizontal-dotted +441 row <- add row, 1 +442 clear-screen-from screen, row, left, left, right +443 ] +444 +445 # replaced in a later layer +446 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 [ +447 local-scope +448 load-ingredients +449 current-sandbox:&:editor <- get *env, current-sandbox:offset +450 left:num <- get *current-sandbox, left:offset +451 right:num <- get *current-sandbox, right:offset +452 row:num, column:num, screen, current-sandbox <- call render-editor, screen, current-sandbox +453 clear-line-until screen, right +454 row <- add row, 1 +455 # draw solid line after code (you'll see why in later layers) +456 draw-horizontal screen, row, left, right +457 row <- add row, 1 +458 clear-screen-from screen, row, left, left, right +459 ] +460 +461 def update-cursor screen:&:screen, recipes:&:editor, current-sandbox:&:editor, sandbox-in-focus?:bool, env:&:environment -> screen:&:screen [ +462 local-scope +463 load-ingredients +464 <update-cursor-special-cases> +465 { +466 ¦ break-if sandbox-in-focus? +467 ¦ cursor-row:num <- get *recipes, cursor-row:offset +468 ¦ cursor-column:num <- get *recipes, cursor-column:offset +469 } +470 { +471 ¦ break-unless sandbox-in-focus? +472 ¦ cursor-row:num <- get *current-sandbox, cursor-row:offset +473 ¦ cursor-column:num <- get *current-sandbox, cursor-column:offset +474 } +475 screen <- move-cursor screen, cursor-row, cursor-column +476 ] +477 +478 # ctrl-l - redraw screen (just in case it printed junk somehow) +479 +480 after <global-type> [ +481 { +482 ¦ redraw-screen?:bool <- equal c, 12/ctrl-l +483 ¦ break-unless redraw-screen? +484 ¦ screen <- render-all screen, env:&:environment, render +485 ¦ sync-screen screen +486 ¦ loop +next-event +487 } +488 ] +489 +490 # ctrl-n - switch focus +491 # todo: test this +492 +493 after <global-type> [ +494 { +495 ¦ switch-side?:bool <- equal c, 14/ctrl-n +496 ¦ break-unless switch-side? +497 ¦ sandbox-in-focus?:bool <- get *env, sandbox-in-focus?:offset +498 ¦ sandbox-in-focus? <- not sandbox-in-focus? +499 ¦ *env <- put *env, sandbox-in-focus?:offset, sandbox-in-focus? +500 ¦ screen <- update-cursor screen, recipes, current-sandbox, sandbox-in-focus?, env +501 ¦ loop +next-event +502 } +503 ] +504 +505 ## helpers +506 +507 def draw-vertical screen:&:screen, col:num, y:num, bottom:num -> screen:&:screen [ +508 local-scope +509 load-ingredients +510 style:char, style-found?:bool <- next-ingredient +511 { +512 ¦ break-if style-found? +513 ¦ style <- copy 9474/vertical +514 } +515 color:num, color-found?:bool <- next-ingredient +516 { +517 ¦ # default color to white +518 ¦ break-if color-found? +519 ¦ color <- copy 245/grey +520 } +521 { +522 ¦ continue?:bool <- lesser-than y, bottom +523 ¦ break-unless continue? +524 ¦ screen <- move-cursor screen, y, col +525 ¦ print screen, style, color +526 ¦ y <- add y, 1 +527 ¦ loop +528 } +529 ] diff --git a/html/edit/005-sandbox.mu.html b/html/edit/005-sandbox.mu.html index 30ea06c6..5fd50c96 100644 --- a/html/edit/005-sandbox.mu.html +++ b/html/edit/005-sandbox.mu.html @@ -75,7 +75,7 @@ if ('onhashchange' in window) { 12 open-console 13 env:&:environment <- new-programming-environment 0/filesystem, 0/screen 14 env <- restore-sandboxes env - 15 render-all 0/screen, env, render + 15 render-all 0/screen, env, render 16 event-loop 0/screen, 0/console, env, 0/filesystem 17 # never gets here 18 ] @@ -193,12 +193,12 @@ if ('onhashchange' in window) { 130 ¦ screen <- update-status screen, [running... ], 245/grey 131 ¦ error?:bool <- run-sandboxes env, resources, screen 132 ¦ # F4 might update warnings and results on both sides - 133 ¦ screen <- render-all screen, env, render + 133 ¦ screen <- render-all screen, env, render 134 ¦ { 135 ¦ ¦ break-if error? 136 ¦ ¦ screen <- update-status screen, [ ], 245/grey 137 ¦ } - 138 ¦ screen <- update-cursor screen, recipes, current-sandbox, sandbox-in-focus?, env + 138 ¦ screen <- update-cursor screen, recipes, current-sandbox, sandbox-in-focus?, env 139 ¦ loop +next-event 140 } 141 ] @@ -802,7 +802,7 @@ if ('onhashchange' in window) { 739 assume-resources [ 740 ] 741 env:&:environment <- new-programming-environment resources, screen, [] - 742 render-all screen, env, render + 742 render-all screen, env, render 743 assume-console [ 744 ¦ press enter 745 ¦ press down-arrow @@ -825,7 +825,7 @@ if ('onhashchange' in window) { 762 assume-resources [ 763 ] 764 env:&:environment <- new-programming-environment resources, screen, [] - 765 render-all screen, env, render + 765 render-all screen, env, render 766 assume-console [ 767 ¦ press enter 768 ¦ press up-arrow @@ -851,7 +851,7 @@ if ('onhashchange' in window) { 788 recipe-bottom:num 789 ] 790 - 791 after <render-recipe-components-end> [ + 791 after <render-recipe-components-end> [ 792 *env <- put *env, recipe-bottom:offset, row 793 ] 794 @@ -905,7 +905,7 @@ if ('onhashchange' in window) { 842 assume-resources [ 843 ] 844 env:&:environment <- new-programming-environment resources, screen, [] - 845 render-all screen, env, render + 845 render-all screen, env, render 846 assume-console [ 847 ¦ # add a line 848 ¦ press enter @@ -933,7 +933,7 @@ if ('onhashchange' in window) { 870 ] 871 env:&:environment <- new-programming-environment resources, screen, [ab 872 cd] - 873 render-all screen, env, render + 873 render-all screen, env, render 874 assume-console [ 875 ¦ # add a line 876 ¦ press enter @@ -965,7 +965,7 @@ if ('onhashchange' in window) { 902 assume-resources [ 903 ] 904 env:&:environment <- new-programming-environment resources, screen, [add 2, 2] - 905 render-all screen, env, render + 905 render-all screen, env, render 906 assume-console [ 907 ¦ # create a sandbox 908 ¦ press F4 @@ -1036,14 +1036,14 @@ if ('onhashchange' in window) { 973 ¦ } 974 ¦ hide-screen screen 975 ¦ screen <- render-sandbox-side screen, env, render - 976 ¦ screen <- update-cursor screen, recipes, current-sandbox, sandbox-in-focus?, env + 976 ¦ screen <- update-cursor screen, recipes, current-sandbox, sandbox-in-focus?, env 977 ¦ show-screen screen 978 ¦ loop +next-event 979 } 980 ] 981 982 # update-cursor takes render-from into account - 983 after <update-cursor-special-cases> [ + 983 after <update-cursor-special-cases> [ 984 { 985 ¦ break-unless sandbox-in-focus? 986 ¦ render-from:num <- get *env, render-from:offset @@ -1068,7 +1068,7 @@ if ('onhashchange' in window) { 1005 ¦ *env <- put *env, render-from:offset, render-from 1006 ¦ hide-screen screen 1007 ¦ screen <- render-sandbox-side screen, env, render -1008 ¦ screen <- update-cursor screen, recipes, current-sandbox, sandbox-in-focus?, env +1008 ¦ screen <- update-cursor screen, recipes, current-sandbox, sandbox-in-focus?, env 1009 ¦ show-screen screen 1010 ¦ loop +next-event 1011 } @@ -1105,7 +1105,7 @@ if ('onhashchange' in window) { 1042 ] 1043 # create a sandbox 1044 env:&:environment <- new-programming-environment resources, screen, [add 2, 2] -1045 render-all screen, env, render +1045 render-all screen, env, render 1046 assume-console [ 1047 ¦ press F4 1048 ] @@ -1137,7 +1137,7 @@ if ('onhashchange' in window) { 1074 assume-resources [ 1075 ] 1076 env:&:environment <- new-programming-environment resources, screen, [] -1077 render-all screen, env, render +1077 render-all screen, env, render 1078 # create 2 sandboxes 1079 assume-console [ 1080 ¦ press ctrl-n @@ -1290,7 +1290,7 @@ if ('onhashchange' in window) { 1227 assume-resources [ 1228 ] 1229 env:&:environment <- new-programming-environment resources, screen, [] -1230 render-all screen, env, render +1230 render-all screen, env, render 1231 # create a sandbox 1232 assume-console [ 1233 ¦ press ctrl-n diff --git a/html/edit/006-sandbox-copy.mu.html b/html/edit/006-sandbox-copy.mu.html index 82d58cb3..91662df1 100644 --- a/html/edit/006-sandbox-copy.mu.html +++ b/html/edit/006-sandbox-copy.mu.html @@ -192,7 +192,7 @@ if ('onhashchange' in window) { 130 ¦ break-unless copy? 131 ¦ hide-screen screen 132 ¦ screen <- render-sandbox-side screen, env, render -133 ¦ screen <- update-cursor screen, recipes, current-sandbox, sandbox-in-focus?, env +133 ¦ screen <- update-cursor screen, recipes, current-sandbox, sandbox-in-focus?, env 134 ¦ show-screen screen 135 ¦ loop +next-event 136 } diff --git a/html/edit/007-sandbox-delete.mu.html b/html/edit/007-sandbox-delete.mu.html index 4d297d8b..538a0d99 100644 --- a/html/edit/007-sandbox-delete.mu.html +++ b/html/edit/007-sandbox-delete.mu.html @@ -136,7 +136,7 @@ if ('onhashchange' in window) { 74 ¦ break-unless delete? 75 ¦ hide-screen screen 76 ¦ screen <- render-sandbox-side screen, env, render - 77 ¦ screen <- update-cursor screen, recipes, current-sandbox, sandbox-in-focus?, env + 77 ¦ screen <- update-cursor screen, recipes, current-sandbox, sandbox-in-focus?, env 78 ¦ show-screen screen 79 ¦ loop +next-event 80 } @@ -218,7 +218,7 @@ if ('onhashchange' in window) { 156 assume-resources [ 157 ] 158 env:&:environment <- new-programming-environment resources, screen, [] -159 render-all screen, env, render +159 render-all screen, env, render 160 # create 2 sandboxes and scroll to second 161 assume-console [ 162 ¦ press ctrl-n @@ -265,7 +265,7 @@ if ('onhashchange' in window) { 203 assume-resources [ 204 ] 205 env:&:environment <- new-programming-environment resources, screen, [] -206 render-all screen, env, render +206 render-all screen, env, render 207 # create 2 sandboxes and scroll to second 208 assume-console [ 209 ¦ press ctrl-n @@ -312,7 +312,7 @@ if ('onhashchange' in window) { 250 assume-resources [ 251 ] 252 env:&:environment <- new-programming-environment resources, screen, [] -253 render-all screen, env, render +253 render-all screen, env, render 254 # create 2 sandboxes and scroll to second 255 assume-console [ 256 ¦ press ctrl-n @@ -361,7 +361,7 @@ if ('onhashchange' in window) { 299 assume-resources [ 300 ] 301 env:&:environment <- new-programming-environment resources, screen, [] -302 render-all screen, env, render +302 render-all screen, env, render 303 # create 2 sandboxes 304 assume-console [ 305 ¦ press ctrl-n diff --git a/html/edit/008-sandbox-edit.mu.html b/html/edit/008-sandbox-edit.mu.html index 29b9b889..4cfa706f 100644 --- a/html/edit/008-sandbox-edit.mu.html +++ b/html/edit/008-sandbox-edit.mu.html @@ -175,7 +175,7 @@ if ('onhashchange' in window) { 113 ¦ break-unless edit? 114 ¦ hide-screen screen 115 ¦ screen <- render-sandbox-side screen, env, render -116 ¦ screen <- update-cursor screen, recipes, current-sandbox, sandbox-in-focus?, env +116 ¦ screen <- update-cursor screen, recipes, current-sandbox, sandbox-in-focus?, env 117 ¦ show-screen screen 118 ¦ loop +next-event 119 } @@ -272,7 +272,7 @@ if ('onhashchange' in window) { 210 assume-resources [ 211 ] 212 env:&:environment <- new-programming-environment resources, screen, [] -213 render-all screen, env, render +213 render-all screen, env, render 214 # create 2 sandboxes and scroll to second 215 assume-console [ 216 ¦ press ctrl-n @@ -321,7 +321,7 @@ if ('onhashchange' in window) { 259 assume-resources [ 260 ] 261 env:&:environment <- new-programming-environment resources, screen, [] -262 render-all screen, env, render +262 render-all screen, env, render 263 # create 2 sandboxes 264 assume-console [ 265 ¦ press ctrl-n diff --git a/html/edit/009-sandbox-test.mu.html b/html/edit/009-sandbox-test.mu.html index 80242905..ccf13ba0 100644 --- a/html/edit/009-sandbox-test.mu.html +++ b/html/edit/009-sandbox-test.mu.html @@ -195,7 +195,7 @@ if ('onhashchange' in window) { 132 ¦ save-sandboxes env, resources 133 ¦ hide-screen screen 134 ¦ screen <- render-sandbox-side screen, env, render -135 ¦ screen <- update-cursor screen, recipes, current-sandbox, sandbox-in-focus?, env +135 ¦ screen <- update-cursor screen, recipes, current-sandbox, sandbox-in-focus?, env 136 ¦ show-screen screen 137 ¦ loop +next-event 138 } diff --git a/html/edit/010-sandbox-trace.mu.html b/html/edit/010-sandbox-trace.mu.html index c1950605..694376d6 100644 --- a/html/edit/010-sandbox-trace.mu.html +++ b/html/edit/010-sandbox-trace.mu.html @@ -265,7 +265,7 @@ if ('onhashchange' in window) { 202 ¦ *sandbox <- put *sandbox, display-trace?:offset, x 203 ¦ hide-screen screen 204 ¦ screen <- render-sandbox-side screen, env, render -205 ¦ screen <- update-cursor screen, recipes, current-sandbox, sandbox-in-focus?, env +205 ¦ screen <- update-cursor screen, recipes, current-sandbox, sandbox-in-focus?, env 206 ¦ show-screen screen 207 ¦ loop +next-event 208 } diff --git a/html/edit/011-errors.mu.html b/html/edit/011-errors.mu.html index 4d09cebb..1929e787 100644 --- a/html/edit/011-errors.mu.html +++ b/html/edit/011-errors.mu.html @@ -86,7 +86,7 @@ if ('onhashchange' in window) { 23 errors-found? <- copy 0/false 24 ] 25 - 26 before <render-components-end> [ + 26 before <render-components-end> [ 27 trace 11, [app], [render status] 28 recipe-errors:text <- get *env, recipe-errors:offset 29 { @@ -95,7 +95,7 @@ if ('onhashchange' in window) { 32 } 33 ] 34 - 35 before <render-recipe-components-end> [ + 35 before <render-recipe-components-end> [ 36 { 37 ¦ recipe-errors:text <- get *env, recipe-errors:offset 38 ¦ break-unless recipe-errors @@ -124,7 +124,7 @@ if ('onhashchange' in window) { 61 } 62 ] 63 - 64 before <render-components-end> [ + 64 before <render-components-end> [ 65 { 66 ¦ break-if recipe-errors 67 ¦ error-index:num <- get *env, error-index:offset @@ -189,7 +189,7 @@ if ('onhashchange' in window) { 126 ¦ ] 127 ] 128 env:&:environment <- new-programming-environment resources, screen, [foo] -129 render-all screen, env, render +129 render-all screen, env, render 130 screen-should-contain [ 131 ¦ . run (F4) . 132 ¦ .recipe foo [ ╎foo . -- cgit 1.4.1-2-gfad0