From 6c52e24e2996a77aa6297b26159003d503aef8a0 Mon Sep 17 00:00:00 2001 From: "Kartik K. Agaram" Date: Tue, 18 Apr 2017 11:33:33 -0700 Subject: 3830 - crosslink shape-shifting containers in html --- html/061text.mu.html | 26 +-- html/064list.mu.html | 146 ++++++++-------- html/065duplex_list.mu.html | 238 +++++++++++++------------- html/066stream.mu.html | 22 +-- html/068random.mu.html | 20 +-- html/070table.mu.html | 30 ++-- html/075channel.mu.html | 82 ++++----- html/084console.mu.html | 2 +- html/088file.mu.html | 50 +++--- html/090scenario_filesystem_test.mu.html | 34 ++-- html/092socket.mu.html | 28 +-- html/channel.mu.html | 16 +- html/chessboard.mu.html | 56 +++--- html/edit/001-editor.mu.html | 18 +- html/edit/002-typing.mu.html | 24 +-- html/edit/003-shortcuts.mu.html | 134 +++++++-------- html/edit/004-programming-environment.mu.html | 8 +- html/edit/005-sandbox.mu.html | 6 +- html/edit/006-sandbox-copy.mu.html | 4 +- html/edit/011-errors.mu.html | 4 +- html/edit/012-editor-undo.mu.html | 144 ++++++++-------- html/filesystem.mu.html | 4 +- html/http-client.mu.html | 4 +- html/http-server.mu.html | 4 +- html/lambda-to-mu.mu.html | 16 +- html/nqueens.mu.html | 10 +- 26 files changed, 565 insertions(+), 565 deletions(-) (limited to 'html') diff --git a/html/061text.mu.html b/html/061text.mu.html index 0a5b7a4e..bc269d39 100644 --- a/html/061text.mu.html +++ b/html/061text.mu.html @@ -185,12 +185,12 @@ if ('onhashchange' in window) { 123 ] 124 125 # A new type to help incrementally construct texts. - 126 container buffer:_elem [ + 126 container buffer:_elem [ 127 length:num 128 data:&:@:_elem 129 ] 130 - 131 def new-buffer capacity:num -> result:&:buffer:_elem [ + 131 def new-buffer capacity:num -> result:&:buffer:_elem [ 132 local-scope 133 load-ingredients 134 result <- new {(buffer _elem): type} @@ -205,7 +205,7 @@ if ('onhashchange' in window) { 143 return result 144 ] 145 - 146 def grow-buffer buf:&:buffer:_elem -> buf:&:buffer:_elem [ + 146 def grow-buffer buf:&:buffer:_elem -> buf:&:buffer:_elem [ 147 local-scope 148 load-ingredients 149 # double buffer size @@ -226,7 +226,7 @@ if ('onhashchange' in window) { 164 } 165 ] 166 - 167 def buffer-full? in:&:buffer:_elem -> result:bool [ + 167 def buffer-full? in:&:buffer:_elem -> result:bool [ 168 local-scope 169 load-ingredients 170 len:num <- get *in, length:offset @@ -236,7 +236,7 @@ if ('onhashchange' in window) { 174 ] 175 176 # most broadly applicable definition of append to a buffer: just call to-text - 177 def append buf:&:buffer:char, x:_elem -> buf:&:buffer:char [ + 177 def append buf:&:buffer:char, x:_elem -> buf:&:buffer:char [ 178 local-scope 179 load-ingredients 180 text:text <- to-text x @@ -252,7 +252,7 @@ if ('onhashchange' in window) { 190 } 191 ] 192 - 193 def append buf:&:buffer:char, c:char -> buf:&:buffer:char [ + 193 def append buf:&:buffer:char, c:char -> buf:&:buffer:char [ 194 local-scope 195 load-ingredients 196 len:num <- get *buf, length:offset @@ -278,7 +278,7 @@ if ('onhashchange' in window) { 216 *buf <- put *buf, length:offset, len 217 ] 218 - 219 def append buf:&:buffer:char, t:text -> buf:&:buffer:char [ + 219 def append buf:&:buffer:char, t:text -> buf:&:buffer:char [ 220 local-scope 221 load-ingredients 222 len:num <- length *t @@ -295,7 +295,7 @@ if ('onhashchange' in window) { 233 234 scenario append-to-empty-buffer [ 235 local-scope - 236 x:&:buffer:char <- new-buffer + 236 x:&:buffer:char <- new-buffer 237 run [ 238 ¦ c:char <- copy 97/a 239 ¦ x <- append x, c @@ -313,7 +313,7 @@ if ('onhashchange' in window) { 251 252 scenario append-to-buffer [ 253 local-scope - 254 x:&:buffer:char <- new-buffer + 254 x:&:buffer:char <- new-buffer 255 c:char <- copy 97/a 256 x <- append x, c 257 run [ @@ -335,7 +335,7 @@ if ('onhashchange' in window) { 273 274 scenario append-grows-buffer [ 275 local-scope - 276 x:&:buffer:char <- new-buffer 3 + 276 x:&:buffer:char <- new-buffer 3 277 s1:text <- get *x, data:offset 278 x <- append x, [abc] # buffer is now full 279 s2:text <- get *x, data:offset @@ -372,7 +372,7 @@ if ('onhashchange' in window) { 310 311 scenario buffer-append-handles-backspace [ 312 local-scope - 313 x:&:buffer:char <- new-buffer + 313 x:&:buffer:char <- new-buffer 314 x <- append x, [ab] 315 run [ 316 ¦ c:char <- copy 8/backspace @@ -387,7 +387,7 @@ if ('onhashchange' in window) { 325 ] 326 ] 327 - 328 def buffer-to-array in:&:buffer:_elem -> result:&:@:_elem [ + 328 def buffer-to-array in:&:buffer:_elem -> result:&:@:_elem [ 329 local-scope 330 load-ingredients 331 { @@ -421,7 +421,7 @@ if ('onhashchange' in window) { 359 def append first:text -> result:text [ 360 local-scope 361 load-ingredients - 362 buf:&:buffer:char <- new-buffer 30 + 362 buf:&:buffer:char <- new-buffer 30 363 # append first ingredient 364 { 365 ¦ break-unless first diff --git a/html/064list.mu.html b/html/064list.mu.html index e1f93300..3f604a5e 100644 --- a/html/064list.mu.html +++ b/html/064list.mu.html @@ -65,26 +65,26 @@ if ('onhashchange' in window) { 3 # The objects must be of the same type. If you want to store multiple types in 4 # a single list, use an exclusive-container. 5 - 6 container list:_elem [ + 6 container list:_elem [ 7 value:_elem - 8 next:&:list:_elem + 8 next:&:list:_elem 9 ] 10 - 11 def push x:_elem, l:&:list:_elem -> l:&:list:_elem [ + 11 def push x:_elem, l:&:list:_elem -> l:&:list:_elem [ 12 local-scope 13 load-ingredients - 14 result:&:list:_elem <- new {(list _elem): type} + 14 result:&:list:_elem <- new {(list _elem): type} 15 *result <- merge x, l 16 return result 17 ] 18 - 19 def first in:&:list:_elem -> result:_elem [ + 19 def first in:&:list:_elem -> result:_elem [ 20 local-scope 21 load-ingredients 22 result <- get *in, value:offset 23 ] 24 - 25 def rest in:&:list:_elem -> result:&:list:_elem/contained-in:in [ + 25 def rest in:&:list:_elem -> result:&:list:_elem/contained-in:in [ 26 local-scope 27 load-ingredients 28 result <- get *in, next:offset @@ -93,7 +93,7 @@ if ('onhashchange' in window) { 31 scenario list-handling [ 32 run [ 33 ¦ local-scope - 34 ¦ x:&:list:num <- push 3, 0 + 34 ¦ x:&:list:num <- push 3, 0 35 ¦ x <- push 4, x 36 ¦ x <- push 5, x 37 ¦ 10:num/raw <- first x @@ -101,7 +101,7 @@ if ('onhashchange' in window) { 39 ¦ 11:num/raw <- first x 40 ¦ x <- rest x 41 ¦ 12:num/raw <- first x - 42 ¦ 20:&:list:num/raw <- rest x + 42 ¦ 20:&:list:num/raw <- rest x 43 ] 44 memory-should-contain [ 45 ¦ 10 <- 5 @@ -111,7 +111,7 @@ if ('onhashchange' in window) { 49 ] 50 ] 51 - 52 def length l:&:list:_elem -> result:num [ + 52 def length l:&:list:_elem -> result:num [ 53 local-scope 54 load-ingredients 55 result <- copy 0 @@ -124,26 +124,26 @@ if ('onhashchange' in window) { 62 ] 63 64 # insert 'x' after 'in' - 65 def insert x:_elem, in:&:list:_elem -> in:&:list:_elem [ + 65 def insert x:_elem, in:&:list:_elem -> in:&:list:_elem [ 66 local-scope 67 load-ingredients - 68 new-node:&:list:_elem <- new {(list _elem): type} + 68 new-node:&:list:_elem <- new {(list _elem): type} 69 *new-node <- put *new-node, value:offset, x - 70 next-node:&:list:_elem <- get *in, next:offset + 70 next-node:&:list:_elem <- get *in, next:offset 71 *in <- put *in, next:offset, new-node 72 *new-node <- put *new-node, next:offset, next-node 73 ] 74 75 scenario inserting-into-list [ 76 local-scope - 77 list:&:list:char <- push 3, 0 - 78 list <- push 4, list - 79 list <- push 5, list + 77 list:&:list:char <- push 3, 0 + 78 list <- push 4, list + 79 list <- push 5, list 80 run [ - 81 ¦ list2:&:list:char <- rest list # inside list + 81 ¦ list2:&:list:char <- rest list # inside list 82 ¦ list2 <- insert 6, list2 83 ¦ # check structure - 84 ¦ list2 <- copy list + 84 ¦ list2 <- copy list 85 ¦ 10:char/raw <- first list2 86 ¦ list2 <- rest list2 87 ¦ 11:char/raw <- first list2 @@ -162,15 +162,15 @@ if ('onhashchange' in window) { 100 101 scenario inserting-at-end-of-list [ 102 local-scope -103 list:&:list:char <- push 3, 0 -104 list <- push 4, list -105 list <- push 5, list +103 list:&:list:char <- push 3, 0 +104 list <- push 4, list +105 list <- push 5, list 106 run [ -107 ¦ list2:&:list:char <- rest list # inside list +107 ¦ list2:&:list:char <- rest list # inside list 108 ¦ list2 <- rest list2 # now at end of list 109 ¦ list2 <- insert 6, list2 110 ¦ # check structure like before -111 ¦ list2 <- copy list +111 ¦ list2 <- copy list 112 ¦ 10:char/raw <- first list2 113 ¦ list2 <- rest list2 114 ¦ 11:char/raw <- first list2 @@ -189,13 +189,13 @@ if ('onhashchange' in window) { 127 128 scenario inserting-after-start-of-list [ 129 local-scope -130 list:&:list:char <- push 3, 0 -131 list <- push 4, list -132 list <- push 5, list +130 list:&:list:char <- push 3, 0 +131 list <- push 4, list +132 list <- push 5, list 133 run [ -134 ¦ list <- insert 6, list +134 ¦ list <- insert 6, list 135 ¦ # check structure like before -136 ¦ list2:&:list:char <- copy list +136 ¦ list2:&:list:char <- copy list 137 ¦ 10:char/raw <- first list2 138 ¦ list2 <- rest list2 139 ¦ 11:char/raw <- first list2 @@ -216,20 +216,20 @@ if ('onhashchange' in window) { 154 # 155 # Returns null if and only if list is empty. Beware: in that case any other 156 # pointers to the head are now invalid. -157 def remove x:&:list:_elem/contained-in:in, in:&:list:_elem -> in:&:list:_elem [ +157 def remove x:&:list:_elem/contained-in:in, in:&:list:_elem -> in:&:list:_elem [ 158 local-scope 159 load-ingredients 160 # if 'x' is null, return 161 return-unless x -162 next-node:&:list:_elem <- rest x +162 next-node:&:list:_elem <- rest x 163 # clear next pointer of 'x' 164 *x <- put *x, next:offset, 0 165 # if 'x' is at the head of 'in', return the new head 166 at-head?:bool <- equal x, in 167 return-if at-head?, next-node 168 # compute prev-node -169 prev-node:&:list:_elem <- copy in -170 curr:&:list:_elem <- rest prev-node +169 prev-node:&:list:_elem <- copy in +170 curr:&:list:_elem <- rest prev-node 171 { 172 ¦ return-unless curr 173 ¦ found?:bool <- equal curr, x @@ -243,19 +243,19 @@ if ('onhashchange' in window) { 181 182 scenario removing-from-list [ 183 local-scope -184 list:&:list:char <- push 3, 0 -185 list <- push 4, list -186 list <- push 5, list +184 list:&:list:char <- push 3, 0 +185 list <- push 4, list +186 list <- push 5, list 187 run [ -188 ¦ list2:&:list:char <- rest list # second element -189 ¦ list <- remove list2, list +188 ¦ list2:&:list:char <- rest list # second element +189 ¦ list <- remove list2, list 190 ¦ 10:bool/raw <- equal list2, 0 191 ¦ # check structure like before -192 ¦ list2 <- copy list +192 ¦ list2 <- copy list 193 ¦ 11:char/raw <- first list2 194 ¦ list2 <- rest list2 195 ¦ 12:char/raw <- first list2 -196 ¦ 20:&:list:char/raw <- rest list2 +196 ¦ 20:&:list:char/raw <- rest list2 197 ] 198 memory-should-contain [ 199 ¦ 10 <- 0 # remove returned non-null @@ -267,17 +267,17 @@ if ('onhashchange' in window) { 205 206 scenario removing-from-start-of-list [ 207 local-scope -208 list:&:list:char <- push 3, 0 -209 list <- push 4, list -210 list <- push 5, list +208 list:&:list:char <- push 3, 0 +209 list <- push 4, list +210 list <- push 5, list 211 run [ -212 ¦ list <- remove list, list +212 ¦ list <- remove list, list 213 ¦ # check structure like before -214 ¦ list2:&:list:char <- copy list +214 ¦ list2:&:list:char <- copy list 215 ¦ 10:char/raw <- first list2 216 ¦ list2 <- rest list2 217 ¦ 11:char/raw <- first list2 -218 ¦ 20:&:list:char/raw <- rest list2 +218 ¦ 20:&:list:char/raw <- rest list2 219 ] 220 memory-should-contain [ 221 ¦ 10 <- 4 # scanning next, skipping deleted element @@ -288,21 +288,21 @@ if ('onhashchange' in window) { 226 227 scenario removing-from-end-of-list [ 228 local-scope -229 list:&:list:char <- push 3, 0 -230 list <- push 4, list -231 list <- push 5, list +229 list:&:list:char <- push 3, 0 +230 list <- push 4, list +231 list <- push 5, list 232 run [ 233 ¦ # delete last element -234 ¦ list2:&:list:char <- rest list +234 ¦ list2:&:list:char <- rest list 235 ¦ list2 <- rest list2 -236 ¦ list <- remove list2, list +236 ¦ list <- remove list2, list 237 ¦ 10:bool/raw <- equal list2, 0 238 ¦ # check structure like before -239 ¦ list2 <- copy list +239 ¦ list2 <- copy list 240 ¦ 11:char/raw <- first list2 241 ¦ list2 <- rest list2 242 ¦ 12:char/raw <- first list2 -243 ¦ 20:&:list:char/raw <- rest list2 +243 ¦ 20:&:list:char/raw <- rest list2 244 ] 245 memory-should-contain [ 246 ¦ 10 <- 0 # remove returned non-null @@ -314,10 +314,10 @@ if ('onhashchange' in window) { 252 253 scenario removing-from-singleton-list [ 254 local-scope -255 list:&:list:char <- push 3, 0 +255 list:&:list:char <- push 3, 0 256 run [ -257 ¦ list <- remove list, list -258 ¦ 1:num/raw <- copy list +257 ¦ list <- remove list, list +258 ¦ 1:num/raw <- copy list 259 ] 260 memory-should-contain [ 261 ¦ 1 <- 0 # back to an empty list @@ -326,50 +326,50 @@ if ('onhashchange' in window) { 264 265 # reverse the elements of a list 266 # (contributed by Caleb Couch) -267 def reverse list:&:list:_elem temp:&:list:_elem/contained-in:result -> result:&:list:_elem [ +267 def reverse list:&:list:_elem temp:&:list:_elem/contained-in:result -> result:&:list:_elem [ 268 local-scope 269 load-ingredients -270 return-unless list, temp -271 object:_elem <- first, list -272 list <- rest list +270 return-unless list, temp +271 object:_elem <- first, list +272 list <- rest list 273 temp <- push object, temp -274 result <- reverse list, temp +274 result <- reverse list, temp 275 ] 276 277 scenario reverse-list [ 278 local-scope -279 list:&:list:number <- push 1, 0 -280 list <- push 2, list -281 list <- push 3, list +279 list:&:list:number <- push 1, 0 +280 list <- push 2, list +281 list <- push 3, list 282 run [ -283 ¦ stash [list:], list -284 ¦ list <- reverse list -285 ¦ stash [reversed:], list +283 ¦ stash [list:], list +284 ¦ list <- reverse list +285 ¦ stash [reversed:], list 286 ] 287 trace-should-contain [ -288 ¦ app: list: 3 -> 2 -> 1 +288 ¦ app: list: 3 -> 2 -> 1 289 ¦ app: reversed: 1 -> 2 -> 3 290 ] 291 ] 292 -293 def to-text in:&:list:_elem -> result:text [ +293 def to-text in:&:list:_elem -> result:text [ 294 local-scope 295 load-ingredients -296 buf:&:buffer:char <- new-buffer 80 +296 buf:&:buffer:char <- new-buffer 80 297 buf <- to-buffer in, buf 298 result <- buffer-to-array buf 299 ] 300 301 # variant of 'to-text' which stops printing after a few elements (and so is robust to cycles) -302 def to-text-line in:&:list:_elem -> result:text [ +302 def to-text-line in:&:list:_elem -> result:text [ 303 local-scope 304 load-ingredients -305 buf:&:buffer:char <- new-buffer 80 +305 buf:&:buffer:char <- new-buffer 80 306 buf <- to-buffer in, buf, 6 # max elements to display 307 result <- buffer-to-array buf 308 ] 309 -310 def to-buffer in:&:list:_elem, buf:&:buffer:char -> buf:&:buffer:char [ +310 def to-buffer in:&:list:_elem, buf:&:buffer:char -> buf:&:buffer:char [ 311 local-scope 312 load-ingredients 313 { @@ -381,7 +381,7 @@ if ('onhashchange' in window) { 319 val:_elem <- get *in, value:offset 320 buf <- append buf, val 321 # now prepare next -322 next:&:list:_elem <- rest in +322 next:&:list:_elem <- rest in 323 nextn:num <- copy next 324 return-unless next 325 buf <- append buf, [ -> ] @@ -406,7 +406,7 @@ if ('onhashchange' in window) { 344 345 scenario stash-empty-list [ 346 local-scope -347 x:&:list:num <- copy 0 +347 x:&:list:num <- copy 0 348 run [ 349 ¦ stash x 350 ] diff --git a/html/065duplex_list.mu.html b/html/065duplex_list.mu.html index fedcd670..55bb4707 100644 --- a/html/065duplex_list.mu.html +++ b/html/065duplex_list.mu.html @@ -62,17 +62,17 @@ if ('onhashchange' in window) {
   1 # A doubly linked list permits bidirectional traversal.
   2 
-  3 container duplex-list:_elem [
+  3 container duplex-list:_elem [
   4   value:_elem
-  5   next:&:duplex-list:_elem
-  6   prev:&:duplex-list:_elem
+  5   next:&:duplex-list:_elem
+  6   prev:&:duplex-list:_elem
   7 ]
   8 
   9 # should I say in/contained-in:result, allow ingredients to refer to products?
- 10 def push x:_elem, in:&:duplex-list:_elem -> in:&:duplex-list:_elem [
+ 10 def push x:_elem, in:&:duplex-list:_elem -> in:&:duplex-list:_elem [
  11   local-scope
  12   load-ingredients
- 13   result:&:duplex-list:_elem <- new {(duplex-list _elem): type}
+ 13   result:&:duplex-list:_elem <- new {(duplex-list _elem): type}
  14   *result <- merge x, in, 0
  15   {
  16   ¦ break-unless in
@@ -81,21 +81,21 @@ if ('onhashchange' in window) {
  19   return result  # needed explicitly because we need to replace 'in' with 'result'
  20 ]
  21 
- 22 def first in:&:duplex-list:_elem -> result:_elem [
+ 22 def first in:&:duplex-list:_elem -> result:_elem [
  23   local-scope
  24   load-ingredients
  25   return-unless in, 0
  26   result <- get *in, value:offset
  27 ]
  28 
- 29 def next in:&:duplex-list:_elem -> result:&:duplex-list:_elem/contained-in:in [
+ 29 def next in:&:duplex-list:_elem -> result:&:duplex-list:_elem/contained-in:in [
  30   local-scope
  31   load-ingredients
  32   return-unless in, 0
  33   result <- get *in, next:offset
  34 ]
  35 
- 36 def prev in:&:duplex-list:_elem -> result:&:duplex-list:_elem/contained-in:in [
+ 36 def prev in:&:duplex-list:_elem -> result:&:duplex-list:_elem/contained-in:in [
  37   local-scope
  38   load-ingredients
  39   return-unless in, 0
@@ -109,24 +109,24 @@ if ('onhashchange' in window) {
  47   ¦ # reserve locations 0-9 to check for missing null check
  48   ¦ 10:num/raw <- copy 34
  49   ¦ 11:num/raw <- copy 35
- 50   ¦ list:&:duplex-list:char <- push 3, 0
- 51   ¦ list <- push 4, list
- 52   ¦ list <- push 5, list
- 53   ¦ list2:&:duplex-list:char <- copy list
+ 50   ¦ list:&:duplex-list:char <- push 3, 0
+ 51   ¦ list <- push 4, list
+ 52   ¦ list <- push 5, list
+ 53   ¦ list2:&:duplex-list:char <- copy list
  54   ¦ 20:char/raw <- first list2
  55   ¦ list2 <- next list2
  56   ¦ 21:char/raw <- first list2
  57   ¦ list2 <- next list2
  58   ¦ 22:char/raw <- first list2
- 59   ¦ 30:&:duplex-list:char/raw <- next list2
- 60   ¦ 31:char/raw <- first 30:&:duplex-list:char/raw
- 61   ¦ 32:&:duplex-list:char/raw <- next 30:&:duplex-list:char/raw
- 62   ¦ 33:&:duplex-list:char/raw <- prev 30:&:duplex-list:char/raw
+ 59   ¦ 30:&:duplex-list:char/raw <- next list2
+ 60   ¦ 31:char/raw <- first 30:&:duplex-list:char/raw
+ 61   ¦ 32:&:duplex-list:char/raw <- next 30:&:duplex-list:char/raw
+ 62   ¦ 33:&:duplex-list:char/raw <- prev 30:&:duplex-list:char/raw
  63   ¦ list2 <- prev list2
  64   ¦ 40:char/raw <- first list2
  65   ¦ list2 <- prev list2
  66   ¦ 41:char/raw <- first list2
- 67   ¦ 50:bool/raw <- equal list, list2
+ 67   ¦ 50:bool/raw <- equal list, list2
  68   ]
  69   memory-should-contain [
  70   ¦ 0 <- 0  # no modifications to null pointers
@@ -145,7 +145,7 @@ if ('onhashchange' in window) {
  83   ]
  84 ]
  85 
- 86 def length l:&:duplex-list:_elem -> result:num [
+ 86 def length l:&:duplex-list:_elem -> result:num [
  87   local-scope
  88   load-ingredients
  89   result <- copy 0
@@ -158,13 +158,13 @@ if ('onhashchange' in window) {
  96 ]
  97 
  98 # insert 'x' after 'in'
- 99 def insert x:_elem, in:&:duplex-list:_elem -> in:&:duplex-list:_elem [
+ 99 def insert x:_elem, in:&:duplex-list:_elem -> in:&:duplex-list:_elem [
 100   local-scope
 101   load-ingredients
-102   new-node:&:duplex-list:_elem <- new {(duplex-list _elem): type}
+102   new-node:&:duplex-list:_elem <- new {(duplex-list _elem): type}
 103   *new-node <- put *new-node, value:offset, x
 104   # save old next before changing it
-105   next-node:&:duplex-list:_elem <- get *in, next:offset
+105   next-node:&:duplex-list:_elem <- get *in, next:offset
 106   *in <- put *in, next:offset, new-node
 107   *new-node <- put *new-node, prev:offset, in
 108   *new-node <- put *new-node, next:offset, next-node
@@ -174,14 +174,14 @@ if ('onhashchange' in window) {
 112 
 113 scenario inserting-into-duplex-list [
 114   local-scope
-115   list:&:duplex-list:char <- push 3, 0
-116   list <- push 4, list
-117   list <- push 5, list
+115   list:&:duplex-list:char <- push 3, 0
+116   list <- push 4, list
+117   list <- push 5, list
 118   run [
-119   ¦ list2:&:duplex-list:char <- next list  # inside list
+119   ¦ list2:&:duplex-list:char <- next list  # inside list
 120   ¦ list2 <- insert 6, list2
 121   ¦ # check structure like before
-122   ¦ list2 <- copy list
+122   ¦ list2 <- copy list
 123   ¦ 10:char/raw <- first list2
 124   ¦ list2 <- next list2
 125   ¦ 11:char/raw <- first list2
@@ -195,7 +195,7 @@ if ('onhashchange' in window) {
 133   ¦ 21:char/raw <- first list2
 134   ¦ list2 <- prev list2
 135   ¦ 22:char/raw <- first list2
-136   ¦ 30:bool/raw <- equal list, list2
+136   ¦ 30:bool/raw <- equal list, list2
 137   ]
 138   memory-should-contain [
 139   ¦ 10 <- 5  # scanning next
@@ -211,15 +211,15 @@ if ('onhashchange' in window) {
 149 
 150 scenario inserting-at-end-of-duplex-list [
 151   local-scope
-152   list:&:duplex-list:char <- push 3, 0
-153   list <- push 4, list
-154   list <- push 5, list
+152   list:&:duplex-list:char <- push 3, 0
+153   list <- push 4, list
+154   list <- push 5, list
 155   run [
-156   ¦ list2:&:duplex-list:char <- next list  # inside list
+156   ¦ list2:&:duplex-list:char <- next list  # inside list
 157   ¦ list2 <- next list2  # now at end of list
 158   ¦ list2 <- insert 6, list2
 159   ¦ # check structure like before
-160   ¦ list2 <- copy list
+160   ¦ list2 <- copy list
 161   ¦ 10:char/raw <- first list2
 162   ¦ list2 <- next list2
 163   ¦ 11:char/raw <- first list2
@@ -233,7 +233,7 @@ if ('onhashchange' in window) {
 171   ¦ 21:char/raw <- first list2
 172   ¦ list2 <- prev list2
 173   ¦ 22:char/raw <- first list2
-174   ¦ 30:bool/raw <- equal list, list2
+174   ¦ 30:bool/raw <- equal list, list2
 175   ]
 176   memory-should-contain [
 177   ¦ 10 <- 5  # scanning next
@@ -249,13 +249,13 @@ if ('onhashchange' in window) {
 187 
 188 scenario inserting-after-start-of-duplex-list [
 189   local-scope
-190   list:&:duplex-list:char <- push 3, 0
-191   list <- push 4, list
-192   list <- push 5, list
+190   list:&:duplex-list:char <- push 3, 0
+191   list <- push 4, list
+192   list <- push 5, list
 193   run [
-194   ¦ list <- insert 6, list
+194   ¦ list <- insert 6, list
 195   ¦ # check structure like before
-196   ¦ list2:&:duplex-list:char <- copy list
+196   ¦ list2:&:duplex-list:char <- copy list
 197   ¦ 10:char/raw <- first list2
 198   ¦ list2 <- next list2
 199   ¦ 11:char/raw <- first list2
@@ -269,7 +269,7 @@ if ('onhashchange' in window) {
 207   ¦ 21:char/raw <- first list2
 208   ¦ list2 <- prev list2
 209   ¦ 22:char/raw <- first list2
-210   ¦ 30:bool/raw <- equal list, list2
+210   ¦ 30:bool/raw <- equal list, list2
 211   ]
 212   memory-should-contain [
 213   ¦ 10 <- 5  # scanning next
@@ -287,13 +287,13 @@ if ('onhashchange' in window) {
 225 #
 226 # Returns null if and only if list is empty. Beware: in that case any other
 227 # pointers to the head are now invalid.
-228 def remove x:&:duplex-list:_elem/contained-in:in, in:&:duplex-list:_elem -> in:&:duplex-list:_elem [
+228 def remove x:&:duplex-list:_elem/contained-in:in, in:&:duplex-list:_elem -> in:&:duplex-list:_elem [
 229   local-scope
 230   load-ingredients
 231   # if 'x' is null, return
 232   return-unless x
-233   next-node:&:duplex-list:_elem <- get *x, next:offset
-234   prev-node:&:duplex-list:_elem <- get *x, prev:offset
+233   next-node:&:duplex-list:_elem <- get *x, next:offset
+234   prev-node:&:duplex-list:_elem <- get *x, prev:offset
 235   # null x's pointers
 236   *x <- put *x, next:offset, 0
 237   *x <- put *x, prev:offset, 0
@@ -315,22 +315,22 @@ if ('onhashchange' in window) {
 253 
 254 scenario removing-from-duplex-list [
 255   local-scope
-256   list:&:duplex-list:char <- push 3, 0
-257   list <- push 4, list
-258   list <- push 5, list
+256   list:&:duplex-list:char <- push 3, 0
+257   list <- push 4, list
+258   list <- push 5, list
 259   run [
-260   ¦ list2:&:duplex-list:char <- next list  # second element
-261   ¦ list <- remove list2, list
+260   ¦ list2:&:duplex-list:char <- next list  # second element
+261   ¦ list <- remove list2, list
 262   ¦ 10:bool/raw <- equal list2, 0
 263   ¦ # check structure like before
-264   ¦ list2 <- copy list
+264   ¦ list2 <- copy list
 265   ¦ 11:char/raw <- first list2
 266   ¦ list2 <- next list2
 267   ¦ 12:char/raw <- first list2
-268   ¦ 20:&:duplex-list:char/raw <- next list2
+268   ¦ 20:&:duplex-list:char/raw <- next list2
 269   ¦ list2 <- prev list2
 270   ¦ 30:char/raw <- first list2
-271   ¦ 40:bool/raw <- equal list, list2
+271   ¦ 40:bool/raw <- equal list, list2
 272   ]
 273   memory-should-contain [
 274   ¦ 10 <- 0  # remove returned non-null
@@ -344,20 +344,20 @@ if ('onhashchange' in window) {
 282 
 283 scenario removing-from-start-of-duplex-list [
 284   local-scope
-285   list:&:duplex-list:char <- push 3, 0
-286   list <- push 4, list
-287   list <- push 5, list
+285   list:&:duplex-list:char <- push 3, 0
+286   list <- push 4, list
+287   list <- push 5, list
 288   run [
-289   ¦ list <- remove list, list
+289   ¦ list <- remove list, list
 290   ¦ # check structure like before
-291   ¦ list2:&:duplex-list:char <- copy list
+291   ¦ list2:&:duplex-list:char <- copy list
 292   ¦ 10:char/raw <- first list2
 293   ¦ list2 <- next list2
 294   ¦ 11:char/raw <- first list2
-295   ¦ 20:&:duplex-list:char/raw <- next list2
+295   ¦ 20:&:duplex-list:char/raw <- next list2
 296   ¦ list2 <- prev list2
 297   ¦ 30:char/raw <- first list2
-298   ¦ 40:bool/raw <- equal list, list2
+298   ¦ 40:bool/raw <- equal list, list2
 299   ]
 300   memory-should-contain [
 301   ¦ 10 <- 4  # scanning next, skipping deleted element
@@ -370,24 +370,24 @@ if ('onhashchange' in window) {
 308 
 309 scenario removing-from-end-of-duplex-list [
 310   local-scope
-311   list:&:duplex-list:char <- push 3, 0
-312   list <- push 4, list
-313   list <- push 5, list
+311   list:&:duplex-list:char <- push 3, 0
+312   list <- push 4, list
+313   list <- push 5, list
 314   run [
 315   ¦ # delete last element
-316   ¦ list2:&:duplex-list:char <- next list
+316   ¦ list2:&:duplex-list:char <- next list
 317   ¦ list2 <- next list2
-318   ¦ list <- remove list2, list
+318   ¦ list <- remove list2, list
 319   ¦ 10:bool/raw <- equal list2, 0
 320   ¦ # check structure like before
-321   ¦ list2 <- copy list
+321   ¦ list2 <- copy list
 322   ¦ 11:char/raw <- first list2
 323   ¦ list2 <- next list2
 324   ¦ 12:char/raw <- first list2
-325   ¦ 20:&:duplex-list:char/raw <- next list2
+325   ¦ 20:&:duplex-list:char/raw <- next list2
 326   ¦ list2 <- prev list2
 327   ¦ 30:char/raw <- first list2
-328   ¦ 40:bool/raw <- equal list, list2
+328   ¦ 40:bool/raw <- equal list, list2
 329   ]
 330   memory-should-contain [
 331   ¦ 10 <- 0  # remove returned non-null
@@ -401,10 +401,10 @@ if ('onhashchange' in window) {
 339 
 340 scenario removing-from-singleton-duplex-list [
 341   local-scope
-342   list:&:duplex-list:char <- push 3, 0
+342   list:&:duplex-list:char <- push 3, 0
 343   run [
-344   ¦ list <- remove list, list
-345   ¦ 1:num/raw <- copy list
+344   ¦ list <- remove list, list
+345   ¦ 1:num/raw <- copy list
 346   ]
 347   memory-should-contain [
 348   ¦ 1 <- 0  # back to an empty list
@@ -416,10 +416,10 @@ if ('onhashchange' in window) {
 354 # set end to 0 to delete everything past start.
 355 # can't set start to 0 to delete everything before end, because there's no
 356 # clean way to return the new head pointer.
-357 def remove-between start:&:duplex-list:_elem, end:&:duplex-list:_elem/contained-in:start -> start:&:duplex-list:_elem [
+357 def remove-between start:&:duplex-list:_elem, end:&:duplex-list:_elem/contained-in:start -> start:&:duplex-list:_elem [
 358   local-scope
 359   load-ingredients
-360   next:&:duplex-list:_elem <- get *start, next:offset
+360   next:&:duplex-list:_elem <- get *start, next:offset
 361   nothing-to-delete?:bool <- equal next, end
 362   return-if nothing-to-delete?
 363   assert next, [malformed duplex list]
@@ -430,8 +430,8 @@ if ('onhashchange' in window) {
 368   return-unless end
 369   # end->prev->next = 0
 370   # end->prev = start
-371   prev:&:duplex-list:_elem <- get *end, prev:offset
-372   assert prev, [malformed duplex list - 2]
+371   prev:&:duplex-list:_elem <- get *end, prev:offset
+372   assert prev, [malformed duplex list - 2]
 373   *prev <- put *prev, next:offset, 0
 374   *end <- put *end, prev:offset, start
 375 ]
@@ -439,25 +439,25 @@ if ('onhashchange' in window) {
 377 scenario remove-range [
 378   # construct a duplex list with six elements [13, 14, 15, 16, 17, 18]
 379   local-scope
-380   list:&:duplex-list:char <- push 18, 0
-381   list <- push 17, list
-382   list <- push 16, list
-383   list <- push 15, list
-384   list <- push 14, list
-385   list <- push 13, list
+380   list:&:duplex-list:char <- push 18, 0
+381   list <- push 17, list
+382   list <- push 16, list
+383   list <- push 15, list
+384   list <- push 14, list
+385   list <- push 13, list
 386   run [
 387   ¦ # delete 16 onwards
 388   ¦ # first pointer: to the third element
-389   ¦ list2:&:duplex-list:char <- next list
+389   ¦ list2:&:duplex-list:char <- next list
 390   ¦ list2 <- next list2
 391   ¦ list2 <- remove-between list2, 0
 392   ¦ # now check the list
 393   ¦ 10:char/raw <- get *list, value:offset
-394   ¦ list <- next list
+394   ¦ list <- next list
 395   ¦ 11:char/raw <- get *list, value:offset
-396   ¦ list <- next list
+396   ¦ list <- next list
 397   ¦ 12:char/raw <- get *list, value:offset
-398   ¦ 20:&:duplex-list:char/raw <- next list
+398   ¦ 20:&:duplex-list:char/raw <- next list
 399   ]
 400   memory-should-contain [
 401   ¦ 10 <- 13
@@ -470,29 +470,29 @@ if ('onhashchange' in window) {
 408 scenario remove-range-to-final [
 409   local-scope
 410   # construct a duplex list with six elements [13, 14, 15, 16, 17, 18]
-411   list:&:duplex-list:char <- push 18, 0
-412   list <- push 17, list
-413   list <- push 16, list
-414   list <- push 15, list
-415   list <- push 14, list
-416   list <- push 13, list
+411   list:&:duplex-list:char <- push 18, 0
+412   list <- push 17, list
+413   list <- push 16, list
+414   list <- push 15, list
+415   list <- push 14, list
+416   list <- push 13, list
 417   run [
 418   ¦ # delete 15, 16 and 17
 419   ¦ # start pointer: to the second element
-420   ¦ list2:&:duplex-list:char <- next list
+420   ¦ list2:&:duplex-list:char <- next list
 421   ¦ # end pointer: to the last (sixth) element
-422   ¦ end:&:duplex-list:char <- next list2
+422   ¦ end:&:duplex-list:char <- next list2
 423   ¦ end <- next end
 424   ¦ end <- next end
 425   ¦ end <- next end
 426   ¦ remove-between list2, end
 427   ¦ # now check the list
 428   ¦ 10:char/raw <- get *list, value:offset
-429   ¦ list <- next list
+429   ¦ list <- next list
 430   ¦ 11:char/raw <- get *list, value:offset
-431   ¦ list <- next list
+431   ¦ list <- next list
 432   ¦ 12:char/raw <- get *list, value:offset
-433   ¦ 20:&:duplex-list:char/raw <- next list
+433   ¦ 20:&:duplex-list:char/raw <- next list
 434   ]
 435   memory-should-contain [
 436   ¦ 10 <- 13
@@ -505,20 +505,20 @@ if ('onhashchange' in window) {
 443 scenario remove-range-empty [
 444   local-scope
 445   # construct a duplex list with three elements [13, 14, 15]
-446   list:&:duplex-list:char <- push 15, 0
-447   list <- push 14, list
-448   list <- push 13, list
+446   list:&:duplex-list:char <- push 15, 0
+447   list <- push 14, list
+448   list <- push 13, list
 449   run [
 450   ¦ # delete between first and second element (i.e. nothing)
-451   ¦ list2:&:duplex-list:char <- next list
-452   ¦ remove-between list, list2
+451   ¦ list2:&:duplex-list:char <- next list
+452   ¦ remove-between list, list2
 453   ¦ # now check the list
 454   ¦ 10:char/raw <- get *list, value:offset
-455   ¦ list <- next list
+455   ¦ list <- next list
 456   ¦ 11:char/raw <- get *list, value:offset
-457   ¦ list <- next list
+457   ¦ list <- next list
 458   ¦ 12:char/raw <- get *list, value:offset
-459   ¦ 20:&:duplex-list:char/raw <- next list
+459   ¦ 20:&:duplex-list:char/raw <- next list
 460   ]
 461   # no change
 462   memory-should-contain [
@@ -532,21 +532,21 @@ if ('onhashchange' in window) {
 470 scenario remove-range-to-end [
 471   local-scope
 472   # construct a duplex list with six elements [13, 14, 15, 16, 17, 18]
-473   list:&:duplex-list:char <- push 18, 0
-474   list <- push 17, list
-475   list <- push 16, list
-476   list <- push 15, list
-477   list <- push 14, list
-478   list <- push 13, list
+473   list:&:duplex-list:char <- push 18, 0
+474   list <- push 17, list
+475   list <- push 16, list
+476   list <- push 15, list
+477   list <- push 14, list
+478   list <- push 13, list
 479   run [
 480   ¦ # remove the third element and beyond
-481   ¦ list2:&:duplex-list:char <- next list
+481   ¦ list2:&:duplex-list:char <- next list
 482   ¦ remove-between list2, 0
 483   ¦ # now check the list
 484   ¦ 10:char/raw <- get *list, value:offset
-485   ¦ list <- next list
+485   ¦ list <- next list
 486   ¦ 11:char/raw <- get *list, value:offset
-487   ¦ 20:&:duplex-list:char/raw <- next list
+487   ¦ 20:&:duplex-list:char/raw <- next list
 488   ]
 489   memory-should-contain [
 490   ¦ 10 <- 13
@@ -556,19 +556,19 @@ if ('onhashchange' in window) {
 494 ]
 495 
 496 # insert list beginning at 'new' after 'in'
-497 def insert-range in:&:duplex-list:_elem, start:&:duplex-list:_elem/contained-in:in -> in:&:duplex-list:_elem [
+497 def insert-range in:&:duplex-list:_elem, start:&:duplex-list:_elem/contained-in:in -> in:&:duplex-list:_elem [
 498   local-scope
 499   load-ingredients
 500   return-unless in
 501   return-unless start
-502   end:&:duplex-list:_elem <- copy start
+502   end:&:duplex-list:_elem <- copy start
 503   {
-504   ¦ next:&:duplex-list:_elem <- next end/insert-range
+504   ¦ next:&:duplex-list:_elem <- next end/insert-range
 505   ¦ break-unless next
 506   ¦ end <- copy next
 507   ¦ loop
 508   }
-509   next:&:duplex-list:_elem <- next in
+509   next:&:duplex-list:_elem <- next in
 510   *end <- put *end, next:offset, next
 511   {
 512   ¦ break-unless next
@@ -578,21 +578,21 @@ if ('onhashchange' in window) {
 516   *start <- put *start, prev:offset, in
 517 ]
 518 
-519 def append in:&:duplex-list:_elem, new:&:duplex-list:_elem/contained-in:in -> in:&:duplex-list:_elem [
+519 def append in:&:duplex-list:_elem, new:&:duplex-list:_elem/contained-in:in -> in:&:duplex-list:_elem [
 520   local-scope
 521   load-ingredients
-522   last:&:duplex-list:_elem <- last in
+522   last:&:duplex-list:_elem <- last in
 523   *last <- put *last, next:offset, new
 524   return-unless new
 525   *new <- put *new, prev:offset, last
 526 ]
 527 
-528 def last in:&:duplex-list:_elem -> result:&:duplex-list:_elem [
+528 def last in:&:duplex-list:_elem -> result:&:duplex-list:_elem [
 529   local-scope
 530   load-ingredients
 531   result <- copy in
 532   {
-533   ¦ next:&:duplex-list:_elem <- next result
+533   ¦ next:&:duplex-list:_elem <- next result
 534   ¦ break-unless next
 535   ¦ result <- copy next
 536   ¦ loop
@@ -600,7 +600,7 @@ if ('onhashchange' in window) {
 538 ]
 539 
 540 # helper for debugging
-541 def dump-from x:&:duplex-list:_elem [
+541 def dump-from x:&:duplex-list:_elem [
 542   local-scope
 543   load-ingredients
 544   $print x, [: ]
diff --git a/html/066stream.mu.html b/html/066stream.mu.html
index 556654bd..4a993384 100644
--- a/html/066stream.mu.html
+++ b/html/066stream.mu.html
@@ -60,12 +60,12 @@ if ('onhashchange' in window) {
 
 
  1 # new type to help incrementally scan arrays
- 2 container stream:_elem [
+ 2 container stream:_elem [
  3   index:num
  4   data:&:@:_elem
  5 ]
  6 
- 7 def new-stream s:&:@:_elem -> result:&:stream:_elem [
+ 7 def new-stream s:&:@:_elem -> result:&:stream:_elem [
  8   local-scope
  9   load-ingredients
 10   return-unless s, 0/null
@@ -74,17 +74,17 @@ if ('onhashchange' in window) {
 13   *result <- put *result, data:offset, s
 14 ]
 15 
-16 def rewind in:&:stream:_elem -> in:&:stream:_elem [
+16 def rewind in:&:stream:_elem -> in:&:stream:_elem [
 17   local-scope
 18   load-ingredients
 19   return-unless in
 20   *in <- put *in, index:offset, 0
 21 ]
 22 
-23 def read in:&:stream:_elem -> result:_elem, empty?:bool, in:&:stream:_elem [
+23 def read in:&:stream:_elem -> result:_elem, empty?:bool, in:&:stream:_elem [
 24   local-scope
 25   load-ingredients
-26   assert in, [cannot read; stream has no data]
+26   assert in, [cannot read; stream has no data]
 27   empty? <- copy 0/false
 28   idx:num <- get *in, index:offset
 29   s:&:@:_elem <- get *in, data:offset
@@ -100,10 +100,10 @@ if ('onhashchange' in window) {
 39   *in <- put *in, index:offset, idx
 40 ]
 41 
-42 def peek in:&:stream:_elem -> result:_elem, empty?:bool [
+42 def peek in:&:stream:_elem -> result:_elem, empty?:bool [
 43   local-scope
 44   load-ingredients
-45   assert in, [cannot peek; stream has no data]
+45   assert in, [cannot peek; stream has no data]
 46   empty?:bool <- copy 0/false
 47   idx:num <- get *in, index:offset
 48   s:&:@:_elem <- get *in, data:offset
@@ -117,10 +117,10 @@ if ('onhashchange' in window) {
 56   result <- index *s, idx
 57 ]
 58 
-59 def read-line in:&:stream:char -> result:text, in:&:stream:char [
+59 def read-line in:&:stream:char -> result:text, in:&:stream:char [
 60   local-scope
 61   load-ingredients
-62   assert in, [cannot read-line; stream has no data]
+62   assert in, [cannot read-line; stream has no data]
 63   idx:num <- get *in, index:offset
 64   s:text <- get *in, data:offset
 65   next-idx:num <- find-next s, 10/newline, idx
@@ -130,10 +130,10 @@ if ('onhashchange' in window) {
 69   *in <- put *in, index:offset, idx
 70 ]
 71 
-72 def end-of-stream? in:&:stream:_elem -> result:bool [
+72 def end-of-stream? in:&:stream:_elem -> result:bool [
 73   local-scope
 74   load-ingredients
-75   assert in, [cannot check end-of-stream?; stream has no data]
+75   assert in, [cannot check end-of-stream?; stream has no data]
 76   idx:num <- get *in, index:offset
 77   s:&:@:_elem <- get *in, data:offset
 78   len:num <- length *s
diff --git a/html/068random.mu.html b/html/068random.mu.html
index 9828a44e..2c695c2f 100644
--- a/html/068random.mu.html
+++ b/html/068random.mu.html
@@ -59,7 +59,7 @@ if ('onhashchange' in window) {
 
 
 
- 1 def random generator:&:stream:num -> result:num, fail?:bool, generator:&:stream:num [
+ 1 def random generator:&:stream:num -> result:num, fail?:bool, generator:&:stream:num [
  2   local-scope
  3   load-ingredients
  4   {
@@ -72,7 +72,7 @@ if ('onhashchange' in window) {
 11 ]
 12 
 13 # helper for tests
-14 def assume-random-numbers -> result:&:stream:num [
+14 def assume-random-numbers -> result:&:stream:num [
 15   local-scope
 16   load-ingredients
 17   # compute result-len, space to allocate in result
@@ -98,11 +98,11 @@ if ('onhashchange' in window) {
 37 
 38 scenario random-numbers-in-scenario [
 39   local-scope
-40   source:&:stream:num <- assume-random-numbers 34, 35, 37
-41   1:num/raw, 2:bool/raw <- random source
-42   3:num/raw, 4:bool/raw <- random source
-43   5:num/raw, 6:bool/raw <- random source
-44   7:num/raw, 8:bool/raw <- random source
+40   source:&:stream:num <- assume-random-numbers 34, 35, 37
+41   1:num/raw, 2:bool/raw <- random source
+42   3:num/raw, 4:bool/raw <- random source
+43   5:num/raw, 6:bool/raw <- random source
+44   7:num/raw, 8:bool/raw <- random source
 45   memory-should-contain [
 46   ¦ 1 <- 34
 47   ¦ 2 <- 0  # everything went well
@@ -116,7 +116,7 @@ if ('onhashchange' in window) {
 55 ]
 56 
 57 # generate a random integer in the semi-open interval [start, end)
-58 def random-in-range generator:&:stream:num, start:num, end:num -> result:num, fail?:bool, generator:&:stream:num [
+58 def random-in-range generator:&:stream:num, start:num, end:num -> result:num, fail?:bool, generator:&:stream:num [
 59   local-scope
 60   load-ingredients
 61   result, fail?, generator <- random generator
@@ -128,8 +128,8 @@ if ('onhashchange' in window) {
 67 
 68 scenario random-in-range [
 69   local-scope
-70   source:&:stream:num <- assume-random-numbers 91
-71   1:num/raw <- random-in-range source, 40, 50
+70   source:&:stream:num <- assume-random-numbers 91
+71   1:num/raw <- random-in-range source, 40, 50
 72   memory-should-contain [
 73   ¦ 1 <- 41
 74   ]
diff --git a/html/070table.mu.html b/html/070table.mu.html
index 2a7ee07f..603e9997 100644
--- a/html/070table.mu.html
+++ b/html/070table.mu.html
@@ -67,7 +67,7 @@ if ('onhashchange' in window) {
   5 
   6 scenario table-read-write [
   7   local-scope
-  8   tab:&:table:num:num <- new-table 30
+  8   tab:&:table:num:num <- new-table 30
   9   run [
  10   ¦ put-index tab, 12, 34
  11   ¦ 60:num/raw, 61:bool/raw <- index tab, 12
@@ -80,7 +80,7 @@ if ('onhashchange' in window) {
  18 
  19 scenario table-read-write-non-integer [
  20   local-scope
- 21   tab:&:table:text:num <- new-table 30
+ 21   tab:&:table:text:num <- new-table 30
  22   run [
  23   ¦ put-index tab, [abc def], 34
  24   ¦ 1:num/raw, 2:bool/raw <- index tab, [abc def]
@@ -93,7 +93,7 @@ if ('onhashchange' in window) {
  31 
  32 scenario table-read-not-found [
  33   local-scope
- 34   tab:&:table:text:num <- new-table 30
+ 34   tab:&:table:text:num <- new-table 30
  35   run [
  36   ¦ 1:num/raw, 2:bool/raw <- index tab, [abc def]
  37   ]
@@ -103,29 +103,29 @@ if ('onhashchange' in window) {
  41   ]
  42 ]
  43 
- 44 container table:_key:_value [
+ 44 container table:_key:_value [
  45   length:num
  46   capacity:num
- 47   data:&:@:table-row:_key:_value
+ 47   data:&:@:table-row:_key:_value
  48 ]
  49 
- 50 container table-row:_key:_value [
+ 50 container table-row:_key:_value [
  51   occupied?:bool
  52   key:_key
  53   value:_value
  54 ]
  55 
- 56 def new-table capacity:num -> result:&:table:_key:_value [
+ 56 def new-table capacity:num -> result:&:table:_key:_value [
  57   local-scope
  58   load-ingredients
  59   result <- new {(table _key _value): type}
- 60   data:&:@:table-row:_key:_value <- new {(table-row _key _value): type}, capacity
+ 60   data:&:@:table-row:_key:_value <- new {(table-row _key _value): type}, capacity
  61   *result <- merge 0/length, capacity, data
  62 ]
  63 
  64 # todo: tag results as /required so that call-sites are forbidden from ignoring them
  65 # then we could handle conflicts simply by resizing the table
- 66 def put-index table:&:table:_key:_value, key:_key, value:_value -> table:&:table:_key:_value [
+ 66 def put-index table:&:table:_key:_value, key:_key, value:_value -> table:&:table:_key:_value [
  67   local-scope
  68   load-ingredients
  69   hash:num <- hash key
@@ -133,16 +133,16 @@ if ('onhashchange' in window) {
  71   capacity:num <- get *table, capacity:offset
  72   _, hash-key:num <- divide-with-remainder hash, capacity
  73   hash-key <- abs hash-key  # in case hash overflows from a double into a negative integer inside 'divide-with-remainder' above
- 74   table-data:&:@:table-row:_key:_value <- get *table, data:offset
- 75   x:table-row:_key:_value <- index *table-data, hash-key
+ 74   table-data:&:@:table-row:_key:_value <- get *table, data:offset
+ 75   x:table-row:_key:_value <- index *table-data, hash-key
  76   occupied?:bool <- get x, occupied?:offset
  77   not-occupied?:bool <- not occupied?:bool
  78   assert not-occupied?, [can't handle collisions yet]
- 79   new-row:table-row:_key:_value <- merge 1/true, key, value
+ 79   new-row:table-row:_key:_value <- merge 1/true, key, value
  80   *table-data <- put-index *table-data, hash-key, new-row
  81 ]
  82 
- 83 def index table:&:table:_key:_value, key:_key -> result:_value, found?:bool [
+ 83 def index table:&:table:_key:_value, key:_key -> result:_value, found?:bool [
  84   local-scope
  85   load-ingredients
  86   hash:num <- hash key
@@ -150,8 +150,8 @@ if ('onhashchange' in window) {
  88   capacity:num <- get *table, capacity:offset
  89   _, hash-key:num <- divide-with-remainder hash, capacity
  90   hash-key <- abs hash-key  # in case hash overflows from a double into a negative integer inside 'divide-with-remainder' above
- 91   table-data:&:@:table-row:_key:_value <- get *table, data:offset
- 92   x:table-row:_key:_value <- index *table-data, hash-key
+ 91   table-data:&:@:table-row:_key:_value <- get *table, data:offset
+ 92   x:table-row:_key:_value <- index *table-data, hash-key
  93   empty:&:_value <- new _value:type
  94   result <- copy *empty
  95   found?:bool <- get x, occupied?:offset
diff --git a/html/075channel.mu.html b/html/075channel.mu.html
index 46c82b68..a5c50400 100644
--- a/html/075channel.mu.html
+++ b/html/075channel.mu.html
@@ -81,9 +81,9 @@ if ('onhashchange' in window) {
  17 scenario channel [
  18   run [
  19   ¦ local-scope
- 20   ¦ source:&:source:num, sink:&:sink:num <- new-channel 3/capacity
- 21   ¦ sink <- write sink, 34
- 22   ¦ 10:num/raw, 11:bool/raw, source <- read source
+ 20   ¦ source:&:source:num, sink:&:sink:num <- new-channel 3/capacity
+ 21   ¦ sink <- write sink, 34
+ 22   ¦ 10:num/raw, 11:bool/raw, source <- read source
  23   ]
  24   memory-should-contain [
  25   ¦ 10 <- 34
@@ -104,15 +104,15 @@ if ('onhashchange' in window) {
  40 # Since channels have two ends, and since it's an error to use either end from
  41 # multiple routines, let's distinguish the ends.
  42 
- 43 container source:_elem [
+ 43 container source:_elem [
  44   chan:&:channel:_elem
  45 ]
  46 
- 47 container sink:_elem [
+ 47 container sink:_elem [
  48   chan:&:channel:_elem
  49 ]
  50 
- 51 def new-channel capacity:num -> in:&:source:_elem, out:&:sink:_elem [
+ 51 def new-channel capacity:num -> in:&:source:_elem, out:&:sink:_elem [
  52   local-scope
  53   load-ingredients
  54   result:&:channel:_elem <- new {(channel _elem): type}
@@ -127,7 +127,7 @@ if ('onhashchange' in window) {
  63   *out <- put *out, chan:offset, result
  64 ]
  65 
- 66 def write out:&:sink:_elem, val:_elem -> out:&:sink:_elem [
+ 66 def write out:&:sink:_elem, val:_elem -> out:&:sink:_elem [
  67   local-scope
  68   load-ingredients
  69   assert out, [write to null channel]
@@ -172,7 +172,7 @@ if ('onhashchange' in window) {
 108   reset lock
 109 ]
 110 
-111 def read in:&:source:_elem -> result:_elem, eof?:bool, in:&:source:_elem [
+111 def read in:&:source:_elem -> result:_elem, eof?:bool, in:&:source:_elem [
 112   local-scope
 113   load-ingredients
 114   assert in, [read on null channel]
@@ -222,7 +222,7 @@ if ('onhashchange' in window) {
 158 # todo: create a notion of iterator and iterable so we can read/write whole
 159 # aggregates (arrays, lists, ..) of _elems at once.
 160 
-161 def clear in:&:source:_elem -> in:&:source:_elem [
+161 def clear in:&:source:_elem -> in:&:source:_elem [
 162   local-scope
 163   load-ingredients
 164   chan:&:channel:_elem <- get *in, chan:offset
@@ -236,7 +236,7 @@ if ('onhashchange' in window) {
 172 scenario channel-initialization [
 173   run [
 174   ¦ local-scope
-175   ¦ source:&:source:num <- new-channel 3/capacity
+175   ¦ source:&:source:num <- new-channel 3/capacity
 176   ¦ chan:&:channel:num <- get *source, chan:offset
 177   ¦ 10:num/raw <- get *chan, first-full:offset
 178   ¦ 11:num/raw <- get *chan, first-free:offset
@@ -249,9 +249,9 @@ if ('onhashchange' in window) {
 185 
 186 scenario channel-write-increments-free [
 187   local-scope
-188   _, sink:&:sink:num <- new-channel 3/capacity
+188   _, sink:&:sink:num <- new-channel 3/capacity
 189   run [
-190   ¦ sink <- write sink, 34
+190   ¦ sink <- write sink, 34
 191   ¦ chan:&:channel:num <- get *sink, chan:offset
 192   ¦ 10:num/raw <- get *chan, first-full:offset
 193   ¦ 11:num/raw <- get *chan, first-free:offset
@@ -264,10 +264,10 @@ if ('onhashchange' in window) {
 200 
 201 scenario channel-read-increments-full [
 202   local-scope
-203   source:&:source:num, sink:&:sink:num <- new-channel 3/capacity
-204   sink <- write sink, 34
+203   source:&:source:num, sink:&:sink:num <- new-channel 3/capacity
+204   sink <- write sink, 34
 205   run [
-206   ¦ _, _, source <- read source
+206   ¦ _, _, source <- read source
 207   ¦ chan:&:channel:num <- get *source, chan:offset
 208   ¦ 10:num/raw <- get *chan, first-full:offset
 209   ¦ 11:num/raw <- get *chan, first-free:offset
@@ -281,20 +281,20 @@ if ('onhashchange' in window) {
 217 scenario channel-wrap [
 218   local-scope
 219   # channel with just 1 slot
-220   source:&:source:num, sink:&:sink:num <- new-channel 1/capacity
+220   source:&:source:num, sink:&:sink:num <- new-channel 1/capacity
 221   chan:&:channel:num <- get *source, chan:offset
 222   # write and read a value
-223   sink <- write sink, 34
-224   _, _, source <- read source
+223   sink <- write sink, 34
+224   _, _, source <- read source
 225   run [
 226   ¦ # first-free will now be 1
 227   ¦ 10:num/raw <- get *chan, first-free:offset
 228   ¦ 11:num/raw <- get *chan, first-free:offset
 229   ¦ # write second value, verify that first-free wraps
-230   ¦ sink <- write sink, 34
+230   ¦ sink <- write sink, 34
 231   ¦ 20:num/raw <- get *chan, first-free:offset
 232   ¦ # read second value, verify that first-full wraps
-233   ¦ _, _, source <- read source
+233   ¦ _, _, source <- read source
 234   ¦ 30:num/raw <- get *chan, first-full:offset
 235   ]
 236   memory-should-contain [
@@ -308,7 +308,7 @@ if ('onhashchange' in window) {
 244 scenario channel-new-empty-not-full [
 245   run [
 246   ¦ local-scope
-247   ¦ source:&:source:num <- new-channel 3/capacity
+247   ¦ source:&:source:num <- new-channel 3/capacity
 248   ¦ chan:&:channel:num <- get *source, chan:offset
 249   ¦ 10:bool/raw <- channel-empty? chan
 250   ¦ 11:bool/raw <- channel-full? chan
@@ -321,10 +321,10 @@ if ('onhashchange' in window) {
 257 
 258 scenario channel-write-not-empty [
 259   local-scope
-260   source:&:source:num, sink:&:sink:num <- new-channel 3/capacity
+260   source:&:source:num, sink:&:sink:num <- new-channel 3/capacity
 261   chan:&:channel:num <- get *source, chan:offset
 262   run [
-263   ¦ sink <- write sink, 34
+263   ¦ sink <- write sink, 34
 264   ¦ 10:bool/raw <- channel-empty? chan
 265   ¦ 11:bool/raw <- channel-full? chan
 266   ]
@@ -336,10 +336,10 @@ if ('onhashchange' in window) {
 272 
 273 scenario channel-write-full [
 274   local-scope
-275   source:&:source:num, sink:&:sink:num <- new-channel 1/capacity
+275   source:&:source:num, sink:&:sink:num <- new-channel 1/capacity
 276   chan:&:channel:num <- get *source, chan:offset
 277   run [
-278   ¦ sink <- write sink, 34
+278   ¦ sink <- write sink, 34
 279   ¦ 10:bool/raw <- channel-empty? chan
 280   ¦ 11:bool/raw <- channel-full? chan
 281   ]
@@ -351,11 +351,11 @@ if ('onhashchange' in window) {
 287 
 288 scenario channel-read-not-full [
 289   local-scope
-290   source:&:source:num, sink:&:sink:num <- new-channel 1/capacity
+290   source:&:source:num, sink:&:sink:num <- new-channel 1/capacity
 291   chan:&:channel:num <- get *source, chan:offset
-292   sink <- write sink, 34
+292   sink <- write sink, 34
 293   run [
-294   ¦ _, _, source <- read source
+294   ¦ _, _, source <- read source
 295   ¦ 10:bool/raw <- channel-empty? chan
 296   ¦ 11:bool/raw <- channel-full? chan
 297   ]
@@ -375,13 +375,13 @@ if ('onhashchange' in window) {
 311 
 312 # a channel can be closed from either the source or the sink
 313 # both routines can modify the 'closed?' bit, but they can only ever set it, so this is a benign race
-314 def close x:&:source:_elem -> x:&:source:_elem [
+314 def close x:&:source:_elem -> x:&:source:_elem [
 315   local-scope
 316   load-ingredients
 317   chan:&:channel:_elem <- get *x, chan:offset
 318   *chan <- put *chan, closed?:offset, 1/true
 319 ]
-320 def close x:&:sink:_elem -> x:&:sink:_elem [
+320 def close x:&:sink:_elem -> x:&:sink:_elem [
 321   local-scope
 322   load-ingredients
 323   chan:&:channel:_elem <- get *x, chan:offset
@@ -449,13 +449,13 @@ if ('onhashchange' in window) {
 385 
 386 ## helpers for channels of characters in particular
 387 
-388 def buffer-lines in:&:source:char, buffered-out:&:sink:char -> buffered-out:&:sink:char, in:&:source:char [
+388 def buffer-lines in:&:source:char, buffered-out:&:sink:char -> buffered-out:&:sink:char, in:&:source:char [
 389   local-scope
 390   load-ingredients
 391   # repeat forever
 392   eof?:bool <- copy 0/false
 393   {
-394   ¦ line:&:buffer:char <- new-buffer 30
+394   ¦ line:&:buffer:char <- new-buffer 30
 395   ¦ # read characters from 'in' until newline, copy into line
 396   ¦ {
 397   ¦ ¦ +next-character
@@ -507,34 +507,34 @@ if ('onhashchange' in window) {
 443 scenario buffer-lines-blocks-until-newline [
 444   run [
 445   ¦ local-scope
-446   ¦ source:&:source:char, sink:&:sink:char <- new-channel 10/capacity
-447   ¦ _, buffered-stdin:&:sink:char/buffered-stdin <- new-channel 10/capacity
+446   ¦ source:&:source:char, sink:&:sink:char <- new-channel 10/capacity
+447   ¦ _, buffered-stdin:&:sink:char/buffered-stdin <- new-channel 10/capacity
 448   ¦ buffered-chan:&:channel:char <- get *buffered-stdin, chan:offset
 449   ¦ empty?:bool <- channel-empty? buffered-chan
 450   ¦ assert empty?, [ 
 451 F buffer-lines-blocks-until-newline: channel should be empty after init]
 452   ¦ # buffer stdin into buffered-stdin, try to read from buffered-stdin
-453   ¦ buffer-routine:num <- start-running buffer-lines, source, buffered-stdin
+453   ¦ buffer-routine:num <- start-running buffer-lines, source, buffered-stdin
 454   ¦ wait-for-routine-to-block buffer-routine
 455   ¦ empty? <- channel-empty? buffered-chan
 456   ¦ assert empty?:bool, [ 
 457 F buffer-lines-blocks-until-newline: channel should be empty after buffer-lines bring-up]
 458   ¦ # write 'a'
-459   ¦ sink <- write sink, 97/a
+459   ¦ sink <- write sink, 97/a
 460   ¦ restart buffer-routine
 461   ¦ wait-for-routine-to-block buffer-routine
 462   ¦ empty? <- channel-empty? buffered-chan
 463   ¦ assert empty?:bool, [ 
 464 F buffer-lines-blocks-until-newline: channel should be empty after writing 'a']
 465   ¦ # write 'b'
-466   ¦ sink <- write sink, 98/b
+466   ¦ sink <- write sink, 98/b
 467   ¦ restart buffer-routine
 468   ¦ wait-for-routine-to-block buffer-routine
 469   ¦ empty? <- channel-empty? buffered-chan
 470   ¦ assert empty?:bool, [ 
 471 F buffer-lines-blocks-until-newline: channel should be empty after writing 'b']
 472   ¦ # write newline
-473   ¦ sink <- write sink, 10/newline
+473   ¦ sink <- write sink, 10/newline
 474   ¦ restart buffer-routine
 475   ¦ wait-for-routine-to-block buffer-routine
 476   ¦ empty? <- channel-empty? buffered-chan
@@ -548,12 +548,12 @@ if ('onhashchange' in window) {
 484   ]
 485 ]
 486 
-487 def drain source:&:source:char -> result:text, source:&:source:char [
+487 def drain source:&:source:char -> result:text, source:&:source:char [
 488   local-scope
 489   load-ingredients
-490   buf:&:buffer:char <- new-buffer 30
+490   buf:&:buffer:char <- new-buffer 30
 491   {
-492   ¦ c:char, done?:bool <- read source
+492   ¦ c:char, done?:bool <- read source
 493   ¦ break-if done?
 494   ¦ buf <- append buf, c
 495   ¦ loop
diff --git a/html/084console.mu.html b/html/084console.mu.html
index 49937f4c..16712057 100644
--- a/html/084console.mu.html
+++ b/html/084console.mu.html
@@ -131,7 +131,7 @@ if ('onhashchange' in window) {
  70   return c, 1/found, 0/quit
  71 ]
  72 
- 73 def send-keys-to-channel console:&:console, chan:&:sink:char, screen:&:screen -> console:&:console, chan:&:sink:char, screen:&:screen [
+ 73 def send-keys-to-channel console:&:console, chan:&:sink:char, screen:&:screen -> console:&:console, chan:&:sink:char, screen:&:screen [
  74   local-scope
  75   load-ingredients
  76   {
diff --git a/html/088file.mu.html b/html/088file.mu.html
index 794e9592..42c94671 100644
--- a/html/088file.mu.html
+++ b/html/088file.mu.html
@@ -79,7 +79,7 @@ if ('onhashchange' in window) {
  18   contents:text
  19 ]
  20 
- 21 def start-reading resources:&:resources, filename:text -> contents:&:source:char, error?:bool [
+ 21 def start-reading resources:&:resources, filename:text -> contents:&:source:char, error?:bool [
  22   local-scope
  23   load-ingredients
  24   error? <- copy 0/false
@@ -92,18 +92,18 @@ if ('onhashchange' in window) {
  31   # real file system
  32   file:num <- $open-file-for-reading filename
  33   return-unless file, 0/contents, 1/error?
- 34   contents:&:source:char, sink:&:sink:char <- new-channel 30
- 35   start-running receive-from-file file, sink
+ 34   contents:&:source:char, sink:&:sink:char <- new-channel 30
+ 35   start-running receive-from-file file, sink
  36 ]
  37 
  38 def slurp resources:&:resources, filename:text -> contents:text, error?:bool [
  39   local-scope
  40   load-ingredients
- 41   source:&:source:char, error?:bool <- start-reading resources, filename
+ 41   source:&:source:char, error?:bool <- start-reading resources, filename
  42   return-if error?, 0/contents
- 43   buf:&:buffer:char <- new-buffer 30/capacity
+ 43   buf:&:buffer:char <- new-buffer 30/capacity
  44   {
- 45   ¦ c:char, done?:bool, source <- read source
+ 45   ¦ c:char, done?:bool, source <- read source
  46   ¦ break-if done?
  47   ¦ buf <- append buf, c
  48   ¦ loop
@@ -111,7 +111,7 @@ if ('onhashchange' in window) {
  50   contents <- buffer-to-array buf
  51 ]
  52 
- 53 def start-reading-from-fake-resource resources:&:resources, resource:text -> contents:&:source:char, error?:bool [
+ 53 def start-reading-from-fake-resource resources:&:resources, resource:text -> contents:&:source:char, error?:bool [
  54   local-scope
  55   load-ingredients
  56   error? <- copy 0/no-error
@@ -126,28 +126,28 @@ if ('onhashchange' in window) {
  65   ¦ curr-resource:text <- get tmp, name:offset
  66   ¦ found?:bool <- equal resource, curr-resource
  67   ¦ loop-unless found?
- 68   ¦ contents:&:source:char, sink:&:sink:char <- new-channel 30
+ 68   ¦ contents:&:source:char, sink:&:sink:char <- new-channel 30
  69   ¦ curr-contents:text <- get tmp, contents:offset
- 70   ¦ start-running receive-from-text curr-contents, sink
+ 70   ¦ start-running receive-from-text curr-contents, sink
  71   ¦ return
  72   }
  73   return 0/not-found, 1/error
  74 ]
  75 
- 76 def receive-from-file file:num, sink:&:sink:char -> sink:&:sink:char [
+ 76 def receive-from-file file:num, sink:&:sink:char -> sink:&:sink:char [
  77   local-scope
  78   load-ingredients
  79   {
  80   ¦ c:char, eof?:bool <- $read-from-file file
  81   ¦ break-if eof?
- 82   ¦ sink <- write sink, c
+ 82   ¦ sink <- write sink, c
  83   ¦ loop
  84   }
- 85   sink <- close sink
+ 85   sink <- close sink
  86   file <- $close-file file
  87 ]
  88 
- 89 def receive-from-text contents:text, sink:&:sink:char -> sink:&:sink:char [
+ 89 def receive-from-text contents:text, sink:&:sink:char -> sink:&:sink:char [
  90   local-scope
  91   load-ingredients
  92   i:num <- copy 0
@@ -156,22 +156,22 @@ if ('onhashchange' in window) {
  95   ¦ done?:bool <- greater-or-equal i, len
  96   ¦ break-if done?
  97   ¦ c:char <- index *contents, i
- 98   ¦ sink <- write sink, c
+ 98   ¦ sink <- write sink, c
  99   ¦ i <- add i, 1
 100   ¦ loop
 101   }
-102   sink <- close sink
+102   sink <- close sink
 103 ]
 104 
-105 def start-writing resources:&:resources, filename:text -> sink:&:sink:char, routine-id:num, error?:bool [
+105 def start-writing resources:&:resources, filename:text -> sink:&:sink:char, routine-id:num, error?:bool [
 106   local-scope
 107   load-ingredients
 108   error? <- copy 0/false
-109   source:&:source:char, sink:&:sink:char <- new-channel 30
+109   source:&:source:char, sink:&:sink:char <- new-channel 30
 110   {
 111   ¦ break-unless resources
 112   ¦ # fake file system
-113   ¦ routine-id <- start-running transmit-to-fake-resource resources, filename, source
+113   ¦ routine-id <- start-running transmit-to-fake-resource resources, filename, source
 114   ¦ return
 115   }
 116   # real file system
@@ -182,7 +182,7 @@ if ('onhashchange' in window) {
 121   ¦ msg:text <- append [no such file: ] filename
 122   ¦ assert file, msg
 123   }
-124   routine-id <- start-running transmit-to-file file, source
+124   routine-id <- start-running transmit-to-file file, source
 125 ]
 126 
 127 def dump resources:&:resources, filename:text, contents:text -> resources:&:resources, error?:bool [
@@ -190,7 +190,7 @@ if ('onhashchange' in window) {
 129   load-ingredients
 130   # todo: really create an empty file
 131   return-unless contents, resources, 0/no-error
-132   sink-file:&:sink:char, write-routine:num, error?:bool <- start-writing resources, filename
+132   sink-file:&:sink:char, write-routine:num, error?:bool <- start-writing resources, filename
 133   return-if error?
 134   i:num <- copy 0
 135   len:num <- length *contents
@@ -208,11 +208,11 @@ if ('onhashchange' in window) {
 147   wait-for-routine write-routine
 148 ]
 149 
-150 def transmit-to-file file:num, source:&:source:char -> source:&:source:char [
+150 def transmit-to-file file:num, source:&:source:char -> source:&:source:char [
 151   local-scope
 152   load-ingredients
 153   {
-154   ¦ c:char, done?:bool, source <- read source
+154   ¦ c:char, done?:bool, source <- read source
 155   ¦ break-if done?
 156   ¦ $write-to-file file, c
 157   ¦ loop
@@ -220,15 +220,15 @@ if ('onhashchange' in window) {
 159   file <- $close-file file
 160 ]
 161 
-162 def transmit-to-fake-resource resources:&:resources, filename:text, source:&:source:char -> resources:&:resources, source:&:source:char [
+162 def transmit-to-fake-resource resources:&:resources, filename:text, source:&:source:char -> resources:&:resources, source:&:source:char [
 163   local-scope
 164   load-ingredients
 165   lock:location <- get-location *resources, lock:offset
 166   wait-for-reset-then-set lock
 167   # compute new file contents
-168   buf:&:buffer:char <- new-buffer 30
+168   buf:&:buffer:char <- new-buffer 30
 169   {
-170   ¦ c:char, done?:bool, source <- read source
+170   ¦ c:char, done?:bool, source <- read source
 171   ¦ break-if done?
 172   ¦ buf <- append buf, c
 173   ¦ loop
diff --git a/html/090scenario_filesystem_test.mu.html b/html/090scenario_filesystem_test.mu.html
index 1fb26361..43f6a5e8 100644
--- a/html/090scenario_filesystem_test.mu.html
+++ b/html/090scenario_filesystem_test.mu.html
@@ -65,7 +65,7 @@ if ('onhashchange' in window) {
  7   ¦ ¦ |xyz|
  8   ¦ ]
  9   ]
-10   contents:&:source:char <- start-reading resources, [a]
+10   contents:&:source:char <- start-reading resources, [a]
 11   1:char/raw <- read contents
 12   2:char/raw <- read contents
 13   3:char/raw <- read contents
@@ -84,10 +84,10 @@ if ('onhashchange' in window) {
 26   local-scope
 27   assume-resources [
 28   ]
-29   sink:&:sink:char, writer:num/routine <- start-writing resources, [a]
-30   sink <- write sink, 120/x
-31   sink <- write sink, 121/y
-32   close sink
+29   sink:&:sink:char, writer:num/routine <- start-writing resources, [a]
+30   sink <- write sink, 120/x
+31   sink <- write sink, 121/y
+32   close sink
 33   wait-for-routine writer
 34   contents-read-back:text <- slurp resources, [a]
 35   10:bool/raw <- equal contents-read-back, [xy]
@@ -103,10 +103,10 @@ if ('onhashchange' in window) {
 45   ¦ ¦ |abc|
 46   ¦ ]
 47   ]
-48   sink:&:sink:char, writer:num/routine <- start-writing resources, [b]
-49   sink <- write sink, 120/x
-50   sink <- write sink, 121/y
-51   close sink
+48   sink:&:sink:char, writer:num/routine <- start-writing resources, [b]
+49   sink <- write sink, 120/x
+50   sink <- write sink, 121/y
+51   close sink
 52   wait-for-routine writer
 53   contents-read-back:text <- slurp resources, [b]
 54   10:bool/raw <- equal contents-read-back, [xy]
@@ -120,10 +120,10 @@ if ('onhashchange' in window) {
 62   assume-resources [
 63   ¦ [a] <- []
 64   ]
-65   sink:&:sink:char, writer:num/routine <- start-writing resources, [a]
-66   sink <- write sink, 120/x
-67   sink <- write sink, 121/y
-68   close sink
+65   sink:&:sink:char, writer:num/routine <- start-writing resources, [a]
+66   sink <- write sink, 120/x
+67   sink <- write sink, 121/y
+68   close sink
 69   wait-for-routine writer
 70   contents-read-back:text <- slurp resources, [a]
 71   10:bool/raw <- equal contents-read-back, [xy]
@@ -140,10 +140,10 @@ if ('onhashchange' in window) {
 82   ¦ ¦ |bcd|
 83   ¦ ]
 84   ]
-85   sink:&:sink:char, writer:num/routine <- start-writing resources, [a]
-86   sink <- write sink, 120/x
-87   sink <- write sink, 121/y
-88   close sink
+85   sink:&:sink:char, writer:num/routine <- start-writing resources, [a]
+86   sink <- write sink, 120/x
+87   sink <- write sink, 121/y
+88   close sink
 89   wait-for-routine writer
 90   contents-read-back:text <- slurp resources, [a]
 91   10:bool/raw <- equal contents-read-back, [xy]
diff --git a/html/092socket.mu.html b/html/092socket.mu.html
index fc6e3b0f..7fd3f9c6 100644
--- a/html/092socket.mu.html
+++ b/html/092socket.mu.html
@@ -76,8 +76,8 @@ if ('onhashchange' in window) {
  14 F - example-server-test: $open-server-socket failed]
  15   ¦ handler-routine:number <- start-running serve-one-request socket, example-handler
  16   ]
- 17   source:&:source:char <- start-reading-from-network 0/real-resources, [localhost/], port
- 18   response:text <- drain source
+ 17   source:&:source:char <- start-reading-from-network 0/real-resources, [localhost/], port
+ 18   response:text <- drain source
  19   10:@:char/raw <- copy *response
  20   memory-should-contain [
  21   ¦ 10:array:character <- [abc]
@@ -102,9 +102,9 @@ if ('onhashchange' in window) {
  40   ¦ ]
  41   ]
  42   run [
- 43   ¦ source:&:source:char <- start-reading-from-network resources, [example.com/]
+ 43   ¦ source:&:source:char <- start-reading-from-network resources, [example.com/]
  44   ]
- 45   contents:text <- drain source
+ 45   contents:text <- drain source
  46   10:@:char/raw <- copy *contents
  47   memory-should-contain [
  48   ¦ 10:array:character <- [abc
@@ -120,15 +120,15 @@ if ('onhashchange' in window) {
  58   session:num <- $accept socket
  59   assert session, [ 
  60 F - example-server-test: $accept failed]
- 61   contents:&:source:char, sink:&:sink:char <- new-channel 30
- 62   start-running receive-from-socket session, sink
+ 61   contents:&:source:char, sink:&:sink:char <- new-channel 30
+ 62   start-running receive-from-socket session, sink
  63   query:text <- drain contents
  64   response:text <- call request-handler, query
  65   write-to-socket session, response
  66   session <- $close-socket session
  67 ]
  68 
- 69 def start-reading-from-network resources:&:resources, uri:text -> contents:&:source:char [
+ 69 def start-reading-from-network resources:&:resources, uri:text -> contents:&:source:char [
  70   local-scope
  71   load-ingredients
  72   {
@@ -148,8 +148,8 @@ if ('onhashchange' in window) {
  86   assert socket, [contents]
  87   req:text <- interpolate [GET _ HTTP/1.1], path
  88   request-socket socket, req
- 89   contents:&:source:char, sink:&:sink:char <- new-channel 10000
- 90   start-running receive-from-client-socket-and-close socket, sink
+ 89   contents:&:source:char, sink:&:sink:char <- new-channel 10000
+ 90   start-running receive-from-client-socket-and-close socket, sink
  91 ]
  92 
  93 def request-socket socket:num, s:text -> socket:num [
@@ -163,7 +163,7 @@ if ('onhashchange' in window) {
 101   $write-to-socket socket, 10/lf
 102 ]
 103 
-104 def receive-from-socket socket:num, sink:&:sink:char -> sink:&:sink:char, socket:num [
+104 def receive-from-socket socket:num, sink:&:sink:char -> sink:&:sink:char, socket:num [
 105   local-scope
 106   load-ingredients
 107   {
@@ -173,7 +173,7 @@ if ('onhashchange' in window) {
 111   ¦ break-if error
 112   ¦ {
 113   ¦ ¦ break-unless found?
-114   ¦ ¦ sink <- write sink, c
+114   ¦ ¦ sink <- write sink, c
 115   ¦ }
 116   ¦ {
 117   ¦ ¦ break-if found?
@@ -181,13 +181,13 @@ if ('onhashchange' in window) {
 119   ¦ }
 120   ¦ loop
 121   }
-122   sink <- close sink
+122   sink <- close sink
 123 ]
 124 
-125 def receive-from-client-socket-and-close socket:num, sink:&:sink:char -> sink:&:sink:char, socket:num [
+125 def receive-from-client-socket-and-close socket:num, sink:&:sink:char -> sink:&:sink:char, socket:num [
 126   local-scope
 127   load-ingredients
-128   sink <- receive-from-socket socket, sink
+128   sink <- receive-from-socket socket, sink
 129   socket <- $close-socket socket
 130 ]
 131 
diff --git a/html/channel.mu.html b/html/channel.mu.html
index bc5b1141..bb0808f1 100644
--- a/html/channel.mu.html
+++ b/html/channel.mu.html
@@ -60,7 +60,7 @@ if ('onhashchange' in window) {
 
  1 # example program: communicating between routines using channels
  2 
- 3 def producer sink:&:sink:char -> sink:&:sink:char [
+ 3 def producer sink:&:sink:char -> sink:&:sink:char [
  4   # produce characters 1 to 5 on a channel
  5   local-scope
  6   load-ingredients
@@ -72,20 +72,20 @@ if ('onhashchange' in window) {
 12   ¦ # other threads might get between these prints
 13   ¦ $print [produce: ], n, [ 
 14 ]
-15   ¦ sink <- write sink, n
+15   ¦ sink <- write sink, n
 16   ¦ n <- add n, 1
 17   ¦ loop
 18   }
-19   close sink
+19   close sink
 20 ]
 21 
-22 def consumer source:&:source:char -> source:&:source:char [
+22 def consumer source:&:source:char -> source:&:source:char [
 23   # consume and print integers from a channel
 24   local-scope
 25   load-ingredients
 26   {
 27   ¦ # read an integer from the channel
-28   ¦ n:char, eof?:bool, source <- read source
+28   ¦ n:char, eof?:bool, source <- read source
 29   ¦ break-if eof?
 30   ¦ # other threads might get between these prints
 31   ¦ $print [consume: ], n:char, [ 
@@ -96,10 +96,10 @@ if ('onhashchange' in window) {
 36 
 37 def main [
 38   local-scope
-39   source:&:source:char, sink:&:sink:char <- new-channel 3/capacity
+39   source:&:source:char, sink:&:sink:char <- new-channel 3/capacity
 40   # create two background 'routines' that communicate by a channel
-41   routine1:num <- start-running producer, sink
-42   routine2:num <- start-running consumer, source
+41   routine1:num <- start-running producer, sink
+42   routine2:num <- start-running consumer, source
 43   wait-for-routine routine1
 44   wait-for-routine routine2
 45 ]
diff --git a/html/chessboard.mu.html b/html/chessboard.mu.html
index a598c8f7..7129dfea 100644
--- a/html/chessboard.mu.html
+++ b/html/chessboard.mu.html
@@ -134,10 +134,10 @@ if ('onhashchange' in window) {
  70   load-ingredients
  71   board:board <- initial-position
  72   # hook up stdin
- 73   stdin-in:&:source:char, stdin-out:&:sink:char <- new-channel 10/capacity
+ 73   stdin-in:&:source:char, stdin-out:&:sink:char <- new-channel 10/capacity
  74   start-running send-keys-to-channel, console, stdin-out, screen
  75   # buffer lines in stdin
- 76   buffered-stdin-in:&:source:char, buffered-stdin-out:&:sink:char <- new-channel 10/capacity
+ 76   buffered-stdin-in:&:source:char, buffered-stdin-out:&:sink:char <- new-channel 10/capacity
  77   start-running buffer-lines, stdin-in, buffered-stdin-out
  78   {
  79   ¦ print screen, [Stupid text-mode chessboard. White pieces in uppercase; black pieces in lowercase. No checking for legal moves.
@@ -298,7 +298,7 @@ if ('onhashchange' in window) {
 234 ]
 235 
 236 # prints only error messages to screen
-237 def read-move stdin:&:source:char, screen:&:screen -> result:&:move, quit?:bool, error?:bool, stdin:&:source:char, screen:&:screen [
+237 def read-move stdin:&:source:char, screen:&:screen -> result:&:move, quit?:bool, error?:bool, stdin:&:source:char, screen:&:screen [
 238   local-scope
 239   load-ingredients
 240   from-file:num, quit?:bool, error?:bool <- read-file stdin, screen
@@ -326,7 +326,7 @@ if ('onhashchange' in window) {
 262 ]
 263 
 264 # valid values for file: 0-7
-265 def read-file stdin:&:source:char, screen:&:screen -> file:num, quit:bool, error:bool, stdin:&:source:char, screen:&:screen [
+265 def read-file stdin:&:source:char, screen:&:screen -> file:num, quit:bool, error:bool, stdin:&:source:char, screen:&:screen [
 266   local-scope
 267   load-ingredients
 268   c:char, eof?:bool, stdin <- read stdin
@@ -373,7 +373,7 @@ if ('onhashchange' in window) {
 309 ]
 310 
 311 # valid values for rank: 0-7
-312 def read-rank stdin:&:source:char, screen:&:screen -> rank:num, quit?:bool, error?:bool, stdin:&:source:char, screen:&:screen [
+312 def read-rank stdin:&:source:char, screen:&:screen -> rank:num, quit?:bool, error?:bool, stdin:&:source:char, screen:&:screen [
 313   local-scope
 314   load-ingredients
 315   c:char, eof?:bool, stdin <- read stdin
@@ -415,7 +415,7 @@ if ('onhashchange' in window) {
 351 
 352 # read a character from the given channel and check that it's what we expect
 353 # return true on error
-354 def expect-from-channel stdin:&:source:char, expected:char, screen:&:screen -> result:bool, stdin:&:source:char, screen:&:screen [
+354 def expect-from-channel stdin:&:source:char, expected:char, screen:&:screen -> result:bool, stdin:&:source:char, screen:&:screen [
 355   local-scope
 356   load-ingredients
 357   c:char, eof?:bool, stdin <- read stdin
@@ -431,8 +431,8 @@ if ('onhashchange' in window) {
 367 scenario read-move-blocking [
 368   local-scope
 369   assume-screen 20/width, 2/height
-370   source:&:source:char, sink:&:sink:char <- new-channel 2/capacity
-371   read-move-routine:num/routine <- start-running read-move, source, screen:&:screen
+370   source:&:source:char, sink:&:sink:char <- new-channel 2/capacity
+371   read-move-routine:num/routine <- start-running read-move, source, screen:&:screen
 372   run [
 373   ¦ # 'read-move' is waiting for input
 374   ¦ wait-for-routine-to-block read-move-routine
@@ -441,7 +441,7 @@ if ('onhashchange' in window) {
 377   ¦ assert waiting?, [ 
 378 F read-move-blocking: routine failed to pause after coming up (before any keys were pressed)]
 379   ¦ # press 'a'
-380   ¦ sink <- write sink, 97/a
+380   ¦ sink <- write sink, 97/a
 381   ¦ restart read-move-routine
 382   ¦ # 'read-move' still waiting for input
 383   ¦ wait-for-routine-to-block read-move-routine
@@ -450,7 +450,7 @@ if ('onhashchange' in window) {
 386   ¦ assert waiting?, [ 
 387 F read-move-blocking: routine failed to pause after rank 'a']
 388   ¦ # press '2'
-389   ¦ sink <- write sink, 50/'2'
+389   ¦ sink <- write sink, 50/'2'
 390   ¦ restart read-move-routine
 391   ¦ # 'read-move' still waiting for input
 392   ¦ wait-for-routine-to-block read-move-routine
@@ -459,7 +459,7 @@ if ('onhashchange' in window) {
 395   ¦ assert waiting?, [ 
 396 F read-move-blocking: routine failed to pause after file 'a2']
 397   ¦ # press '-'
-398   ¦ sink <- write sink, 45/'-'
+398   ¦ sink <- write sink, 45/'-'
 399   ¦ restart read-move-routine
 400   ¦ # 'read-move' still waiting for input
 401   ¦ wait-for-routine-to-block read-move-routine
@@ -468,7 +468,7 @@ if ('onhashchange' in window) {
 404   ¦ assert waiting?, [ 
 405 F read-move-blocking: routine failed to pause after hyphen 'a2-']
 406   ¦ # press 'a'
-407   ¦ sink <- write sink, 97/a
+407   ¦ sink <- write sink, 97/a
 408   ¦ restart read-move-routine
 409   ¦ # 'read-move' still waiting for input
 410   ¦ wait-for-routine-to-block read-move-routine
@@ -477,7 +477,7 @@ if ('onhashchange' in window) {
 413   ¦ assert waiting?, [ 
 414 F read-move-blocking: routine failed to pause after rank 'a2-a']
 415   ¦ # press '4'
-416   ¦ sink <- write sink, 52/'4'
+416   ¦ sink <- write sink, 52/'4'
 417   ¦ restart read-move-routine
 418   ¦ # 'read-move' still waiting for input
 419   ¦ wait-for-routine-to-block read-move-routine
@@ -486,7 +486,7 @@ if ('onhashchange' in window) {
 422   ¦ assert waiting?, [ 
 423 F read-move-blocking: routine failed to pause after file 'a2-a4']
 424   ¦ # press 'newline'
-425   ¦ sink <- write sink, 10  # newline
+425   ¦ sink <- write sink, 10  # newline
 426   ¦ restart read-move-routine
 427   ¦ # 'read-move' now completes
 428   ¦ wait-for-routine-to-block read-move-routine
@@ -504,8 +504,8 @@ if ('onhashchange' in window) {
 440 scenario read-move-quit [
 441   local-scope
 442   assume-screen 20/width, 2/height
-443   source:&:source:char, sink:&:sink:char <- new-channel 2/capacity
-444   read-move-routine:num <- start-running read-move, source, screen:&:screen
+443   source:&:source:char, sink:&:sink:char <- new-channel 2/capacity
+444   read-move-routine:num <- start-running read-move, source, screen:&:screen
 445   run [
 446   ¦ # 'read-move' is waiting for input
 447   ¦ wait-for-routine-to-block read-move-routine
@@ -514,7 +514,7 @@ if ('onhashchange' in window) {
 450   ¦ assert waiting?, [ 
 451 F read-move-quit: routine failed to pause after coming up (before any keys were pressed)]
 452   ¦ # press 'q'
-453   ¦ sink <- write sink, 113/q
+453   ¦ sink <- write sink, 113/q
 454   ¦ restart read-move-routine
 455   ¦ # 'read-move' completes
 456   ¦ wait-for-routine-to-block read-move-routine
@@ -532,8 +532,8 @@ if ('onhashchange' in window) {
 468 scenario read-move-illegal-file [
 469   local-scope
 470   assume-screen 20/width, 2/height
-471   source:&:source:char, sink:&:sink:char <- new-channel 2/capacity
-472   read-move-routine:num <- start-running read-move, source, screen:&:screen
+471   source:&:source:char, sink:&:sink:char <- new-channel 2/capacity
+472   read-move-routine:num <- start-running read-move, source, screen:&:screen
 473   run [
 474   ¦ # 'read-move' is waiting for input
 475   ¦ wait-for-routine-to-block read-move-routine
@@ -541,7 +541,7 @@ if ('onhashchange' in window) {
 477   ¦ waiting?:bool <- not-equal read-move-state, 2/discontinued
 478   ¦ assert waiting?, [ 
 479 F read-move-illegal-file: routine failed to pause after coming up (before any keys were pressed)]
-480   ¦ sink <- write sink, 50/'2'
+480   ¦ sink <- write sink, 50/'2'
 481   ¦ restart read-move-routine
 482   ¦ wait-for-routine-to-block read-move-routine
 483   ]
@@ -554,8 +554,8 @@ if ('onhashchange' in window) {
 490 scenario read-move-illegal-rank [
 491   local-scope
 492   assume-screen 20/width, 2/height
-493   source:&:source:char, sink:&:sink:char <- new-channel 2/capacity
-494   read-move-routine:num <- start-running read-move, source, screen:&:screen
+493   source:&:source:char, sink:&:sink:char <- new-channel 2/capacity
+494   read-move-routine:num <- start-running read-move, source, screen:&:screen
 495   run [
 496   ¦ # 'read-move' is waiting for input
 497   ¦ wait-for-routine-to-block read-move-routine
@@ -563,8 +563,8 @@ if ('onhashchange' in window) {
 499   ¦ waiting?:bool <- not-equal read-move-state, 2/discontinued
 500   ¦ assert waiting?, [ 
 501 F read-move-illegal-rank: routine failed to pause after coming up (before any keys were pressed)]
-502   ¦ sink <- write sink, 97/a
-503   ¦ sink <- write sink, 97/a
+502   ¦ sink <- write sink, 97/a
+503   ¦ sink <- write sink, 97/a
 504   ¦ restart read-move-routine
 505   ¦ wait-for-routine-to-block read-move-routine
 506   ]
@@ -577,8 +577,8 @@ if ('onhashchange' in window) {
 513 scenario read-move-empty [
 514   local-scope
 515   assume-screen 20/width, 2/height
-516   source:&:source:char, sink:&:sink:char <- new-channel 2/capacity
-517   read-move-routine:num <- start-running read-move, source, screen:&:screen
+516   source:&:source:char, sink:&:sink:char <- new-channel 2/capacity
+517   read-move-routine:num <- start-running read-move, source, screen:&:screen
 518   run [
 519   ¦ # 'read-move' is waiting for input
 520   ¦ wait-for-routine-to-block read-move-routine
@@ -586,8 +586,8 @@ if ('onhashchange' in window) {
 522   ¦ waiting?:bool <- not-equal read-move-state, 2/discontinued
 523   ¦ assert waiting?, [ 
 524 F read-move-empty: routine failed to pause after coming up (before any keys were pressed)]
-525   ¦ sink <- write sink, 10/newline
-526   ¦ sink <- write sink, 97/a
+525   ¦ sink <- write sink, 10/newline
+526   ¦ sink <- write sink, 97/a
 527   ¦ restart read-move-routine
 528   ¦ wait-for-routine-to-block read-move-routine
 529   ]
diff --git a/html/edit/001-editor.mu.html b/html/edit/001-editor.mu.html
index f9282fcc..14307ec2 100644
--- a/html/edit/001-editor.mu.html
+++ b/html/edit/001-editor.mu.html
@@ -92,11 +92,11 @@ if ('onhashchange' in window) {
  29 
  30 container editor [
  31   # editable text: doubly linked list of characters (head contains a special sentinel)
- 32   data:&:duplex-list:char
- 33   top-of-screen:&:duplex-list:char
- 34   bottom-of-screen:&:duplex-list:char
+ 32   data:&:duplex-list:char
+ 33   top-of-screen:&:duplex-list:char
+ 34   bottom-of-screen:&:duplex-list:char
  35   # location before cursor inside data
- 36   before-cursor:&:duplex-list:char
+ 36   before-cursor:&:duplex-list:char
  37 
  38   # raw bounds of display area on screen
  39   # always displays from row 1 (leaving row 0 for a menu) and at most until bottom of screen
@@ -123,7 +123,7 @@ if ('onhashchange' in window) {
  60   *result <- put *result, cursor-row:offset, 1/top
  61   *result <- put *result, cursor-column:offset, left
  62   # initialize empty contents
- 63   init:&:duplex-list:char <- push 167/§, 0/tail
+ 63   init:&:duplex-list:char <- push 167/§, 0/tail
  64   *result <- put *result, data:offset, init
  65   *result <- put *result, top-of-screen:offset, init
  66   *result <- put *result, before-cursor:offset, init
@@ -140,7 +140,7 @@ if ('onhashchange' in window) {
  77   return-unless len
  78   idx:num <- copy 0
  79   # now we can start appending the rest, character by character
- 80   curr:&:duplex-list:char <- get *editor, data:offset
+ 80   curr:&:duplex-list:char <- get *editor, data:offset
  81   {
  82   ¦ done?:bool <- greater-or-equal idx, len
  83   ¦ break-if done?
@@ -189,8 +189,8 @@ if ('onhashchange' in window) {
 126   screen-height:num <- screen-height screen
 127   right:num <- get *editor, right:offset
 128   # traversing editor
-129   curr:&:duplex-list:char <- get *editor, top-of-screen:offset
-130   prev:&:duplex-list:char <- copy curr  # just in case curr becomes null and we can't compute prev
+129   curr:&:duplex-list:char <- get *editor, top-of-screen:offset
+130   prev:&:duplex-list:char <- copy curr  # just in case curr becomes null and we can't compute prev
 131   curr <- next curr
 132   # traversing screen
 133   color:num <- copy 7/white
@@ -198,7 +198,7 @@ if ('onhashchange' in window) {
 135   column:num <- copy left
 136   cursor-row:num <- get *editor, cursor-row:offset
 137   cursor-column:num <- get *editor, cursor-column:offset
-138   before-cursor:&:duplex-list:char <- get *editor, before-cursor:offset
+138   before-cursor:&:duplex-list:char <- get *editor, before-cursor:offset
 139   screen <- move-cursor screen, row, column
 140   {
 141   ¦ +next-character
diff --git a/html/edit/002-typing.mu.html b/html/edit/002-typing.mu.html
index 3b48c3cc..ad249e5c 100644
--- a/html/edit/002-typing.mu.html
+++ b/html/edit/002-typing.mu.html
@@ -141,8 +141,8 @@ if ('onhashchange' in window) {
   78   right:num <- get *editor, right:offset
   79   screen-height:num <- screen-height screen
   80   # count newlines until screen row
-  81   curr:&:duplex-list:char <- get *editor, top-of-screen:offset
-  82   prev:&:duplex-list:char <- copy curr  # just in case curr becomes null and we can't compute prev
+  81   curr:&:duplex-list:char <- get *editor, top-of-screen:offset
+  82   prev:&:duplex-list:char <- copy curr  # just in case curr becomes null and we can't compute prev
   83   curr <- next curr
   84   row:num <- copy 1/top
   85   column:num <- copy left
@@ -150,7 +150,7 @@ if ('onhashchange' in window) {
   87   cursor-row:num <- copy target-row
   88   *editor <- put *editor, cursor-column:offset, target-column
   89   cursor-column:num <- copy target-column
-  90   before-cursor:&:duplex-list:char <- get *editor, before-cursor:offset
+  90   before-cursor:&:duplex-list:char <- get *editor, before-cursor:offset
   91   {
   92   ¦ +next-character
   93   ¦ break-unless curr
@@ -232,7 +232,7 @@ if ('onhashchange' in window) {
  169   screen-height:num <- screen-height screen
  170   left:num <- get *editor, left:offset
  171   right:num <- get *editor, right:offset
- 172   before-cursor:&:duplex-list:char <- get *editor, before-cursor:offset
+ 172   before-cursor:&:duplex-list:char <- get *editor, before-cursor:offset
  173   cursor-row:num <- get *editor, cursor-row:offset
  174   cursor-column:num <- get *editor, cursor-column:offset
  175   save-row:num <- copy cursor-row
@@ -264,7 +264,7 @@ if ('onhashchange' in window) {
  201 def insert-at-cursor editor:&:editor, c:char, screen:&:screen -> go-render?:bool, editor:&:editor, screen:&:screen [
  202   local-scope
  203   load-ingredients
- 204   before-cursor:&:duplex-list:char <- get *editor, before-cursor:offset
+ 204   before-cursor:&:duplex-list:char <- get *editor, before-cursor:offset
  205   insert c, before-cursor
  206   before-cursor <- next before-cursor
  207   *editor <- put *editor, before-cursor:offset, before-cursor
@@ -281,7 +281,7 @@ if ('onhashchange' in window) {
  218   # but mostly we'll just move the cursor right
  219   cursor-column <- add cursor-column, 1
  220   *editor <- put *editor, cursor-column:offset, cursor-column
- 221   next:&:duplex-list:char <- next before-cursor
+ 221   next:&:duplex-list:char <- next before-cursor
  222   {
  223   ¦ # at end of all text? no need to scroll? just print the character and leave
  224   ¦ at-end?:bool <- equal next, 0/null
@@ -300,7 +300,7 @@ if ('onhashchange' in window) {
  237   ¦ break-unless next
  238   ¦ at-right?:bool <- greater-or-equal cursor-column, screen-width
  239   ¦ break-if at-right?
- 240   ¦ curr:&:duplex-list:char <- copy before-cursor
+ 240   ¦ curr:&:duplex-list:char <- copy before-cursor
  241   ¦ move-cursor screen, save-row, save-column
  242   ¦ curr-column:num <- copy save-column
  243   ¦ {
@@ -760,7 +760,7 @@ if ('onhashchange' in window) {
  697   ¦ before-wrap-column:num <- subtract wrap-column, 1
  698   ¦ at-wrap?:bool <- greater-or-equal cursor-column, wrap-column
  699   ¦ just-before-wrap?:bool <- greater-or-equal cursor-column, before-wrap-column
- 700   ¦ next:&:duplex-list:char <- next before-cursor
+ 700   ¦ next:&:duplex-list:char <- next before-cursor
  701   ¦ # at end of line? next == 0 || next.value == 10/newline
  702   ¦ at-end-of-line?:bool <- equal next, 0
  703   ¦ {
@@ -929,7 +929,7 @@ if ('onhashchange' in window) {
  866   load-ingredients
  867   cursor-row:num <- get *editor, cursor-row:offset
  868   cursor-column:num <- get *editor, cursor-column:offset
- 869   before-cursor:&:duplex-list:char <- get *editor, before-cursor:offset
+ 869   before-cursor:&:duplex-list:char <- get *editor, before-cursor:offset
  870   left:num <- get *editor, left:offset
  871   right:num <- get *editor, right:offset
  872   screen-height:num <- screen-height screen
@@ -952,8 +952,8 @@ if ('onhashchange' in window) {
  889   # indent if necessary
  890   indent?:bool <- get *editor, indent?:offset
  891   return-unless indent?
- 892   d:&:duplex-list:char <- get *editor, data:offset
- 893   end-of-previous-line:&:duplex-list:char <- prev before-cursor
+ 892   d:&:duplex-list:char <- get *editor, data:offset
+ 893   end-of-previous-line:&:duplex-list:char <- prev before-cursor
  894   indent:num <- line-indent end-of-previous-line, d
  895   i:num <- copy 0
  896   {
@@ -967,7 +967,7 @@ if ('onhashchange' in window) {
  904 
  905 # takes a pointer 'curr' into the doubly-linked list and its sentinel, counts
  906 # the number of spaces at the start of the line containing 'curr'.
- 907 def line-indent curr:&:duplex-list:char, start:&:duplex-list:char -> result:num [
+ 907 def line-indent curr:&:duplex-list:char, start:&:duplex-list:char -> result:num [
  908   local-scope
  909   load-ingredients
  910   result:num <- copy 0
diff --git a/html/edit/003-shortcuts.mu.html b/html/edit/003-shortcuts.mu.html
index c1fd5eca..83871010 100644
--- a/html/edit/003-shortcuts.mu.html
+++ b/html/edit/003-shortcuts.mu.html
@@ -133,7 +133,7 @@ if ('onhashchange' in window) {
   71   ¦ delete-previous-character?:bool <- equal c, 8/backspace
   72   ¦ break-unless delete-previous-character?
   73   ¦ <backspace-character-begin>
-  74   ¦ go-render?:bool, backspaced-cell:&:duplex-list:char <- delete-before-cursor editor, screen
+  74   ¦ go-render?:bool, backspaced-cell:&:duplex-list:char <- delete-before-cursor editor, screen
   75   ¦ <backspace-character-end>
   76   ¦ return
   77   }
@@ -142,18 +142,18 @@ if ('onhashchange' in window) {
   80 # return values:
   81 #   go-render? - whether caller needs to update the screen
   82 #   backspaced-cell - value deleted (or 0 if nothing was deleted) so we can save it for undo, etc.
-  83 def delete-before-cursor editor:&:editor, screen:&:screen -> go-render?:bool, backspaced-cell:&:duplex-list:char, editor:&:editor, screen:&:screen [
+  83 def delete-before-cursor editor:&:editor, screen:&:screen -> go-render?:bool, backspaced-cell:&:duplex-list:char, editor:&:editor, screen:&:screen [
   84   local-scope
   85   load-ingredients
-  86   before-cursor:&:duplex-list:char <- get *editor, before-cursor:offset
-  87   data:&:duplex-list:char <- get *editor, data:offset
+  86   before-cursor:&:duplex-list:char <- get *editor, before-cursor:offset
+  87   data:&:duplex-list:char <- get *editor, data:offset
   88   # if at start of text (before-cursor at § sentinel), return
-  89   prev:&:duplex-list:char <- prev before-cursor
+  89   prev:&:duplex-list:char <- prev before-cursor
   90   return-unless prev, 0/no-more-render, 0/nothing-deleted
   91   trace 10, [app], [delete-before-cursor]
   92   original-row:num <- get *editor, cursor-row:offset
   93   scroll?:bool <- move-cursor-coordinates-left editor
-  94   backspaced-cell:&:duplex-list:char <- copy before-cursor
+  94   backspaced-cell:&:duplex-list:char <- copy before-cursor
   95   data <- remove before-cursor, data  # will also neatly trim next/prev pointers in backspaced-cell/before-cursor
   96   before-cursor <- copy prev
   97   *editor <- put *editor, before-cursor:offset, before-cursor
@@ -166,7 +166,7 @@ if ('onhashchange' in window) {
  104   return-unless same-row?, 1/go-render
  105   left:num <- get *editor, left:offset
  106   right:num <- get *editor, right:offset
- 107   curr:&:duplex-list:char <- next before-cursor
+ 107   curr:&:duplex-list:char <- next before-cursor
  108   screen <- move-cursor screen, cursor-row, cursor-column
  109   curr-column:num <- copy cursor-column
  110   {
@@ -193,7 +193,7 @@ if ('onhashchange' in window) {
  131   local-scope
  132   load-ingredients
  133   go-render?:bool <- copy 0/false
- 134   before-cursor:&:duplex-list:char <- get *editor, before-cursor:offset
+ 134   before-cursor:&:duplex-list:char <- get *editor, before-cursor:offset
  135   cursor-row:num <- get *editor, cursor-row:offset
  136   cursor-column:num <- get *editor, cursor-column:offset
  137   left:num <- get *editor, left:offset
@@ -225,7 +225,7 @@ if ('onhashchange' in window) {
  163   ¦ break-unless previous-character-is-newline?
  164   ¦ # compute length of previous line
  165   ¦ trace 10, [app], [switching to previous line]
- 166   ¦ d:&:duplex-list:char <- get *editor, data:offset
+ 166   ¦ d:&:duplex-list:char <- get *editor, data:offset
  167   ¦ end-of-line:num <- previous-line-length before-cursor, d
  168   ¦ right:num <- get *editor, right:offset
  169   ¦ width:num <- subtract right, left
@@ -252,7 +252,7 @@ if ('onhashchange' in window) {
  190 
  191 # takes a pointer 'curr' into the doubly-linked list and its sentinel, counts
  192 # the length of the previous line before the 'curr' pointer.
- 193 def previous-line-length curr:&:duplex-list:char, start:&:duplex-list:char -> result:num [
+ 193 def previous-line-length curr:&:duplex-list:char, start:&:duplex-list:char -> result:num [
  194   local-scope
  195   load-ingredients
  196   result:num <- copy 0
@@ -401,25 +401,25 @@ if ('onhashchange' in window) {
  339   ¦ delete-next-character?:bool <- equal k, 65522/delete
  340   ¦ break-unless delete-next-character?
  341   ¦ <delete-character-begin>
- 342   ¦ go-render?:bool, deleted-cell:&:duplex-list:char <- delete-at-cursor editor, screen
+ 342   ¦ go-render?:bool, deleted-cell:&:duplex-list:char <- delete-at-cursor editor, screen
  343   ¦ <delete-character-end>
  344   ¦ return
  345   }
  346 ]
  347 
- 348 def delete-at-cursor editor:&:editor, screen:&:screen -> go-render?:bool, deleted-cell:&:duplex-list:char, editor:&:editor, screen:&:screen [
+ 348 def delete-at-cursor editor:&:editor, screen:&:screen -> go-render?:bool, deleted-cell:&:duplex-list:char, editor:&:editor, screen:&:screen [
  349   local-scope
  350   load-ingredients
- 351   before-cursor:&:duplex-list:char <- get *editor, before-cursor:offset
- 352   data:&:duplex-list:char <- get *editor, data:offset
- 353   deleted-cell:&:duplex-list:char <- next before-cursor
+ 351   before-cursor:&:duplex-list:char <- get *editor, before-cursor:offset
+ 352   data:&:duplex-list:char <- get *editor, data:offset
+ 353   deleted-cell:&:duplex-list:char <- next before-cursor
  354   return-unless deleted-cell, 0/don't-render
  355   currc:char <- get *deleted-cell, value:offset
  356   data <- remove deleted-cell, data
  357   deleted-newline?:bool <- equal currc, 10/newline
  358   return-if deleted-newline?, 1/go-render
  359   # wasn't a newline? render rest of line
- 360   curr:&:duplex-list:char <- next before-cursor  # refresh after remove above
+ 360   curr:&:duplex-list:char <- next before-cursor  # refresh after remove above
  361   cursor-row:num <- get *editor, cursor-row:offset
  362   cursor-column:num <- get *editor, cursor-column:offset
  363   screen <- move-cursor screen, cursor-row, cursor-column
@@ -474,7 +474,7 @@ if ('onhashchange' in window) {
  412   ¦ move-to-next-character?:bool <- equal k, 65514/right-arrow
  413   ¦ break-unless move-to-next-character?
  414   ¦ # if not at end of text
- 415   ¦ next-cursor:&:duplex-list:char <- next before-cursor
+ 415   ¦ next-cursor:&:duplex-list:char <- next before-cursor
  416   ¦ break-unless next-cursor
  417   ¦ # scan to next character
  418   ¦ <move-cursor-begin>
@@ -491,7 +491,7 @@ if ('onhashchange' in window) {
  429 def move-cursor-coordinates-right editor:&:editor, screen-height:num -> go-render?:bool, editor:&:editor [
  430   local-scope
  431   load-ingredients
- 432   before-cursor:&:duplex-list:char <- get *editor before-cursor:offset
+ 432   before-cursor:&:duplex-list:char <- get *editor before-cursor:offset
  433   cursor-row:num <- get *editor, cursor-row:offset
  434   cursor-column:num <- get *editor, cursor-column:offset
  435   left:num <- get *editor, left:offset
@@ -519,7 +519,7 @@ if ('onhashchange' in window) {
  457   ¦ at-wrap?:bool <- equal cursor-column, wrap-column
  458   ¦ break-unless at-wrap?
  459   ¦ # and if next character isn't newline
- 460   ¦ next:&:duplex-list:char <- next before-cursor
+ 460   ¦ next:&:duplex-list:char <- next before-cursor
  461   ¦ break-unless next
  462   ¦ next-character:char <- get *next, value:offset
  463   ¦ newline?:bool <- equal next-character, 10/newline
@@ -759,7 +759,7 @@ if ('onhashchange' in window) {
  697   ¦ break-unless move-to-previous-character?
  698   ¦ trace 10, [app], [left arrow]
  699   ¦ # if not at start of text (before-cursor at § sentinel)
- 700   ¦ prev:&:duplex-list:char <- prev before-cursor
+ 700   ¦ prev:&:duplex-list:char <- prev before-cursor
  701   ¦ return-unless prev, 0/don't-render
  702   ¦ <move-cursor-begin>
  703   ¦ go-render? <- move-cursor-coordinates-left editor
@@ -1041,7 +1041,7 @@ if ('onhashchange' in window) {
  979   go-render?:bool <- copy 0/false
  980   cursor-row:num <- get *editor, cursor-row:offset
  981   cursor-column:num <- get *editor, cursor-column:offset
- 982   before-cursor:&:duplex-list:char <- get *editor, before-cursor:offset
+ 982   before-cursor:&:duplex-list:char <- get *editor, before-cursor:offset
  983   left:num <- get *editor, left:offset
  984   right:num <- get *editor, right:offset
  985   already-at-top?:bool <- lesser-or-equal cursor-row, 1/top
@@ -1051,13 +1051,13 @@ if ('onhashchange' in window) {
  989   ¦ # if not at newline, move to start of line (previous newline)
  990   ¦ # then scan back another line
  991   ¦ # if either step fails, give up without modifying cursor or coordinates
- 992   ¦ curr:&:duplex-list:char <- copy before-cursor
+ 992   ¦ curr:&:duplex-list:char <- copy before-cursor
  993   ¦ {
- 994   ¦ ¦ old:&:duplex-list:char <- copy curr
+ 994   ¦ ¦ old:&:duplex-list:char <- copy curr
  995   ¦ ¦ c2:char <- get *curr, value:offset
  996   ¦ ¦ at-newline?:bool <- equal c2, 10/newline
  997   ¦ ¦ break-if at-newline?
- 998   ¦ ¦ curr:&:duplex-list:char <- before-previous-line curr, editor
+ 998   ¦ ¦ curr:&:duplex-list:char <- before-previous-line curr, editor
  999   ¦ ¦ no-motion?:bool <- equal curr, old
 1000   ¦ ¦ return-if no-motion?
 1001   ¦ }
@@ -1078,7 +1078,7 @@ if ('onhashchange' in window) {
 1016   ¦ {
 1017   ¦ ¦ done?:bool <- greater-or-equal cursor-column, target-column
 1018   ¦ ¦ break-if done?
-1019   ¦ ¦ curr:&:duplex-list:char <- next before-cursor
+1019   ¦ ¦ curr:&:duplex-list:char <- next before-cursor
 1020   ¦ ¦ break-unless curr
 1021   ¦ ¦ currc:char <- get *curr, value:offset
 1022   ¦ ¦ at-newline?:bool <- equal currc, 10/newline
@@ -1271,7 +1271,7 @@ if ('onhashchange' in window) {
 1209   load-ingredients
 1210   cursor-row:num <- get *editor, cursor-row:offset
 1211   cursor-column:num <- get *editor, cursor-column:offset
-1212   before-cursor:&:duplex-list:char <- get *editor, before-cursor:offset
+1212   before-cursor:&:duplex-list:char <- get *editor, before-cursor:offset
 1213   left:num <- get *editor, left:offset
 1214   right:num <- get *editor, right:offset
 1215   last-line:num <- subtract screen-height, 1
@@ -1281,7 +1281,7 @@ if ('onhashchange' in window) {
 1219   ¦ break-if already-at-bottom?
 1220   ¦ # scan to start of next line, then to right column or until end of line
 1221   ¦ max:num <- subtract right, left
-1222   ¦ next-line:&:duplex-list:char <- before-start-of-next-line before-cursor, max
+1222   ¦ next-line:&:duplex-list:char <- before-start-of-next-line before-cursor, max
 1223   ¦ {
 1224   ¦ ¦ # already at end of buffer? try to scroll up (so we can see more
 1225   ¦ ¦ # warnings or sandboxes below)
@@ -1301,7 +1301,7 @@ if ('onhashchange' in window) {
 1239   ¦ {
 1240   ¦ ¦ done?:bool <- greater-or-equal cursor-column, target-column
 1241   ¦ ¦ break-if done?
-1242   ¦ ¦ curr:&:duplex-list:char <- next before-cursor
+1242   ¦ ¦ curr:&:duplex-list:char <- next before-cursor
 1243   ¦ ¦ break-unless curr
 1244   ¦ ¦ currc:char <- get *curr, value:offset
 1245   ¦ ¦ at-newline?:bool <- equal currc, 10/newline
@@ -1417,8 +1417,8 @@ if ('onhashchange' in window) {
 1355   cursor-column:num <- copy left
 1356   *editor <- put *editor, cursor-column:offset, cursor-column
 1357   # update before-cursor
-1358   before-cursor:&:duplex-list:char <- get *editor, before-cursor:offset
-1359   init:&:duplex-list:char <- get *editor, data:offset
+1358   before-cursor:&:duplex-list:char <- get *editor, before-cursor:offset
+1359   init:&:duplex-list:char <- get *editor, data:offset
 1360   # while not at start of line, move
 1361   {
 1362   ¦ at-start-of-text?:bool <- equal before-cursor, init
@@ -1586,11 +1586,11 @@ if ('onhashchange' in window) {
 1524 def move-to-end-of-line editor:&:editor -> editor:&:editor [
 1525   local-scope
 1526   load-ingredients
-1527   before-cursor:&:duplex-list:char <- get *editor, before-cursor:offset
+1527   before-cursor:&:duplex-list:char <- get *editor, before-cursor:offset
 1528   cursor-column:num <- get *editor, cursor-column:offset
 1529   # while not at start of line, move
 1530   {
-1531   ¦ next:&:duplex-list:char <- next before-cursor
+1531   ¦ next:&:duplex-list:char <- next before-cursor
 1532   ¦ break-unless next  # end of text
 1533   ¦ nextc:char <- get *next, value:offset
 1534   ¦ at-end-of-line?:bool <- equal nextc, 10/newline
@@ -1712,20 +1712,20 @@ if ('onhashchange' in window) {
 1650   ¦ delete-to-start-of-line?:bool <- equal c, 21/ctrl-u
 1651   ¦ break-unless delete-to-start-of-line?
 1652   ¦ <delete-to-start-of-line-begin>
-1653   ¦ deleted-cells:&:duplex-list:char <- delete-to-start-of-line editor
+1653   ¦ deleted-cells:&:duplex-list:char <- delete-to-start-of-line editor
 1654   ¦ <delete-to-start-of-line-end>
 1655   ¦ return 1/go-render
 1656   }
 1657 ]
 1658 
-1659 def delete-to-start-of-line editor:&:editor -> result:&:duplex-list:char, editor:&:editor [
+1659 def delete-to-start-of-line editor:&:editor -> result:&:duplex-list:char, editor:&:editor [
 1660   local-scope
 1661   load-ingredients
 1662   # compute range to delete
-1663   init:&:duplex-list:char <- get *editor, data:offset
-1664   before-cursor:&:duplex-list:char <- get *editor, before-cursor:offset
-1665   start:&:duplex-list:char <- copy before-cursor
-1666   end:&:duplex-list:char <- next before-cursor
+1663   init:&:duplex-list:char <- get *editor, data:offset
+1664   before-cursor:&:duplex-list:char <- get *editor, before-cursor:offset
+1665   start:&:duplex-list:char <- copy before-cursor
+1666   end:&:duplex-list:char <- next before-cursor
 1667   {
 1668   ¦ at-start-of-text?:bool <- equal start, init
 1669   ¦ break-if at-start-of-text?
@@ -1737,7 +1737,7 @@ if ('onhashchange' in window) {
 1675   ¦ loop
 1676   }
 1677   # snip it out
-1678   result:&:duplex-list:char <- next start
+1678   result:&:duplex-list:char <- next start
 1679   remove-between start, end
 1680   # adjust cursor
 1681   before-cursor <- copy start
@@ -1849,18 +1849,18 @@ if ('onhashchange' in window) {
 1787   ¦ delete-to-end-of-line?:bool <- equal c, 11/ctrl-k
 1788   ¦ break-unless delete-to-end-of-line?
 1789   ¦ <delete-to-end-of-line-begin>
-1790   ¦ deleted-cells:&:duplex-list:char <- delete-to-end-of-line editor
+1790   ¦ deleted-cells:&:duplex-list:char <- delete-to-end-of-line editor
 1791   ¦ <delete-to-end-of-line-end>
 1792   ¦ return 1/go-render
 1793   }
 1794 ]
 1795 
-1796 def delete-to-end-of-line editor:&:editor -> result:&:duplex-list:char, editor:&:editor [
+1796 def delete-to-end-of-line editor:&:editor -> result:&:duplex-list:char, editor:&:editor [
 1797   local-scope
 1798   load-ingredients
 1799   # compute range to delete
-1800   start:&:duplex-list:char <- get *editor, before-cursor:offset
-1801   end:&:duplex-list:char <- next start
+1800   start:&:duplex-list:char <- get *editor, before-cursor:offset
+1801   end:&:duplex-list:char <- next start
 1802   {
 1803   ¦ at-end-of-text?:bool <- equal end, 0/null
 1804   ¦ break-if at-end-of-text?
@@ -2033,11 +2033,11 @@ if ('onhashchange' in window) {
 1971 
 1972 after <scroll-down> [
 1973   trace 10, [app], [scroll down]
-1974   top-of-screen:&:duplex-list:char <- get *editor, top-of-screen:offset
+1974   top-of-screen:&:duplex-list:char <- get *editor, top-of-screen:offset
 1975   left:num <- get *editor, left:offset
 1976   right:num <- get *editor, right:offset
 1977   max:num <- subtract right, left
-1978   old-top:&:duplex-list:char <- copy top-of-screen
+1978   old-top:&:duplex-list:char <- copy top-of-screen
 1979   top-of-screen <- before-start-of-next-line top-of-screen, max
 1980   *editor <- put *editor, top-of-screen:offset, top-of-screen
 1981   no-movement?:bool <- equal old-top, top-of-screen
@@ -2047,11 +2047,11 @@ if ('onhashchange' in window) {
 1985 # takes a pointer into the doubly-linked list, scans ahead at most 'max'
 1986 # positions until the next newline
 1987 # beware: never return null pointer.
-1988 def before-start-of-next-line original:&:duplex-list:char, max:num -> curr:&:duplex-list:char [
+1988 def before-start-of-next-line original:&:duplex-list:char, max:num -> curr:&:duplex-list:char [
 1989   local-scope
 1990   load-ingredients
 1991   count:num <- copy 0
-1992   curr:&:duplex-list:char <- copy original
+1992   curr:&:duplex-list:char <- copy original
 1993   # skip the initial newline if it exists
 1994   {
 1995   ¦ c:char <- get *curr, value:offset
@@ -2415,8 +2415,8 @@ if ('onhashchange' in window) {
 2353 
 2354 after <scroll-up> [
 2355   trace 10, [app], [scroll up]
-2356   top-of-screen:&:duplex-list:char <- get *editor, top-of-screen:offset
-2357   old-top:&:duplex-list:char <- copy top-of-screen
+2356   top-of-screen:&:duplex-list:char <- get *editor, top-of-screen:offset
+2357   old-top:&:duplex-list:char <- copy top-of-screen
 2358   top-of-screen <- before-previous-line top-of-screen, editor
 2359   *editor <- put *editor, top-of-screen:offset, top-of-screen
 2360   no-movement?:bool <- equal old-top, top-of-screen
@@ -2426,10 +2426,10 @@ if ('onhashchange' in window) {
 2364 # takes a pointer into the doubly-linked list, scans back to before start of
 2365 # previous *wrapped* line
 2366 # beware: never return null pointer
-2367 def before-previous-line in:&:duplex-list:char, editor:&:editor -> out:&:duplex-list:char [
+2367 def before-previous-line in:&:duplex-list:char, editor:&:editor -> out:&:duplex-list:char [
 2368   local-scope
 2369   load-ingredients
-2370   curr:&:duplex-list:char <- copy in
+2370   curr:&:duplex-list:char <- copy in
 2371   c:char <- get *curr, value:offset
 2372   # compute max, number of characters to skip
 2373   #   1 + len%(width-1)
@@ -2437,12 +2437,12 @@ if ('onhashchange' in window) {
 2375   left:num <- get *editor, left:offset
 2376   right:num <- get *editor, right:offset
 2377   max-line-length:num <- subtract right, left, -1/exclusive-right, 1/wrap-icon
-2378   sentinel:&:duplex-list:char <- get *editor, data:offset
+2378   sentinel:&:duplex-list:char <- get *editor, data:offset
 2379   len:num <- previous-line-length curr, sentinel
 2380   {
 2381   ¦ break-if len
 2382   ¦ # empty line; just skip this newline
-2383   ¦ prev:&:duplex-list:char <- prev curr
+2383   ¦ prev:&:duplex-list:char <- prev curr
 2384   ¦ return-unless prev, curr
 2385   ¦ return prev
 2386   }
@@ -2458,7 +2458,7 @@ if ('onhashchange' in window) {
 2396   {
 2397   ¦ done?:bool <- greater-or-equal count, max
 2398   ¦ break-if done?
-2399   ¦ prev:&:duplex-list:char <- prev curr
+2399   ¦ prev:&:duplex-list:char <- prev curr
 2400   ¦ break-unless prev
 2401   ¦ curr <- copy prev
 2402   ¦ count <- add count, 1
@@ -2820,12 +2820,12 @@ if ('onhashchange' in window) {
 2758   {
 2759   ¦ page-down?:bool <- equal c, 6/ctrl-f
 2760   ¦ break-unless page-down?
-2761   ¦ old-top:&:duplex-list:char <- get *editor, top-of-screen:offset
+2761   ¦ old-top:&:duplex-list:char <- get *editor, top-of-screen:offset
 2762   ¦ <move-cursor-begin>
 2763   ¦ page-down editor
 2764   ¦ undo-coalesce-tag:num <- copy 0/never
 2765   ¦ <move-cursor-end>
-2766   ¦ top-of-screen:&:duplex-list:char <- get *editor, top-of-screen:offset
+2766   ¦ top-of-screen:&:duplex-list:char <- get *editor, top-of-screen:offset
 2767   ¦ movement?:bool <- not-equal top-of-screen, old-top
 2768   ¦ return movement?/go-render
 2769   }
@@ -2835,12 +2835,12 @@ if ('onhashchange' in window) {
 2773   {
 2774   ¦ page-down?:bool <- equal k, 65518/page-down
 2775   ¦ break-unless page-down?
-2776   ¦ old-top:&:duplex-list:char <- get *editor, top-of-screen:offset
+2776   ¦ old-top:&:duplex-list:char <- get *editor, top-of-screen:offset
 2777   ¦ <move-cursor-begin>
 2778   ¦ page-down editor
 2779   ¦ undo-coalesce-tag:num <- copy 0/never
 2780   ¦ <move-cursor-end>
-2781   ¦ top-of-screen:&:duplex-list:char <- get *editor, top-of-screen:offset
+2781   ¦ top-of-screen:&:duplex-list:char <- get *editor, top-of-screen:offset
 2782   ¦ movement?:bool <- not-equal top-of-screen, old-top
 2783   ¦ return movement?/go-render
 2784   }
@@ -2852,11 +2852,11 @@ if ('onhashchange' in window) {
 2790   local-scope
 2791   load-ingredients
 2792   # if editor contents don't overflow screen, do nothing
-2793   bottom-of-screen:&:duplex-list:char <- get *editor, bottom-of-screen:offset
+2793   bottom-of-screen:&:duplex-list:char <- get *editor, bottom-of-screen:offset
 2794   return-unless bottom-of-screen
 2795   # if not, position cursor at final character
-2796   before-cursor:&:duplex-list:char <- get *editor, before-cursor:offset
-2797   before-cursor:&:duplex-list:char <- prev bottom-of-screen
+2796   before-cursor:&:duplex-list:char <- get *editor, before-cursor:offset
+2797   before-cursor:&:duplex-list:char <- prev bottom-of-screen
 2798   *editor <- put *editor, before-cursor:offset, before-cursor
 2799   # keep one line in common with previous page
 2800   {
@@ -3019,12 +3019,12 @@ if ('onhashchange' in window) {
 2957   {
 2958   ¦ page-up?:bool <- equal c, 2/ctrl-b
 2959   ¦ break-unless page-up?
-2960   ¦ old-top:&:duplex-list:char <- get *editor, top-of-screen:offset
+2960   ¦ old-top:&:duplex-list:char <- get *editor, top-of-screen:offset
 2961   ¦ <move-cursor-begin>
 2962   ¦ editor <- page-up editor, screen-height
 2963   ¦ undo-coalesce-tag:num <- copy 0/never
 2964   ¦ <move-cursor-end>
-2965   ¦ top-of-screen:&:duplex-list:char <- get *editor, top-of-screen:offset
+2965   ¦ top-of-screen:&:duplex-list:char <- get *editor, top-of-screen:offset
 2966   ¦ movement?:bool <- not-equal top-of-screen, old-top
 2967   ¦ return movement?/go-render
 2968   }
@@ -3034,12 +3034,12 @@ if ('onhashchange' in window) {
 2972   {
 2973   ¦ page-up?:bool <- equal k, 65519/page-up
 2974   ¦ break-unless page-up?
-2975   ¦ old-top:&:duplex-list:char <- get *editor, top-of-screen:offset
+2975   ¦ old-top:&:duplex-list:char <- get *editor, top-of-screen:offset
 2976   ¦ <move-cursor-begin>
 2977   ¦ editor <- page-up editor, screen-height
 2978   ¦ undo-coalesce-tag:num <- copy 0/never
 2979   ¦ <move-cursor-end>
-2980   ¦ top-of-screen:&:duplex-list:char <- get *editor, top-of-screen:offset
+2980   ¦ top-of-screen:&:duplex-list:char <- get *editor, top-of-screen:offset
 2981   ¦ movement?:bool <- not-equal top-of-screen, old-top
 2982   ¦ # don't bother re-rendering if nothing changed. todo: test this
 2983   ¦ return movement?/go-render
@@ -3051,11 +3051,11 @@ if ('onhashchange' in window) {
 2989   load-ingredients
 2990   max:num <- subtract screen-height, 1/menu-bar, 1/overlapping-line
 2991   count:num <- copy 0
-2992   top-of-screen:&:duplex-list:char <- get *editor, top-of-screen:offset
+2992   top-of-screen:&:duplex-list:char <- get *editor, top-of-screen:offset
 2993   {
 2994   ¦ done?:bool <- greater-or-equal count, max
 2995   ¦ break-if done?
-2996   ¦ prev:&:duplex-list:char <- before-previous-line top-of-screen, editor
+2996   ¦ prev:&:duplex-list:char <- before-previous-line top-of-screen, editor
 2997   ¦ break-unless prev
 2998   ¦ top-of-screen <- copy prev
 2999   ¦ *editor <- put *editor, top-of-screen:offset, top-of-screen
diff --git a/html/edit/004-programming-environment.mu.html b/html/edit/004-programming-environment.mu.html
index 639825f9..2aeba796 100644
--- a/html/edit/004-programming-environment.mu.html
+++ b/html/edit/004-programming-environment.mu.html
@@ -257,19 +257,19 @@ if ('onhashchange' in window) {
 194   left:num <- get *editor, left:offset
 195   screen-height:num <- screen-height screen
 196   right:num <- get *editor, right:offset
-197   curr:&:duplex-list:char <- get *editor, top-of-screen:offset
-198   prev:&:duplex-list:char <- copy curr  # just in case curr becomes null and we can't compute prev
+197   curr:&:duplex-list:char <- get *editor, top-of-screen:offset
+198   prev:&:duplex-list:char <- copy curr  # just in case curr becomes null and we can't compute prev
 199   curr <- next curr
 200   color:num <- copy 7/white
 201   row:num <- copy 1/top
 202   column:num <- copy left
 203   # save before-cursor
-204   old-before-cursor:&:duplex-list:char <- get *editor, before-cursor:offset
+204   old-before-cursor:&:duplex-list:char <- get *editor, before-cursor:offset
 205   # initialze cursor-row/cursor-column/before-cursor to the top of the screen
 206   # by default
 207   *editor <- put *editor, cursor-row:offset, row
 208   *editor <- put *editor, cursor-column:offset, column
-209   top-of-screen:&:duplex-list:char <- get *editor, top-of-screen:offset
+209   top-of-screen:&:duplex-list:char <- get *editor, top-of-screen:offset
 210   *editor <- put *editor, before-cursor:offset, top-of-screen
 211   screen <- move-cursor screen, row, column
 212   {
diff --git a/html/edit/005-sandbox.mu.html b/html/edit/005-sandbox.mu.html
index 8346152a..9eb7d9f8 100644
--- a/html/edit/005-sandbox.mu.html
+++ b/html/edit/005-sandbox.mu.html
@@ -227,7 +227,7 @@ if ('onhashchange' in window) {
  164   ¦ sandbox-count <- add sandbox-count, 1
  165   ¦ *env <- put *env, number-of-sandboxes:offset, sandbox-count
  166   ¦ # clear sandbox editor
- 167   ¦ init:&:duplex-list:char <- push 167/§, 0/tail
+ 167   ¦ init:&:duplex-list:char <- push 167/§, 0/tail
  168   ¦ *current-sandbox <- put *current-sandbox, data:offset, init
  169   ¦ *current-sandbox <- put *current-sandbox, top-of-screen:offset, init
  170   }
@@ -759,8 +759,8 @@ if ('onhashchange' in window) {
  696 def editor-contents editor:&:editor -> result:text [
  697   local-scope
  698   load-ingredients
- 699   buf:&:buffer <- new-buffer 80
- 700   curr:&:duplex-list:char <- get *editor, data:offset
+ 699   buf:&:buffer <- new-buffer 80
+ 700   curr:&:duplex-list:char <- get *editor, data:offset
  701   # skip § sentinel
  702   assert curr, [editor without data is illegal; must have at least a sentinel]
  703   curr <- next curr
diff --git a/html/edit/006-sandbox-copy.mu.html b/html/edit/006-sandbox-copy.mu.html
index 16b8d819..61a06072 100644
--- a/html/edit/006-sandbox-copy.mu.html
+++ b/html/edit/006-sandbox-copy.mu.html
@@ -263,8 +263,8 @@ if ('onhashchange' in window) {
 201 def empty-editor? editor:&:editor -> result:bool [
 202   local-scope
 203   load-ingredients
-204   head:&:duplex-list:char <- get *editor, data:offset
-205   first:&:duplex-list:char <- next head
+204   head:&:duplex-list:char <- get *editor, data:offset
+205   first:&:duplex-list:char <- next head
 206   result <- not first
 207 ]
 208 
diff --git a/html/edit/011-errors.mu.html b/html/edit/011-errors.mu.html
index a22244b0..8c2a1f1c 100644
--- a/html/edit/011-errors.mu.html
+++ b/html/edit/011-errors.mu.html
@@ -377,12 +377,12 @@ if ('onhashchange' in window) {
 314   # overload a well-known shape-shifting recipe
 315   assume-resources [
 316   ¦ [lesson/recipes.mu] <- [
-317   ¦ ¦ |recipe length l:&:list:_elem -> n:num [|
+317   ¦ ¦ |recipe length l:&:list:_elem -> n:num [|
 318   ¦ ¦ |]|
 319   ¦ ]
 320   ]
 321   # call code that uses other variants of it, but not it itself
-322   test-sandbox:text <- new [x:&:list:num <- copy 0
+322   test-sandbox:text <- new [x:&:list:num <- copy 0
 323 to-text x]
 324   env:&:environment <- new-programming-environment resources, screen, test-sandbox
 325   # run it once
diff --git a/html/edit/012-editor-undo.mu.html b/html/edit/012-editor-undo.mu.html
index bf1b7c99..2c227c0f 100644
--- a/html/edit/012-editor-undo.mu.html
+++ b/html/edit/012-editor-undo.mu.html
@@ -74,13 +74,13 @@ if ('onhashchange' in window) {
   11 container insert-operation [
   12   before-row:num
   13   before-column:num
-  14   before-top-of-screen:&:duplex-list:char
+  14   before-top-of-screen:&:duplex-list:char
   15   after-row:num
   16   after-column:num
-  17   after-top-of-screen:&:duplex-list:char
+  17   after-top-of-screen:&:duplex-list:char
   18   # inserted text is from 'insert-from' until 'insert-until'; list doesn't have to terminate
-  19   insert-from:&:duplex-list:char
-  20   insert-until:&:duplex-list:char
+  19   insert-from:&:duplex-list:char
+  20   insert-until:&:duplex-list:char
   21   tag:num  # event causing this operation; might be used to coalesce runs of similar events
   22   ¦ # 0: no coalesce (enter+indent)
   23   ¦ # 1: regular alphanumeric characters
@@ -89,10 +89,10 @@ if ('onhashchange' in window) {
   26 container move-operation [
   27   before-row:num
   28   before-column:num
-  29   before-top-of-screen:&:duplex-list:char
+  29   before-top-of-screen:&:duplex-list:char
   30   after-row:num
   31   after-column:num
-  32   after-top-of-screen:&:duplex-list:char
+  32   after-top-of-screen:&:duplex-list:char
   33   tag:num  # event causing this operation; might be used to coalesce runs of similar events
   34   ¦ # 0: no coalesce (touch events, etc)
   35   ¦ # 1: left arrow
@@ -104,13 +104,13 @@ if ('onhashchange' in window) {
   41 container delete-operation [
   42   before-row:num
   43   before-column:num
-  44   before-top-of-screen:&:duplex-list:char
+  44   before-top-of-screen:&:duplex-list:char
   45   after-row:num
   46   after-column:num
-  47   after-top-of-screen:&:duplex-list:char
-  48   deleted-text:&:duplex-list:char
-  49   delete-from:&:duplex-list:char
-  50   delete-until:&:duplex-list:char
+  47   after-top-of-screen:&:duplex-list:char
+  48   deleted-text:&:duplex-list:char
+  49   delete-from:&:duplex-list:char
+  50   delete-until:&:duplex-list:char
   51   tag:num  # event causing this operation; might be used to coalesce runs of similar events
   52   ¦ # 0: no coalesce (ctrl-k, ctrl-u)
   53   ¦ # 1: backspace
@@ -119,8 +119,8 @@ if ('onhashchange' in window) {
   56 
   57 # every editor accumulates a list of operations to undo/redo
   58 container editor [
-  59   undo:&:list:&:operation
-  60   redo:&:list:&:operation
+  59   undo:&:list:&:operation
+  60   redo:&:list:&:operation
   61 ]
   62 
   63 # ctrl-z - undo operation
@@ -128,12 +128,12 @@ if ('onhashchange' in window) {
   65   {
   66   ¦ undo?:bool <- equal c, 26/ctrl-z
   67   ¦ break-unless undo?
-  68   ¦ undo:&:list:&:operation <- get *editor, undo:offset
+  68   ¦ undo:&:list:&:operation <- get *editor, undo:offset
   69   ¦ break-unless undo
   70   ¦ op:&:operation <- first undo
   71   ¦ undo <- rest undo
   72   ¦ *editor <- put *editor, undo:offset, undo
-  73   ¦ redo:&:list:&:operation <- get *editor, redo:offset
+  73   ¦ redo:&:list:&:operation <- get *editor, redo:offset
   74   ¦ redo <- push op, redo
   75   ¦ *editor <- put *editor, redo:offset, redo
   76   ¦ <handle-undo>
@@ -146,12 +146,12 @@ if ('onhashchange' in window) {
   83   {
   84   ¦ redo?:bool <- equal c, 25/ctrl-y
   85   ¦ break-unless redo?
-  86   ¦ redo:&:list:&:operation <- get *editor, redo:offset
+  86   ¦ redo:&:list:&:operation <- get *editor, redo:offset
   87   ¦ break-unless redo
   88   ¦ op:&:operation <- first redo
   89   ¦ redo <- rest redo
   90   ¦ *editor <- put *editor, redo:offset, redo
-  91   ¦ undo:&:list:&:operation <- get *editor, undo:offset
+  91   ¦ undo:&:list:&:operation <- get *editor, undo:offset
   92   ¦ undo <- push op, undo
   93   ¦ *editor <- put *editor, undo:offset, undo
   94   ¦ <handle-redo>
@@ -202,14 +202,14 @@ if ('onhashchange' in window) {
  139 
  140 # save operation to undo
  141 after <insert-character-begin> [
- 142   top-before:&:duplex-list:char <- get *editor, top-of-screen:offset
- 143   cursor-before:&:duplex-list:char <- get *editor, before-cursor:offset
+ 142   top-before:&:duplex-list:char <- get *editor, top-of-screen:offset
+ 143   cursor-before:&:duplex-list:char <- get *editor, before-cursor:offset
  144 ]
  145 before <insert-character-end> [
- 146   top-after:&:duplex-list:char <- get *editor, top-of-screen:offset
+ 146   top-after:&:duplex-list:char <- get *editor, top-of-screen:offset
  147   cursor-row:num <- get *editor, cursor-row:offset
  148   cursor-column:num <- get *editor, cursor-column:offset
- 149   undo:&:list:&:operation <- get *editor, undo:offset
+ 149   undo:&:list:&:operation <- get *editor, undo:offset
  150   {
  151   ¦ # if previous operation was an insert, coalesce this operation with it
  152   ¦ break-unless undo
@@ -218,8 +218,8 @@ if ('onhashchange' in window) {
  155   ¦ break-unless is-insert?
  156   ¦ previous-coalesce-tag:num <- get typing, tag:offset
  157   ¦ break-unless previous-coalesce-tag
- 158   ¦ before-cursor:&:duplex-list:char <- get *editor, before-cursor:offset
- 159   ¦ insert-until:&:duplex-list:char <- next before-cursor
+ 158   ¦ before-cursor:&:duplex-list:char <- get *editor, before-cursor:offset
+ 159   ¦ insert-until:&:duplex-list:char <- next before-cursor
  160   ¦ typing <- put typing, insert-until:offset, insert-until
  161   ¦ typing <- put typing, after-row:offset, cursor-row
  162   ¦ typing <- put typing, after-column:offset, cursor-column
@@ -228,8 +228,8 @@ if ('onhashchange' in window) {
  165   ¦ break +done-adding-insert-operation
  166   }
  167   # if not, create a new operation
- 168   insert-from:&:duplex-list:char <- next cursor-before
- 169   insert-to:&:duplex-list:char <- next insert-from
+ 168   insert-from:&:duplex-list:char <- next cursor-before
+ 169   insert-to:&:duplex-list:char <- next insert-from
  170   op:&:operation <- new operation:type
  171   *op <- merge 0/insert-operation, save-row/before, save-column/before, top-before, cursor-row/after, cursor-column/after, top-after, insert-from, insert-to, 1/coalesce
  172   editor <- add-operation editor, op
@@ -240,17 +240,17 @@ if ('onhashchange' in window) {
  177 after <insert-enter-begin> [
  178   cursor-row-before:num <- copy cursor-row
  179   cursor-column-before:num <- copy cursor-column
- 180   top-before:&:duplex-list:char <- get *editor, top-of-screen:offset
- 181   cursor-before:&:duplex-list:char <- get *editor, before-cursor:offset
+ 180   top-before:&:duplex-list:char <- get *editor, top-of-screen:offset
+ 181   cursor-before:&:duplex-list:char <- get *editor, before-cursor:offset
  182 ]
  183 before <insert-enter-end> [
- 184   top-after:&:duplex-list:char <- get *editor, top-of-screen:offset
+ 184   top-after:&:duplex-list:char <- get *editor, top-of-screen:offset
  185   cursor-row:num <- get *editor, cursor-row:offset
  186   cursor-column:num <- get *editor, cursor-row:offset
  187   # never coalesce
- 188   insert-from:&:duplex-list:char <- next cursor-before
- 189   before-cursor:&:duplex-list:char <- get *editor, before-cursor:offset
- 190   insert-to:&:duplex-list:char <- next before-cursor
+ 188   insert-from:&:duplex-list:char <- next cursor-before
+ 189   before-cursor:&:duplex-list:char <- get *editor, before-cursor:offset
+ 190   insert-to:&:duplex-list:char <- next before-cursor
  191   op:&:operation <- new operation:type
  192   *op <- merge 0/insert-operation, cursor-row-before, cursor-column-before, top-before, cursor-row/after, cursor-column/after, top-after, insert-from, insert-to, 0/never-coalesce
  193   editor <- add-operation editor, op
@@ -263,10 +263,10 @@ if ('onhashchange' in window) {
  200 def add-operation editor:&:editor, op:&:operation -> editor:&:editor [
  201   local-scope
  202   load-ingredients
- 203   undo:&:list:&:operation <- get *editor, undo:offset
+ 203   undo:&:list:&:operation <- get *editor, undo:offset
  204   undo <- push op undo
  205   *editor <- put *editor, undo:offset, undo
- 206   redo:&:list:&:operation <- get *editor, redo:offset
+ 206   redo:&:list:&:operation <- get *editor, redo:offset
  207   redo <- copy 0
  208   *editor <- put *editor, redo:offset, redo
  209 ]
@@ -275,17 +275,17 @@ if ('onhashchange' in window) {
  212   {
  213   ¦ typing:insert-operation, is-insert?:bool <- maybe-convert *op, typing:variant
  214   ¦ break-unless is-insert?
- 215   ¦ start:&:duplex-list:char <- get typing, insert-from:offset
- 216   ¦ end:&:duplex-list:char <- get typing, insert-until:offset
+ 215   ¦ start:&:duplex-list:char <- get typing, insert-from:offset
+ 216   ¦ end:&:duplex-list:char <- get typing, insert-until:offset
  217   ¦ # assert cursor-row/cursor-column/top-of-screen match after-row/after-column/after-top-of-screen
- 218   ¦ before-cursor:&:duplex-list:char <- prev start
+ 218   ¦ before-cursor:&:duplex-list:char <- prev start
  219   ¦ *editor <- put *editor, before-cursor:offset, before-cursor
  220   ¦ remove-between before-cursor, end
  221   ¦ cursor-row <- get typing, before-row:offset
  222   ¦ *editor <- put *editor, cursor-row:offset, cursor-row
  223   ¦ cursor-column <- get typing, before-column:offset
  224   ¦ *editor <- put *editor, cursor-column:offset, cursor-column
- 225   ¦ top:&:duplex-list:char <- get typing, before-top-of-screen:offset
+ 225   ¦ top:&:duplex-list:char <- get typing, before-top-of-screen:offset
  226   ¦ *editor <- put *editor, top-of-screen:offset, top
  227   }
  228 ]
@@ -476,7 +476,7 @@ if ('onhashchange' in window) {
  413   ¦ typing:insert-operation, is-insert?:bool <- maybe-convert *op, typing:variant
  414   ¦ break-unless is-insert?
  415   ¦ before-cursor <- get *editor, before-cursor:offset
- 416   ¦ insert-from:&:duplex-list:char <- get typing, insert-from:offset  # ignore insert-to because it's already been spliced away
+ 416   ¦ insert-from:&:duplex-list:char <- get typing, insert-from:offset  # ignore insert-to because it's already been spliced away
  417   ¦ # assert insert-to matches next(before-cursor)
  418   ¦ insert-range before-cursor, insert-from
  419   ¦ # assert cursor-row/cursor-column/top-of-screen match after-row/after-column/after-top-of-screen
@@ -484,7 +484,7 @@ if ('onhashchange' in window) {
  421   ¦ *editor <- put *editor, cursor-row:offset, cursor-row
  422   ¦ cursor-column <- get typing, after-column:offset
  423   ¦ *editor <- put *editor, cursor-column:offset, cursor-column
- 424   ¦ top:&:duplex-list:char <- get typing, after-top-of-screen:offset
+ 424   ¦ top:&:duplex-list:char <- get typing, after-top-of-screen:offset
  425   ¦ *editor <- put *editor, top-of-screen:offset, top
  426   }
  427 ]
@@ -782,17 +782,17 @@ if ('onhashchange' in window) {
  719 after <move-cursor-begin> [
  720   cursor-row-before:num <- get *editor, cursor-row:offset
  721   cursor-column-before:num <- get *editor, cursor-column:offset
- 722   top-before:&:duplex-list:char <- get *editor, top-of-screen:offset
+ 722   top-before:&:duplex-list:char <- get *editor, top-of-screen:offset
  723 ]
  724 before <move-cursor-end> [
- 725   top-after:&:duplex-list:char <- get *editor, top-of-screen:offset
+ 725   top-after:&:duplex-list:char <- get *editor, top-of-screen:offset
  726   cursor-row:num <- get *editor, cursor-row:offset
  727   cursor-column:num <- get *editor, cursor-column:offset
  728   {
  729   ¦ break-unless undo-coalesce-tag
  730   ¦ # if previous operation was also a move, and also had the same coalesce
  731   ¦ # tag, coalesce with it
- 732   ¦ undo:&:list:&:operation <- get *editor, undo:offset
+ 732   ¦ undo:&:list:&:operation <- get *editor, undo:offset
  733   ¦ break-unless undo
  734   ¦ op:&:operation <- first undo
  735   ¦ move:move-operation, is-move?:bool <- maybe-convert *op, move:variant
@@ -821,7 +821,7 @@ if ('onhashchange' in window) {
  758   ¦ *editor <- put *editor, cursor-row:offset, cursor-row
  759   ¦ cursor-column <- get move, before-column:offset
  760   ¦ *editor <- put *editor, cursor-column:offset, cursor-column
- 761   ¦ top:&:duplex-list:char <- get move, before-top-of-screen:offset
+ 761   ¦ top:&:duplex-list:char <- get move, before-top-of-screen:offset
  762   ¦ *editor <- put *editor, top-of-screen:offset, top
  763   }
  764 ]
@@ -1457,7 +1457,7 @@ if ('onhashchange' in window) {
 1394   ¦ *editor <- put *editor, cursor-row:offset, cursor-row
 1395   ¦ cursor-column <- get move, after-column:offset
 1396   ¦ *editor <- put *editor, cursor-column:offset, cursor-column
-1397   ¦ top:&:duplex-list:char <- get move, after-top-of-screen:offset
+1397   ¦ top:&:duplex-list:char <- get move, after-top-of-screen:offset
 1398   ¦ *editor <- put *editor, top-of-screen:offset, top
 1399   }
 1400 ]
@@ -1678,16 +1678,16 @@ if ('onhashchange' in window) {
 1615 
 1616 # save operation to undo
 1617 after <backspace-character-begin> [
-1618   top-before:&:duplex-list:char <- get *editor, top-of-screen:offset
+1618   top-before:&:duplex-list:char <- get *editor, top-of-screen:offset
 1619 ]
 1620 before <backspace-character-end> [
 1621   {
 1622   ¦ break-unless backspaced-cell  # backspace failed; don't add an undo operation
-1623   ¦ top-after:&:duplex-list:char <- get *editor, top-of-screen:offset
+1623   ¦ top-after:&:duplex-list:char <- get *editor, top-of-screen:offset
 1624   ¦ cursor-row:num <- get *editor, cursor-row:offset
 1625   ¦ cursor-column:num <- get *editor, cursor-row:offset
-1626   ¦ before-cursor:&:duplex-list:char <- get *editor, before-cursor:offset
-1627   ¦ undo:&:list:&:operation <- get *editor, undo:offset
+1626   ¦ before-cursor:&:duplex-list:char <- get *editor, before-cursor:offset
+1627   ¦ undo:&:list:&:operation <- get *editor, undo:offset
 1628   ¦ {
 1629   ¦ ¦ # if previous operation was an insert, coalesce this operation with it
 1630   ¦ ¦ break-unless undo
@@ -1698,7 +1698,7 @@ if ('onhashchange' in window) {
 1635   ¦ ¦ coalesce?:bool <- equal previous-coalesce-tag, 1/coalesce-backspace
 1636   ¦ ¦ break-unless coalesce?
 1637   ¦ ¦ deletion <- put deletion, delete-from:offset, before-cursor
-1638   ¦ ¦ backspaced-so-far:&:duplex-list:char <- get deletion, deleted-text:offset
+1638   ¦ ¦ backspaced-so-far:&:duplex-list:char <- get deletion, deleted-text:offset
 1639   ¦ ¦ insert-range backspaced-cell, backspaced-so-far
 1640   ¦ ¦ deletion <- put deletion, deleted-text:offset, backspaced-cell
 1641   ¦ ¦ deletion <- put deletion, after-row:offset, cursor-row
@@ -1709,7 +1709,7 @@ if ('onhashchange' in window) {
 1646   ¦ }
 1647   ¦ # if not, create a new operation
 1648   ¦ op:&:operation <- new operation:type
-1649   ¦ deleted-until:&:duplex-list:char <- next before-cursor
+1649   ¦ deleted-until:&:duplex-list:char <- next before-cursor
 1650   ¦ *op <- merge 2/delete-operation, save-row/before, save-column/before, top-before, cursor-row/after, cursor-column/after, top-after, backspaced-cell/deleted, before-cursor/delete-from, deleted-until, 1/coalesce-backspace
 1651   ¦ editor <- add-operation editor, op
 1652   ¦ +done-adding-backspace-operation
@@ -1720,10 +1720,10 @@ if ('onhashchange' in window) {
 1657   {
 1658   ¦ deletion:delete-operation, is-delete?:bool <- maybe-convert *op, delete:variant
 1659   ¦ break-unless is-delete?
-1660   ¦ anchor:&:duplex-list:char <- get deletion, delete-from:offset
+1660   ¦ anchor:&:duplex-list:char <- get deletion, delete-from:offset
 1661   ¦ break-unless anchor
-1662   ¦ deleted:&:duplex-list:char <- get deletion, deleted-text:offset
-1663   ¦ old-cursor:&:duplex-list:char <- last deleted
+1662   ¦ deleted:&:duplex-list:char <- get deletion, deleted-text:offset
+1663   ¦ old-cursor:&:duplex-list:char <- last deleted
 1664   ¦ insert-range anchor, deleted
 1665   ¦ # assert cursor-row/cursor-column/top-of-screen match after-row/after-column/after-top-of-screen
 1666   ¦ before-cursor <- copy old-cursor
@@ -1731,7 +1731,7 @@ if ('onhashchange' in window) {
 1668   ¦ *editor <- put *editor, cursor-row:offset, cursor-row
 1669   ¦ cursor-column <- get deletion, before-column:offset
 1670   ¦ *editor <- put *editor, cursor-column:offset, cursor-column
-1671   ¦ top:&:duplex-list:char <- get deletion, before-top-of-screen:offset
+1671   ¦ top:&:duplex-list:char <- get deletion, before-top-of-screen:offset
 1672   ¦ *editor <- put *editor, top-of-screen:offset, top
 1673   }
 1674 ]
@@ -1740,16 +1740,16 @@ if ('onhashchange' in window) {
 1677   {
 1678   ¦ deletion:delete-operation, is-delete?:bool <- maybe-convert *op, delete:variant
 1679   ¦ break-unless is-delete?
-1680   ¦ start:&:duplex-list:char <- get deletion, delete-from:offset
-1681   ¦ end:&:duplex-list:char <- get deletion, delete-until:offset
-1682   ¦ data:&:duplex-list:char <- get *editor, data:offset
+1680   ¦ start:&:duplex-list:char <- get deletion, delete-from:offset
+1681   ¦ end:&:duplex-list:char <- get deletion, delete-until:offset
+1682   ¦ data:&:duplex-list:char <- get *editor, data:offset
 1683   ¦ remove-between start, end
 1684   ¦ # assert cursor-row/cursor-column/top-of-screen match after-row/after-column/after-top-of-screen
 1685   ¦ cursor-row <- get deletion, after-row:offset
 1686   ¦ *editor <- put *editor, cursor-row:offset, cursor-row
 1687   ¦ cursor-column <- get deletion, after-column:offset
 1688   ¦ *editor <- put *editor, cursor-column:offset, cursor-column
-1689   ¦ top:&:duplex-list:char <- get deletion, before-top-of-screen:offset
+1689   ¦ top:&:duplex-list:char <- get deletion, before-top-of-screen:offset
 1690   ¦ *editor <- put *editor, top-of-screen:offset, top
 1691   }
 1692 ]
@@ -1904,16 +1904,16 @@ if ('onhashchange' in window) {
 1841 ]
 1842 
 1843 after <delete-character-begin> [
-1844   top-before:&:duplex-list:char <- get *editor, top-of-screen:offset
+1844   top-before:&:duplex-list:char <- get *editor, top-of-screen:offset
 1845 ]
 1846 before <delete-character-end> [
 1847   {
 1848   ¦ break-unless deleted-cell  # delete failed; don't add an undo operation
-1849   ¦ top-after:&:duplex-list:char <- get *editor, top-of-screen:offset
+1849   ¦ top-after:&:duplex-list:char <- get *editor, top-of-screen:offset
 1850   ¦ cursor-row:num <- get *editor, cursor-row:offset
 1851   ¦ cursor-column:num <- get *editor, cursor-column:offset
-1852   ¦ before-cursor:&:duplex-list:char <- get *editor, before-cursor:offset
-1853   ¦ undo:&:list:&:operation <- get *editor, undo:offset
+1852   ¦ before-cursor:&:duplex-list:char <- get *editor, before-cursor:offset
+1853   ¦ undo:&:list:&:operation <- get *editor, undo:offset
 1854   ¦ {
 1855   ¦ ¦ # if previous operation was an insert, coalesce this operation with it
 1856   ¦ ¦ break-unless undo
@@ -1923,9 +1923,9 @@ if ('onhashchange' in window) {
 1860   ¦ ¦ previous-coalesce-tag:num <- get deletion, tag:offset
 1861   ¦ ¦ coalesce?:bool <- equal previous-coalesce-tag, 2/coalesce-delete
 1862   ¦ ¦ break-unless coalesce?
-1863   ¦ ¦ delete-until:&:duplex-list:char <- next before-cursor
+1863   ¦ ¦ delete-until:&:duplex-list:char <- next before-cursor
 1864   ¦ ¦ deletion <- put deletion, delete-until:offset, delete-until
-1865   ¦ ¦ deleted-so-far:&:duplex-list:char <- get deletion, deleted-text:offset
+1865   ¦ ¦ deleted-so-far:&:duplex-list:char <- get deletion, deleted-text:offset
 1866   ¦ ¦ deleted-so-far <- append deleted-so-far, deleted-cell
 1867   ¦ ¦ deletion <- put deletion, deleted-text:offset, deleted-so-far
 1868   ¦ ¦ deletion <- put deletion, after-row:offset, cursor-row
@@ -1936,7 +1936,7 @@ if ('onhashchange' in window) {
 1873   ¦ }
 1874   ¦ # if not, create a new operation
 1875   ¦ op:&:operation <- new operation:type
-1876   ¦ deleted-until:&:duplex-list:char <- next before-cursor
+1876   ¦ deleted-until:&:duplex-list:char <- next before-cursor
 1877   ¦ *op <- merge 2/delete-operation, save-row/before, save-column/before, top-before, cursor-row/after, cursor-column/after, top-after, deleted-cell/deleted, before-cursor/delete-from, deleted-until, 2/coalesce-delete
 1878   ¦ editor <- add-operation editor, op
 1879   ¦ +done-adding-delete-operation
@@ -2030,15 +2030,15 @@ if ('onhashchange' in window) {
 1967 ]
 1968 
 1969 after <delete-to-end-of-line-begin> [
-1970   top-before:&:duplex-list:char <- get *editor, top-of-screen:offset
+1970   top-before:&:duplex-list:char <- get *editor, top-of-screen:offset
 1971 ]
 1972 before <delete-to-end-of-line-end> [
 1973   {
 1974   ¦ break-unless deleted-cells  # delete failed; don't add an undo operation
-1975   ¦ top-after:&:duplex-list:char <- get *editor, top-of-screen:offset
+1975   ¦ top-after:&:duplex-list:char <- get *editor, top-of-screen:offset
 1976   ¦ cursor-row:num <- get *editor, cursor-row:offset
 1977   ¦ cursor-column:num <- get *editor, cursor-column:offset
-1978   ¦ deleted-until:&:duplex-list:char <- next before-cursor
+1978   ¦ deleted-until:&:duplex-list:char <- next before-cursor
 1979   ¦ op:&:operation <- new operation:type
 1980   ¦ *op <- merge 2/delete-operation, save-row/before, save-column/before, top-before, cursor-row/after, cursor-column/after, top-after, deleted-cells/deleted, before-cursor/delete-from, deleted-until, 0/never-coalesce
 1981   ¦ editor <- add-operation editor, op
@@ -2133,15 +2133,15 @@ if ('onhashchange' in window) {
 2070 ]
 2071 
 2072 after <delete-to-start-of-line-begin> [
-2073   top-before:&:duplex-list:char <- get *editor, top-of-screen:offset
+2073   top-before:&:duplex-list:char <- get *editor, top-of-screen:offset
 2074 ]
 2075 before <delete-to-start-of-line-end> [
 2076   {
 2077   ¦ break-unless deleted-cells  # delete failed; don't add an undo operation
-2078   ¦ top-after:&:duplex-list:char <- get *editor, top-of-screen:offset
+2078   ¦ top-after:&:duplex-list:char <- get *editor, top-of-screen:offset
 2079   ¦ op:&:operation <- new operation:type
-2080   ¦ before-cursor:&:duplex-list:char <- get *editor, before-cursor:offset
-2081   ¦ deleted-until:&:duplex-list:char <- next before-cursor
+2080   ¦ before-cursor:&:duplex-list:char <- get *editor, before-cursor:offset
+2081   ¦ deleted-until:&:duplex-list:char <- next before-cursor
 2082   ¦ cursor-row:num <- get *editor, cursor-row:offset
 2083   ¦ cursor-column:num <- get *editor, cursor-column:offset
 2084   ¦ *op <- merge 2/delete-operation, save-row/before, save-column/before, top-before, cursor-row/after, cursor-column/after, top-after, deleted-cells/deleted, before-cursor/delete-from, deleted-until, 0/never-coalesce
diff --git a/html/filesystem.mu.html b/html/filesystem.mu.html
index 64776808..40703554 100644
--- a/html/filesystem.mu.html
+++ b/html/filesystem.mu.html
@@ -65,8 +65,8 @@ if ('onhashchange' in window) {
  5 
  6 def main [
  7   local-scope
- 8   source-file:&:source:char <- start-reading 0/real-filesystem, [/tmp/mu-x]
- 9   sink-file:&:sink:char, write-routine:num <- start-writing 0/real-filesystem, [/tmp/mu-y]
+ 8   source-file:&:source:char <- start-reading 0/real-filesystem, [/tmp/mu-x]
+ 9   sink-file:&:sink:char, write-routine:num <- start-writing 0/real-filesystem, [/tmp/mu-y]
 10   {
 11   ¦ c:char, done?:bool, source-file <- read source-file
 12   ¦ break-if done?
diff --git a/html/http-client.mu.html b/html/http-client.mu.html
index 90b72559..17cb6fde 100644
--- a/html/http-client.mu.html
+++ b/html/http-client.mu.html
@@ -62,9 +62,9 @@ if ('onhashchange' in window) {
  2 
  3 def main [
  4   local-scope
- 5   google:&:source:char <- start-reading-from-network 0/real-resources, [google.com/]
+ 5   google:&:source:char <- start-reading-from-network 0/real-resources, [google.com/]
  6   n:num <- copy 0
- 7   buf:&:buffer <- new-buffer 30
+ 7   buf:&:buffer <- new-buffer 30
  8   {
  9   ¦ c:char, done?:bool <- read google
 10   ¦ break-if done?
diff --git a/html/http-server.mu.html b/html/http-server.mu.html
index f1e97cc7..21ee77c7 100644
--- a/html/http-server.mu.html
+++ b/html/http-server.mu.html
@@ -71,8 +71,8 @@ if ('onhashchange' in window) {
 13   $print [Mu socket creation returned ], socket, 10/newline
 14   return-unless socket
 15   session:num <- $accept socket
-16   contents:&:source:char, sink:&:sink:char <- new-channel 30
-17   sink <- start-running receive-from-socket session, sink
+16   contents:&:source:char, sink:&:sink:char <- new-channel 30
+17   sink <- start-running receive-from-socket session, sink
 18   query:text <- drain contents
 19   $print [Done reading from socket.], 10/newline
 20   write-to-socket session, [HTTP/1.0 200 OK
diff --git a/html/lambda-to-mu.mu.html b/html/lambda-to-mu.mu.html
index 3a15158f..978ba9fb 100644
--- a/html/lambda-to-mu.mu.html
+++ b/html/lambda-to-mu.mu.html
@@ -240,12 +240,12 @@ if ('onhashchange' in window) {
 176 def parse in:text -> out:&:cell [
 177   local-scope
 178   load-ingredients
-179   s:&:stream:char <- new-stream in
+179   s:&:stream:char <- new-stream in
 180   out, s <- parse s
 181   trace 2, [app/parse], out
 182 ]
 183 
-184 def parse in:&:stream:char -> out:&:cell, in:&:stream:char [
+184 def parse in:&:stream:char -> out:&:cell, in:&:stream:char [
 185   local-scope
 186   load-ingredients
 187   # skip whitespace
@@ -256,7 +256,7 @@ if ('onhashchange' in window) {
 192   {
 193   ¦ break-if pair?
 194   ¦ # atom
-195   ¦ buf:&:buffer <- new-buffer 30
+195   ¦ buf:&:buffer <- new-buffer 30
 196   ¦ {
 197   ¦ ¦ done?:bool <- end-of-stream? in
 198   ¦ ¦ break-if done?
@@ -335,7 +335,7 @@ if ('onhashchange' in window) {
 271   }
 272 ]
 273 
-274 def skip-whitespace in:&:stream:char -> in:&:stream:char [
+274 def skip-whitespace in:&:stream:char -> in:&:stream:char [
 275   local-scope
 276   load-ingredients
 277   {
@@ -352,12 +352,12 @@ if ('onhashchange' in window) {
 288 def to-text x:&:cell -> out:text [
 289   local-scope
 290   load-ingredients
-291   buf:&:buffer <- new-buffer 30
+291   buf:&:buffer <- new-buffer 30
 292   buf <- to-buffer x, buf
 293   out <- buffer-to-array buf
 294 ]
 295 
-296 def to-buffer x:&:cell, buf:&:buffer -> buf:&:buffer [
+296 def to-buffer x:&:cell, buf:&:buffer -> buf:&:buffer [
 297   local-scope
 298   load-ingredients
 299   # base case: empty cell
@@ -639,12 +639,12 @@ if ('onhashchange' in window) {
 575 def to-mu in:&:cell -> out:text [
 576   local-scope
 577   load-ingredients
-578   buf:&:buffer <- new-buffer 30
+578   buf:&:buffer <- new-buffer 30
 579   buf <- to-mu in, buf
 580   out <- buffer-to-array buf
 581 ]
 582 
-583 def to-mu in:&:cell, buf:&:buffer -> buf:&:buffer, result-name:text [
+583 def to-mu in:&:cell, buf:&:buffer -> buf:&:buffer, result-name:text [
 584   local-scope
 585   load-ingredients
 586   # null cell? no change.
diff --git a/html/nqueens.mu.html b/html/nqueens.mu.html
index 1c89c974..0e10c100 100644
--- a/html/nqueens.mu.html
+++ b/html/nqueens.mu.html
@@ -69,7 +69,7 @@ if ('onhashchange' in window) {
  8   file:num
  9 ]
 10 
-11 def nqueens n:num, queens:&:list:square -> result:num, queens:&:list:square [
+11 def nqueens n:num, queens:&:list:square -> result:num, queens:&:list:square [
 12   local-scope
 13   load-ingredients
 14   # if 'queens' is already long enough, print it and return
@@ -97,7 +97,7 @@ if ('onhashchange' in window) {
 36   ¦ {
 37   ¦ ¦ curr-conflicts?:bool <- conflict? curr, queens
 38   ¦ ¦ break-if curr-conflicts?
-39   ¦ ¦ queens:&:list:square <- push curr, queens
+39   ¦ ¦ queens:&:list:square <- push curr, queens
 40   ¦ ¦ sub-result:num <- nqueens n, queens
 41   ¦ ¦ result <- add result, sub-result
 42   ¦ ¦ queens <- rest queens
@@ -107,7 +107,7 @@ if ('onhashchange' in window) {
 46   }
 47 ]
 48 
-49 def conflict? curr:square, queens:&:list:square -> result:bool [
+49 def conflict? curr:square, queens:&:list:square -> result:bool [
 50   local-scope
 51   load-ingredients
 52   result1:bool <- conflicting-file? curr, queens
@@ -116,7 +116,7 @@ if ('onhashchange' in window) {
 55   return result2
 56 ]
 57 
-58 def conflicting-file? curr:square, queens:&:list:square -> result:bool [
+58 def conflicting-file? curr:square, queens:&:list:square -> result:bool [
 59   local-scope
 60   load-ingredients
 61   curr-file:num <- get curr, file:offset
@@ -132,7 +132,7 @@ if ('onhashchange' in window) {
 71   return 0/no-conflict-found
 72 ]
 73 
-74 def conflicting-diagonal? curr:square, queens:&:list:square -> result:bool [
+74 def conflicting-diagonal? curr:square, queens:&:list:square -> result:bool [
 75   local-scope
 76   load-ingredients
 77   curr-rank:num <- get curr, rank:offset
-- 
cgit 1.4.1-2-gfad0