about summary refs log tree commit diff stats
path: root/edit.mu
diff options
context:
space:
mode:
authorKartik K. Agaram <vc@akkartik.com>2015-07-17 12:51:32 -0700
committerKartik K. Agaram <vc@akkartik.com>2015-07-17 12:58:37 -0700
commit32cd40ec3c9dad33738caf6f55fb742a316bd5be (patch)
treec6612fefc35741b43e1058826445d2913e94b3ba /edit.mu
parentfe9e53ed19f84a1771d56bfa0cf7d1d017e07559 (diff)
downloadmu-32cd40ec3c9dad33738caf6f55fb742a316bd5be.tar.gz
1799 - continue to debug memory corruption of 1795
Things I figured out:
- 'row' in render-screen doesn't perfectly track cursor-row in screen
- proximal cause was forgetting to add left:number to stop-printing
- trying to print to screen outside bounds was silently succeeding and
  corrupting simulated memory
- if we silently ignore prints outside bounds things are fine

But why are prints outside screen bounds working? We should be accessing
screen data using 'index', and that's checking its bounds.
Diffstat (limited to 'edit.mu')
-rw-r--r--edit.mu355
1 files changed, 147 insertions, 208 deletions
diff --git a/edit.mu b/edit.mu
index 5828ebdc..4bbf47b5 100644
--- a/edit.mu
+++ b/edit.mu
@@ -3,52 +3,13 @@
 recipe main [
   local-scope
   open-console
-  initial-recipe:address:array:character <- new [ 
-# return true if a list of numbers contains the pattern 1, 5, 3
-recipe check [
-  default-space:address:array:location <- new location:type, 30:literal
-  state:number <- copy 0:literal
-  {
-    +next-number
-    curr:number, found?:boolean <- next-ingredient
-    break-unless found?:boolean
-    # if curr is 1, state = 1
-    {
-      state1:boolean <- equal curr:number, 1:literal
-      break-unless state1:boolean
-      state:number <- copy 1:literal
-      loop +next-number:label
-    }
-    # if state is 1 and curr is 5, state = 2
-    {
-      state-is-1?:boolean <- equal state:number, 1:literal
-      break-unless state-is-1?:boolean
-      state2:boolean <- equal curr:number, 5:literal
-      break-unless state2:boolean
-      state:number <- copy 2:literal
-      loop +next-number:label
-    }
-    # if state is 2 and curr is 3, return true
-    {
-      state-is-2?:boolean <- equal state:number, 2:literal
-      break-unless state-is-2?:boolean
-      state3:boolean <- equal curr:number, 3:literal
-      break-unless state3:boolean
-      reply 1:literal/found
-    }
-    # otherwise reset state
-    #state:number <- copy 0:literal
-    loop
-  }
-  reply 0:literal/not-found
+  initial-recipe:address:array:character <- new [recipe new-add [
+  x:number <- next-ingredient
+  y:number <- next-ingredient
+  z:number <- add x:number, y:number
+  reply z:number
 ]]
-#?   initial-recipe:address:array:character <- new [recipe new-add [
-#?   x:number <- next-ingredient
-#?   y:number <- next-ingredient
-#?   z:number <- add x:number, y:number
-#?   reply z:number
-#? ]]
-  initial-sandbox:address:array:character <- new []
+  initial-sandbox:address:array:character <- new [print-character screen:address, 97]
   env:address:programming-environment-data <- new-programming-environment 0:literal/screen, initial-recipe:address:array:character, initial-sandbox:address:array:character
   event-loop 0:literal/screen, 0:literal/console, env:address:programming-environment-data
 ]
@@ -302,6 +263,7 @@ recipe render [
 ]
 
 # row:number, screen:address <- render-string screen:address, s:address:array:character, left:number, right:number, color:number, row:number
+# move cursor at start of next line
 # print a string 's' to 'editor' in 'color' starting at 'row'
 # leave cursor at start of next line
 recipe render-string [
@@ -370,6 +332,76 @@ recipe render-string [
   reply row:number/same-as-ingredient:5, screen:address/same-as-ingredient:0
 ]
 
+# row:number, screen:address <- render-screen screen:address, sandbox-screen:address:screen, left:number, right:number, row:number
+# print the fake sandbox screen to 'screen' with appropriate delimiters
+# leave cursor at start of next line
+recipe render-screen [
+  local-scope
+  screen:address <- next-ingredient
+  s:address:screen <- next-ingredient
+  left:number <- next-ingredient
+  right:number <- next-ingredient
+  row:number <- next-ingredient
+  row:number <- add row:number, 1:literal
+  reply-unless s:address:screen, row:number/same-as-ingredient:4, screen:address/same-as-ingredient:0
+#?   $start-tracing #? 1
+  # print 'screen:'
+  column:number <- copy left:number
+  move-cursor screen:address, row:number, column:number
+  screen-height:number <- screen-height screen:address
+  header:address:array:character <- new [screen:]
+  row:number <- subtract row:number, 1:literal  # compensate for render-string below
+  row:number <- render-string screen:address, header:address:array:character, left:number, right:number, 245:literal/grey, row:number
+  # start printing s
+  column:number <- copy left:number
+  move-cursor screen:address, row:number, column:number
+  s-width:number <- screen-width s:address:screen
+  s-height:number <- screen-height s:address:screen
+  buf:address:array:screen-cell <- get s:address:screen/deref, data:offset
+  stop-printing:number <- add s-width:number, 3:literal
+#?   stop-printing:number <- add left:number, s-width:number, 3:literal
+  max-column:number <- min stop-printing:number, right:number
+  i:number <- copy 0:literal
+  len:number <- length buf:address:array:screen-cell/deref
+  {
+    done?:boolean <- greater-or-equal i:number, len:number
+    break-if done?:boolean
+    done?:boolean <- greater-or-equal row:number, screen-height:number
+    break-if done?:boolean
+    column:number <- copy left:number
+    move-cursor screen:address, row:number, column:number
+    # initial leader for each row: two spaces and a '.'
+    print-character screen:address, 32:literal/space, 245:literal/grey
+    print-character screen:address, 32:literal/space, 245:literal/grey
+    print-character screen:address, 46:literal/full-stop, 245:literal/grey
+    column:number <- add left:number, 3:literal
+    {
+      # print row
+      row-done?:boolean <- greater-than column:number, max-column:number
+      break-if row-done?:boolean
+      curr:screen-cell <- index buf:address:array:screen-cell/deref, i:number
+      print-character screen:address, 32:literal/space
+      column:number <- add column:number, 1:literal
+      i:number <- add i:number, 1:literal
+      loop
+    }
+    # print final '.'
+    print-character screen:address, 46:literal/full-stop, 245:literal/grey
+    column:number <- add column:number, 1:literal
+    {
+      # clear rest of current line
+      line-done?:boolean <- greater-than column:number, right:number
+      break-if line-done?:boolean
+      print-character screen:address, 32:literal/space
+      column:number <- add column:number, 1:literal
+      loop
+    }
+    row:number <- add row:number, 1:literal
+    loop
+  }
+  reply row:number/same-as-ingredient:4, screen:address/same-as-ingredient:0
+]
+
 recipe clear-line-delimited [
   local-scope
   screen:address <- next-ingredient
@@ -522,19 +554,10 @@ recipe event-loop [
         loop +next-event:label
       }
     }
-    # 'touch' event
+    # 'touch' event - send to both editors
     {
       t:address:touch-event <- maybe-convert e:event, touch:variant
       break-unless t:address:touch-event
-      # on a sandbox delete icon? process delete
-      {
-        was-delete?:boolean <- delete-sandbox t:address:touch-event/deref, env:address:programming-environment-data
-        break-unless was-delete?:boolean
-        screen:address <- render-sandbox-side screen:address, env:address:programming-environment-data, 1:literal/clear
-        update-cursor screen:address, recipes:address:editor-data, current-sandbox:address:editor-data, sandbox-in-focus?:address:boolean/deref
-        loop +next-event:label
-      }
-      # if not, send to both editors
       _ <- move-cursor-in-editor screen:address, recipes:address:editor-data, t:address:touch-event/deref
       sandbox-in-focus?:address:boolean/deref <- move-cursor-in-editor screen:address, current-sandbox:address:editor-data, t:address:touch-event/deref
       jump +continue:label
@@ -1063,7 +1086,6 @@ recipe render-sandbox-side [
   local-scope
   screen:address <- next-ingredient
   env:address:programming-environment-data <- next-ingredient
-  clear:boolean <- next-ingredient
   current-sandbox:address:editor-data <- get env:address:programming-environment-data/deref, current-sandbox:offset
   left:number <- get current-sandbox:address:editor-data/deref, left:offset
   right:number <- get current-sandbox:address:editor-data/deref, right:offset
@@ -1076,62 +1098,61 @@ recipe render-sandbox-side [
   row:number <- add row:number, 1:literal
   move-cursor screen:address, row:number, left:number
   clear-line-delimited screen:address, left:number, right:number
-  reply-unless clear:boolean, screen:address/same-as-ingredient:0
-  screen-height:number <- screen-height screen:address
-  {
-    at-bottom-of-screen?:boolean <- greater-or-equal row:number, screen-height:number
-    break-if at-bottom-of-screen?:boolean
-    move-cursor screen:address, row:number, left:number
-    clear-line-delimited screen:address, left:number, right:number
-    row:number <- add row:number, 1:literal
-    loop
-  }
   reply screen:address/same-as-ingredient:0
 ]
 
 recipe render-sandboxes [
   local-scope
-  screen:address <- next-ingredient
+  screen:address:screen <- next-ingredient
   sandbox:address:sandbox-data <- next-ingredient
   left:number <- next-ingredient
   right:number <- next-ingredient
   row:number <- next-ingredient
-  reply-unless sandbox:address:sandbox-data, row:number/same-as-ingredient:4, screen:address/same-as-ingredient:0
-  screen-height:number <- screen-width screen:address
+  reply-unless sandbox:address:sandbox-data, row:number/same-as-ingredient:4, screen:address:screen/same-as-ingredient:0
+  screen-height:number <- screen-height screen:address:screen
   at-bottom?:boolean <- greater-or-equal row:number screen-height:number
-  reply-if at-bottom?:boolean, row:number/same-as-ingredient:4, screen:address/same-as-ingredient:0
-#?   $print [rendering sandbox ], sandbox:address:sandbox-data, [ 
-#? ] #? 1
-  # render sandbox menu
-  row:number <- add row:number, 1:literal
-  move-cursor screen:address, row:number, left:number
-  clear-line-delimited screen:address, left:number, right:number
-  print-character screen:address, 120:literal/x, 245:literal/grey
-  # save menu row so we can detect clicks to it later
-  starting-row:address:number <- get-address sandbox:address:sandbox-data/deref, starting-row-on-screen:offset
-  starting-row:address:number/deref <- copy row:number
+  reply-if at-bottom?:boolean, row:number/same-as-ingredient:4, screen:address:screen/same-as-ingredient:0
   # render sandbox contents
   sandbox-data:address:array:character <- get sandbox:address:sandbox-data/deref, data:offset
-  row:number, screen:address <- render-string screen:address, sandbox-data:address:array:character, left:number, right:number, 7:literal/white, row:number
+  row:number, screen:address:screen <- render-string screen:address:screen, sandbox-data:address:array:character, left:number, right:number, 7:literal/white, row:number
   # render sandbox warnings or response, in that order
   sandbox-response:address:array:character <- get sandbox:address:sandbox-data/deref, response:offset
   sandbox-warnings:address:array:character <- get sandbox:address:sandbox-data/deref, warnings:offset
+  sandbox-screen:address:screen <- get sandbox:address:sandbox-data/deref, screen:offset
   {
     break-unless sandbox-warnings:address:array:character
-    row:number, screen:address <- render-string screen:address, sandbox-warnings:address:array:character, left:number, right:number, 1:literal/red, row:number
+    row:number, screen:address:screen <- render-string screen:address:screen, sandbox-warnings:address:array:character, left:number, right:number, 1:literal/red, row:number
   }
   {
     break-if sandbox-warnings:address:array:character
-    row:number, screen:address <- render-string screen:address, sandbox-response:address:array:character, left:number, right:number, 245:literal/grey, row:number
+    row:number, screen:address:screen <- render-string screen:address:screen, sandbox-response:address:array:character, left:number, right:number, 245:literal/grey, row:number
   }
+  # render sandbox screen if necessary
+  at-bottom?:boolean <- greater-or-equal row:number screen-height:number
+  reply-if at-bottom?:boolean, row:number/same-as-ingredient:4, screen:address:screen/same-as-ingredient:0
+  {
+    empty-screen?:boolean <- fake-screen-is-clear? sandbox-screen:address:screen
+    break-if empty-screen?:boolean
+    row:number, screen:address:screen <- render-screen screen:address:screen, sandbox-screen:address:screen, left:number, right:number, row:number
+  }
+  at-bottom?:boolean <- greater-or-equal row:number screen-height:number
+  reply-if at-bottom?:boolean, row:number/same-as-ingredient:4, screen:address:screen/same-as-ingredient:0
   # draw solid line after sandbox
-  draw-horizontal screen:address, row:number, left:number, right:number, 9473:literal/horizontal-double
+#?   $print [aaa ]
+#?   $dump screen:address:screen
+#?   $dump right:number
+#?   $foo screen:address:screen
+#?   xxx:address:array:screen-cell <- get screen:address:screen/deref, data:offset
+#?   $dump xxx:address:array:screen-cell
+#?   yyy:number <- length xxx:address:array:screen-cell/deref
+#?   $dump yyy:number
+  draw-horizontal screen:address:screen, row:number, left:number, right:number, 9473:literal/horizontal-double
+#?   $print [zzz ]
+#?   $dump screen:address:screen
   # draw next sandbox
   next-sandbox:address:sandbox-data <- get sandbox:address:sandbox-data/deref, next-sandbox:offset
-#?   $print [next sandbox is ], next-sandbox:address:sandbox-data, [ 
-#? ] #? 1
-  row:number, screen:address <- render-sandboxes screen:address, next-sandbox:address:sandbox-data, left:number, right:number, row:number
-  reply row:number/same-as-ingredient:4, screen:address/same-as-ingredient:0
+  row:number, screen:address:screen <- render-sandboxes screen:address:screen, next-sandbox:address:sandbox-data, left:number, right:number, row:number
+  reply row:number/same-as-ingredient:4, screen:address:screen/same-as-ingredient:0
 ]
 
 recipe update-cursor [
@@ -2542,13 +2563,13 @@ container sandbox-data [
   data:address:array:character
   response:address:array:character
   warnings:address:array:character
-  starting-row-on-screen:number  # to track clicks on delete
+  screen:address:screen
   next-sandbox:address:sandbox-data
 ]
 
 scenario run-and-show-results [
   $close-trace  # trace too long for github
-  assume-screen 100:literal/width, 15:literal/height
+  assume-screen 100:literal/width, 12:literal/height
   # recipe editor is empty
   1:address:array:character <- new []
   # sandbox editor contains an instruction without storing outputs
@@ -2566,7 +2587,6 @@ scenario run-and-show-results [
     .                                                                                 run (F10)          .
     .                                                  ┊                                                 .
     .┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┊━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━.
-    .                                                  ┊                                                x.
     .                                                  ┊divide-with-remainder 11:literal, 3:literal      .
     .                                                  ┊3                                                .
     .                                                  ┊2                                                .
@@ -2577,7 +2597,6 @@ scenario run-and-show-results [
     .                                                                                                    .
     .                                                                                                    .
     .                                                                                                    .
-    .                                                                                                    .
     .                                                   divide-with-remainder 11:literal, 3:literal      .
     .                                                                                                    .
     .                                                                                                    .
@@ -2588,7 +2607,6 @@ scenario run-and-show-results [
     .                                                                                                    .
     .                                                  ┊                                                 .
     .┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┊━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━.
-    .                                                  ┊                                                x.
     .                                                  ┊                                                 .
     .                                                  ┊3                                                .
     .                                                  ┊2                                                .
@@ -2609,11 +2627,9 @@ scenario run-and-show-results [
     .                                                                                 run (F10)          .
     .                                                  ┊                                                 .
     .┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┊━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━.
-    .                                                  ┊                                                x.
     .                                                  ┊add 2:literal, 2:literal                         .
     .                                                  ┊4                                                .
     .                                                  ┊━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━.
-    .                                                  ┊                                                x.
     .                                                  ┊divide-with-remainder 11:literal, 3:literal      .
     .                                                  ┊3                                                .
     .                                                  ┊2                                                .
@@ -2648,14 +2664,15 @@ recipe run-sandboxes [
     init:address:address:duplex-list <- get-address current-sandbox:address:editor-data/deref, data:offset
     init:address:address:duplex-list/deref <- push-duplex 167:literal/§, 0:literal/tail
   }
-  # rerun other sandboxes
+  # run all sandboxes
   curr:address:sandbox-data <- get env:address:programming-environment-data/deref, sandbox:offset
   {
     break-unless curr:address:sandbox-data
     data:address:address:array:character <- get-address curr:address:sandbox-data/deref, data:offset
     response:address:address:array:character <- get-address curr:address:sandbox-data/deref, response:offset
     warnings:address:address:array:character <- get-address curr:address:sandbox-data/deref, warnings:offset
-    response:address:address:array:character/deref, warnings:address:address:array:character/deref <- run-interactive data:address:address:array:character/deref
+    fake-screen:address:address:screen <- get-address curr:address:sandbox-data/deref, screen:offset
+    response:address:address:array:character/deref, warnings:address:address:array:character/deref, fake-screen:address:address:screen/deref <- run-interactive data:address:address:array:character/deref
 #?     $print warnings:address:address:array:character/deref, [ ], warnings:address:address:array:character/deref/deref, [ 
 #? ] #? 1
     curr:address:sandbox-data <- get curr:address:sandbox-data/deref, next-sandbox:offset
@@ -2663,55 +2680,6 @@ recipe run-sandboxes [
   }
 ]
 
-# was-deleted?:boolean <- delete-sandbox t:touch-event, env:address:programming-environment-data
-recipe delete-sandbox [
-  local-scope
-  t:touch-event <- next-ingredient
-  env:address:programming-environment-data <- next-ingredient
-  click-column:number <- get t:touch-event, column:offset
-  current-sandbox:address:editor-data <- get env:address:programming-environment-data/deref, current-sandbox:offset
-  right:number <- get current-sandbox:address:editor-data/deref, right:offset
-#?   $print [comparing column ], click-column:number, [ vs ], right:number, [ 
-#? ] #? 1
-  at-right?:boolean <- equal click-column:number, right:number
-  reply-unless at-right?:boolean, 0:literal/false
-#?   $print [trying to delete
-#? ] #? 1
-  click-row:number <- get t:touch-event, row:offset
-  prev:address:address:sandbox-data <- get-address env:address:programming-environment-data/deref, sandbox:offset
-#?   $print [prev: ], prev:address:address:sandbox-data, [ -> ], prev:address:address:sandbox-data/deref, [ 
-#? ] #? 1
-  curr:address:sandbox-data <- get env:address:programming-environment-data/deref, sandbox:offset
-  {
-#?     $print [next sandbox
-#? ] #? 1
-    break-unless curr:address:sandbox-data
-    # more sandboxes to check
-    {
-#?       $print [checking
-#? ] #? 1
-      target-row:number <- get curr:address:sandbox-data/deref, starting-row-on-screen:offset
-#?       $print [comparing row ], target-row:number, [ vs ], click-row:number, [ 
-#? ] #? 1
-      delete-curr?:boolean <- equal target-row:number, click-row:number
-      break-unless delete-curr?:boolean
-#?       $print [found!
-#? ] #? 1
-      # delete this sandbox, rerender and stop
-      prev:address:address:sandbox-data/deref <- get curr:address:sandbox-data/deref, next-sandbox:offset
-#?       $print [setting prev: ], prev:address:address:sandbox-data, [ -> ], prev:address:address:sandbox-data/deref, [ 
-#? ] #? 1
-      reply 1:literal/true
-    }
-    prev:address:address:sandbox-data <- get-address curr:address:sandbox-data/deref, next-sandbox:offset
-#?     $print [prev: ], prev:address:address:sandbox-data, [ -> ], prev:address:address:sandbox-data/deref, [ 
-#? ] #? 1
-    curr:address:sandbox-data <- get curr:address:sandbox-data/deref, next-sandbox:offset
-    loop
-  }
-  reply 0:literal/false
-]
-
 scenario run-updates-results [
   $close-trace  # trace too long for github
   assume-screen 100:literal/width, 12:literal/height
@@ -2735,10 +2703,9 @@ z:number <- add 2:literal, 2:literal
     .                                                                                 run (F10)          .
     .                                                  ┊                                                 .
     .recipe foo [                                      ┊━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━.
-    .z:number <- add 2:literal, 2:literal              ┊                                                x.
-    .]                                                 ┊foo                                              .
-    .┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┊4                                                .
-    .                                                  ┊━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━.
+    .z:number <- add 2:literal, 2:literal              ┊foo                                              .
+    .]                                                 ┊4                                                .
+    .┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┊━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━.
     .                                                  ┊                                                 .
   ]
   # make a change (incrementing one of the args to 'add'), then rerun
@@ -2757,10 +2724,9 @@ z:number <- add 2:literal, 2:literal
     .                                                                                 run (F10)          .
     .                                                  ┊                                                 .
     .recipe foo [                                      ┊━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━.
-    .z:number <- add 2:literal, 3:literal              ┊                                                x.
-    .]                                                 ┊foo                                              .
-    .┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┊5                                                .
-    .                                                  ┊━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━.
+    .z:number <- add 2:literal, 3:literal              ┊foo                                              .
+    .]                                                 ┊5                                                .
+    .┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┊━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━.
     .                                                  ┊                                                 .
   ]
 ]
@@ -2785,7 +2751,6 @@ scenario run-instruction-and-print-warnings [
     .                                                                                 run (F10)          .
     .                                                  ┊                                                 .
     .┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┊━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━.
-    .                                                  ┊                                                x.
     .                                                  ┊get 1234:number, foo:offset                      .
     .                                                  ┊unknown element foo in container number          .
     .                                                  ┊━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━.
@@ -2795,7 +2760,6 @@ scenario run-instruction-and-print-warnings [
     .                                                                                                    .
     .                                                                                                    .
     .                                                                                                    .
-    .                                                                                                    .
     .                                                   get 1234:number, foo:offset                      .
     .                                                                                                    .
     .                                                                                                    .
@@ -2806,7 +2770,6 @@ scenario run-instruction-and-print-warnings [
     .                                                                                                    .
     .                                                                                                    .
     .                                                                                                    .
-    .                                                                                                    .
     .                                                   unknown element foo in container number          .
     .                                                                                                    .
   ]
@@ -2814,7 +2777,6 @@ scenario run-instruction-and-print-warnings [
     .                                                                                                    .
     .                                                  ┊                                                 .
     .┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┊━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━.
-    .                                                  ┊                                                x.
     .                                                  ┊                                                 .
     .                                                  ┊                                                 .
     .                                                  ┊━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━.
@@ -2843,7 +2805,6 @@ scenario run-instruction-and-print-warnings-only-once [
     .                                                                                 run (F10)          .
     .                                                  ┊                                                 .
     .┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┊━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━.
-    .                                                  ┊                                                x.
     .                                                  ┊get 1234:number, foo:offset                      .
     .                                                  ┊unknown element foo in container number          .
     .                                                  ┊━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━.
@@ -2851,69 +2812,37 @@ scenario run-instruction-and-print-warnings-only-once [
   ]
 ]
 
-scenario deleting-sandboxes [
-  $close-trace  # trace too long for github
-  assume-screen 100:literal/width, 15:literal/height
+scenario run-instruction-manages-screen-per-sandbox [
+  $close-trace  # trace too long for github #? 1
+  assume-screen 100:literal/width, 20:literal/height
+  # left editor is empty
   1:address:array:character <- new []
-  2:address:array:character <- new []
+  # right editor contains an illegal instruction
+  2:address:array:character <- new [print-integer screen:address, 4]
   3:address:programming-environment-data <- new-programming-environment screen:address, 1:address:array:character, 2:address:array:character
-  # run a few commands
+  # run the code in the editor
   assume-console [
-    left-click 1, 80
-    type [divide-with-remainder 11:literal, 3:literal]
-    press 65526  # F10
-    type [add 2:literal, 2:literal]
     press 65526  # F10
   ]
   run [
     event-loop screen:address, console:address, 3:address:programming-environment-data
   ]
+  # check that it prints a little 5x5 toy screen
+  # hack: screen address is brittle
   screen-should-contain [
     .                                                                                 run (F10)          .
     .                                                  ┊                                                 .
     .┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┊━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━.
-    .                                                  ┊                                                x.
-    .                                                  ┊add 2:literal, 2:literal                         .
-    .                                                  ┊4                                                .
-    .                                                  ┊━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━.
-    .                                                  ┊                                                x.
-    .                                                  ┊divide-with-remainder 11:literal, 3:literal      .
-    .                                                  ┊3                                                .
-    .                                                  ┊2                                                .
-    .                                                  ┊━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━.
-    .                                                  ┊                                                 .
-  ]
-  # delete second sandbox
-  assume-console [
-    left-click 7, 99
-  ]
-  run [
-    event-loop screen:address, console:address, 3:address:programming-environment-data
-  ]
-  screen-should-contain [
-    .                                                                                 run (F10)          .
-    .                                                  ┊                                                 .
-    .┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┊━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━.
-    .                                                  ┊                                                x.
-    .                                                  ┊add 2:literal, 2:literal                         .
-    .                                                  ┊4                                                .
+    .                                                  ┊print-integer screen:address, 4                  .
+    .                                                  ┊5557                                             .
+    .                                                  ┊screen:                                          .
+    .                                                  ┊  .4    .                                        .
+    .                                                  ┊  .     .                                        .
+    .                                                  ┊  .     .                                        .
+    .                                                  ┊  .     .                                        .
+    .                                                  ┊  .     .                                        .
     .                                                  ┊━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━.
     .                                                  ┊                                                 .
-    .                                                  ┊                                                 .
-  ]
-  # delete first sandbox
-  assume-console [
-    left-click 3, 99
-  ]
-  run [
-    event-loop screen:address, console:address, 3:address:programming-environment-data
-  ]
-  screen-should-contain [
-    .                                                                                 run (F10)          .
-    .                                                  ┊                                                 .
-    .┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┊━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━.
-    .                                                  ┊                                                 .
-    .                                                  ┊                                                 .
   ]
 ]
 
@@ -3007,12 +2936,22 @@ recipe draw-horizontal [
     break-if bg-color-found?:boolean
     bg-color:number <- copy 0:literal/black
   }
+#?   $print [bbb ], 5155:number/raw, [  #? 1
+#? ] #? 1
   move-cursor screen:address, row:number, x:number
   {
+#?   $print [ccc ], 5155:number/raw, [  #? 1
+#? ] #? 1
     continue?:boolean <- lesser-or-equal x:number, right:number  # right is inclusive, to match editor-data semantics
     break-unless continue?:boolean
+#?   $print [ddd ], 5155:number/raw, [  #? 1
+#? ] #? 1
     print-character screen:address, style:character, color:number, bg-color:number
+#?   $print [xxx ], 5155:number/raw, [  #? 1
+#? ] #? 1
     x:number <- add x:number, 1:literal
+#?   $print [yyy ], 5155:number/raw, [  #? 1
+#? ] #? 1
     loop
   }
 ]