about summary refs log blame commit diff stats
path: root/html/edit.mu.html
blob: f86b4c35007c51b7c2a7b8ab39ea8da240ac7981 (plain) (tree)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
2157
2158
2159
2160
2161
2162
2163
2164
2165
2166
2167
2168
2169
2170
2171
2172
2173
2174
2175
2176
2177
2178
2179
2180
2181
2182
2183
2184
2185
2186
2187
2188
2189
2190
2191
2192
2193
2194
2195
2196
2197
2198
2199
2200
2201
2202
2203
2204
2205
2206
2207
2208
2209
2210
2211
2212
2213
2214
2215
2216
2217
2218
2219
2220
2221
2222
2223
2224
2225
2226
2227
2228
2229
2230
2231
2232
2233
2234
2235
2236
2237
2238
2239
2240
2241
2242
2243
2244
2245
2246
2247
2248
2249
2250
2251
2252
2253
2254
2255
2256
2257
2258
2259
2260
2261
2262
2263
2264
2265
2266
2267
2268
2269
2270
2271
2272
2273
2274
2275
2276
2277
2278
2279
2280
2281
2282
2283
2284
2285
2286
2287
2288
2289
2290
2291
2292
2293
2294
2295
2296
2297
2298
2299
2300
2301
2302
2303
2304
2305
2306
2307
2308
2309
2310
2311
2312
2313
2314
2315
2316
2317
2318
2319
2320
2321
2322
2323
2324
2325
2326
2327
2328
2329
2330
2331
2332
2333
2334
2335
2336
2337
2338
2339
2340
2341
2342
2343
2344
2345
2346
2347
2348
2349
2350
2351
2352
2353
2354
2355
2356
2357
2358
2359
2360
2361
2362
2363
2364
2365
2366
2367
2368
2369
2370
2371
2372
2373
2374
2375
2376
2377
2378
2379
2380
2381
2382
2383
2384
2385
2386
2387
2388
2389
2390
2391
2392
2393
2394
2395
2396
2397
2398
2399
2400
2401
2402
2403
2404
2405
2406
2407
2408
2409
2410
2411
2412
2413
2414
2415
2416
2417
2418
2419
2420
2421
2422
2423
2424
2425
2426
2427
2428
2429
2430
2431
2432
2433
2434
2435
2436
2437
2438
2439
2440
2441
2442
2443
2444
2445
2446
2447
2448
2449
2450
2451
2452
2453
2454
2455
2456
2457
2458
2459
2460
2461
2462
2463
2464
2465
2466
2467
2468
2469
2470
2471
2472
2473
2474
2475
2476
2477
2478
2479
2480
2481
2482
2483
2484
2485
2486
2487
2488
2489
2490
2491
2492
2493
2494
2495
2496
2497
2498
2499
2500
2501
2502
2503
2504
2505
2506
2507
2508
2509
2510
2511
2512
2513
2514
2515
2516
2517
2518
2519
2520
2521
2522
2523
2524
2525
2526
2527
2528













                                                                                                 
                        
                               
                                   

                                  

                             
                            
                              
                             










                               
                                                                             
 
                                           
                                           
              
                                                                                                                              
                                                                                                                 
                                                                                                                                                                                                                                         


                                                                                                                                        
                                                                                                                                                      
                                                










                                                                                                                             
                                           














                                                                                                                                                                                                                                                                                    
                                                                                                                                  








                                                                                                                                                                                                                             
                                                                                                                          
                                                                                  




                                                                                                              
                                                                                                        
                                                                                                                                                      

                         
                                              








                                                                                                                
                                                                                                                   
                          

                                                                   
 
                                                                     
                                                                                              
             





                                                                 
                                                                                                                                                   



                                                                                                        
                                           
                                                                                                            
                                                                                                 
                                                      




                                                                                                                



                                                                                                                

                                                                                                                     
                                                                                                            

                                                                                                                        

                                                                                                                                                                                  
                                                                                                                                     
                                                                                                                    




                                                                                                   
                                                                                            
                                                                                                         
                                  


                                                                                                    



                                                                                                         

                                       
                                                                   
                                                                                                                                     
                                                                                                                    

                                                                                                        





                                                                                                             
                                                                                                                                                                                                                                 


                                                                                     





                                                                                             





                                         

 
                                                                                                                    
                                             
                                           
                                                                                                 
                                                                                                             
                                                                                                                                                          
                                                                                                  
                                                                                      

                                                                                                    


                                                                                                                  
                                                  
                                                                                                               

                                                                                                  
                                                  
                                                                                                
                                                                   


                                                                                                                                                 
                                                       
                                  
                                                 


                                                                                                            


                                                                                                           
                                    


                                                                                                                   
                                                                    
                                                                                                                             

                                                                                                   
                                                                                                                                             



                                                                                                                             







                                                                                                                                

                                                                      
                                                                      
                                                      



                                                                                                           
                                                                                                      


                                                                                             

                                                                                                       

                                                                                            
                                                    






                                                                                                                                                  
                                                             
                                                                                                    
                                                                                                    
                                                                                                               

                                       







                                                                                                                                     

                                                                                            








                                                                                                                                                     
                                                                                                                    
                                  





                                                                                                                                                                            
                                                                
                                                                                          
                                                                                          
                                                    
                                           












                                                                                                                                             
                                  


                                                                                          

                                                                                                      
                                                                                                  
                                    








                                                                                                                                                  
                                    
                                                                                                     
                                    














                                                                                                                             
                                    


                                                                                                               
                                  
                                  









                                                                                                               




































































                                                                                                                                                                                                   
                                                           
                                           









                                                                                                               
                                  


                                                                                 
                                                                                                             


                                                                                                       
                                                                                                                                                     

                         
                                         






                                                                           
                                                                                                             

                                                                                                        
                                                                                                                                                     

                         
                                         
                                         




                                                                                           
                                                                                                             


                                                                                                       
                                                                                                                                                     

                         
                                         



                                         

 
                                                                            
                                                                                                             

                                                                                                            
                                                                                                                                                     

                         
                                         



                                           
                                                                                 




















                                                                                                                                                     
                                                                                 
                                         





                                           
                                                                        
                                                                                                             

                                                                                                     
                                                                                                                                                                                                              








                                                                                                     
                                                                                     



                                                                                        









































































































                                                                                                                                                     
                                                                                                  

                                                 
                                           
                                                                                                 
                                                                                                  



                                                                                                                                                           
                                  

                                                                                           



                                                                                                                         
                                                                                                                 
                                    






                                                                                                                                        

                                                                                                                             


                                                                                                                                               
                                      
                                    
                                                
                                    

                                                                                                   








                                                                                                                                                                                     


                                                                                                                                                                                       
                                    
                                                                                 
                                    
                                      

                                                                                          
                                      





                                                                                                  


                                                                                                       



                                                                                              
                                                                             
                                    
                                       
                                  

 

                                                                 
                                           






























                                                                                                                         
                                                   
                                           



                                                                                                             
                                                                        
                                          


                                                                                              
                                                               






                                                                                                                                              




























                                                                                                                                         
                                                                                          

                                        
                                                             






                                                                                                                                                 

                                                                                                    















                                                                                                                                                            
                                                                                            








                                                                                                                                       


                                                                                                                          
                                                                        

                                                                                                                  
                                                                                                                        


                                                                                                                                                     
                                                                                            











                                                                                                                                                               
                                                                        






                                                                                                                                                  
                                                                            









                                                                                                                                                                
                                                                             








                                                                                                                                                          


















                                                                                                                                                                                                 
                                                                                                                                                           





                                                                                                                                                        













                                                                                                                                   

 

                                                                                       
                                                            
                                           
                                                                                                 
                                                                                                             
                                                                                                
                                                                                                                       


                                                                                                       
                                                                                                              

                                                                                                          
                                                                                                               




                                                                                                                                    

                                                                                   


                                                       
                                           

                                                                                                             
                                                                                                 
                                                                                         


                                                                                                                                                 
                                                                                                                                                

                                                                                                                                    

                                                                                                    





                                                                                                                                                   
                                                                                          




                                                                                                  
                                                                                                                        
                                                                                                                                             


















                                                                                                                                                       
                                           












                                                                                                                                                            
                                                                                                                               




                                                                                                          
                                           

















                                                                                                                             

 

































































































                                                                                                                                                         
                                                 


                                                                                                                           

                                                                                                                                                                                     









                                                                                                                                                   




                                                                                                                                                   




















                                                                                                                                  
                                                                                                

                                                                                                                                   




                                                                                                                                                       
                                                     



                                                                                                                                                                                                                           
                                                                 








                                                                                                                                     
                                                                                  









                                                                                                                     


                                                                          
                                                    
                                           




















                                                                                                                               

                                                                                                              
                                                                                                      
                                                                                                                                                                                                             

                                                 
                                                                            

                         
                                              






                                                                                                              
                                                                                                      
                                                                                                                                                                                                             
                  
                                                              

       
                                                                            



                                                                                                     
                                              



                                              
                                                                                               



                                                                                         


                                                                                                              
                                                                                                                                                                                                             
                  
                                                                                   

       
                                                                            



                                                                                                     
                                                                                     







                                                                                                              
                                                                                                                                                                                                             
                  
                                                                                       

       
                                                                            



                                                                                                     
                                                                                     







                                                                                                              
                                                                                                                                                                                                             
                  
                                                              

       
                                                                            



                                                                                                     
                                                                                     







                                                                                                              
                                                                                                                                                                                                            




                                                                
                                                                            



                                                                                                     
                                              



                                              
                                                                                                  






                                                                                                              
                                                                                                                                                                                                            



                                            
                                                                            

                         
                                              







                                                                                                              
                                                                                                                                                                                                             

                                          
                   


                                          
                                                                            

                         
                                              







                                                                                                              
                                                                                                                                                                                                             
                  
                                                                      


                                                                                        
                                                                            

                         
                                              







                                                                                                              
                                                                                                                                                                                                             




                                                                                        
                                                                            

                         
                                              








                                                                                                              
                                                                                                                                                                                                             




                                                                                        
                                                                            

                         
                                              









                                                                                                              
                                                                                                                                                                                                             




                                                                                                                      
                                                                            

                         
                                              





                                              
                                                                      


                                                                                                                                                                                                            




                                              
                                                                            


                                            


                                         






                                                     
                                                                            


                                         
                                         
                                           
                                         





                                                                                                              

                                                                                                                                                                                                            



                                           
                                                                            

                         

                                              






                                                                                                              
                                                                                                                                                                                                            
                  
                                                                                  


                                          
                                                                            



                                                                                                     
                                              




                                                
                                                                                     






                                                                                                              
                                                                                                                                                                                                            
                  
                                                                              


                                          
                                                                            



                                                                                                     
                                              




                                                
                                                                                     






                                                                                                              
                                                                                                                                                                                                             




                                         
                                                                            

                         
                                              





                                              


















                                                                                                                                                                                                             


                                                                                                              
                                                                                                                                                                                                            




                                                       






                                                
       
                                                                            



                                                             


                                                




                                                                       

                                                                                                              
                                                                                                                                                                                                             
                  
                   




                                                                                                                                                                                                                                                          
                                                                            



                                                                                                     
                                              



                                              
                                          






                                                                                                              


                                                                                                                                                                                                            
                  
                                                                                          




                                                                                                                                                                                                                                                          
                                                                            

                         
                                              




                                              
                                                                             
                                                                                                              

                                                                                                                                                                                                             
                  

                                                           
   
       
                                                                            

                         

                                              



                                              
                                                                                            
                                                                                                              


                                                                                                                                                                                                             

                                                           


                                                                       


                                          
                                                                            

                         


                                              



                                              
                                                                                              


                                                                                                              
                                                                                                                                                                                                             







                                                                       
                                                                            

                         


                                              






                                                                                                              
                                                                                                                                                                                                            
                  
                   


                                                           
                                                                            



                                                                                                     
                                              




                                                
                                          



                                          
                                                                                                      
                                                                                                              
                                                          
                                                                                                        

                                                                                                                                                                                                            
                  
                   


                                                           













                                                                                                     



                                                                                                     

                                          


   
                                                                                                      
                                                                                                              

                                                                                                                                                                                                            
                  
                   


                                                           
                                                                            


                                                                                                     





                                                
                         

                                          






                                                                                                              
                                                                                                                                                                                                             
                  
                   



                                                                       
                                                                            

                         
                                              








                                                                                                              
                                                                                                                                                                                                             
                  
                   



                                                          
                                                                            

                         
                                              









                                                                                                                
                                                                                                                                                                                                             

                                                                                                         
                   
                                                          

       


                                                                                                     
   


                                          








                                                                                                                  
                                                                                                                                                                                                             


                                                                                                           
                   



                                                          
                                                                            

                         
                                              











                                                                                                                  
                                                                                                                                                                                                             

                                                                 
                   



                                                                                
                                                                            

                         
                                              












                                                                                                                  
                                                                                                                                                                                                             

                                                                       
                   



                                                          
                                                                            

                         
                                              










                                                                                                              
                                                                                                                                                                                                            
                         
                                              





                                                                       
                   


                                                          
                                                                            



                                                                                                     
                                                                                       







                                                                                                              
                                                                                                                                                                                                             
                  
                   


                                                        
                                                                            



                                                                                                     
                                          







                                                                                                              

                                                                                                                                                                                                             



                                                          
                                                                            


                                                                                                     
                                                     
                         
                                          







                                                                                                              
                                                                                                                                                                                                             
                  
                   


                                                        
                                                                            



                                                                                                     
                                          







                                                                                                              
                                                                                                                                                                                                             
                  
                   


                                                          
                                                                            



                                                                                                     
                                          



                                          





                                                                                                                                                                                                             
                  

                                                                                 
   

                                                                                                                                                                                                                                                    
       


                                                                                                     
   
                                                              
                         

                                          


   





                                                                                                                                                                                                             
                  

                                                                                 
   

                                                                                                                                                                                                                                                    
       


                                                                                                     
   
                                                              
                         

                                          


   



















































































































































































































































































































































































                                                                                                                                                                                                                                                     
                                            
























                                                                                                                                                                            
                                            









































                                                                                                                                                                            
                                            
                                                                                                               
       
                                                                                                        

                                                                                                                                                                              


                                                        

                                                                                                  
                                                                                                                                                                                                                        

                                                                                                  



                                                                       
                                            
                                                                                                              
                                                                                                      


                                                                                                      
       

                                                                                                                                                                              

                                                                                                                                    
                                                              
                         

                                                                      
                                                                                                                              
                                                                    





                                                        

                                                                                                                                                                              



                                                                                                                                    












                                                                                                                              

                                                                                         




                                                                        
                                                                                                                
















                                                                                                                                                                                                                                                                                                                                                
                                                                                                                                          









                                                                                                                                                                                                                                            
                                                                                                                                        





                                                                                                                                        
                                                                                  


                                                                                                                                                                                                                                                                                                                                                
                                                                                                                                          



















                                                                                                                                                                                                                                                                                                                                                
                                                                                                                                          


                                                                                                                                                                                                                                            
                                                                                                                                          








                                                                                                                                                                                                                                            
                                           


                                                                                                                                                   
                                                                                                       
                                                                                                           
                                                                             

                                                                                                                                                                       

                                                                                               



                                                                                                                                   

                                                                                 











                                                                                                                                                                                    











                                                                                                                                    





                                                                                                                                            







                                                                                                                                                                                                                                          








































































































                                                                                                                                                                                                                               





































                                                                                                                                                                              


                                                                                                                         
                                                                                    
























                                                                                                                                                                                                                                            



                                                                                                                                                                                                                                              

















                                                                                                                                                                                                                                                          



                                                                                                                                                                                                                                              
                                                                                                                                          


   



















                                                                                                                                                                                                                                                                                                                                                
                                                                                                                                          








                                                                                                                                                                                                                                            
                                                                                                                                        




                                                                                                                                        

                                                                                                                                        






                                                                                                                                        
                                                                                  


                                                                                                                                                                                                                                                                                                                                                
                                                                                                                                          






                                                                                                                                                                                                                                            
































































































































                                                                                                                                                                                                                                                                                                                                                
                                                      
                                           
                                                                                                             





                                                                                                                                
                                  



                                                                                                    

                                       



















                                                                                                                                                                                                             

 






























































































































                                                                                                                                                                                                                                                                                                                                                


                                                                         
                                           

                                                                                                 
                                                                                              
                                                                                                
                                                                                               
                                                                                                                     
                                  


                                                                                                       
                                  
                                           








                                                                                        
                                                     




                                                      
                                           



                                                                                                 




                                                                                                                        
                                                                                                                     
                                  


                                                                                                       
                                  




                                                                                                                           
                                                  
                                  
                                                                                                                                                                                  
                                                                 
                                                                                  
                                                                                                     
                                       
                                  


                                                    
                                           



                                                                                                 




                                                                                                                        





                                                                                                                     

                                                                                            
                                                                 
                                                    
                                                                 
                                                                                                     
                                       
                                  


                                                    
                                           








                                                                                                                     
                                                     



                                                                                                     
                                           













                                                                                                                     
                                           













                                                                                                                     
                                           










                                                                                                                     
 

                                                                            
                                           








                                                                                                            
                                                                                                                                   









                                                                                                     
                                                                                              




                                                                            



                                     
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
<title>Mu - edit.mu</title>
<meta name="Generator" content="Vim/7.4">
<meta name="plugin-version" content="vim7.4_v1">
<meta name="syntax" content="none">
<meta name="settings" content="use_css,pre_wrap,no_foldcolumn,expand_tabs,prevent_copy=">
<meta name="colorscheme" content="minimal">
<style type="text/css">
<!--
pre { white-space: pre-wrap; font-family: monospace; color: #eeeeee; background-color: #080808; }
body { font-family: monospace; color: #eeeeee; background-color: #080808; }
* { font-size: 1.05em; }
.muScenario { color: #00af00; }
.SalientComment { color: #00ffff; }
.Delimiter { color: #a04060; }
.CommentedCode { color: #6c6c6c; }
.Comment { color: #9090ff; }
.Constant { color: #00a0a0; }
.Special { color: #ff6060; }
.muControl { color: #c0a020; }
.muRecipe { color: #ff8700; }
-->
</style>

<script type='text/javascript'>
<!--

-->
</script>
</head>
<body>
<pre id='vimCodeElement'>
<span class="Comment"># Environment for learning programming using mu.</span>

<span class="muRecipe">recipe</span> main [
  <span class="Constant">local-scope</span>
  open-console
  initial-recipe:address:array:character<span class="Special"> &lt;- </span>restore <span class="Constant">[recipes.mu]</span>
  initial-sandbox:address:array:character<span class="Special"> &lt;- </span>new <span class="Constant">[]</span>
  env:address:programming-environment-data<span class="Special"> &lt;- </span>new-programming-environment <span class="Constant">0:literal/screen</span>, initial-recipe:address:array:character, initial-sandbox:address:array:character
  env:address:programming-environment-data<span class="Special"> &lt;- </span>restore-sandboxes env:address:programming-environment-data
  render-all <span class="Constant">0:literal/screen</span>, env:address:programming-environment-data
  show-screen <span class="Constant">0:literal/screen</span>
  event-loop <span class="Constant">0:literal/screen</span>, <span class="Constant">0:literal/console</span>, env:address:programming-environment-data
  <span class="Comment"># never gets here</span>
]

container programming-environment-data [
  recipes:address:editor-data
  recipe-warnings:address:array:character
  current-sandbox:address:editor-data
  sandbox:address:sandbox-data
  sandbox-in-focus?:boolean  <span class="Comment"># false =&gt; focus in recipes; true =&gt; focus in current-sandbox</span>
]

<span class="muRecipe">recipe</span> new-programming-environment [
  <span class="Constant">local-scope</span>
  screen:address<span class="Special"> &lt;- </span><span class="Constant">next-ingredient</span>
  initial-recipe-contents:address:array:character<span class="Special"> &lt;- </span><span class="Constant">next-ingredient</span>
  initial-sandbox-contents:address:array:character<span class="Special"> &lt;- </span><span class="Constant">next-ingredient</span>
  width:number<span class="Special"> &lt;- </span>screen-width screen:address
  height:number<span class="Special"> &lt;- </span>screen-height screen:address
  <span class="Comment"># top menu</span>
  result:address:programming-environment-data<span class="Special"> &lt;- </span>new programming-environment-data:type
  draw-horizontal screen:address, <span class="Constant">0:literal</span>, <span class="Constant">0:literal/left</span>, width:number, <span class="Constant">32:literal/space</span>, <span class="Constant">0:literal/black</span>, <span class="Constant">238:literal/grey</span>
  button-start:number<span class="Special"> &lt;- </span>subtract width:number, <span class="Constant">20:literal</span>
  button-on-screen?:boolean<span class="Special"> &lt;- </span>greater-or-equal button-start:number, <span class="Constant">0:literal</span>
  assert button-on-screen?:boolean, <span class="Constant">[screen too narrow for menu]</span>
  move-cursor screen:address, <span class="Constant">0:literal/row</span>, button-start:number/column
  run-button:address:array:character<span class="Special"> &lt;- </span>new <span class="Constant">[ run (F10)  ]</span>
  print-string screen:address, run-button:address:array:character, <span class="Constant">255:literal/white</span>, <span class="Constant">161:literal/reddish</span>
  <span class="Comment"># dotted line down the middle</span>
  divider:number, _<span class="Special"> &lt;- </span>divide-with-remainder width:number, <span class="Constant">2:literal</span>
  draw-vertical screen:address, divider:number, <span class="Constant">1:literal/top</span>, height:number, <span class="Constant">9482:literal/vertical-dotted</span>
  <span class="Comment"># recipe editor on the left</span>
  recipes:address:address:editor-data<span class="Special"> &lt;- </span>get-address result:address:programming-environment-data/deref, recipes:offset
  recipes:address:address:editor-data/deref<span class="Special"> &lt;- </span>new-editor initial-recipe-contents:address:array:character, screen:address, <span class="Constant">0:literal/left</span>, divider:number/right
  <span class="Comment"># sandbox editor on the right</span>
  new-left:number<span class="Special"> &lt;- </span>add divider:number, <span class="Constant">1:literal</span>
  new-right:number<span class="Special"> &lt;- </span>add new-left:number, <span class="Constant">5:literal</span>
  current-sandbox:address:address:editor-data<span class="Special"> &lt;- </span>get-address result:address:programming-environment-data/deref, current-sandbox:offset
  current-sandbox:address:address:editor-data/deref<span class="Special"> &lt;- </span>new-editor initial-sandbox-contents:address:array:character, screen:address, new-left:number, width:number
  screen:address<span class="Special"> &lt;- </span>render-all screen:address, result:address:programming-environment-data
  <span class="muControl">reply</span> result:address:programming-environment-data
]

<span class="muScenario">scenario</span> editor-initially-prints-string-to-screen [
  assume-screen <span class="Constant">10:literal/width</span>, <span class="Constant">5:literal/height</span>
  run [
    1:address:array:character<span class="Special"> &lt;- </span>new <span class="Constant">[abc]</span>
    new-editor 1:address:array:character, screen:address, <span class="Constant">0:literal/left</span>, <span class="Constant">10:literal/right</span>
  ]
  screen-should-contain [
   <span class="Constant"> .          .</span>
   <span class="Constant"> .abc       .</span>
   <span class="Constant"> .          .</span>
  ]
]

<span class="SalientComment">## In which we introduce the editor data structure, and show how it displays</span>
<span class="SalientComment">## text to the screen.</span>

container editor-data [
  <span class="Comment"># editable text: doubly linked list of characters (head contains a special sentinel)</span>
  data:address:duplex-list
  <span class="Comment"># location before cursor inside data</span>
  before-cursor:address:duplex-list

  <span class="Comment"># raw bounds of display area on screen</span>
  <span class="Comment"># always displays from row 1 and at most until bottom of screen</span>
  left:number
  right:number
  <span class="Comment"># raw screen coordinates of cursor</span>
  cursor-row:number
  cursor-column:number
]

<span class="Comment"># editor:address, screen:address &lt;- new-editor s:address:array:character, screen:address, left:number, right:number</span>
<span class="Comment"># creates a new editor widget and renders its initial appearance to screen.</span>
<span class="Comment">#   top/left/right constrain the screen area available to the new editor.</span>
<span class="Comment">#   right is exclusive.</span>
<span class="muRecipe">recipe</span> new-editor [
  <span class="Constant">local-scope</span>
  s:address:array:character<span class="Special"> &lt;- </span><span class="Constant">next-ingredient</span>
  screen:address<span class="Special"> &lt;- </span><span class="Constant">next-ingredient</span>
  <span class="Comment"># no clipping of bounds</span>
  left:number<span class="Special"> &lt;- </span><span class="Constant">next-ingredient</span>
  right:number<span class="Special"> &lt;- </span><span class="Constant">next-ingredient</span>
  right:number<span class="Special"> &lt;- </span>subtract right:number, <span class="Constant">1:literal</span>
  result:address:editor-data<span class="Special"> &lt;- </span>new editor-data:type
  <span class="Comment"># initialize screen-related fields</span>
  x:address:number<span class="Special"> &lt;- </span>get-address result:address:editor-data/deref, left:offset
  x:address:number/deref<span class="Special"> &lt;- </span>copy left:number
  x:address:number<span class="Special"> &lt;- </span>get-address result:address:editor-data/deref, right:offset
  x:address:number/deref<span class="Special"> &lt;- </span>copy right:number
  <span class="Comment"># initialize cursor</span>
  x:address:number<span class="Special"> &lt;- </span>get-address result:address:editor-data/deref, cursor-row:offset
  x:address:number/deref<span class="Special"> &lt;- </span>copy <span class="Constant">1:literal/top</span>
  x:address:number<span class="Special"> &lt;- </span>get-address result:address:editor-data/deref, cursor-column:offset
  x:address:number/deref<span class="Special"> &lt;- </span>copy left:number
  init:address:address:duplex-list<span class="Special"> &lt;- </span>get-address result:address:editor-data/deref, data:offset
  init:address:address:duplex-list/deref<span class="Special"> &lt;- </span>push-duplex <span class="Constant">167:literal/§</span>, <span class="Constant">0:literal/tail</span>
  y:address:address:duplex-list<span class="Special"> &lt;- </span>get-address result:address:editor-data/deref, before-cursor:offset
  y:address:address:duplex-list/deref<span class="Special"> &lt;- </span>copy init:address:address:duplex-list/deref
  <span class="Comment"># early exit if s is empty</span>
  <span class="muControl">reply-unless</span> s:address:array:character, result:address:editor-data
  len:number<span class="Special"> &lt;- </span>length s:address:array:character/deref
  <span class="muControl">reply-unless</span> len:number, result:address:editor-data
  idx:number<span class="Special"> &lt;- </span>copy <span class="Constant">0:literal</span>
  <span class="Comment"># now we can start appending the rest, character by character</span>
  curr:address:duplex-list<span class="Special"> &lt;- </span>copy init:address:address:duplex-list/deref
  <span class="Delimiter">{</span>
    done?:boolean<span class="Special"> &lt;- </span>greater-or-equal idx:number, len:number
    <span class="muControl">break-if</span> done?:boolean
    c:character<span class="Special"> &lt;- </span>index s:address:array:character/deref, idx:number
    insert-duplex c:character, curr:address:duplex-list
    <span class="Comment"># next iter</span>
    curr:address:duplex-list<span class="Special"> &lt;- </span>next-duplex curr:address:duplex-list
    idx:number<span class="Special"> &lt;- </span>add idx:number, <span class="Constant">1:literal</span>
    <span class="muControl">loop</span>
  <span class="Delimiter">}</span>
  <span class="Comment"># initialize cursor to top of screen</span>
  y:address:address:duplex-list<span class="Special"> &lt;- </span>get-address result:address:editor-data/deref, before-cursor:offset
  y:address:address:duplex-list/deref<span class="Special"> &lt;- </span>copy init:address:address:duplex-list/deref
  <span class="Comment"># initial render to screen, just for some old tests</span>
  _, screen:address<span class="Special"> &lt;- </span>render screen:address, result:address:editor-data
  <span class="muControl">reply</span> result:address:editor-data
]

<span class="muScenario">scenario</span> editor-initializes-without-data [
  assume-screen <span class="Constant">5:literal/width</span>, <span class="Constant">3:literal/height</span>
  run [
    1:address:editor-data<span class="Special"> &lt;- </span>new-editor <span class="Constant">0:literal/data</span>, screen:address, <span class="Constant">2:literal/left</span>, <span class="Constant">5:literal/right</span>
    2:editor-data<span class="Special"> &lt;- </span>copy 1:address:editor-data/deref
  ]
  memory-should-contain [
    <span class="Comment"># 2 (data) &lt;- just the § sentinel</span>
    <span class="Comment"># 3 (before cursor) &lt;- the § sentinel</span>
    4<span class="Special"> &lt;- </span>2  <span class="Comment"># left</span>
    5<span class="Special"> &lt;- </span>4  <span class="Comment"># right  (inclusive)</span>
    6<span class="Special"> &lt;- </span>1  <span class="Comment"># cursor row</span>
    7<span class="Special"> &lt;- </span>2  <span class="Comment"># cursor column</span>
  ]
  screen-should-contain [
   <span class="Constant"> .     .</span>
   <span class="Constant"> .     .</span>
   <span class="Constant"> .     .</span>
  ]
]

<span class="Comment"># bottom:number, screen:address &lt;- render screen:address, editor:address:editor-data</span>
<span class="muRecipe">recipe</span> render [
  <span class="Constant">local-scope</span>
  screen:address<span class="Special"> &lt;- </span><span class="Constant">next-ingredient</span>
  editor:address:editor-data<span class="Special"> &lt;- </span><span class="Constant">next-ingredient</span>
  <span class="muControl">reply-unless</span> editor:address:editor-data, <span class="Constant">1:literal/top</span>, screen:address/same-as-ingredient:0
  left:number<span class="Special"> &lt;- </span>get editor:address:editor-data/deref, left:offset
  screen-height:number<span class="Special"> &lt;- </span>screen-height screen:address
  right:number<span class="Special"> &lt;- </span>get editor:address:editor-data/deref, right:offset
  hide-screen screen:address
  <span class="Comment"># highlight mu code with color</span>
  color:number<span class="Special"> &lt;- </span>copy <span class="Constant">7:literal/white</span>
  highlighting-state:number<span class="Special"> &lt;- </span>copy <span class="Constant">0:literal/normal</span>
  <span class="Comment"># traversing editor</span>
  curr:address:duplex-list<span class="Special"> &lt;- </span>get editor:address:editor-data/deref, data:offset
  prev:address:duplex-list<span class="Special"> &lt;- </span>copy curr:address:duplex-list
  curr:address:duplex-list<span class="Special"> &lt;- </span>next-duplex curr:address:duplex-list
  <span class="Comment"># traversing screen</span>
  row:number<span class="Special"> &lt;- </span>copy <span class="Constant">1:literal/top</span>
  column:number<span class="Special"> &lt;- </span>copy left:number
  cursor-row:address:number<span class="Special"> &lt;- </span>get-address editor:address:editor-data/deref, cursor-row:offset
  cursor-column:address:number<span class="Special"> &lt;- </span>get-address editor:address:editor-data/deref, cursor-column:offset
  before-cursor:address:address:duplex-list<span class="Special"> &lt;- </span>get-address editor:address:editor-data/deref, before-cursor:offset
  move-cursor screen:address, row:number, column:number
  <span class="Delimiter">{</span>
<span class="Constant">    +next-character</span>
    <span class="muControl">break-unless</span> curr:address:duplex-list
    off-screen?:boolean<span class="Special"> &lt;- </span>greater-or-equal row:number, screen-height:number
    <span class="muControl">break-if</span> off-screen?:boolean
    <span class="Comment"># update editor-data.before-cursor</span>
    <span class="Comment"># Doing so at the start of each iteration ensures it stays one step behind</span>
    <span class="Comment"># the current character.</span>
    <span class="Delimiter">{</span>
      at-cursor-row?:boolean<span class="Special"> &lt;- </span>equal row:number, cursor-row:address:number/deref
      <span class="muControl">break-unless</span> at-cursor-row?:boolean
      at-cursor?:boolean<span class="Special"> &lt;- </span>equal column:number, cursor-column:address:number/deref
      <span class="muControl">break-unless</span> at-cursor?:boolean
      before-cursor:address:address:duplex-list/deref<span class="Special"> &lt;- </span>prev-duplex curr:address:duplex-list
    <span class="Delimiter">}</span>
    c:character<span class="Special"> &lt;- </span>get curr:address:duplex-list/deref, value:offset
    color:number, highlighting-state:number<span class="Special"> &lt;- </span>get-color color:number, highlighting-state:number, c:character
    <span class="Delimiter">{</span>
      <span class="Comment"># newline? move to left rather than 0</span>
      newline?:boolean<span class="Special"> &lt;- </span>equal c:character, <span class="Constant">10:literal/newline</span>
      <span class="muControl">break-unless</span> newline?:boolean
      <span class="Comment"># adjust cursor if necessary</span>
      <span class="Delimiter">{</span>
        at-cursor-row?:boolean<span class="Special"> &lt;- </span>equal row:number, cursor-row:address:number/deref
        <span class="muControl">break-unless</span> at-cursor-row?:boolean
        left-of-cursor?:boolean<span class="Special"> &lt;- </span>lesser-than column:number, cursor-column:address:number/deref
        <span class="muControl">break-unless</span> left-of-cursor?:boolean
        cursor-column:address:number/deref<span class="Special"> &lt;- </span>copy column:number
        before-cursor:address:address:duplex-list/deref<span class="Special"> &lt;- </span>prev-duplex curr:address:duplex-list
      <span class="Delimiter">}</span>
      <span class="Comment"># clear rest of line in this window</span>
      clear-line-delimited screen:address, column:number, right:number
      <span class="Comment"># skip to next line</span>
      row:number<span class="Special"> &lt;- </span>add row:number, <span class="Constant">1:literal</span>
      column:number<span class="Special"> &lt;- </span>copy left:number
      move-cursor screen:address, row:number, column:number
      curr:address:duplex-list<span class="Special"> &lt;- </span>next-duplex curr:address:duplex-list
      prev:address:duplex-list<span class="Special"> &lt;- </span>next-duplex prev:address:duplex-list
      <span class="muControl">loop</span> <span class="Constant">+next-character:label</span>
    <span class="Delimiter">}</span>
    <span class="Delimiter">{</span>
      <span class="Comment"># at right? wrap. even if there's only one more letter left; we need</span>
      <span class="Comment"># room for clicking on the cursor after it.</span>
      at-right?:boolean<span class="Special"> &lt;- </span>equal column:number, right:number
      <span class="muControl">break-unless</span> at-right?:boolean
      <span class="Comment"># print wrap icon</span>
      print-character screen:address, <span class="Constant">8617:literal/loop-back-to-left</span>, <span class="Constant">245:literal/grey</span>
      column:number<span class="Special"> &lt;- </span>copy left:number
      row:number<span class="Special"> &lt;- </span>add row:number, <span class="Constant">1:literal</span>
      move-cursor screen:address, row:number, column:number
      <span class="Comment"># don't increment curr</span>
      <span class="muControl">loop</span> <span class="Constant">+next-character:label</span>
    <span class="Delimiter">}</span>
    print-character screen:address, c:character, color:number
    curr:address:duplex-list<span class="Special"> &lt;- </span>next-duplex curr:address:duplex-list
    prev:address:duplex-list<span class="Special"> &lt;- </span>next-duplex prev:address:duplex-list
    column:number<span class="Special"> &lt;- </span>add column:number, <span class="Constant">1:literal</span>
    <span class="muControl">loop</span>
  <span class="Delimiter">}</span>
  <span class="Comment"># is cursor to the right of the last line? move to end</span>
  <span class="Delimiter">{</span>
    at-cursor-row?:boolean<span class="Special"> &lt;- </span>equal row:number, cursor-row:address:number/deref
    cursor-outside-line?:boolean<span class="Special"> &lt;- </span>lesser-or-equal column:number, cursor-column:address:number/deref
    before-cursor-on-same-line?:boolean<span class="Special"> &lt;- </span>and at-cursor-row?:boolean, cursor-outside-line?:boolean
    above-cursor-row?:boolean<span class="Special"> &lt;- </span>lesser-than row:number, cursor-row:address:number/deref
    before-cursor?:boolean<span class="Special"> &lt;- </span>or before-cursor-on-same-line?:boolean, above-cursor-row?:boolean
    <span class="muControl">break-unless</span> before-cursor?:boolean
    cursor-row:address:number/deref<span class="Special"> &lt;- </span>copy row:number
    cursor-column:address:number/deref<span class="Special"> &lt;- </span>copy column:number
    <span class="Comment"># line not wrapped but cursor outside bounds? wrap cursor</span>
    <span class="Delimiter">{</span>
      too-far-right?:boolean<span class="Special"> &lt;- </span>greater-than cursor-column:address:number/deref, right:number
      <span class="muControl">break-unless</span> too-far-right?:boolean
      cursor-column:address:number/deref<span class="Special"> &lt;- </span>copy left:number
      cursor-row:address:number/deref<span class="Special"> &lt;- </span>add cursor-row:address:number/deref, <span class="Constant">1:literal</span>
      above-screen-bottom?:boolean<span class="Special"> &lt;- </span>lesser-than cursor-row:address:number/deref, screen-height:number
      assert above-screen-bottom?:boolean, <span class="Constant">[unimplemented: wrapping cursor past bottom of screen]</span>
    <span class="Delimiter">}</span>
    before-cursor:address:address:duplex-list/deref<span class="Special"> &lt;- </span>copy prev:address:duplex-list
  <span class="Delimiter">}</span>
  <span class="Comment"># clear rest of current line</span>
  clear-line-delimited screen:address, column:number, right:number
  <span class="muControl">reply</span> row:number, screen:address/same-as-ingredient:0
]

<span class="Comment"># row:number, screen:address &lt;- render-string screen:address, s:address:array:character, left:number, right:number, color:number, row:number</span>
<span class="Comment"># move cursor at start of next line</span>
<span class="Comment"># print a string 's' to 'editor' in 'color' starting at 'row'</span>
<span class="Comment"># clear rest of last line, but don't move cursor to next line</span>
<span class="muRecipe">recipe</span> render-string [
  <span class="Constant">local-scope</span>
  screen:address<span class="Special"> &lt;- </span><span class="Constant">next-ingredient</span>
  s:address:array:character<span class="Special"> &lt;- </span><span class="Constant">next-ingredient</span>
  left:number<span class="Special"> &lt;- </span><span class="Constant">next-ingredient</span>
  right:number<span class="Special"> &lt;- </span><span class="Constant">next-ingredient</span>
  color:number<span class="Special"> &lt;- </span><span class="Constant">next-ingredient</span>
  row:number<span class="Special"> &lt;- </span><span class="Constant">next-ingredient</span>
  row:number<span class="Special"> &lt;- </span>add row:number, <span class="Constant">1:literal</span>
  <span class="muControl">reply-unless</span> s:address:array:character, row:number/same-as-ingredient:5, screen:address/same-as-ingredient:0
  column:number<span class="Special"> &lt;- </span>copy left:number
  move-cursor screen:address, row:number, column:number
  screen-height:number<span class="Special"> &lt;- </span>screen-height screen:address
  i:number<span class="Special"> &lt;- </span>copy <span class="Constant">0:literal</span>
  len:number<span class="Special"> &lt;- </span>length s:address:array:character/deref
  <span class="Delimiter">{</span>
<span class="Constant">    +next-character</span>
    done?:boolean<span class="Special"> &lt;- </span>greater-or-equal i:number, len:number
    <span class="muControl">break-if</span> done?:boolean
    done?:boolean<span class="Special"> &lt;- </span>greater-or-equal row:number, screen-height:number
    <span class="muControl">break-if</span> done?:boolean
    c:character<span class="Special"> &lt;- </span>index s:address:array:character/deref, i:number
    <span class="Delimiter">{</span>
      <span class="Comment"># at right? wrap.</span>
      at-right?:boolean<span class="Special"> &lt;- </span>equal column:number, right:number
      <span class="muControl">break-unless</span> at-right?:boolean
      <span class="Comment"># print wrap icon</span>
      print-character screen:address, <span class="Constant">8617:literal/loop-back-to-left</span>, <span class="Constant">245:literal/grey</span>
      column:number<span class="Special"> &lt;- </span>copy left:number
      row:number<span class="Special"> &lt;- </span>add row:number, <span class="Constant">1:literal</span>
      move-cursor screen:address, row:number, column:number
      <span class="muControl">loop</span> <span class="Constant">+next-character:label</span>  <span class="Comment"># retry i</span>
    <span class="Delimiter">}</span>
    i:number<span class="Special"> &lt;- </span>add i:number, <span class="Constant">1:literal</span>
    <span class="Delimiter">{</span>
      <span class="Comment"># newline? move to left rather than 0</span>
      newline?:boolean<span class="Special"> &lt;- </span>equal c:character, <span class="Constant">10:literal/newline</span>
      <span class="muControl">break-unless</span> newline?:boolean
      <span class="Comment"># clear rest of line in this window</span>
      <span class="Delimiter">{</span>
        done?:boolean<span class="Special"> &lt;- </span>greater-than column:number, right:number
        <span class="muControl">break-if</span> done?:boolean
        print-character screen:address, <span class="Constant">32:literal/space</span>
        column:number<span class="Special"> &lt;- </span>add column:number, <span class="Constant">1:literal</span>
        <span class="muControl">loop</span>
      <span class="Delimiter">}</span>
      row:number<span class="Special"> &lt;- </span>add row:number, <span class="Constant">1:literal</span>
      column:number<span class="Special"> &lt;- </span>copy left:number
      move-cursor screen:address, row:number, column:number
      <span class="muControl">loop</span> <span class="Constant">+next-character:label</span>
    <span class="Delimiter">}</span>
    print-character screen:address, c:character, color:number
    column:number<span class="Special"> &lt;- </span>add column:number, <span class="Constant">1:literal</span>
    <span class="muControl">loop</span>
  <span class="Delimiter">}</span>
  <span class="Delimiter">{</span>
    <span class="Comment"># clear rest of current line</span>
    line-done?:boolean<span class="Special"> &lt;- </span>greater-than column:number, right:number
    <span class="muControl">break-if</span> line-done?:boolean
    print-character screen:address, <span class="Constant">32:literal/space</span>
    column:number<span class="Special"> &lt;- </span>add column:number, <span class="Constant">1:literal</span>
    <span class="muControl">loop</span>
  <span class="Delimiter">}</span>
  <span class="muControl">reply</span> row:number/same-as-ingredient:5, screen:address/same-as-ingredient:0
]

<span class="Comment"># row:number, screen:address &lt;- render-screen screen:address, sandbox-screen:address, left:number, right:number, row:number</span>
<span class="Comment"># print the fake sandbox screen to 'screen' with appropriate delimiters</span>
<span class="Comment"># leave cursor at start of next line</span>
<span class="muRecipe">recipe</span> render-screen [
  <span class="Constant">local-scope</span>
  screen:address<span class="Special"> &lt;- </span><span class="Constant">next-ingredient</span>
  s:address:screen<span class="Special"> &lt;- </span><span class="Constant">next-ingredient</span>
  left:number<span class="Special"> &lt;- </span><span class="Constant">next-ingredient</span>
  right:number<span class="Special"> &lt;- </span><span class="Constant">next-ingredient</span>
  row:number<span class="Special"> &lt;- </span><span class="Constant">next-ingredient</span>
  row:number<span class="Special"> &lt;- </span>add row:number, <span class="Constant">1:literal</span>
  <span class="muControl">reply-unless</span> s:address:screen, row:number/same-as-ingredient:4, screen:address/same-as-ingredient:0
  <span class="Comment"># print 'screen:'</span>
  header:address:array:character<span class="Special"> &lt;- </span>new <span class="Constant">[screen:]</span>
  row:number<span class="Special"> &lt;- </span>subtract row:number, <span class="Constant">1:literal</span>  <span class="Comment"># compensate for render-string below</span>
  row:number<span class="Special"> &lt;- </span>render-string screen:address, header:address:array:character, left:number, right:number, <span class="Constant">245:literal/grey</span>, row:number
  <span class="Comment"># newline</span>
  row:number<span class="Special"> &lt;- </span>add row:number, <span class="Constant">1:literal</span>
  move-cursor screen:address, row:number, left:number
  <span class="Comment"># start printing s</span>
  column:number<span class="Special"> &lt;- </span>copy left:number
  s-width:number<span class="Special"> &lt;- </span>screen-width s:address:screen
  s-height:number<span class="Special"> &lt;- </span>screen-height s:address:screen
  buf:address:array:screen-cell<span class="Special"> &lt;- </span>get s:address:screen/deref, data:offset
  stop-printing:number<span class="Special"> &lt;- </span>add left:number, s-width:number, <span class="Constant">3:literal</span>
  max-column:number<span class="Special"> &lt;- </span>min stop-printing:number, right:number
  i:number<span class="Special"> &lt;- </span>copy <span class="Constant">0:literal</span>
  len:number<span class="Special"> &lt;- </span>length buf:address:array:screen-cell/deref
  screen-height:number<span class="Special"> &lt;- </span>screen-height screen:address
  <span class="Delimiter">{</span>
    done?:boolean<span class="Special"> &lt;- </span>greater-or-equal i:number, len:number
    <span class="muControl">break-if</span> done?:boolean
    done?:boolean<span class="Special"> &lt;- </span>greater-or-equal row:number, screen-height:number
    <span class="muControl">break-if</span> done?:boolean
    column:number<span class="Special"> &lt;- </span>copy left:number
    move-cursor screen:address, row:number, column:number
    <span class="Comment"># initial leader for each row: two spaces and a '.'</span>
    print-character screen:address, <span class="Constant">32:literal/space</span>, <span class="Constant">245:literal/grey</span>
    print-character screen:address, <span class="Constant">32:literal/space</span>, <span class="Constant">245:literal/grey</span>
    print-character screen:address, <span class="Constant">46:literal/full-stop</span>, <span class="Constant">245:literal/grey</span>
    column:number<span class="Special"> &lt;- </span>add left:number, <span class="Constant">3:literal</span>
    <span class="Delimiter">{</span>
      <span class="Comment"># print row</span>
      row-done?:boolean<span class="Special"> &lt;- </span>greater-or-equal column:number, max-column:number
      <span class="muControl">break-if</span> row-done?:boolean
      curr:screen-cell<span class="Special"> &lt;- </span>index buf:address:array:screen-cell/deref, i:number
      c:character<span class="Special"> &lt;- </span>get curr:screen-cell, contents:offset
      print-character screen:address, c:character, <span class="Constant">245:literal/grey</span>
      column:number<span class="Special"> &lt;- </span>add column:number, <span class="Constant">1:literal</span>
      i:number<span class="Special"> &lt;- </span>add i:number, <span class="Constant">1:literal</span>
      <span class="muControl">loop</span>
    <span class="Delimiter">}</span>
    <span class="Comment"># print final '.'</span>
    print-character screen:address, <span class="Constant">46:literal/full-stop</span>, <span class="Constant">245:literal/grey</span>
    column:number<span class="Special"> &lt;- </span>add column:number, <span class="Constant">1:literal</span>
    <span class="Delimiter">{</span>
      <span class="Comment"># clear rest of current line</span>
      line-done?:boolean<span class="Special"> &lt;- </span>greater-than column:number, right:number
      <span class="muControl">break-if</span> line-done?:boolean
      print-character screen:address, <span class="Constant">32:literal/space</span>
      column:number<span class="Special"> &lt;- </span>add column:number, <span class="Constant">1:literal</span>
      <span class="muControl">loop</span>
    <span class="Delimiter">}</span>
    row:number<span class="Special"> &lt;- </span>add row:number, <span class="Constant">1:literal</span>
    <span class="muControl">loop</span>
  <span class="Delimiter">}</span>
  <span class="muControl">reply</span> row:number/same-as-ingredient:4, screen:address/same-as-ingredient:0
]

<span class="muRecipe">recipe</span> clear-line-delimited [
  <span class="Constant">local-scope</span>
  screen:address<span class="Special"> &lt;- </span><span class="Constant">next-ingredient</span>
  left:number<span class="Special"> &lt;- </span><span class="Constant">next-ingredient</span>
  right:number<span class="Special"> &lt;- </span><span class="Constant">next-ingredient</span>
  column:number<span class="Special"> &lt;- </span>copy left:number
  <span class="Delimiter">{</span>
    done?:boolean<span class="Special"> &lt;- </span>greater-than column:number, right:number
    <span class="muControl">break-if</span> done?:boolean
    print-character screen:address, <span class="Constant">32:literal/space</span>
    column:number<span class="Special"> &lt;- </span>add column:number, <span class="Constant">1:literal</span>
    <span class="muControl">loop</span>
  <span class="Delimiter">}</span>
]

<span class="muScenario">scenario</span> editor-initially-prints-multiple-lines [
  assume-screen <span class="Constant">5:literal/width</span>, <span class="Constant">5:literal/height</span>
  run [
    s:address:array:character<span class="Special"> &lt;- </span>new <span class="Constant">[abc</span>
<span class="Constant">def]</span>
    new-editor s:address:array:character, screen:address, <span class="Constant">0:literal/left</span>, <span class="Constant">5:literal/right</span>
  ]
  screen-should-contain [
   <span class="Constant"> .     .</span>
   <span class="Constant"> .abc  .</span>
   <span class="Constant"> .def  .</span>
   <span class="Constant"> .     .</span>
  ]
]

<span class="muScenario">scenario</span> editor-initially-handles-offsets [
  assume-screen <span class="Constant">5:literal/width</span>, <span class="Constant">5:literal/height</span>
  run [
    s:address:array:character<span class="Special"> &lt;- </span>new <span class="Constant">[abc]</span>
    new-editor s:address:array:character, screen:address, <span class="Constant">1:literal/left</span>, <span class="Constant">5:literal/right</span>
  ]
  screen-should-contain [
   <span class="Constant"> .     .</span>
   <span class="Constant"> . abc .</span>
   <span class="Constant"> .     .</span>
  ]
]

<span class="muScenario">scenario</span> editor-initially-prints-multiple-lines-at-offset [
  assume-screen <span class="Constant">5:literal/width</span>, <span class="Constant">5:literal/height</span>
  run [
    s:address:array:character<span class="Special"> &lt;- </span>new <span class="Constant">[abc</span>
<span class="Constant">def]</span>
    new-editor s:address:array:character, screen:address, <span class="Constant">1:literal/left</span>, <span class="Constant">5:literal/right</span>
  ]
  screen-should-contain [
   <span class="Constant"> .     .</span>
   <span class="Constant"> . abc .</span>
   <span class="Constant"> . def .</span>
   <span class="Constant"> .     .</span>
  ]
]

<span class="muScenario">scenario</span> editor-initially-wraps-long-lines [
  assume-screen <span class="Constant">5:literal/width</span>, <span class="Constant">5:literal/height</span>
  run [
    s:address:array:character<span class="Special"> &lt;- </span>new <span class="Constant">[abc def]</span>
    new-editor s:address:array:character, screen:address, <span class="Constant">0:literal/left</span>, <span class="Constant">5:literal/right</span>
  ]
  screen-should-contain [
   <span class="Constant"> .     .</span>
   <span class="Constant"> .abc ↩.</span>
   <span class="Constant"> .def  .</span>
   <span class="Constant"> .     .</span>
  ]
  screen-should-contain-in-color <span class="Constant">245:literal/grey</span> [
   <span class="Constant"> .     .</span>
   <span class="Constant"> .    ↩.</span>
   <span class="Constant"> .     .</span>
   <span class="Constant"> .     .</span>
  ]
]

<span class="muScenario">scenario</span> editor-initially-wraps-barely-long-lines [
  assume-screen <span class="Constant">5:literal/width</span>, <span class="Constant">5:literal/height</span>
  run [
    s:address:array:character<span class="Special"> &lt;- </span>new <span class="Constant">[abcde]</span>
    new-editor s:address:array:character, screen:address, <span class="Constant">0:literal/left</span>, <span class="Constant">5:literal/right</span>
  ]
  <span class="Comment"># still wrap, even though the line would fit. We need room to click on the</span>
  <span class="Comment"># end of the line</span>
  screen-should-contain [
   <span class="Constant"> .     .</span>
<span class="Constant">    .abcd↩.</span>
   <span class="Constant"> .e    .</span>
   <span class="Constant"> .     .</span>
  ]
  screen-should-contain-in-color <span class="Constant">245:literal/grey</span> [
   <span class="Constant"> .     .</span>
   <span class="Constant"> .    ↩.</span>
   <span class="Constant"> .     .</span>
   <span class="Constant"> .     .</span>
  ]
]

<span class="muScenario">scenario</span> editor-initializes-empty-text [
  assume-screen <span class="Constant">5:literal/width</span>, <span class="Constant">5:literal/height</span>
  run [
    1:address:array:character<span class="Special"> &lt;- </span>new <span class="Constant">[]</span>
    2:address:editor-data<span class="Special"> &lt;- </span>new-editor 1:address:array:character, screen:address, <span class="Constant">0:literal/left</span>, <span class="Constant">5:literal/right</span>
    3:number<span class="Special"> &lt;- </span>get 2:address:editor-data/deref, cursor-row:offset
    4:number<span class="Special"> &lt;- </span>get 2:address:editor-data/deref, cursor-column:offset
  ]
  screen-should-contain [
   <span class="Constant"> .     .</span>
   <span class="Constant"> .     .</span>
   <span class="Constant"> .     .</span>
  ]
  memory-should-contain [
    3<span class="Special"> &lt;- </span>1  <span class="Comment"># cursor row</span>
    4<span class="Special"> &lt;- </span>0  <span class="Comment"># cursor column</span>
  ]
]

<span class="SalientComment">## highlighting mu code</span>

<span class="muScenario">scenario</span> render-colors-comments [
  assume-screen <span class="Constant">5:literal/width</span>, <span class="Constant">5:literal/height</span>
  run [
    s:address:array:character<span class="Special"> &lt;- </span>new <span class="Constant">[abc</span>
<span class="Constant"># de</span>
<span class="Constant">f]</span>
    new-editor s:address:array:character, screen:address, <span class="Constant">0:literal/left</span>, <span class="Constant">5:literal/right</span>
  ]
  screen-should-contain [
   <span class="Constant"> .     .</span>
   <span class="Constant"> .abc  .</span>
   <span class="Constant"> .# de .</span>
   <span class="Constant"> .f    .</span>
   <span class="Constant"> .     .</span>
  ]
  screen-should-contain-in-color <span class="Constant">12:literal/lightblue</span>, [
   <span class="Constant"> .     .</span>
   <span class="Constant"> .     .</span>
   <span class="Constant"> .# de .</span>
   <span class="Constant"> .     .</span>
   <span class="Constant"> .     .</span>
  ]
  screen-should-contain-in-color <span class="Constant">7:literal/white</span>, [
   <span class="Constant"> .     .</span>
   <span class="Constant"> .abc  .</span>
   <span class="Constant"> .     .</span>
   <span class="Constant"> .f    .</span>
   <span class="Constant"> .     .</span>
  ]
]

<span class="Comment"># color:number, highlighting-state:number &lt;- get-color color:number, highlighting-state:number, c:character</span>
<span class="muRecipe">recipe</span> get-color [
  <span class="Constant">local-scope</span>
  color:number<span class="Special"> &lt;- </span><span class="Constant">next-ingredient</span>
  highlighting-state:number<span class="Special"> &lt;- </span><span class="Constant">next-ingredient</span>
  c:character<span class="Special"> &lt;- </span><span class="Constant">next-ingredient</span>
  color-is-white?:boolean<span class="Special"> &lt;- </span>equal color:number, <span class="Constant">7:literal/white</span>
<span class="CommentedCode">#?   $print [character: ], c:character, 10:literal/newline #? 1</span>
  <span class="Comment"># if color is white and next character is '#', switch color to blue</span>
  <span class="Delimiter">{</span>
    <span class="muControl">break-unless</span> color-is-white?:boolean
    starting-comment?:boolean<span class="Special"> &lt;- </span>equal c:character, <span class="Constant">35:literal/#</span>
    <span class="muControl">break-unless</span> starting-comment?:boolean
<span class="CommentedCode">#?     $print [switch color back to blue], 10:literal/newline #? 1</span>
    color:number<span class="Special"> &lt;- </span>copy <span class="Constant">12:literal/lightblue</span>
    <span class="muControl">jump</span> <span class="Constant">+exit:label</span>
  <span class="Delimiter">}</span>
  <span class="Comment"># if color is blue and next character is newline, switch color to white</span>
  <span class="Delimiter">{</span>
    color-is-blue?:boolean<span class="Special"> &lt;- </span>equal color:number, <span class="Constant">12:literal/lightblue</span>
    <span class="muControl">break-unless</span> color-is-blue?:boolean
    ending-comment?:boolean<span class="Special"> &lt;- </span>equal c:character, <span class="Constant">10:literal/newline</span>
    <span class="muControl">break-unless</span> ending-comment?:boolean
<span class="CommentedCode">#?     $print [switch color back to white], 10:literal/newline #? 1</span>
    color:number<span class="Special"> &lt;- </span>copy <span class="Constant">7:literal/white</span>
    <span class="muControl">jump</span> <span class="Constant">+exit:label</span>
  <span class="Delimiter">}</span>
  <span class="Comment"># if color is white (no comments) and next character is '&lt;', switch color to red</span>
  <span class="Delimiter">{</span>
    <span class="muControl">break-unless</span> color-is-white?:boolean
    starting-assignment?:boolean<span class="Special"> &lt;- </span>equal c:character, <span class="Constant">60:literal/&lt;</span>
    <span class="muControl">break-unless</span> starting-assignment?:boolean
    color:number<span class="Special"> &lt;- </span>copy <span class="Constant">1:literal/red</span>
    <span class="muControl">jump</span> <span class="Constant">+exit:label</span>
  <span class="Delimiter">}</span>
  <span class="Comment"># if color is red and next character is space, switch color to white</span>
  <span class="Delimiter">{</span>
    color-is-red?:boolean<span class="Special"> &lt;- </span>equal color:number, <span class="Constant">1:literal/red</span>
    <span class="muControl">break-unless</span> color-is-red?:boolean
    ending-assignment?:boolean<span class="Special"> &lt;- </span>equal c:character, <span class="Constant">32:literal/space</span>
    <span class="muControl">break-unless</span> ending-assignment?:boolean
    color:number<span class="Special"> &lt;- </span>copy <span class="Constant">7:literal/white</span>
    <span class="muControl">jump</span> <span class="Constant">+exit:label</span>
  <span class="Delimiter">}</span>
  <span class="Comment"># otherwise no change</span>
<span class="Constant">  +exit</span>
  <span class="muControl">reply</span> color:number, highlighting-state:number
]

<span class="muScenario">scenario</span> render-colors-assignment [
  assume-screen <span class="Constant">8:literal/width</span>, <span class="Constant">5:literal/height</span>
  run [
    s:address:array:character<span class="Special"> &lt;- </span>new <span class="Constant">[abc</span>
<span class="Constant">d &lt;- e</span>
<span class="Constant">f]</span>
    new-editor s:address:array:character, screen:address, <span class="Constant">0:literal/left</span>, <span class="Constant">8:literal/right</span>
  ]
  screen-should-contain [
   <span class="Constant"> .        .</span>
   <span class="Constant"> .abc     .</span>
   <span class="Constant"> .d &lt;- e  .</span>
   <span class="Constant"> .f       .</span>
   <span class="Constant"> .        .</span>
  ]
  screen-should-contain-in-color <span class="Constant">1:literal/red</span>, [
   <span class="Constant"> .        .</span>
   <span class="Constant"> .        .</span>
   <span class="Constant"> .  &lt;-    .</span>
   <span class="Constant"> .        .</span>
   <span class="Constant"> .        .</span>
  ]
]

<span class="SalientComment">## handling events from the keyboard, mouse, touch screen, ...</span>

<span class="muRecipe">recipe</span> event-loop [
  <span class="Constant">local-scope</span>
  screen:address<span class="Special"> &lt;- </span><span class="Constant">next-ingredient</span>
  console:address<span class="Special"> &lt;- </span><span class="Constant">next-ingredient</span>
  env:address:programming-environment-data<span class="Special"> &lt;- </span><span class="Constant">next-ingredient</span>
  recipes:address:editor-data<span class="Special"> &lt;- </span>get env:address:programming-environment-data/deref, recipes:offset
  current-sandbox:address:editor-data<span class="Special"> &lt;- </span>get env:address:programming-environment-data/deref, current-sandbox:offset
  sandbox-in-focus?:address:boolean<span class="Special"> &lt;- </span>get-address env:address:programming-environment-data/deref, sandbox-in-focus?:offset
  <span class="Delimiter">{</span>
    <span class="Comment"># looping over each (keyboard or touch) event as it occurs</span>
<span class="Constant">    +next-event</span>
    e:event, console:address, found?:boolean, quit?:boolean<span class="Special"> &lt;- </span>read-event console:address
    <span class="muControl">loop-unless</span> found?:boolean
    <span class="muControl">break-if</span> quit?:boolean  <span class="Comment"># only in tests</span>
    trace <span class="Constant">[app]</span>, <span class="Constant">[next-event]</span>
    <span class="Comment"># check for global events that will trigger regardless of which editor has focus</span>
    <span class="Delimiter">{</span>
      k:address:number<span class="Special"> &lt;- </span>maybe-convert e:event, keycode:variant
      <span class="muControl">break-unless</span> k:address:number
      <span class="Comment"># F10? load all code and run all sandboxes.</span>
      <span class="Delimiter">{</span>
        do-run?:boolean<span class="Special"> &lt;- </span>equal k:address:number/deref, <span class="Constant">65526:literal/F10</span>
        <span class="muControl">break-unless</span> do-run?:boolean
        run-sandboxes env:address:programming-environment-data
        <span class="Comment"># F10 might update warnings and results on both sides</span>
        screen:address<span class="Special"> &lt;- </span>render-all screen:address, env:address:programming-environment-data
        update-cursor screen:address, recipes:address:editor-data, current-sandbox:address:editor-data, sandbox-in-focus?:address:boolean/deref
        show-screen screen:address
        <span class="muControl">loop</span> <span class="Constant">+next-event:label</span>
      <span class="Delimiter">}</span>
    <span class="Delimiter">}</span>
    <span class="Comment"># 'touch' event</span>
    <span class="Delimiter">{</span>
      t:address:touch-event<span class="Special"> &lt;- </span>maybe-convert e:event, touch:variant
      <span class="muControl">break-unless</span> t:address:touch-event
      <span class="Comment"># on a sandbox delete icon? process delete</span>
      <span class="Delimiter">{</span>
        was-delete?:boolean<span class="Special"> &lt;- </span>delete-sandbox t:address:touch-event/deref, env:address:programming-environment-data
        <span class="muControl">break-unless</span> was-delete?:boolean
        screen:address<span class="Special"> &lt;- </span>render-sandbox-side screen:address, env:address:programming-environment-data, <span class="Constant">1:literal/clear</span>
        update-cursor screen:address, recipes:address:editor-data, current-sandbox:address:editor-data, sandbox-in-focus?:address:boolean/deref
        <span class="muControl">loop</span> <span class="Constant">+next-event:label</span>
      <span class="Delimiter">}</span>
      <span class="Comment"># if not, send to both editors</span>
      _<span class="Special"> &lt;- </span>move-cursor-in-editor screen:address, recipes:address:editor-data, t:address:touch-event/deref
      sandbox-in-focus?:address:boolean/deref<span class="Special"> &lt;- </span>move-cursor-in-editor screen:address, current-sandbox:address:editor-data, t:address:touch-event/deref
      <span class="muControl">jump</span> <span class="Constant">+continue:label</span>
    <span class="Delimiter">}</span>
    <span class="Comment"># if it's not global, send to appropriate editor</span>
    <span class="Delimiter">{</span>
      <span class="Delimiter">{</span>
        <span class="muControl">break-if</span> sandbox-in-focus?:address:boolean/deref
        handle-event screen:address, console:address, recipes:address:editor-data, e:event
      <span class="Delimiter">}</span>
      <span class="Delimiter">{</span>
        <span class="muControl">break-unless</span> sandbox-in-focus?:address:boolean/deref
        handle-event screen:address, console:address, current-sandbox:address:editor-data, e:event
      <span class="Delimiter">}</span>
    <span class="Delimiter">}</span>
<span class="Constant">    +continue</span>
    <span class="Comment"># if no more events currently left to process, render.</span>
    <span class="Comment"># we rely on 'render' to update 'before-cursor' on pointer events, but</span>
    <span class="Comment"># they won't usually come fast enough to trigger this.</span>
    <span class="Comment"># todo: test this</span>
    <span class="Delimiter">{</span>
      more-events?:boolean<span class="Special"> &lt;- </span>has-more-events? console:address
      <span class="muControl">break-if</span> more-events?:boolean
      render-minimal screen:address, env:address:programming-environment-data
    <span class="Delimiter">}</span>
    <span class="muControl">loop</span>
  <span class="Delimiter">}</span>
]

<span class="Comment"># helper for testing a single editor</span>
<span class="muRecipe">recipe</span> editor-event-loop [
  <span class="Constant">local-scope</span>
  screen:address<span class="Special"> &lt;- </span><span class="Constant">next-ingredient</span>
  console:address<span class="Special"> &lt;- </span><span class="Constant">next-ingredient</span>
  editor:address:editor-data<span class="Special"> &lt;- </span><span class="Constant">next-ingredient</span>
  <span class="Delimiter">{</span>
    <span class="Comment"># looping over each (keyboard or touch) event as it occurs</span>
<span class="Constant">    +next-event</span>
    e:event, console:address, found?:boolean, quit?:boolean<span class="Special"> &lt;- </span>read-event console:address
    <span class="muControl">loop-unless</span> found?:boolean
    <span class="muControl">break-if</span> quit?:boolean  <span class="Comment"># only in tests</span>
    trace <span class="Constant">[app]</span>, <span class="Constant">[next-event]</span>
    <span class="Comment"># 'touch' event - send to both editors</span>
    <span class="Delimiter">{</span>
      t:address:touch-event<span class="Special"> &lt;- </span>maybe-convert e:event, touch:variant
      <span class="muControl">break-unless</span> t:address:touch-event
      move-cursor-in-editor screen:address, editor:address:editor-data, t:address:touch-event/deref
      <span class="muControl">jump</span> <span class="Constant">+continue:label</span>
    <span class="Delimiter">}</span>
    <span class="Comment"># other events - send to appropriate editor</span>
    handle-event screen:address, console:address, editor:address:editor-data, e:event
<span class="Constant">    +continue</span>
    row:number, screen:address<span class="Special"> &lt;- </span>render screen:address, editor:address:editor-data
    <span class="Comment"># clear next line, in case we just processed a backspace</span>
    left:number<span class="Special"> &lt;- </span>get editor:address:editor-data/deref, left:offset
    right:number<span class="Special"> &lt;- </span>get editor:address:editor-data/deref, right:offset
    row:number<span class="Special"> &lt;- </span>add row:number, <span class="Constant">1:literal</span>
    move-cursor screen:address, row:number, left:number
    clear-line-delimited screen:address, left:number, right:number
    <span class="muControl">loop</span>
  <span class="Delimiter">}</span>
]

<span class="muRecipe">recipe</span> handle-event [
  <span class="Constant">local-scope</span>
  screen:address<span class="Special"> &lt;- </span><span class="Constant">next-ingredient</span>
  console:address<span class="Special"> &lt;- </span><span class="Constant">next-ingredient</span>
  editor:address:editor-data<span class="Special"> &lt;- </span><span class="Constant">next-ingredient</span>
  e:event<span class="Special"> &lt;- </span><span class="Constant">next-ingredient</span>
  <span class="muControl">reply-unless</span> editor:address:editor-data
  <span class="Comment"># character</span>
  <span class="Delimiter">{</span>
    c:address:character<span class="Special"> &lt;- </span>maybe-convert e:event, text:variant
    <span class="muControl">break-unless</span> c:address:character
    <span class="Comment"># check for special characters</span>
    <span class="Comment"># unless it's a backspace</span>
    <span class="Delimiter">{</span>
      backspace?:boolean<span class="Special"> &lt;- </span>equal c:address:character/deref, <span class="Constant">8:literal/backspace</span>
      <span class="muControl">break-unless</span> backspace?:boolean
      delete-before-cursor editor:address:editor-data
      <span class="muControl">reply</span>
    <span class="Delimiter">}</span>
    <span class="Comment"># ctrl-a</span>
    <span class="Delimiter">{</span>
      ctrl-a?:boolean<span class="Special"> &lt;- </span>equal c:address:character/deref, <span class="Constant">1:literal/ctrl-a</span>
      <span class="muControl">break-unless</span> ctrl-a?:boolean
      move-to-start-of-line editor:address:editor-data
      <span class="muControl">reply</span>
    <span class="Delimiter">}</span>
    <span class="Comment"># ctrl-e</span>
    <span class="Delimiter">{</span>
      ctrl-e?:boolean<span class="Special"> &lt;- </span>equal c:address:character/deref, <span class="Constant">5:literal/ctrl-e</span>
      <span class="muControl">break-unless</span> ctrl-e?:boolean
      move-to-end-of-line editor:address:editor-data
      <span class="muControl">reply</span>
    <span class="Delimiter">}</span>
    <span class="Comment"># ctrl-u</span>
    <span class="Delimiter">{</span>
      ctrl-u?:boolean<span class="Special"> &lt;- </span>equal c:address:character/deref, <span class="Constant">21:literal/ctrl-u</span>
      <span class="muControl">break-unless</span> ctrl-u?:boolean
      delete-to-start-of-line editor:address:editor-data
      <span class="muControl">reply</span>
    <span class="Delimiter">}</span>
    <span class="Comment"># ctrl-k</span>
    <span class="Delimiter">{</span>
      ctrl-k?:boolean<span class="Special"> &lt;- </span>equal c:address:character/deref, <span class="Constant">11:literal/ctrl-k</span>
      <span class="muControl">break-unless</span> ctrl-k?:boolean
      delete-to-end-of-line editor:address:editor-data
      <span class="muControl">reply</span>
    <span class="Delimiter">}</span>
    <span class="Comment"># otherwise type it in</span>
    insert-at-cursor editor:address:editor-data, c:address:character/deref, screen:address
    <span class="muControl">reply</span>
  <span class="Delimiter">}</span>
  <span class="Comment"># otherwise it's a special key</span>
  k:address:number<span class="Special"> &lt;- </span>maybe-convert e:event, keycode:variant
  assert k:address:number, <span class="Constant">[event was of unknown type; neither keyboard nor mouse]</span>
  d:address:duplex-list<span class="Special"> &lt;- </span>get editor:address:editor-data/deref, data:offset
  before-cursor:address:address:duplex-list<span class="Special"> &lt;- </span>get-address editor:address:editor-data/deref, before-cursor:offset
  cursor-row:address:number<span class="Special"> &lt;- </span>get-address editor:address:editor-data/deref, cursor-row:offset
  cursor-column:address:number<span class="Special"> &lt;- </span>get-address editor:address:editor-data/deref, cursor-column:offset
  screen-height:number<span class="Special"> &lt;- </span>screen-height screen:address
  left:number<span class="Special"> &lt;- </span>get editor:address:editor-data/deref, left:offset
  right:number<span class="Special"> &lt;- </span>get editor:address:editor-data/deref, right:offset
  <span class="Comment"># arrows; update cursor-row and cursor-column, leave before-cursor to 'render'.</span>
  <span class="Comment"># right arrow</span>
  <span class="Delimiter">{</span>
    move-to-next-character?:boolean<span class="Special"> &lt;- </span>equal k:address:number/deref, <span class="Constant">65514:literal/right-arrow</span>
    <span class="muControl">break-unless</span> move-to-next-character?:boolean
    <span class="Comment"># if not at end of text</span>
    old-cursor:address:duplex-list<span class="Special"> &lt;- </span>next-duplex before-cursor:address:address:duplex-list/deref
    <span class="muControl">break-unless</span> old-cursor:address:duplex-list
    <span class="Comment"># scan to next character</span>
    before-cursor:address:address:duplex-list/deref<span class="Special"> &lt;- </span>copy old-cursor:address:duplex-list
    <span class="Comment"># if crossed a newline, move cursor to start of next row</span>
    <span class="Delimiter">{</span>
      old-cursor-character:character<span class="Special"> &lt;- </span>get before-cursor:address:address:duplex-list/deref/deref, value:offset
      was-at-newline?:boolean<span class="Special"> &lt;- </span>equal old-cursor-character:character, <span class="Constant">10:literal/newline</span>
      <span class="muControl">break-unless</span> was-at-newline?:boolean
      cursor-row:address:number/deref<span class="Special"> &lt;- </span>add cursor-row:address:number/deref, <span class="Constant">1:literal</span>
      cursor-column:address:number/deref<span class="Special"> &lt;- </span>copy left:number
      <span class="Comment"># todo: what happens when cursor is too far down?</span>
      screen-height:number<span class="Special"> &lt;- </span>screen-height screen:address
      above-screen-bottom?:boolean<span class="Special"> &lt;- </span>lesser-than cursor-row:address:number/deref, screen-height:number
      assert above-screen-bottom?:boolean, <span class="Constant">[unimplemented: moving past bottom of screen]</span>
      <span class="muControl">reply</span>
    <span class="Delimiter">}</span>
    <span class="Comment"># if the line wraps, move cursor to start of next row</span>
    <span class="Delimiter">{</span>
      <span class="Comment"># if we're at the column just before the wrap indicator</span>
      wrap-column:number<span class="Special"> &lt;- </span>subtract right:number, <span class="Constant">1:literal</span>
      at-wrap?:boolean<span class="Special"> &lt;- </span>equal cursor-column:address:number/deref, wrap-column:number
      <span class="muControl">break-unless</span> at-wrap?:boolean
      <span class="Comment"># and if next character isn't newline</span>
      new-cursor:address:duplex-list<span class="Special"> &lt;- </span>next-duplex old-cursor:address:duplex-list
      <span class="muControl">break-unless</span> new-cursor:address:duplex-list
      next-character:character<span class="Special"> &lt;- </span>get new-cursor:address:duplex-list/deref, value:offset
      newline?:boolean<span class="Special"> &lt;- </span>equal next-character:character, <span class="Constant">10:literal/newline</span>
      <span class="muControl">break-if</span> newline?:boolean
      cursor-row:address:number/deref<span class="Special"> &lt;- </span>add cursor-row:address:number/deref, <span class="Constant">1:literal</span>
      cursor-column:address:number/deref<span class="Special"> &lt;- </span>copy left:number
      <span class="Comment"># todo: what happens when cursor is too far down?</span>
      above-screen-bottom?:boolean<span class="Special"> &lt;- </span>lesser-than cursor-row:address:number/deref, screen-height:number
      assert above-screen-bottom?:boolean, <span class="Constant">[unimplemented: moving past bottom of screen]</span>
      <span class="muControl">reply</span>
    <span class="Delimiter">}</span>
    <span class="Comment"># otherwise move cursor one character right</span>
    cursor-column:address:number/deref<span class="Special"> &lt;- </span>add cursor-column:address:number/deref, <span class="Constant">1:literal</span>
  <span class="Delimiter">}</span>
  <span class="Comment"># left arrow</span>
  <span class="Delimiter">{</span>
    move-to-previous-character?:boolean<span class="Special"> &lt;- </span>equal k:address:number/deref, <span class="Constant">65515:literal/left-arrow</span>
    <span class="muControl">break-unless</span> move-to-previous-character?:boolean
<span class="CommentedCode">#?     trace [app], [left arrow] #? 1</span>
    <span class="Comment"># if not at start of text (before-cursor at § sentinel)</span>
    prev:address:duplex-list<span class="Special"> &lt;- </span>prev-duplex before-cursor:address:address:duplex-list/deref
    <span class="muControl">break-unless</span> prev:address:duplex-list
    <span class="Comment"># if cursor not at left margin, move one character left</span>
    <span class="Delimiter">{</span>
      at-left-margin?:boolean<span class="Special"> &lt;- </span>equal cursor-column:address:number/deref, <span class="Constant">0:literal</span>
      <span class="muControl">break-if</span> at-left-margin?:boolean
<span class="CommentedCode">#?       trace [app], [decrementing] #? 1</span>
      cursor-column:address:number/deref<span class="Special"> &lt;- </span>subtract cursor-column:address:number/deref, <span class="Constant">1:literal</span>
      <span class="muControl">reply</span>
    <span class="Delimiter">}</span>
    <span class="Comment"># if at left margin, there's guaranteed to be a previous line, since we're</span>
    <span class="Comment"># not at start of text</span>
    <span class="Delimiter">{</span>
      <span class="Comment"># if before-cursor is at newline, figure out how long the previous line is</span>
      prevc:character<span class="Special"> &lt;- </span>get before-cursor:address:address:duplex-list/deref/deref, value:offset
      previous-character-is-newline?:boolean<span class="Special"> &lt;- </span>equal prevc:character, <span class="Constant">10:literal/newline</span>
      <span class="muControl">break-unless</span> previous-character-is-newline?:boolean
<span class="CommentedCode">#?       trace [app], [previous line] #? 1</span>
      <span class="Comment"># compute length of previous line</span>
      end-of-line:number<span class="Special"> &lt;- </span>previous-line-length before-cursor:address:address:duplex-list/deref, d:address:duplex-list
      cursor-row:address:number/deref<span class="Special"> &lt;- </span>subtract cursor-row:address:number/deref, <span class="Constant">1:literal</span>
      cursor-column:address:number/deref<span class="Special"> &lt;- </span>copy end-of-line:number
      <span class="muControl">reply</span>
    <span class="Delimiter">}</span>
    <span class="Comment"># if before-cursor is not at newline, we're just at a wrapped line</span>
    assert cursor-row:address:number/deref, <span class="Constant">[unimplemented: moving cursor above top of screen]</span>
    cursor-row:address:number/deref<span class="Special"> &lt;- </span>subtract cursor-row:address:number/deref, <span class="Constant">1:literal</span>
    cursor-column:address:number/deref<span class="Special"> &lt;- </span>subtract right:number, <span class="Constant">1:literal</span>  <span class="Comment"># leave room for wrap icon</span>
  <span class="Delimiter">}</span>
  <span class="Comment"># down arrow</span>
  <span class="Delimiter">{</span>
    move-to-next-line?:boolean<span class="Special"> &lt;- </span>equal k:address:number/deref, <span class="Constant">65516:literal/down-arrow</span>
    <span class="muControl">break-unless</span> move-to-next-line?:boolean
    <span class="Comment"># todo: support scrolling</span>
    already-at-bottom?:boolean<span class="Special"> &lt;- </span>greater-or-equal cursor-row:address:number/deref, screen-height:number
    <span class="muControl">break-if</span> already-at-bottom?:boolean
<span class="CommentedCode">#?     $print [moving down</span>
<span class="CommentedCode">#? ] #? 1</span>
    cursor-row:address:number/deref<span class="Special"> &lt;- </span>add cursor-row:address:number/deref, <span class="Constant">1:literal</span>
    <span class="Comment"># that's it; render will adjust cursor-column as necessary</span>
  <span class="Delimiter">}</span>
  <span class="Comment"># up arrow</span>
  <span class="Delimiter">{</span>
    move-to-previous-line?:boolean<span class="Special"> &lt;- </span>equal k:address:number/deref, <span class="Constant">65517:literal/up-arrow</span>
    <span class="muControl">break-unless</span> move-to-previous-line?:boolean
    <span class="Comment"># todo: support scrolling</span>
    already-at-top?:boolean<span class="Special"> &lt;- </span>lesser-or-equal cursor-row:address:number/deref, <span class="Constant">1:literal/top</span>
    <span class="muControl">break-if</span> already-at-top?:boolean
<span class="CommentedCode">#?     $print [moving up</span>
<span class="CommentedCode">#? ] #? 1</span>
    cursor-row:address:number/deref<span class="Special"> &lt;- </span>subtract cursor-row:address:number/deref, <span class="Constant">1:literal</span>
    <span class="Comment"># that's it; render will adjust cursor-column as necessary</span>
  <span class="Delimiter">}</span>
  <span class="Comment"># home</span>
  <span class="Delimiter">{</span>
    home?:boolean<span class="Special"> &lt;- </span>equal k:address:number/deref, <span class="Constant">65521:literal/home</span>
    <span class="muControl">break-unless</span> home?:boolean
    move-to-start-of-line editor:address:editor-data
    <span class="muControl">reply</span>
  <span class="Delimiter">}</span>
  <span class="Comment"># end</span>
  <span class="Delimiter">{</span>
    end?:boolean<span class="Special"> &lt;- </span>equal k:address:number/deref, <span class="Constant">65520:literal/end</span>
    <span class="muControl">break-unless</span> end?:boolean
    move-to-end-of-line editor:address:editor-data
    <span class="muControl">reply</span>
  <span class="Delimiter">}</span>
]

<span class="Comment"># process click, return if it was on current editor</span>
<span class="Comment"># todo: ignores menu bar (for now just displays shortcuts)</span>
<span class="muRecipe">recipe</span> move-cursor-in-editor [
  <span class="Constant">local-scope</span>
  screen:address<span class="Special"> &lt;- </span><span class="Constant">next-ingredient</span>
  editor:address:editor-data<span class="Special"> &lt;- </span><span class="Constant">next-ingredient</span>
  t:touch-event<span class="Special"> &lt;- </span><span class="Constant">next-ingredient</span>
  <span class="muControl">reply-unless</span> editor:address:editor-data, <span class="Constant">0:literal/false</span>
  click-column:number<span class="Special"> &lt;- </span>get t:touch-event, column:offset
  left:number<span class="Special"> &lt;- </span>get editor:address:editor-data/deref, left:offset
  too-far-left?:boolean<span class="Special"> &lt;- </span>lesser-than click-column:number, left:number
  <span class="muControl">reply-if</span> too-far-left?:boolean, <span class="Constant">0:literal/false</span>
  right:number<span class="Special"> &lt;- </span>get editor:address:editor-data/deref, right:offset
  too-far-right?:boolean<span class="Special"> &lt;- </span>greater-than click-column:number, right:number
  <span class="muControl">reply-if</span> too-far-right?:boolean, <span class="Constant">0:literal/false</span>
  <span class="Comment"># update cursor</span>
  cursor-row:address:number<span class="Special"> &lt;- </span>get-address editor:address:editor-data/deref, cursor-row:offset
  cursor-row:address:number/deref<span class="Special"> &lt;- </span>get t:touch-event, row:offset
  cursor-column:address:number<span class="Special"> &lt;- </span>get-address editor:address:editor-data/deref, cursor-column:offset
  cursor-column:address:number/deref<span class="Special"> &lt;- </span>get t:touch-event, column:offset
  <span class="Comment"># gain focus</span>
  <span class="muControl">reply</span> <span class="Constant">1:literal/true</span>
]

<span class="muRecipe">recipe</span> insert-at-cursor [
  <span class="Constant">local-scope</span>
  editor:address:editor-data<span class="Special"> &lt;- </span><span class="Constant">next-ingredient</span>
  c:character<span class="Special"> &lt;- </span><span class="Constant">next-ingredient</span>
  screen:address<span class="Special"> &lt;- </span><span class="Constant">next-ingredient</span>
<span class="CommentedCode">#?   $print [insert ], c:character, 10:literal/newline</span>
  before-cursor:address:address:duplex-list<span class="Special"> &lt;- </span>get-address editor:address:editor-data/deref, before-cursor:offset
  d:address:duplex-list<span class="Special"> &lt;- </span>get editor:address:editor-data/deref, data:offset
  insert-duplex c:character, before-cursor:address:address:duplex-list/deref
  before-cursor:address:address:duplex-list/deref<span class="Special"> &lt;- </span>next-duplex before-cursor:address:address:duplex-list/deref
  cursor-row:address:number<span class="Special"> &lt;- </span>get-address editor:address:editor-data/deref, cursor-row:offset
  cursor-column:address:number<span class="Special"> &lt;- </span>get-address editor:address:editor-data/deref, cursor-column:offset
  left:number<span class="Special"> &lt;- </span>get editor:address:editor-data/deref, left:offset
  right:number<span class="Special"> &lt;- </span>get editor:address:editor-data/deref, right:offset
  <span class="Comment"># update cursor: if newline, move cursor to start of next line</span>
  <span class="Comment"># todo: bottom of screen</span>
  <span class="Delimiter">{</span>
    newline?:boolean<span class="Special"> &lt;- </span>equal c:character, <span class="Constant">10:literal/newline</span>
    <span class="muControl">break-unless</span> newline?:boolean
    cursor-row:address:number/deref<span class="Special"> &lt;- </span>add cursor-row:address:number/deref, <span class="Constant">1:literal</span>
    cursor-column:address:number/deref<span class="Special"> &lt;- </span>copy left:number
    <span class="muControl">reply</span>
  <span class="Delimiter">}</span>
  <span class="Comment"># if the line wraps at the cursor, move cursor to start of next row</span>
  <span class="Delimiter">{</span>
    <span class="Comment"># if we're at the column just before the wrap indicator</span>
    wrap-column:number<span class="Special"> &lt;- </span>subtract right:number, <span class="Constant">1:literal</span>
<span class="CommentedCode">#?     $print [wrap? ], cursor-column:address:number/deref, [ vs ], wrap-column:number, 10:literal/newline</span>
    at-wrap?:boolean<span class="Special"> &lt;- </span>greater-or-equal cursor-column:address:number/deref, wrap-column:number
    <span class="muControl">break-unless</span> at-wrap?:boolean
<span class="CommentedCode">#?     $print [wrap!</span>
<span class="CommentedCode">#? ] #? 1</span>
    cursor-column:address:number/deref<span class="Special"> &lt;- </span>subtract cursor-column:address:number/deref, wrap-column:number
    cursor-row:address:number/deref<span class="Special"> &lt;- </span>add cursor-row:address:number/deref, <span class="Constant">1:literal</span>
    <span class="Comment"># todo: what happens when cursor is too far down?</span>
    screen-height:number<span class="Special"> &lt;- </span>screen-height screen:address
    above-screen-bottom?:boolean<span class="Special"> &lt;- </span>lesser-than cursor-row:address:number/deref, screen-height:number
    assert above-screen-bottom?:boolean, <span class="Constant">[unimplemented: typing past bottom of screen]</span>
<span class="CommentedCode">#?     $print [return</span>
<span class="CommentedCode">#? ] #? 1</span>
    <span class="muControl">reply</span>
  <span class="Delimiter">}</span>
  <span class="Comment"># otherwise move cursor right</span>
  cursor-column:address:number/deref<span class="Special"> &lt;- </span>add cursor-column:address:number/deref, <span class="Constant">1:literal</span>
]

<span class="muRecipe">recipe</span> delete-before-cursor [
  <span class="Constant">local-scope</span>
  editor:address:editor-data<span class="Special"> &lt;- </span><span class="Constant">next-ingredient</span>
  before-cursor:address:address:duplex-list<span class="Special"> &lt;- </span>get-address editor:address:editor-data/deref, before-cursor:offset
  d:address:duplex-list<span class="Special"> &lt;- </span>get editor:address:editor-data/deref, data:offset
  <span class="Comment"># unless already at start</span>
  at-start?:boolean<span class="Special"> &lt;- </span>equal before-cursor:address:address:duplex-list/deref, d:address:duplex-list
  <span class="muControl">reply-if</span> at-start?:boolean
  <span class="Comment"># delete character</span>
  prev:address:duplex-list<span class="Special"> &lt;- </span>prev-duplex before-cursor:address:address:duplex-list/deref
  remove-duplex before-cursor:address:address:duplex-list/deref
  <span class="Comment"># update cursor</span>
  before-cursor:address:address:duplex-list/deref<span class="Special"> &lt;- </span>copy prev:address:duplex-list
  cursor-column:address:number<span class="Special"> &lt;- </span>get-address editor:address:editor-data/deref, cursor-column:offset
  cursor-column:address:number/deref<span class="Special"> &lt;- </span>subtract cursor-column:address:number/deref, <span class="Constant">1:literal</span>
<span class="CommentedCode">#?   $print [delete-before-cursor: ], cursor-column:address:number/deref, 10:literal/newline</span>
]

<span class="Comment"># takes a pointer 'curr' into the doubly-linked list and its sentinel, counts</span>
<span class="Comment"># the length of the previous line before the 'curr' pointer.</span>
<span class="muRecipe">recipe</span> previous-line-length [
  <span class="Constant">local-scope</span>
  curr:address:duplex-list<span class="Special"> &lt;- </span><span class="Constant">next-ingredient</span>
  start:address:duplex-list<span class="Special"> &lt;- </span><span class="Constant">next-ingredient</span>
  result:number<span class="Special"> &lt;- </span>copy <span class="Constant">0:literal</span>
  <span class="muControl">reply-unless</span> curr:address:duplex-list, result:number
  at-start?:boolean<span class="Special"> &lt;- </span>equal curr:address:duplex-list, start:address:duplex-list
  <span class="muControl">reply-if</span> at-start?:boolean, result:number
  <span class="Delimiter">{</span>
    curr:address:duplex-list<span class="Special"> &lt;- </span>prev-duplex curr:address:duplex-list
    <span class="muControl">break-unless</span> curr:address:duplex-list
    at-start?:boolean<span class="Special"> &lt;- </span>equal curr:address:duplex-list, start:address:duplex-list
    <span class="muControl">break-if</span> at-start?:boolean
    c:character<span class="Special"> &lt;- </span>get curr:address:duplex-list/deref, value:offset
    at-newline?:boolean<span class="Special"> &lt;- </span>equal c:character <span class="Constant">10:literal/newline</span>
    <span class="muControl">break-if</span> at-newline?:boolean
    result:number<span class="Special"> &lt;- </span>add result:number, <span class="Constant">1:literal</span>
    <span class="muControl">loop</span>
  <span class="Delimiter">}</span>
  <span class="muControl">reply</span> result:number
]

<span class="muRecipe">recipe</span> move-to-start-of-line [
  <span class="Constant">local-scope</span>
  editor:address:editor-data<span class="Special"> &lt;- </span><span class="Constant">next-ingredient</span>
  <span class="Comment"># update cursor column</span>
  left:number<span class="Special"> &lt;- </span>get editor:address:editor-data/deref, left:offset
  cursor-column:address:number<span class="Special"> &lt;- </span>get-address editor:address:editor-data/deref, cursor-column:offset
  cursor-column:address:number/deref<span class="Special"> &lt;- </span>copy left:number
  <span class="Comment"># update before-cursor</span>
  before-cursor:address:address:duplex-list<span class="Special"> &lt;- </span>get-address editor:address:editor-data/deref, before-cursor:offset
  init:address:duplex-list<span class="Special"> &lt;- </span>get editor:address:editor-data/deref, data:offset
  <span class="Comment"># while not at start of line, move </span>
  <span class="Delimiter">{</span>
    at-start-of-text?:boolean<span class="Special"> &lt;- </span>equal before-cursor:address:address:duplex-list/deref, init:address:duplex-list
    <span class="muControl">break-if</span> at-start-of-text?:boolean
    prev:character<span class="Special"> &lt;- </span>get before-cursor:address:address:duplex-list/deref/deref, value:offset
    at-start-of-line?:boolean<span class="Special"> &lt;- </span>equal prev:character, <span class="Constant">10:literal/newline</span>
    <span class="muControl">break-if</span> at-start-of-line?:boolean
    before-cursor:address:address:duplex-list/deref<span class="Special"> &lt;- </span>prev-duplex before-cursor:address:address:duplex-list/deref
    assert before-cursor:address:address:duplex-list/deref, <span class="Constant">[move-to-start-of-line tried to move before start of text]</span>
    <span class="muControl">loop</span>
  <span class="Delimiter">}</span>
]

<span class="muRecipe">recipe</span> move-to-end-of-line [
  <span class="Constant">local-scope</span>
  editor:address:editor-data<span class="Special"> &lt;- </span><span class="Constant">next-ingredient</span>
  before-cursor:address:address:duplex-list<span class="Special"> &lt;- </span>get-address editor:address:editor-data/deref, before-cursor:offset
  cursor-column:address:number<span class="Special"> &lt;- </span>get-address editor:address:editor-data/deref, cursor-column:offset
  <span class="Comment"># while not at start of line, move </span>
  <span class="Delimiter">{</span>
    next:address:duplex-list<span class="Special"> &lt;- </span>next-duplex before-cursor:address:address:duplex-list/deref
    <span class="muControl">break-unless</span> next:address:duplex-list  <span class="Comment"># end of text</span>
    nextc:character<span class="Special"> &lt;- </span>get next:address:duplex-list/deref, value:offset
    at-end-of-line?:boolean<span class="Special"> &lt;- </span>equal nextc:character, <span class="Constant">10:literal/newline</span>
    <span class="muControl">break-if</span> at-end-of-line?:boolean
    before-cursor:address:address:duplex-list/deref<span class="Special"> &lt;- </span>copy next:address:duplex-list
    cursor-column:address:number/deref<span class="Special"> &lt;- </span>add cursor-column:address:number/deref, <span class="Constant">1:literal</span>
    <span class="muControl">loop</span>
  <span class="Delimiter">}</span>
  <span class="Comment"># move one past end of line</span>
  cursor-column:address:number/deref<span class="Special"> &lt;- </span>add cursor-column:address:number/deref, <span class="Constant">1:literal</span>
]

<span class="muRecipe">recipe</span> delete-to-start-of-line [
  <span class="Constant">local-scope</span>
  editor:address:editor-data<span class="Special"> &lt;- </span><span class="Constant">next-ingredient</span>
  <span class="Comment"># compute range to delete</span>
  init:address:duplex-list<span class="Special"> &lt;- </span>get editor:address:editor-data/deref, data:offset
  before-cursor:address:address:duplex-list<span class="Special"> &lt;- </span>get-address editor:address:editor-data/deref, before-cursor:offset
  start:address:duplex-list<span class="Special"> &lt;- </span>copy before-cursor:address:address:duplex-list/deref
  end:address:duplex-list<span class="Special"> &lt;- </span>next-duplex before-cursor:address:address:duplex-list/deref
  <span class="Delimiter">{</span>
    at-start-of-text?:boolean<span class="Special"> &lt;- </span>equal start:address:duplex-list, init:address:duplex-list
    <span class="muControl">break-if</span> at-start-of-text?:boolean
    curr:character<span class="Special"> &lt;- </span>get start:address:duplex-list/deref, value:offset
    at-start-of-line?:boolean<span class="Special"> &lt;- </span>equal curr:character, <span class="Constant">10:literal/newline</span>
    <span class="muControl">break-if</span> at-start-of-line?:boolean
    start:address:duplex-list<span class="Special"> &lt;- </span>prev-duplex start:address:duplex-list
    assert start:address:duplex-list, <span class="Constant">[delete-to-start-of-line tried to move before start of text]</span>
    <span class="muControl">loop</span>
  <span class="Delimiter">}</span>
  <span class="Comment"># snip it out</span>
  start-next:address:address:duplex-list<span class="Special"> &lt;- </span>get-address start:address:duplex-list/deref, next:offset
  start-next:address:address:duplex-list/deref<span class="Special"> &lt;- </span>copy end:address:duplex-list
  end-prev:address:address:duplex-list<span class="Special"> &lt;- </span>get-address end:address:duplex-list/deref, prev:offset
  end-prev:address:address:duplex-list/deref<span class="Special"> &lt;- </span>copy start:address:duplex-list
  <span class="Comment"># adjust cursor</span>
  before-cursor:address:address:duplex-list/deref<span class="Special"> &lt;- </span>prev-duplex end:address:duplex-list
  left:number<span class="Special"> &lt;- </span>get editor:address:editor-data/deref, left:offset
  cursor-column:address:number<span class="Special"> &lt;- </span>get-address editor:address:editor-data/deref, cursor-column:offset
  cursor-column:address:number/deref<span class="Special"> &lt;- </span>copy left:number
]

<span class="muRecipe">recipe</span> delete-to-end-of-line [
  <span class="Constant">local-scope</span>
  editor:address:editor-data<span class="Special"> &lt;- </span><span class="Constant">next-ingredient</span>
  <span class="Comment"># compute range to delete</span>
  start:address:duplex-list<span class="Special"> &lt;- </span>get editor:address:editor-data/deref, before-cursor:offset
  end:address:duplex-list<span class="Special"> &lt;- </span>next-duplex start:address:duplex-list
  <span class="Delimiter">{</span>
    at-end-of-text?:boolean<span class="Special"> &lt;- </span>equal end:address:duplex-list, <span class="Constant">0:literal/null</span>
    <span class="muControl">break-if</span> at-end-of-text?:boolean
    curr:character<span class="Special"> &lt;- </span>get end:address:duplex-list/deref, value:offset
    at-end-of-line?:boolean<span class="Special"> &lt;- </span>equal curr:character, <span class="Constant">10:literal/newline</span>
    <span class="muControl">break-if</span> at-end-of-line?:boolean
    end:address:duplex-list<span class="Special"> &lt;- </span>next-duplex end:address:duplex-list
    <span class="muControl">loop</span>
  <span class="Delimiter">}</span>
  <span class="Comment"># snip it out</span>
  start-next:address:address:duplex-list<span class="Special"> &lt;- </span>get-address start:address:duplex-list/deref, next:offset
  start-next:address:address:duplex-list/deref<span class="Special"> &lt;- </span>copy end:address:duplex-list
  <span class="Delimiter">{</span>
    <span class="muControl">break-unless</span> end:address:duplex-list
    end-prev:address:address:duplex-list<span class="Special"> &lt;- </span>get-address end:address:duplex-list/deref, prev:offset
    end-prev:address:address:duplex-list/deref<span class="Special"> &lt;- </span>copy start:address:duplex-list
  <span class="Delimiter">}</span>
]

<span class="muRecipe">recipe</span> render-all [
  <span class="Constant">local-scope</span>
  screen:address<span class="Special"> &lt;- </span><span class="Constant">next-ingredient</span>
  env:address:programming-environment-data<span class="Special"> &lt;- </span><span class="Constant">next-ingredient</span>
  screen:address<span class="Special"> &lt;- </span>render-recipes screen:address, env:address:programming-environment-data, <span class="Constant">1:literal/clear-below</span>
  screen:address<span class="Special"> &lt;- </span>render-sandbox-side screen:address, env:address:programming-environment-data, <span class="Constant">1:literal/clear-below</span>
  recipes:address:editor-data<span class="Special"> &lt;- </span>get env:address:programming-environment-data/deref, recipes:offset
  current-sandbox:address:editor-data<span class="Special"> &lt;- </span>get env:address:programming-environment-data/deref, current-sandbox:offset
  sandbox-in-focus?:boolean<span class="Special"> &lt;- </span>get env:address:programming-environment-data/deref, sandbox-in-focus?:offset
  update-cursor screen:address, recipes:address:editor-data, current-sandbox:address:editor-data, sandbox-in-focus?:boolean
  show-screen screen:address
  <span class="muControl">reply</span> screen:address/same-as-ingredient:0
]

<span class="muRecipe">recipe</span> render-minimal [
  <span class="Constant">local-scope</span>
  screen:address<span class="Special"> &lt;- </span><span class="Constant">next-ingredient</span>
  env:address:programming-environment-data<span class="Special"> &lt;- </span><span class="Constant">next-ingredient</span>
  recipes:address:editor-data<span class="Special"> &lt;- </span>get env:address:programming-environment-data/deref, recipes:offset
  current-sandbox:address:editor-data<span class="Special"> &lt;- </span>get env:address:programming-environment-data/deref, current-sandbox:offset
  sandbox-in-focus?:boolean<span class="Special"> &lt;- </span>get env:address:programming-environment-data/deref, sandbox-in-focus?:offset
  <span class="Delimiter">{</span>
    <span class="muControl">break-if</span> sandbox-in-focus?:boolean
    screen:address<span class="Special"> &lt;- </span>render-recipes screen:address, env:address:programming-environment-data
    cursor-row:number<span class="Special"> &lt;- </span>get recipes:address:editor-data/deref, cursor-row:offset
    cursor-column:number<span class="Special"> &lt;- </span>get recipes:address:editor-data/deref, cursor-column:offset
  <span class="Delimiter">}</span>
  <span class="Delimiter">{</span>
    <span class="muControl">break-unless</span> sandbox-in-focus?:boolean
    screen:address<span class="Special"> &lt;- </span>render-sandbox-side screen:address, env:address:programming-environment-data
    cursor-row:number<span class="Special"> &lt;- </span>get current-sandbox:address:editor-data/deref, cursor-row:offset
    cursor-column:number<span class="Special"> &lt;- </span>get current-sandbox:address:editor-data/deref, cursor-column:offset
  <span class="Delimiter">}</span>
  move-cursor screen:address, cursor-row:number, cursor-column:number
  show-screen screen:address
  <span class="muControl">reply</span> screen:address/same-as-ingredient:0
]

<span class="muRecipe">recipe</span> render-recipes [
  <span class="Constant">local-scope</span>
  screen:address<span class="Special"> &lt;- </span><span class="Constant">next-ingredient</span>
  env:address:programming-environment-data<span class="Special"> &lt;- </span><span class="Constant">next-ingredient</span>
  clear:boolean<span class="Special"> &lt;- </span><span class="Constant">next-ingredient</span>
  recipes:address:editor-data<span class="Special"> &lt;- </span>get env:address:programming-environment-data/deref, recipes:offset
  <span class="Comment"># render recipes</span>
  left:number<span class="Special"> &lt;- </span>get recipes:address:editor-data/deref, left:offset
  right:number<span class="Special"> &lt;- </span>get recipes:address:editor-data/deref, right:offset
  row:number, screen:address<span class="Special"> &lt;- </span>render screen:address, recipes:address:editor-data
  recipe-warnings:address:array:character<span class="Special"> &lt;- </span>get env:address:programming-environment-data/deref, recipe-warnings:offset
  <span class="Delimiter">{</span>
    <span class="Comment"># print any warnings</span>
    <span class="muControl">break-unless</span> recipe-warnings:address:array:character
    row:number, screen:address<span class="Special"> &lt;- </span>render-string screen:address, recipe-warnings:address:array:character, left:number, right:number, <span class="Constant">1:literal/red</span>, row:number
  <span class="Delimiter">}</span>
  <span class="Delimiter">{</span>
    <span class="Comment"># no warnings? move to next line</span>
    <span class="muControl">break-if</span> recipe-warnings:address:array:character
    row:number<span class="Special"> &lt;- </span>add row:number, <span class="Constant">1:literal</span>
  <span class="Delimiter">}</span>
  <span class="Comment"># draw dotted line after recipes</span>
  draw-horizontal screen:address, row:number, left:number, right:number, <span class="Constant">9480:literal/horizontal-dotted</span>
  <span class="Comment"># clear next line, in case we just processed a backspace</span>
  row:number<span class="Special"> &lt;- </span>add row:number, <span class="Constant">1:literal</span>
  move-cursor screen:address, row:number, left:number
  clear-line-delimited screen:address, left:number, right:number
  <span class="Comment"># clear rest of screen in this column, if requested</span>
  <span class="muControl">reply-unless</span> clear:boolean, screen:address/same-as-ingredient:0
  screen-height:number<span class="Special"> &lt;- </span>screen-height screen:address
  <span class="Delimiter">{</span>
    at-bottom-of-screen?:boolean<span class="Special"> &lt;- </span>greater-or-equal row:number, screen-height:number
    <span class="muControl">break-if</span> at-bottom-of-screen?:boolean
    move-cursor screen:address, row:number, left:number
    clear-line-delimited screen:address, left:number, right:number
    row:number<span class="Special"> &lt;- </span>add row:number, <span class="Constant">1:literal</span>
    <span class="muControl">loop</span>
  <span class="Delimiter">}</span>
  <span class="muControl">reply</span> screen:address/same-as-ingredient:0
]

<span class="muRecipe">recipe</span> update-cursor [
  <span class="Constant">local-scope</span>
  screen:address<span class="Special"> &lt;- </span><span class="Constant">next-ingredient</span>
  recipes:address:editor-data<span class="Special"> &lt;- </span><span class="Constant">next-ingredient</span>
  current-sandbox:address:editor-data<span class="Special"> &lt;- </span><span class="Constant">next-ingredient</span>
  sandbox-in-focus?:boolean<span class="Special"> &lt;- </span><span class="Constant">next-ingredient</span>
  <span class="Delimiter">{</span>
    <span class="muControl">break-if</span> sandbox-in-focus?:boolean
<span class="CommentedCode">#?     $print [recipes in focus</span>
<span class="CommentedCode">#? ] #? 1</span>
    cursor-row:number<span class="Special"> &lt;- </span>get recipes:address:editor-data/deref, cursor-row:offset
    cursor-column:number<span class="Special"> &lt;- </span>get recipes:address:editor-data/deref, cursor-column:offset
  <span class="Delimiter">}</span>
  <span class="Delimiter">{</span>
    <span class="muControl">break-unless</span> sandbox-in-focus?:boolean
<span class="CommentedCode">#?     $print [sandboxes in focus</span>
<span class="CommentedCode">#? ] #? 1</span>
    cursor-row:number<span class="Special"> &lt;- </span>get current-sandbox:address:editor-data/deref, cursor-row:offset
    cursor-column:number<span class="Special"> &lt;- </span>get current-sandbox:address:editor-data/deref, cursor-column:offset
  <span class="Delimiter">}</span>
  move-cursor screen:address, cursor-row:number, cursor-column:number
]

<span class="muScenario">scenario</span> editor-handles-empty-event-queue [
  assume-screen <span class="Constant">10:literal/width</span>, <span class="Constant">5:literal/height</span>
  1:address:array:character<span class="Special"> &lt;- </span>new <span class="Constant">[abc]</span>
  2:address:editor-data<span class="Special"> &lt;- </span>new-editor 1:address:array:character, screen:address, <span class="Constant">0:literal/left</span>, <span class="Constant">10:literal/right</span>
  assume-console <span class="Constant">[]</span>
  run [
    editor-event-loop screen:address, console:address, 2:address:editor-data
  ]
  screen-should-contain [
   <span class="Constant"> .          .</span>
   <span class="Constant"> .abc       .</span>
   <span class="Constant"> .          .</span>
  ]
]

<span class="muScenario">scenario</span> editor-handles-mouse-clicks [
  assume-screen <span class="Constant">10:literal/width</span>, <span class="Constant">5:literal/height</span>
  1:address:array:character<span class="Special"> &lt;- </span>new <span class="Constant">[abc]</span>
  2:address:editor-data<span class="Special"> &lt;- </span>new-editor 1:address:array:character, screen:address, <span class="Constant">0:literal/left</span>, <span class="Constant">10:literal/right</span>
  assume-console [
    left-click 1, 1  <span class="Comment"># on the 'b'</span>
  ]
  run [
    editor-event-loop screen:address, console:address, 2:address:editor-data
    3:number<span class="Special"> &lt;- </span>get 2:address:editor-data/deref, cursor-row:offset
    4:number<span class="Special"> &lt;- </span>get 2:address:editor-data/deref, cursor-column:offset
  ]
  screen-should-contain [
   <span class="Constant"> .          .</span>
   <span class="Constant"> .abc       .</span>
   <span class="Constant"> .          .</span>
  ]
  memory-should-contain [
    3<span class="Special"> &lt;- </span>1  <span class="Comment"># cursor is at row 0..</span>
    4<span class="Special"> &lt;- </span>1  <span class="Comment"># ..and column 1</span>
  ]
]

<span class="muScenario">scenario</span> editor-handles-mouse-clicks-outside-text [
  assume-screen <span class="Constant">10:literal/width</span>, <span class="Constant">5:literal/height</span>
  1:address:array:character<span class="Special"> &lt;- </span>new <span class="Constant">[abc]</span>
  2:address:editor-data<span class="Special"> &lt;- </span>new-editor 1:address:array:character, screen:address, <span class="Constant">0:literal/left</span>, <span class="Constant">10:literal/right</span>
  assume-console [
    left-click 1, 7  <span class="Comment"># last line, to the right of text</span>
  ]
  run [
    editor-event-loop screen:address, console:address, 2:address:editor-data
    3:number<span class="Special"> &lt;- </span>get 2:address:editor-data/deref, cursor-row:offset
    4:number<span class="Special"> &lt;- </span>get 2:address:editor-data/deref, cursor-column:offset
  ]
  memory-should-contain [
    3<span class="Special"> &lt;- </span>1  <span class="Comment"># cursor row</span>
    4<span class="Special"> &lt;- </span>3  <span class="Comment"># cursor column</span>
  ]
]

<span class="muScenario">scenario</span> editor-handles-mouse-clicks-outside-text-2 [
  assume-screen <span class="Constant">10:literal/width</span>, <span class="Constant">5:literal/height</span>
  1:address:array:character<span class="Special"> &lt;- </span>new <span class="Constant">[abc</span>
<span class="Constant">def]</span>
  2:address:editor-data<span class="Special"> &lt;- </span>new-editor 1:address:array:character, screen:address, <span class="Constant">0:literal/left</span>, <span class="Constant">10:literal/right</span>
  assume-console [
    left-click 1, 7  <span class="Comment"># interior line, to the right of text</span>
  ]
  run [
    editor-event-loop screen:address, console:address, 2:address:editor-data
    3:number<span class="Special"> &lt;- </span>get 2:address:editor-data/deref, cursor-row:offset
    4:number<span class="Special"> &lt;- </span>get 2:address:editor-data/deref, cursor-column:offset
  ]
  memory-should-contain [
    3<span class="Special"> &lt;- </span>1  <span class="Comment"># cursor row</span>
    4<span class="Special"> &lt;- </span>3  <span class="Comment"># cursor column</span>
  ]
]

<span class="muScenario">scenario</span> editor-handles-mouse-clicks-outside-text-3 [
  assume-screen <span class="Constant">10:literal/width</span>, <span class="Constant">5:literal/height</span>
  1:address:array:character<span class="Special"> &lt;- </span>new <span class="Constant">[abc</span>
<span class="Constant">def]</span>
  2:address:editor-data<span class="Special"> &lt;- </span>new-editor 1:address:array:character, screen:address, <span class="Constant">0:literal/left</span>, <span class="Constant">10:literal/right</span>
  assume-console [
    left-click 3, 7  <span class="Comment"># below text</span>
  ]
  run [
    editor-event-loop screen:address, console:address, 2:address:editor-data
    3:number<span class="Special"> &lt;- </span>get 2:address:editor-data/deref, cursor-row:offset
    4:number<span class="Special"> &lt;- </span>get 2:address:editor-data/deref, cursor-column:offset
  ]
  memory-should-contain [
    3<span class="Special"> &lt;- </span>2  <span class="Comment"># cursor row</span>
    4<span class="Special"> &lt;- </span>3  <span class="Comment"># cursor column</span>
  ]
]

<span class="muScenario">scenario</span> editor-handles-mouse-clicks-outside-column [
  assume-screen <span class="Constant">10:literal/width</span>, <span class="Constant">5:literal/height</span>
  1:address:array:character<span class="Special"> &lt;- </span>new <span class="Constant">[abc]</span>
  <span class="Comment"># editor occupies only left half of screen</span>
  2:address:editor-data<span class="Special"> &lt;- </span>new-editor 1:address:array:character, screen:address, <span class="Constant">0:literal/left</span>, <span class="Constant">5:literal/right</span>
  assume-console [
    <span class="Comment"># click on right half of screen</span>
    left-click 3, 8
  ]
  run [
    editor-event-loop screen:address, console:address, 2:address:editor-data
    3:number<span class="Special"> &lt;- </span>get 2:address:editor-data/deref, cursor-row:offset
    4:number<span class="Special"> &lt;- </span>get 2:address:editor-data/deref, cursor-column:offset
  ]
  screen-should-contain [
   <span class="Constant"> .          .</span>
   <span class="Constant"> .abc       .</span>
   <span class="Constant"> .          .</span>
  ]
  memory-should-contain [
    3<span class="Special"> &lt;- </span>1  <span class="Comment"># no change to cursor row</span>
    4<span class="Special"> &lt;- </span>0  <span class="Comment"># ..or column</span>
  ]
]

<span class="muScenario">scenario</span> editor-inserts-characters-into-empty-editor [
  assume-screen <span class="Constant">10:literal/width</span>, <span class="Constant">5:literal/height</span>
  1:address:array:character<span class="Special"> &lt;- </span>new <span class="Constant">[]</span>
  2:address:editor-data<span class="Special"> &lt;- </span>new-editor 1:address:array:character, screen:address, <span class="Constant">0:literal/left</span>, <span class="Constant">5:literal/right</span>
  assume-console [
    type <span class="Constant">[abc]</span>
  ]
  run [
    editor-event-loop screen:address, console:address, 2:address:editor-data
  ]
  screen-should-contain [
   <span class="Constant"> .          .</span>
   <span class="Constant"> .abc       .</span>
   <span class="Constant"> .          .</span>
  ]
]

<span class="muScenario">scenario</span> editor-inserts-characters-at-cursor [
  assume-screen <span class="Constant">10:literal/width</span>, <span class="Constant">5:literal/height</span>
  1:address:array:character<span class="Special"> &lt;- </span>new <span class="Constant">[abc]</span>
  2:address:editor-data<span class="Special"> &lt;- </span>new-editor 1:address:array:character, screen:address, <span class="Constant">0:literal/left</span>, <span class="Constant">10:literal/right</span>
  assume-console [
    type <span class="Constant">[0]</span>
    left-click 1, 2
    type <span class="Constant">[d]</span>
  ]
  run [
    editor-event-loop screen:address, console:address, 2:address:editor-data
  ]
  screen-should-contain [
   <span class="Constant"> .          .</span>
   <span class="Constant"> .0adbc     .</span>
   <span class="Constant"> .          .</span>
  ]
]

<span class="muScenario">scenario</span> editor-inserts-characters-at-cursor-2 [
  assume-screen <span class="Constant">10:literal/width</span>, <span class="Constant">5:literal/height</span>
  1:address:array:character<span class="Special"> &lt;- </span>new <span class="Constant">[abc]</span>
  2:address:editor-data<span class="Special"> &lt;- </span>new-editor 1:address:array:character, screen:address, <span class="Constant">0:literal/left</span>, <span class="Constant">10:literal/right</span>
  assume-console [
    left-click 1, 5  <span class="Comment"># right of last line</span>
    type <span class="Constant">[d]</span>  <span class="Comment"># should append</span>
  ]
  run [
    editor-event-loop screen:address, console:address, 2:address:editor-data
  ]
  screen-should-contain [
   <span class="Constant"> .          .</span>
   <span class="Constant"> .abcd      .</span>
   <span class="Constant"> .          .</span>
  ]
]

<span class="muScenario">scenario</span> editor-inserts-characters-at-cursor-3 [
  assume-screen <span class="Constant">10:literal/width</span>, <span class="Constant">5:literal/height</span>
  1:address:array:character<span class="Special"> &lt;- </span>new <span class="Constant">[abc]</span>
  2:address:editor-data<span class="Special"> &lt;- </span>new-editor 1:address:array:character, screen:address, <span class="Constant">0:literal/left</span>, <span class="Constant">10:literal/right</span>
  assume-console [
    left-click 3, 5  <span class="Comment"># below all text</span>
    type <span class="Constant">[d]</span>  <span class="Comment"># should append</span>
  ]
  run [
    editor-event-loop screen:address, console:address, 2:address:editor-data
  ]
  screen-should-contain [
   <span class="Constant"> .          .</span>
   <span class="Constant"> .abcd      .</span>
   <span class="Constant"> .          .</span>
  ]
]

<span class="muScenario">scenario</span> editor-inserts-characters-at-cursor-4 [
  assume-screen <span class="Constant">10:literal/width</span>, <span class="Constant">5:literal/height</span>
  1:address:array:character<span class="Special"> &lt;- </span>new <span class="Constant">[abc</span>
<span class="Constant">d]</span>
  2:address:editor-data<span class="Special"> &lt;- </span>new-editor 1:address:array:character, screen:address, <span class="Constant">0:literal/left</span>, <span class="Constant">10:literal/right</span>
  assume-console [
    left-click 3, 5  <span class="Comment"># below all text</span>
    type <span class="Constant">[e]</span>  <span class="Comment"># should append</span>
  ]
  run [
    editor-event-loop screen:address, console:address, 2:address:editor-data
  ]
  screen-should-contain [
   <span class="Constant"> .          .</span>
   <span class="Constant"> .abc       .</span>
   <span class="Constant"> .de        .</span>
   <span class="Constant"> .          .</span>
  ]
]

<span class="muScenario">scenario</span> editor-inserts-characters-at-cursor-5 [
  assume-screen <span class="Constant">10:literal/width</span>, <span class="Constant">5:literal/height</span>
  1:address:array:character<span class="Special"> &lt;- </span>new <span class="Constant">[abc</span>
<span class="Constant">d]</span>
  2:address:editor-data<span class="Special"> &lt;- </span>new-editor 1:address:array:character, screen:address, <span class="Constant">0:literal/left</span>, <span class="Constant">10:literal/right</span>
  assume-console [
    left-click 3, 5  <span class="Comment"># below all text</span>
    type <span class="Constant">[ef]</span>  <span class="Comment"># should append multiple characters in order</span>
  ]
  run [
    editor-event-loop screen:address, console:address, 2:address:editor-data
  ]
  screen-should-contain [
   <span class="Constant"> .          .</span>
   <span class="Constant"> .abc       .</span>
   <span class="Constant"> .def       .</span>
   <span class="Constant"> .          .</span>
  ]
]

<span class="muScenario">scenario</span> editor-wraps-line-on-insert [
  assume-screen <span class="Constant">5:literal/width</span>, <span class="Constant">5:literal/height</span>
  1:address:array:character<span class="Special"> &lt;- </span>new <span class="Constant">[abc]</span>
  2:address:editor-data<span class="Special"> &lt;- </span>new-editor 1:address:array:character, screen:address, <span class="Constant">0:literal/left</span>, <span class="Constant">5:literal/right</span>
  <span class="Comment"># type a letter</span>
  assume-console [
    type <span class="Constant">[e]</span>
  ]
  run [
    editor-event-loop screen:address, console:address, 2:address:editor-data
  ]
  <span class="Comment"># no wrap yet</span>
  screen-should-contain [
   <span class="Constant"> .     .</span>
   <span class="Constant"> .eabc .</span>
   <span class="Constant"> .     .</span>
   <span class="Constant"> .     .</span>
  ]
  <span class="Comment"># type a second letter</span>
  assume-console [
    type <span class="Constant">[f]</span>
  ]
  run [
    editor-event-loop screen:address, console:address, 2:address:editor-data
  ]
  <span class="Comment"># now wrap</span>
  screen-should-contain [
   <span class="Constant"> .     .</span>
<span class="Constant">    .efab↩.</span>
   <span class="Constant"> .c    .</span>
   <span class="Constant"> .     .</span>
  ]
]

<span class="muScenario">scenario</span> editor-moves-cursor-after-inserting-characters [
  assume-screen <span class="Constant">10:literal/width</span>, <span class="Constant">5:literal/height</span>
  1:address:array:character<span class="Special"> &lt;- </span>new <span class="Constant">[ab]</span>
  2:address:editor-data<span class="Special"> &lt;- </span>new-editor 1:address:array:character, screen:address, <span class="Constant">0:literal/left</span>, <span class="Constant">5:literal/right</span>
  assume-console [
    type <span class="Constant">[01]</span>
  ]
  run [
    editor-event-loop screen:address, console:address, 2:address:editor-data
  ]
  screen-should-contain [
   <span class="Constant"> .          .</span>
   <span class="Constant"> .01ab      .</span>
   <span class="Constant"> .          .</span>
  ]
]

<span class="muScenario">scenario</span> editor-wraps-cursor-after-inserting-characters [
  assume-screen <span class="Constant">10:literal/width</span>, <span class="Constant">5:literal/height</span>
  1:address:array:character<span class="Special"> &lt;- </span>new <span class="Constant">[abcde]</span>
  2:address:editor-data<span class="Special"> &lt;- </span>new-editor 1:address:array:character, screen:address, <span class="Constant">0:literal/left</span>, <span class="Constant">5:literal/right</span>
  assume-console [
    left-click 1, 4  <span class="Comment"># line is full; no wrap icon yet</span>
    type <span class="Constant">[f]</span>
  ]
  run [
    editor-event-loop screen:address, console:address, 2:address:editor-data
    3:number<span class="Special"> &lt;- </span>get 2:address:editor-data/deref, cursor-row:offset
    4:number<span class="Special"> &lt;- </span>get 2:address:editor-data/deref, cursor-column:offset
  ]
  screen-should-contain [
   <span class="Constant"> .          .</span>
   <span class="Constant"> .abcd↩     .</span>
   <span class="Constant"> .fe        .</span>
   <span class="Constant"> .          .</span>
  ]
  memory-should-contain [
    3<span class="Special"> &lt;- </span>2  <span class="Comment"># cursor row</span>
    4<span class="Special"> &lt;- </span>1  <span class="Comment"># cursor column</span>
  ]
]

<span class="muScenario">scenario</span> editor-wraps-cursor-after-inserting-characters-2 [
  assume-screen <span class="Constant">10:literal/width</span>, <span class="Constant">5:literal/height</span>
  1:address:array:character<span class="Special"> &lt;- </span>new <span class="Constant">[abcde]</span>
  2:address:editor-data<span class="Special"> &lt;- </span>new-editor 1:address:array:character, screen:address, <span class="Constant">0:literal/left</span>, <span class="Constant">5:literal/right</span>
  assume-console [
    left-click 1, 3  <span class="Comment"># right before the wrap icon</span>
    type <span class="Constant">[f]</span>
  ]
  run [
    editor-event-loop screen:address, console:address, 2:address:editor-data
    3:number<span class="Special"> &lt;- </span>get 2:address:editor-data/deref, cursor-row:offset
    4:number<span class="Special"> &lt;- </span>get 2:address:editor-data/deref, cursor-column:offset
  ]
  screen-should-contain [
   <span class="Constant"> .          .</span>
   <span class="Constant"> .abcf↩     .</span>
   <span class="Constant"> .de        .</span>
   <span class="Constant"> .          .</span>
  ]
  memory-should-contain [
    3<span class="Special"> &lt;- </span>2  <span class="Comment"># cursor row</span>
    4<span class="Special"> &lt;- </span>0  <span class="Comment"># cursor column</span>
  ]
]

<span class="muScenario">scenario</span> editor-moves-cursor-down-after-inserting-newline [
  assume-screen <span class="Constant">10:literal/width</span>, <span class="Constant">5:literal/height</span>
  1:address:array:character<span class="Special"> &lt;- </span>new <span class="Constant">[abc]</span>
  2:address:editor-data<span class="Special"> &lt;- </span>new-editor 1:address:array:character, screen:address, <span class="Constant">0:literal/left</span>, <span class="Constant">10:literal/right</span>
  assume-console [
    type <span class="Constant">[0</span>
<span class="Constant">1]</span>
  ]
  run [
    editor-event-loop screen:address, console:address, 2:address:editor-data
  ]
  screen-should-contain [
   <span class="Constant"> .          .</span>
   <span class="Constant"> .0         .</span>
   <span class="Constant"> .1abc      .</span>
   <span class="Constant"> .          .</span>
  ]
]

<span class="muScenario">scenario</span> editor-moves-cursor-down-after-inserting-newline-2 [
  assume-screen <span class="Constant">10:literal/width</span>, <span class="Constant">5:literal/height</span>
  1:address:array:character<span class="Special"> &lt;- </span>new <span class="Constant">[abc]</span>
  2:address:editor-data<span class="Special"> &lt;- </span>new-editor 1:address:array:character, screen:address, <span class="Constant">1:literal/left</span>, <span class="Constant">10:literal/right</span>
  assume-console [
    type <span class="Constant">[0</span>
<span class="Constant">1]</span>
  ]
  run [
    editor-event-loop screen:address, console:address, 2:address:editor-data
  ]
  screen-should-contain [
   <span class="Constant"> .          .</span>
   <span class="Constant"> . 0        .</span>
   <span class="Constant"> . 1abc     .</span>
   <span class="Constant"> .          .</span>
  ]
]

<span class="muScenario">scenario</span> editor-clears-previous-line-completely-after-inserting-newline [
  assume-screen <span class="Constant">10:literal/width</span>, <span class="Constant">5:literal/height</span>
  1:address:array:character<span class="Special"> &lt;- </span>new <span class="Constant">[abcde]</span>
  2:address:editor-data<span class="Special"> &lt;- </span>new-editor 1:address:array:character, screen:address, <span class="Constant">0:literal/left</span>, <span class="Constant">5:literal/right</span>
  <span class="Comment"># press just a 'newline'</span>
  assume-console [
    type [
]
  ]
  screen-should-contain [
   <span class="Constant"> .          .</span>
   <span class="Constant"> .abcd↩     .</span>
   <span class="Constant"> .e         .</span>
   <span class="Constant"> .          .</span>
   <span class="Constant"> .          .</span>
  ]
  run [
    editor-event-loop screen:address, console:address, 2:address:editor-data
  ]
  <span class="Comment"># line should be fully cleared</span>
  screen-should-contain [
   <span class="Constant"> .          .</span>
   <span class="Constant"> .          .</span>
   <span class="Constant"> .abcd↩     .</span>
   <span class="Constant"> .e         .</span>
   <span class="Constant"> .          .</span>
  ]
]

<span class="muScenario">scenario</span> editor-handles-backspace-key [
  assume-screen <span class="Constant">10:literal/width</span>, <span class="Constant">5:literal/height</span>
  1:address:array:character<span class="Special"> &lt;- </span>new <span class="Constant">[abc]</span>
  2:address:editor-data<span class="Special"> &lt;- </span>new-editor 1:address:array:character, screen:address, <span class="Constant">0:literal/left</span>, <span class="Constant">10:literal/right</span>
  assume-console [
    left-click 1, 1
    type <span class="Constant">[«]</span>
  ]
  3:event/backspace<span class="Special"> &lt;- </span>merge <span class="Constant">0:literal/text</span>, <span class="Constant">8:literal/backspace</span>, <span class="Constant">0:literal/dummy</span>, <span class="Constant">0:literal/dummy</span>
  replace-in-console <span class="Constant">171:literal/«</span>, 3:event/backspace
  run [
    editor-event-loop screen:address, console:address, 2:address:editor-data
    4:number<span class="Special"> &lt;- </span>get 2:address:editor-data/deref, cursor-row:offset
    5:number<span class="Special"> &lt;- </span>get 2:address:editor-data/deref, cursor-column:offset
  ]
  screen-should-contain [
   <span class="Constant"> .          .</span>
   <span class="Constant"> .bc        .</span>
   <span class="Constant"> .          .</span>
  ]
  memory-should-contain [
    4<span class="Special"> &lt;- </span>1
    5<span class="Special"> &lt;- </span>0
  ]
]

<span class="muScenario">scenario</span> editor-clears-last-line-on-backspace [
  assume-screen <span class="Constant">10:literal/width</span>, <span class="Constant">5:literal/height</span>
  <span class="Comment"># just one character in final line</span>
  1:address:array:character<span class="Special"> &lt;- </span>new <span class="Constant">[ab</span>
<span class="Constant">cd]</span>
  2:address:editor-data<span class="Special"> &lt;- </span>new-editor 1:address:array:character, screen:address, <span class="Constant">0:literal/left</span>, <span class="Constant">5:literal/right</span>
  assume-console [
    left-click 2, 0  <span class="Comment"># cursor at only character in final line</span>
    type <span class="Constant">[«]</span>
  ]
  3:event/backspace<span class="Special"> &lt;- </span>merge <span class="Constant">0:literal/text</span>, <span class="Constant">8:literal/backspace</span>, <span class="Constant">0:literal/dummy</span>, <span class="Constant">0:literal/dummy</span>
  replace-in-console <span class="Constant">171:literal/«</span>, 3:event/backspace
  run [
    editor-event-loop screen:address, console:address, 2:address:editor-data
  ]
  screen-should-contain [
   <span class="Constant"> .          .</span>
   <span class="Constant"> .abcd      .</span>
   <span class="Constant"> .          .</span>
  ]
]

<span class="muScenario">scenario</span> editor-moves-cursor-right-with-key [
  assume-screen <span class="Constant">10:literal/width</span>, <span class="Constant">5:literal/height</span>
  1:address:array:character<span class="Special"> &lt;- </span>new <span class="Constant">[abc]</span>
  2:address:editor-data<span class="Special"> &lt;- </span>new-editor 1:address:array:character, screen:address, <span class="Constant">0:literal/left</span>, <span class="Constant">10:literal/right</span>
  assume-console [
    press 65514  <span class="Comment"># right arrow</span>
    type <span class="Constant">[0]</span>
  ]
  run [
    editor-event-loop screen:address, console:address, 2:address:editor-data
  ]
  screen-should-contain [
   <span class="Constant"> .          .</span>
   <span class="Constant"> .a0bc      .</span>
   <span class="Constant"> .          .</span>
  ]
]

<span class="muScenario">scenario</span> editor-moves-cursor-to-next-line-with-right-arrow [
  assume-screen <span class="Constant">10:literal/width</span>, <span class="Constant">5:literal/height</span>
  1:address:array:character<span class="Special"> &lt;- </span>new <span class="Constant">[abc</span>
<span class="Constant">d]</span>
  2:address:editor-data<span class="Special"> &lt;- </span>new-editor 1:address:array:character, screen:address, <span class="Constant">0:literal/left</span>, <span class="Constant">10:literal/right</span>
  assume-console [
    press 65514  <span class="Comment"># right arrow</span>
    press 65514  <span class="Comment"># right arrow</span>
    press 65514  <span class="Comment"># right arrow</span>
    press 65514  <span class="Comment"># right arrow - next line</span>
    type <span class="Constant">[0]</span>
  ]
  run [
    editor-event-loop screen:address, console:address, 2:address:editor-data
  ]
  screen-should-contain [
   <span class="Constant"> .          .</span>
   <span class="Constant"> .abc       .</span>
   <span class="Constant"> .0d        .</span>
   <span class="Constant"> .          .</span>
  ]
]

<span class="muScenario">scenario</span> editor-moves-cursor-to-next-line-with-right-arrow-2 [
  assume-screen <span class="Constant">10:literal/width</span>, <span class="Constant">5:literal/height</span>
  1:address:array:character<span class="Special"> &lt;- </span>new <span class="Constant">[abc</span>
<span class="Constant">d]</span>
  2:address:editor-data<span class="Special"> &lt;- </span>new-editor 1:address:array:character, screen:address, <span class="Constant">1:literal/left</span>, <span class="Constant">10:literal/right</span>
  assume-console [
    press 65514  <span class="Comment"># right arrow</span>
    press 65514  <span class="Comment"># right arrow</span>
    press 65514  <span class="Comment"># right arrow</span>
    press 65514  <span class="Comment"># right arrow - next line</span>
    type <span class="Constant">[0]</span>
  ]
  run [
    editor-event-loop screen:address, console:address, 2:address:editor-data
  ]
  screen-should-contain [
   <span class="Constant"> .          .</span>
   <span class="Constant"> . abc      .</span>
   <span class="Constant"> . 0d       .</span>
   <span class="Constant"> .          .</span>
  ]
]

<span class="muScenario">scenario</span> editor-moves-cursor-to-next-wrapped-line-with-right-arrow [
  assume-screen <span class="Constant">10:literal/width</span>, <span class="Constant">5:literal/height</span>
  1:address:array:character<span class="Special"> &lt;- </span>new <span class="Constant">[abcdef]</span>
  2:address:editor-data<span class="Special"> &lt;- </span>new-editor 1:address:array:character, screen:address, <span class="Constant">0:literal/left</span>, <span class="Constant">5:literal/right</span>
  assume-console [
    left-click 1, 3
    press 65514  <span class="Comment"># right arrow</span>
  ]
  run [
    editor-event-loop screen:address, console:address, 2:address:editor-data
    3:number<span class="Special"> &lt;- </span>get 2:address:editor-data/deref, cursor-row:offset
    4:number<span class="Special"> &lt;- </span>get 2:address:editor-data/deref, cursor-column:offset
  ]
  screen-should-contain [
   <span class="Constant"> .          .</span>
   <span class="Constant"> .abcd↩     .</span>
   <span class="Constant"> .ef        .</span>
   <span class="Constant"> .          .</span>
  ]
  memory-should-contain [
    3<span class="Special"> &lt;- </span>2
    4<span class="Special"> &lt;- </span>0
  ]
]

<span class="muScenario">scenario</span> editor-moves-cursor-to-next-wrapped-line-with-right-arrow-2 [
  assume-screen <span class="Constant">10:literal/width</span>, <span class="Constant">5:literal/height</span>
  <span class="Comment"># line just barely wrapping</span>
  1:address:array:character<span class="Special"> &lt;- </span>new <span class="Constant">[abcde]</span>
  2:address:editor-data<span class="Special"> &lt;- </span>new-editor 1:address:array:character, screen:address, <span class="Constant">0:literal/left</span>, <span class="Constant">5:literal/right</span>
  <span class="Comment"># position cursor at last character before wrap and hit right-arrow</span>
  assume-console [
    left-click 1, 3
    press 65514  <span class="Comment"># right arrow</span>
  ]
  run [
    editor-event-loop screen:address, console:address, 2:address:editor-data
    3:number<span class="Special"> &lt;- </span>get 2:address:editor-data/deref, cursor-row:offset
    4:number<span class="Special"> &lt;- </span>get 2:address:editor-data/deref, cursor-column:offset
  ]
  memory-should-contain [
    3<span class="Special"> &lt;- </span>2
    4<span class="Special"> &lt;- </span>0
  ]
  <span class="Comment"># now hit right arrow again</span>
  assume-console [
    press 65514
  ]
  run [
    editor-event-loop screen:address, console:address, 2:address:editor-data
    3:number<span class="Special"> &lt;- </span>get 2:address:editor-data/deref, cursor-row:offset
    4:number<span class="Special"> &lt;- </span>get 2:address:editor-data/deref, cursor-column:offset
  ]
  memory-should-contain [
    3<span class="Special"> &lt;- </span>2
    4<span class="Special"> &lt;- </span>1
  ]
]

<span class="muScenario">scenario</span> editor-moves-cursor-to-next-wrapped-line-with-right-arrow-3 [
  assume-screen <span class="Constant">10:literal/width</span>, <span class="Constant">5:literal/height</span>
  1:address:array:character<span class="Special"> &lt;- </span>new <span class="Constant">[abcdef]</span>
  2:address:editor-data<span class="Special"> &lt;- </span>new-editor 1:address:array:character, screen:address, <span class="Constant">1:literal/left</span>, <span class="Constant">6:literal/right</span>
  assume-console [
    left-click 1, 4
    press 65514  <span class="Comment"># right arrow</span>
  ]
  run [
    editor-event-loop screen:address, console:address, 2:address:editor-data
    3:number<span class="Special"> &lt;- </span>get 2:address:editor-data/deref, cursor-row:offset
    4:number<span class="Special"> &lt;- </span>get 2:address:editor-data/deref, cursor-column:offset
  ]
  screen-should-contain [
   <span class="Constant"> .          .</span>
   <span class="Constant"> . abcd↩    .</span>
   <span class="Constant"> . ef       .</span>
   <span class="Constant"> .          .</span>
  ]
  memory-should-contain [
    3<span class="Special"> &lt;- </span>2
    4<span class="Special"> &lt;- </span>1
  ]
]

<span class="muScenario">scenario</span> editor-moves-cursor-to-next-line-with-right-arrow-at-end-of-line [
  assume-screen <span class="Constant">10:literal/width</span>, <span class="Constant">5:literal/height</span>
  1:address:array:character<span class="Special"> &lt;- </span>new <span class="Constant">[abc</span>
<span class="Constant">d]</span>
  2:address:editor-data<span class="Special"> &lt;- </span>new-editor 1:address:array:character, screen:address, <span class="Constant">0:literal/left</span>, <span class="Constant">10:literal/right</span>
  assume-console [
    left-click 1, 3
    press 65514  <span class="Comment"># right arrow - next line</span>
    type <span class="Constant">[0]</span>
  ]
  run [
    editor-event-loop screen:address, console:address, 2:address:editor-data
  ]
  screen-should-contain [
   <span class="Constant"> .          .</span>
   <span class="Constant"> .abc       .</span>
   <span class="Constant"> .0d        .</span>
   <span class="Constant"> .          .</span>
  ]
]

<span class="muScenario">scenario</span> editor-moves-cursor-left-with-key [
  assume-screen <span class="Constant">10:literal/width</span>, <span class="Constant">5:literal/height</span>
  1:address:array:character<span class="Special"> &lt;- </span>new <span class="Constant">[abc]</span>
  2:address:editor-data<span class="Special"> &lt;- </span>new-editor 1:address:array:character, screen:address, <span class="Constant">0:literal/left</span>, <span class="Constant">10:literal/right</span>
  assume-console [
    left-click 1, 2
    press 65515  <span class="Comment"># left arrow</span>
    type <span class="Constant">[0]</span>
  ]
  run [
    editor-event-loop screen:address, console:address, 2:address:editor-data
  ]
  screen-should-contain [
   <span class="Constant"> .          .</span>
   <span class="Constant"> .a0bc      .</span>
   <span class="Constant"> .          .</span>
  ]
]

<span class="muScenario">scenario</span> editor-moves-cursor-to-previous-line-with-left-arrow-at-start-of-line [
  assume-screen <span class="Constant">10:literal/width</span>, <span class="Constant">5:literal/height</span>
  <span class="Comment"># initialize editor with two lines</span>
  1:address:array:character<span class="Special"> &lt;- </span>new <span class="Constant">[abc</span>
<span class="Constant">d]</span>
  2:address:editor-data<span class="Special"> &lt;- </span>new-editor 1:address:array:character, screen:address, <span class="Constant">0:literal/left</span>, <span class="Constant">10:literal/right</span>
  <span class="Comment"># position cursor at start of second line (so there's no previous newline)</span>
  assume-console [
    left-click 2, 0
    press 65515  <span class="Comment"># left arrow</span>
  ]
  run [
    editor-event-loop screen:address, console:address, 2:address:editor-data
    3:number<span class="Special"> &lt;- </span>get 2:address:editor-data/deref, cursor-row:offset
    4:number<span class="Special"> &lt;- </span>get 2:address:editor-data/deref, cursor-column:offset
  ]
  memory-should-contain [
    3<span class="Special"> &lt;- </span>1
    4<span class="Special"> &lt;- </span>3
  ]
]

<span class="muScenario">scenario</span> editor-moves-cursor-to-previous-line-with-left-arrow-at-start-of-line-2 [
  assume-screen <span class="Constant">10:literal/width</span>, <span class="Constant">5:literal/height</span>
  <span class="Comment"># initialize editor with three lines</span>
  1:address:array:character<span class="Special"> &lt;- </span>new <span class="Constant">[abc</span>
<span class="Constant">def</span>
<span class="Constant">g]</span>
  2:address:editor-data<span class="Special"> &lt;- </span>new-editor 1:address:array:character, screen:address, <span class="Constant">0:literal/left</span>, <span class="Constant">10:literal/right</span>
  <span class="Comment"># position cursor further down (so there's a newline before the character at</span>
  <span class="Comment"># the cursor)</span>
  assume-console [
    left-click 3, 0
    press 65515  <span class="Comment"># left arrow</span>
    type <span class="Constant">[0]</span>
  ]
  run [
    editor-event-loop screen:address, console:address, 2:address:editor-data
  ]
  screen-should-contain [
   <span class="Constant"> .          .</span>
   <span class="Constant"> .abc       .</span>
   <span class="Constant"> .def0      .</span>
   <span class="Constant"> .g         .</span>
   <span class="Constant"> .          .</span>
  ]
]

<span class="muScenario">scenario</span> editor-moves-cursor-to-previous-line-with-left-arrow-at-start-of-line-3 [
  assume-screen <span class="Constant">10:literal/width</span>, <span class="Constant">5:literal/height</span>
  1:address:array:character<span class="Special"> &lt;- </span>new <span class="Constant">[abc</span>
<span class="Constant">def</span>
<span class="Constant">g]</span>
  2:address:editor-data<span class="Special"> &lt;- </span>new-editor 1:address:array:character, screen:address, <span class="Constant">0:literal/left</span>, <span class="Constant">10:literal/right</span>
  <span class="Comment"># position cursor at start of text</span>
  assume-console [
    left-click 1, 0
    press 65515  <span class="Comment"># left arrow should have no effect</span>
    type <span class="Constant">[0]</span>
  ]
  run [
    editor-event-loop screen:address, console:address, 2:address:editor-data
  ]
  screen-should-contain [
   <span class="Constant"> .          .</span>
   <span class="Constant"> .0abc      .</span>
   <span class="Constant"> .def       .</span>
   <span class="Constant"> .g         .</span>
   <span class="Constant"> .          .</span>
  ]
]

<span class="muScenario">scenario</span> editor-moves-cursor-to-previous-line-with-left-arrow-at-start-of-line-4 [
  assume-screen <span class="Constant">10:literal/width</span>, <span class="Constant">5:literal/height</span>
  <span class="Comment"># initialize editor with text containing an empty line</span>
  1:address:array:character<span class="Special"> &lt;- </span>new <span class="Constant">[abc</span>

d]
  2:address:editor-data<span class="Special"> &lt;- </span>new-editor 1:address:array:character, screen:address, <span class="Constant">0:literal/left</span>, <span class="Constant">10:literal/right</span>
  <span class="Comment"># position cursor right after empty line</span>
  assume-console [
    left-click 3, 0
    press 65515  <span class="Comment"># left arrow</span>
    type <span class="Constant">[0]</span>
  ]
  run [
    editor-event-loop screen:address, console:address, 2:address:editor-data
  ]
  screen-should-contain [
   <span class="Constant"> .          .</span>
   <span class="Constant"> .abc       .</span>
   <span class="Constant"> .0         .</span>
   <span class="Constant"> .d         .</span>
   <span class="Constant"> .          .</span>
  ]
]

<span class="muScenario">scenario</span> editor-moves-across-screen-lines-across-wrap-with-left-arrow [
  assume-screen <span class="Constant">10:literal/width</span>, <span class="Constant">5:literal/height</span>
  <span class="Comment"># initialize editor with text containing an empty line</span>
  1:address:array:character<span class="Special"> &lt;- </span>new <span class="Constant">[abcdef]</span>
  2:address:editor-data<span class="Special"> &lt;- </span>new-editor 1:address:array:character, screen:address, <span class="Constant">0:literal/left</span>, <span class="Constant">5:literal/right</span>
  screen-should-contain [
   <span class="Constant"> .          .</span>
   <span class="Constant"> .abcd↩     .</span>
   <span class="Constant"> .ef        .</span>
   <span class="Constant"> .          .</span>
  ]
  <span class="Comment"># position cursor right after empty line</span>
  assume-console [
    left-click 2, 0
    press 65515  <span class="Comment"># left arrow</span>
  ]
  run [
    editor-event-loop screen:address, console:address, 2:address:editor-data
    3:number<span class="Special"> &lt;- </span>get 2:address:editor-data/deref, cursor-row:offset
    4:number<span class="Special"> &lt;- </span>get 2:address:editor-data/deref, cursor-column:offset
  ]
  memory-should-contain [
    3<span class="Special"> &lt;- </span>1  <span class="Comment"># previous row</span>
    4<span class="Special"> &lt;- </span>3  <span class="Comment"># end of wrapped line</span>
  ]
]

<span class="muScenario">scenario</span> editor-moves-to-previous-line-with-up-arrow [
  assume-screen <span class="Constant">10:literal/width</span>, <span class="Constant">5:literal/height</span>
  1:address:array:character<span class="Special"> &lt;- </span>new <span class="Constant">[abc</span>
<span class="Constant">def]</span>
  2:address:editor-data<span class="Special"> &lt;- </span>new-editor 1:address:array:character, screen:address, <span class="Constant">0:literal/left</span>, <span class="Constant">10:literal/right</span>
  assume-console [
    left-click 2, 1
    press 65517  <span class="Comment"># up arrow</span>
  ]
  run [
    editor-event-loop screen:address, console:address, 2:address:editor-data
    3:number<span class="Special"> &lt;- </span>get 2:address:editor-data/deref, cursor-row:offset
    4:number<span class="Special"> &lt;- </span>get 2:address:editor-data/deref, cursor-column:offset
  ]
  memory-should-contain [
    3<span class="Special"> &lt;- </span>1
    4<span class="Special"> &lt;- </span>1
  ]
]

<span class="muScenario">scenario</span> editor-moves-to-next-line-with-down-arrow [
  assume-screen <span class="Constant">10:literal/width</span>, <span class="Constant">5:literal/height</span>
  1:address:array:character<span class="Special"> &lt;- </span>new <span class="Constant">[abc</span>
<span class="Constant">def]</span>
  2:address:editor-data<span class="Special"> &lt;- </span>new-editor 1:address:array:character, screen:address, <span class="Constant">0:literal/left</span>, <span class="Constant">10:literal/right</span>
  <span class="Comment"># cursor starts out at (1, 0)</span>
  assume-console [
    press 65516  <span class="Comment"># down arrow</span>
  ]
  run [
    editor-event-loop screen:address, console:address, 2:address:editor-data
    3:number<span class="Special"> &lt;- </span>get 2:address:editor-data/deref, cursor-row:offset
    4:number<span class="Special"> &lt;- </span>get 2:address:editor-data/deref, cursor-column:offset
  ]
  <span class="Comment"># ..and ends at (2, 0)</span>
  memory-should-contain [
    3<span class="Special"> &lt;- </span>2
    4<span class="Special"> &lt;- </span>0
  ]
]

<span class="muScenario">scenario</span> editor-adjusts-column-at-previous-line [
  assume-screen <span class="Constant">10:literal/width</span>, <span class="Constant">5:literal/height</span>
  1:address:array:character<span class="Special"> &lt;- </span>new <span class="Constant">[ab</span>
<span class="Constant">def]</span>
  2:address:editor-data<span class="Special"> &lt;- </span>new-editor 1:address:array:character, screen:address, <span class="Constant">0:literal/left</span>, <span class="Constant">10:literal/right</span>
  assume-console [
    left-click 2, 3
    press 65517  <span class="Comment"># up arrow</span>
  ]
  run [
    editor-event-loop screen:address, console:address, 2:address:editor-data
    3:number<span class="Special"> &lt;- </span>get 2:address:editor-data/deref, cursor-row:offset
    4:number<span class="Special"> &lt;- </span>get 2:address:editor-data/deref, cursor-column:offset
  ]
  memory-should-contain [
    3<span class="Special"> &lt;- </span>1
    4<span class="Special"> &lt;- </span>2
  ]
]

<span class="muScenario">scenario</span> editor-adjusts-column-at-next-line [
  assume-screen <span class="Constant">10:literal/width</span>, <span class="Constant">5:literal/height</span>
  1:address:array:character<span class="Special"> &lt;- </span>new <span class="Constant">[abc</span>
<span class="Constant">de]</span>
  2:address:editor-data<span class="Special"> &lt;- </span>new-editor 1:address:array:character, screen:address, <span class="Constant">0:literal/left</span>, <span class="Constant">10:literal/right</span>
  assume-console [
    left-click 1, 3
    press 65516  <span class="Comment"># down arrow</span>
  ]
  run [
    editor-event-loop screen:address, console:address, 2:address:editor-data
    3:number<span class="Special"> &lt;- </span>get 2:address:editor-data/deref, cursor-row:offset
    4:number<span class="Special"> &lt;- </span>get 2:address:editor-data/deref, cursor-column:offset
  ]
  memory-should-contain [
    3<span class="Special"> &lt;- </span>2
    4<span class="Special"> &lt;- </span>2
  ]
]

<span class="muScenario">scenario</span> editor-moves-to-start-of-line-with-ctrl-a [
  assume-screen <span class="Constant">10:literal/width</span>, <span class="Constant">5:literal/height</span>
  1:address:array:character<span class="Special"> &lt;- </span>new <span class="Constant">[123</span>
<span class="Constant">456]</span>
  2:address:editor-data<span class="Special"> &lt;- </span>new-editor 1:address:array:character, screen:address, <span class="Constant">0:literal/left</span>, <span class="Constant">10:literal/right</span>
  <span class="Comment"># start on second line, press ctrl-a</span>
  assume-console [
    left-click 2, 3
    type <span class="Constant">[a]</span>  <span class="Comment"># ctrl-a</span>
  ]
  3:event/ctrl-a<span class="Special"> &lt;- </span>merge <span class="Constant">0:literal/text</span>, <span class="Constant">1:literal/ctrl-a</span>, <span class="Constant">0:literal/dummy</span>, <span class="Constant">0:literal/dummy</span>
  replace-in-console <span class="Constant">97:literal/a</span>, 3:event/ctrl-a
  run [
    editor-event-loop screen:address, console:address, 2:address:editor-data
    4:number<span class="Special"> &lt;- </span>get 2:address:editor-data/deref, cursor-row:offset
    5:number<span class="Special"> &lt;- </span>get 2:address:editor-data/deref, cursor-column:offset
  ]
  <span class="Comment"># cursor moves to start of line</span>
  memory-should-contain [
    4<span class="Special"> &lt;- </span>2
    5<span class="Special"> &lt;- </span>0
  ]
]

<span class="muScenario">scenario</span> editor-moves-to-start-of-line-with-ctrl-a-2 [
  assume-screen <span class="Constant">10:literal/width</span>, <span class="Constant">5:literal/height</span>
  1:address:array:character<span class="Special"> &lt;- </span>new <span class="Constant">[123</span>
<span class="Constant">456]</span>
  2:address:editor-data<span class="Special"> &lt;- </span>new-editor 1:address:array:character, screen:address, <span class="Constant">0:literal/left</span>, <span class="Constant">10:literal/right</span>
  <span class="Comment"># start on first line (no newline before), press ctrl-a</span>
  assume-console [
    left-click 1, 3
    type <span class="Constant">[a]</span>  <span class="Comment"># ctrl-a</span>
  ]
  3:event/ctrl-a<span class="Special"> &lt;- </span>merge <span class="Constant">0:literal/text</span>, <span class="Constant">1:literal/ctrl-a</span>, <span class="Constant">0:literal/dummy</span>, <span class="Constant">0:literal/dummy</span>
  replace-in-console <span class="Constant">97:literal/a</span>, 3:event/ctrl-a
  run [
    editor-event-loop screen:address, console:address, 2:address:editor-data
    4:number<span class="Special"> &lt;- </span>get 2:address:editor-data/deref, cursor-row:offset
    5:number<span class="Special"> &lt;- </span>get 2:address:editor-data/deref, cursor-column:offset
  ]
  <span class="Comment"># cursor moves to start of line</span>
  memory-should-contain [
    4<span class="Special"> &lt;- </span>1
    5<span class="Special"> &lt;- </span>0
  ]
]

<span class="muScenario">scenario</span> editor-moves-to-start-of-line-with-home [
  assume-screen <span class="Constant">10:literal/width</span>, <span class="Constant">5:literal/height</span>
  1:address:array:character<span class="Special"> &lt;- </span>new <span class="Constant">[123</span>
<span class="Constant">456]</span>
  2:address:editor-data<span class="Special"> &lt;- </span>new-editor 1:address:array:character, screen:address, <span class="Constant">0:literal/left</span>, <span class="Constant">10:literal/right</span>
  <span class="Comment"># start on second line, press 'home'</span>
  assume-console [
    left-click 2, 3
    press 65521  <span class="Comment"># 'home'</span>
  ]
  run [
    editor-event-loop screen:address, console:address, 2:address:editor-data
    3:number<span class="Special"> &lt;- </span>get 2:address:editor-data/deref, cursor-row:offset
    4:number<span class="Special"> &lt;- </span>get 2:address:editor-data/deref, cursor-column:offset
  ]
  <span class="Comment"># cursor moves to start of line</span>
  memory-should-contain [
    3<span class="Special"> &lt;- </span>2
    4<span class="Special"> &lt;- </span>0
  ]
]

<span class="muScenario">scenario</span> editor-moves-to-start-of-line-with-home-2 [
  assume-screen <span class="Constant">10:literal/width</span>, <span class="Constant">5:literal/height</span>
  1:address:array:character<span class="Special"> &lt;- </span>new <span class="Constant">[123</span>
<span class="Constant">456]</span>
  2:address:editor-data<span class="Special"> &lt;- </span>new-editor 1:address:array:character, screen:address, <span class="Constant">0:literal/left</span>, <span class="Constant">10:literal/right</span>
  <span class="Comment"># start on first line (no newline before), press 'home'</span>
  assume-console [
    left-click 1, 3
    press 65521  <span class="Comment"># 'home'</span>
  ]
  run [
    editor-event-loop screen:address, console:address, 2:address:editor-data
    3:number<span class="Special"> &lt;- </span>get 2:address:editor-data/deref, cursor-row:offset
    4:number<span class="Special"> &lt;- </span>get 2:address:editor-data/deref, cursor-column:offset
  ]
  <span class="Comment"># cursor moves to start of line</span>
  memory-should-contain [
    3<span class="Special"> &lt;- </span>1
    4<span class="Special"> &lt;- </span>0
  ]
]

<span class="muScenario">scenario</span> editor-moves-to-start-of-line-with-ctrl-e [
  assume-screen <span class="Constant">10:literal/width</span>, <span class="Constant">5:literal/height</span>
  1:address:array:character<span class="Special"> &lt;- </span>new <span class="Constant">[123</span>
<span class="Constant">456]</span>
  2:address:editor-data<span class="Special"> &lt;- </span>new-editor 1:address:array:character, screen:address, <span class="Constant">0:literal/left</span>, <span class="Constant">10:literal/right</span>
  <span class="Comment"># start on first line, press ctrl-e</span>
  assume-console [
    left-click 1, 1
    type <span class="Constant">[e]</span>  <span class="Comment"># ctrl-e</span>
  ]
  3:event/ctrl-e<span class="Special"> &lt;- </span>merge <span class="Constant">0:literal/text</span>, <span class="Constant">5:literal/ctrl-e</span>, <span class="Constant">0:literal/dummy</span>, <span class="Constant">0:literal/dummy</span>
  replace-in-console <span class="Constant">101:literal/e</span>, 3:event/ctrl-e
  run [
    editor-event-loop screen:address, console:address, 2:address:editor-data
    4:number<span class="Special"> &lt;- </span>get 2:address:editor-data/deref, cursor-row:offset
    5:number<span class="Special"> &lt;- </span>get 2:address:editor-data/deref, cursor-column:offset
  ]
  <span class="Comment"># cursor moves to end of line</span>
  memory-should-contain [
    4<span class="Special"> &lt;- </span>1
    5<span class="Special"> &lt;- </span>3
  ]
  <span class="Comment"># editor inserts future characters at cursor</span>
  assume-console [
    type <span class="Constant">[z]</span>
  ]
  run [
    editor-event-loop screen:address, console:address, 2:address:editor-data
    4:number<span class="Special"> &lt;- </span>get 2:address:editor-data/deref, cursor-row:offset
    5:number<span class="Special"> &lt;- </span>get 2:address:editor-data/deref, cursor-column:offset
  ]
  memory-should-contain [
    4<span class="Special"> &lt;- </span>1
    5<span class="Special"> &lt;- </span>4
  ]
  screen-should-contain [
   <span class="Constant"> .          .</span>
   <span class="Constant"> .123z      .</span>
   <span class="Constant"> .456       .</span>
   <span class="Constant"> .          .</span>
  ]
]

<span class="muScenario">scenario</span> editor-moves-to-end-of-line-with-ctrl-e-2 [
  assume-screen <span class="Constant">10:literal/width</span>, <span class="Constant">5:literal/height</span>
  1:address:array:character<span class="Special"> &lt;- </span>new <span class="Constant">[123</span>
<span class="Constant">456]</span>
  2:address:editor-data<span class="Special"> &lt;- </span>new-editor 1:address:array:character, screen:address, <span class="Constant">0:literal/left</span>, <span class="Constant">10:literal/right</span>
  <span class="Comment"># start on second line (no newline after), press ctrl-e</span>
  assume-console [
    left-click 2, 1
    type <span class="Constant">[e]</span>  <span class="Comment"># ctrl-e</span>
  ]
  3:event/ctrl-e<span class="Special"> &lt;- </span>merge <span class="Constant">0:literal/text</span>, <span class="Constant">5:literal/ctrl-e</span>, <span class="Constant">0:literal/dummy</span>, <span class="Constant">0:literal/dummy</span>
  replace-in-console <span class="Constant">101:literal/e</span>, 3:event/ctrl-e
  run [
    editor-event-loop screen:address, console:address, 2:address:editor-data
    4:number<span class="Special"> &lt;- </span>get 2:address:editor-data/deref, cursor-row:offset
    5:number<span class="Special"> &lt;- </span>get 2:address:editor-data/deref, cursor-column:offset
  ]
  <span class="Comment"># cursor moves to end of line</span>
  memory-should-contain [
    4<span class="Special"> &lt;- </span>2
    5<span class="Special"> &lt;- </span>3
  ]
]

<span class="muScenario">scenario</span> editor-moves-to-end-of-line-with-end [
  assume-screen <span class="Constant">10:literal/width</span>, <span class="Constant">5:literal/height</span>
  1:address:array:character<span class="Special"> &lt;- </span>new <span class="Constant">[123</span>
<span class="Constant">456]</span>
  2:address:editor-data<span class="Special"> &lt;- </span>new-editor 1:address:array:character, screen:address, <span class="Constant">0:literal/left</span>, <span class="Constant">10:literal/right</span>
  <span class="Comment"># start on first line, press 'end'</span>
  assume-console [
    left-click 1, 1
    press 65520  <span class="Comment"># 'end'</span>
  ]
  run [
    editor-event-loop screen:address, console:address, 2:address:editor-data
    3:number<span class="Special"> &lt;- </span>get 2:address:editor-data/deref, cursor-row:offset
    4:number<span class="Special"> &lt;- </span>get 2:address:editor-data/deref, cursor-column:offset
  ]
  <span class="Comment"># cursor moves to end of line</span>
  memory-should-contain [
    3<span class="Special"> &lt;- </span>1
    4<span class="Special"> &lt;- </span>3
  ]
]

<span class="muScenario">scenario</span> editor-moves-to-end-of-line-with-end-2 [
  assume-screen <span class="Constant">10:literal/width</span>, <span class="Constant">5:literal/height</span>
  1:address:array:character<span class="Special"> &lt;- </span>new <span class="Constant">[123</span>
<span class="Constant">456]</span>
  2:address:editor-data<span class="Special"> &lt;- </span>new-editor 1:address:array:character, screen:address, <span class="Constant">0:literal/left</span>, <span class="Constant">10:literal/right</span>
  <span class="Comment"># start on second line (no newline after), press 'end'</span>
  assume-console [
    left-click 2, 1
    press 65520  <span class="Comment"># 'end'</span>
  ]
  run [
    editor-event-loop screen:address, console:address, 2:address:editor-data
    3:number<span class="Special"> &lt;- </span>get 2:address:editor-data/deref, cursor-row:offset
    4:number<span class="Special"> &lt;- </span>get 2:address:editor-data/deref, cursor-column:offset
  ]
  <span class="Comment"># cursor moves to end of line</span>
  memory-should-contain [
    3<span class="Special"> &lt;- </span>2
    4<span class="Special"> &lt;- </span>3
  ]
]

<span class="muScenario">scenario</span> editor-deletes-to-start-of-line-with-ctrl-u [
  assume-screen <span class="Constant">10:literal/width</span>, <span class="Constant">5:literal/height</span>
  1:address:array:character<span class="Special"> &lt;- </span>new <span class="Constant">[123</span>
<span class="Constant">456]</span>
  2:address:editor-data<span class="Special"> &lt;- </span>new-editor 1:address:array:character, screen:address, <span class="Constant">0:literal/left</span>, <span class="Constant">10:literal/right</span>
  <span class="Comment"># start on second line, press ctrl-u</span>
  assume-console [
    left-click 2, 2
    type <span class="Constant">[u]</span>  <span class="Comment"># ctrl-u</span>
  ]
  3:event/ctrl-a<span class="Special"> &lt;- </span>merge <span class="Constant">0:literal/text</span>, <span class="Constant">21:literal/ctrl-u</span>, <span class="Constant">0:literal/dummy</span>, <span class="Constant">0:literal/dummy</span>
  replace-in-console <span class="Constant">117:literal/u</span>, 3:event/ctrl-u
  run [
    editor-event-loop screen:address, console:address, 2:address:editor-data
  ]
  <span class="Comment"># cursor deletes to start of line</span>
  screen-should-contain [
   <span class="Constant"> .          .</span>
   <span class="Constant"> .123       .</span>
   <span class="Constant"> .6         .</span>
   <span class="Constant"> .          .</span>
  ]
]

<span class="muScenario">scenario</span> editor-deletes-to-start-of-line-with-ctrl-u-2 [
  assume-screen <span class="Constant">10:literal/width</span>, <span class="Constant">5:literal/height</span>
  1:address:array:character<span class="Special"> &lt;- </span>new <span class="Constant">[123</span>
<span class="Constant">456]</span>
  2:address:editor-data<span class="Special"> &lt;- </span>new-editor 1:address:array:character, screen:address, <span class="Constant">0:literal/left</span>, <span class="Constant">10:literal/right</span>
  <span class="Comment"># start on first line (no newline before), press ctrl-u</span>
  assume-console [
    left-click 1, 2
    type <span class="Constant">[u]</span>  <span class="Comment"># ctrl-u</span>
  ]
  3:event/ctrl-u<span class="Special"> &lt;- </span>merge <span class="Constant">0:literal/text</span>, <span class="Constant">21:literal/ctrl-a</span>, <span class="Constant">0:literal/dummy</span>, <span class="Constant">0:literal/dummy</span>
  replace-in-console <span class="Constant">117:literal/a</span>, 3:event/ctrl-u
  run [
    editor-event-loop screen:address, console:address, 2:address:editor-data
  ]
  <span class="Comment"># cursor deletes to start of line</span>
  screen-should-contain [
   <span class="Constant"> .          .</span>
   <span class="Constant"> .3         .</span>
   <span class="Constant"> .456       .</span>
   <span class="Constant"> .          .</span>
  ]
]

<span class="muScenario">scenario</span> editor-deletes-to-start-of-line-with-ctrl-u-3 [
  assume-screen <span class="Constant">10:literal/width</span>, <span class="Constant">5:literal/height</span>
  1:address:array:character<span class="Special"> &lt;- </span>new <span class="Constant">[123</span>
<span class="Constant">456]</span>
  2:address:editor-data<span class="Special"> &lt;- </span>new-editor 1:address:array:character, screen:address, <span class="Constant">0:literal/left</span>, <span class="Constant">10:literal/right</span>
  <span class="Comment"># start past end of line, press ctrl-u</span>
  assume-console [
    left-click 1, 3
    type <span class="Constant">[u]</span>  <span class="Comment"># ctrl-u</span>
  ]
  3:event/ctrl-u<span class="Special"> &lt;- </span>merge <span class="Constant">0:literal/text</span>, <span class="Constant">21:literal/ctrl-a</span>, <span class="Constant">0:literal/dummy</span>, <span class="Constant">0:literal/dummy</span>
  replace-in-console <span class="Constant">117:literal/a</span>, 3:event/ctrl-u
  run [
    editor-event-loop screen:address, console:address, 2:address:editor-data
  ]
  <span class="Comment"># cursor deletes to start of line</span>
  screen-should-contain [
   <span class="Constant"> .          .</span>
   <span class="Constant"> .          .</span>
   <span class="Constant"> .456       .</span>
   <span class="Constant"> .          .</span>
  ]
]

<span class="muScenario">scenario</span> editor-deletes-to-end-of-line-with-ctrl-k [
  assume-screen <span class="Constant">10:literal/width</span>, <span class="Constant">5:literal/height</span>
  1:address:array:character<span class="Special"> &lt;- </span>new <span class="Constant">[123</span>
<span class="Constant">456]</span>
  2:address:editor-data<span class="Special"> &lt;- </span>new-editor 1:address:array:character, screen:address, <span class="Constant">0:literal/left</span>, <span class="Constant">10:literal/right</span>
  <span class="Comment"># start on first line, press ctrl-k</span>
  assume-console [
    left-click 1, 1
    type <span class="Constant">[k]</span>  <span class="Comment"># ctrl-k</span>
  ]
  3:event/ctrl-k<span class="Special"> &lt;- </span>merge <span class="Constant">0:literal/text</span>, <span class="Constant">11:literal/ctrl-k</span>, <span class="Constant">0:literal/dummy</span>, <span class="Constant">0:literal/dummy</span>
  replace-in-console <span class="Constant">107:literal/k</span>, 3:event/ctrl-k
  run [
    editor-event-loop screen:address, console:address, 2:address:editor-data
  ]
  <span class="Comment"># cursor deletes to end of line</span>
  screen-should-contain [
   <span class="Constant"> .          .</span>
   <span class="Constant"> .1         .</span>
   <span class="Constant"> .456       .</span>
   <span class="Constant"> .          .</span>
  ]
]

<span class="muScenario">scenario</span> editor-deletes-to-end-of-line-with-ctrl-k-2 [
  assume-screen <span class="Constant">10:literal/width</span>, <span class="Constant">5:literal/height</span>
  1:address:array:character<span class="Special"> &lt;- </span>new <span class="Constant">[123</span>
<span class="Constant">456]</span>
  2:address:editor-data<span class="Special"> &lt;- </span>new-editor 1:address:array:character, screen:address, <span class="Constant">0:literal/left</span>, <span class="Constant">10:literal/right</span>
  <span class="Comment"># start on second line (no newline after), press ctrl-k</span>
  assume-console [
    left-click 2, 1
    type <span class="Constant">[k]</span>  <span class="Comment"># ctrl-k</span>
  ]
  3:event/ctrl-k<span class="Special"> &lt;- </span>merge <span class="Constant">0:literal/text</span>, <span class="Constant">11:literal/ctrl-k</span>, <span class="Constant">0:literal/dummy</span>, <span class="Constant">0:literal/dummy</span>
  replace-in-console <span class="Constant">107:literal/k</span>, 3:event/ctrl-k
  run [
    editor-event-loop screen:address, console:address, 2:address:editor-data
  ]
  <span class="Comment"># cursor deletes to end of line</span>
  screen-should-contain [
   <span class="Constant"> .          .</span>
   <span class="Constant"> .123       .</span>
   <span class="Constant"> .4         .</span>
   <span class="Constant"> .          .</span>
  ]
]

<span class="muScenario">scenario</span> editor-deletes-to-end-of-line-with-ctrl-k-3 [
  assume-screen <span class="Constant">10:literal/width</span>, <span class="Constant">5:literal/height</span>
  1:address:array:character<span class="Special"> &lt;- </span>new <span class="Constant">[123</span>
<span class="Constant">456]</span>
  2:address:editor-data<span class="Special"> &lt;- </span>new-editor 1:address:array:character, screen:address, <span class="Constant">0:literal/left</span>, <span class="Constant">10:literal/right</span>
  <span class="Comment"># start at end of line</span>
  assume-console [
    left-click 1, 2
    type <span class="Constant">[k]</span>  <span class="Comment"># ctrl-k</span>
  ]
  3:event/ctrl-k<span class="Special"> &lt;- </span>merge <span class="Constant">0:literal/text</span>, <span class="Constant">11:literal/ctrl-k</span>, <span class="Constant">0:literal/dummy</span>, <span class="Constant">0:literal/dummy</span>
  replace-in-console <span class="Constant">107:literal/k</span>, 3:event/ctrl-k
  run [
    editor-event-loop screen:address, console:address, 2:address:editor-data
  ]
  <span class="Comment"># cursor deletes to end of line</span>
  screen-should-contain [
   <span class="Constant"> .          .</span>
   <span class="Constant"> .12        .</span>
   <span class="Constant"> .456       .</span>
   <span class="Constant"> .          .</span>
  ]
]

<span class="muScenario">scenario</span> editor-deletes-to-end-of-line-with-ctrl-k-4 [
  assume-screen <span class="Constant">10:literal/width</span>, <span class="Constant">5:literal/height</span>
  1:address:array:character<span class="Special"> &lt;- </span>new <span class="Constant">[123</span>
<span class="Constant">456]</span>
  2:address:editor-data<span class="Special"> &lt;- </span>new-editor 1:address:array:character, screen:address, <span class="Constant">0:literal/left</span>, <span class="Constant">10:literal/right</span>
  <span class="Comment"># start past end of line</span>
  assume-console [
    left-click 1, 3
    type <span class="Constant">[k]</span>  <span class="Comment"># ctrl-k</span>
  ]
  3:event/ctrl-k<span class="Special"> &lt;- </span>merge <span class="Constant">0:literal/text</span>, <span class="Constant">11:literal/ctrl-k</span>, <span class="Constant">0:literal/dummy</span>, <span class="Constant">0:literal/dummy</span>
  replace-in-console <span class="Constant">107:literal/k</span>, 3:event/ctrl-k
  run [
    editor-event-loop screen:address, console:address, 2:address:editor-data
  ]
  <span class="Comment"># cursor deletes to end of line</span>
  screen-should-contain [
   <span class="Constant"> .          .</span>
   <span class="Constant"> .123       .</span>
   <span class="Constant"> .456       .</span>
   <span class="Constant"> .          .</span>
  ]
]

<span class="muScenario">scenario</span> editor-deletes-to-end-of-line-with-ctrl-k-5 [
  assume-screen <span class="Constant">10:literal/width</span>, <span class="Constant">5:literal/height</span>
  1:address:array:character<span class="Special"> &lt;- </span>new <span class="Constant">[123</span>
<span class="Constant">456]</span>
  2:address:editor-data<span class="Special"> &lt;- </span>new-editor 1:address:array:character, screen:address, <span class="Constant">0:literal/left</span>, <span class="Constant">10:literal/right</span>
  <span class="Comment"># start at end of text</span>
  assume-console [
    left-click 2, 2
    type <span class="Constant">[k]</span>  <span class="Comment"># ctrl-k</span>
  ]
  3:event/ctrl-k<span class="Special"> &lt;- </span>merge <span class="Constant">0:literal/text</span>, <span class="Constant">11:literal/ctrl-k</span>, <span class="Constant">0:literal/dummy</span>, <span class="Constant">0:literal/dummy</span>
  replace-in-console <span class="Constant">107:literal/k</span>, 3:event/ctrl-k
  run [
    editor-event-loop screen:address, console:address, 2:address:editor-data
  ]
  <span class="Comment"># cursor deletes to end of line</span>
  screen-should-contain [
   <span class="Constant"> .          .</span>
   <span class="Constant"> .123       .</span>
   <span class="Constant"> .45        .</span>
   <span class="Constant"> .          .</span>
  ]
]

<span class="muScenario">scenario</span> editor-deletes-to-end-of-line-with-ctrl-k-6 [
  assume-screen <span class="Constant">10:literal/width</span>, <span class="Constant">5:literal/height</span>
  1:address:array:character<span class="Special"> &lt;- </span>new <span class="Constant">[123</span>
<span class="Constant">456]</span>
  2:address:editor-data<span class="Special"> &lt;- </span>new-editor 1:address:array:character, screen:address, <span class="Constant">0:literal/left</span>, <span class="Constant">10:literal/right</span>
  <span class="Comment"># start past end of text</span>
  assume-console [
    left-click 2, 3
    type <span class="Constant">[k]</span>  <span class="Comment"># ctrl-k</span>
  ]
  3:event/ctrl-k<span class="Special"> &lt;- </span>merge <span class="Constant">0:literal/text</span>, <span class="Constant">11:literal/ctrl-k</span>, <span class="Constant">0:literal/dummy</span>, <span class="Constant">0:literal/dummy</span>
  replace-in-console <span class="Constant">107:literal/k</span>, 3:event/ctrl-k
  run [
    editor-event-loop screen:address, console:address, 2:address:editor-data
  ]
  <span class="Comment"># cursor deletes to end of line</span>
  screen-should-contain [
   <span class="Constant"> .          .</span>
   <span class="Constant"> .123       .</span>
   <span class="Constant"> .456       .</span>
   <span class="Constant"> .          .</span>
  ]
]

<span class="muScenario">scenario</span> point-at-multiple-editors [
<span class="Constant">  $close-trace</span>
  assume-screen <span class="Constant">30:literal/width</span>, <span class="Constant">5:literal/height</span>
  <span class="Comment"># initialize both halves of screen</span>
  1:address:array:character<span class="Special"> &lt;- </span>new <span class="Constant">[abc]</span>
  2:address:array:character<span class="Special"> &lt;- </span>new <span class="Constant">[def]</span>
  3:address:programming-environment-data<span class="Special"> &lt;- </span>new-programming-environment screen:address, 1:address:array:character, 2:address:array:character
  <span class="Comment"># focus on both sides</span>
  assume-console [
    left-click 1, 1
    left-click 1, 17
  ]
  <span class="Comment"># check cursor column in each</span>
  run [
    event-loop screen:address, console:address, 3:address:programming-environment-data
    4:address:editor-data<span class="Special"> &lt;- </span>get 3:address:programming-environment-data/deref, recipes:offset
    5:number<span class="Special"> &lt;- </span>get 4:address:editor-data/deref, cursor-column:offset
    6:address:editor-data<span class="Special"> &lt;- </span>get 3:address:programming-environment-data/deref, current-sandbox:offset
    7:number<span class="Special"> &lt;- </span>get 6:address:editor-data/deref, cursor-column:offset
  ]
  memory-should-contain [
    5<span class="Special"> &lt;- </span>1
    7<span class="Special"> &lt;- </span>17
  ]
]

<span class="muScenario">scenario</span> edit-multiple-editors [
<span class="Constant">  $close-trace</span>
  assume-screen <span class="Constant">30:literal/width</span>, <span class="Constant">5:literal/height</span>
  <span class="Comment"># initialize both halves of screen</span>
  1:address:array:character<span class="Special"> &lt;- </span>new <span class="Constant">[abc]</span>
  2:address:array:character<span class="Special"> &lt;- </span>new <span class="Constant">[def]</span>
  3:address:programming-environment-data<span class="Special"> &lt;- </span>new-programming-environment screen:address, 1:address:array:character, 2:address:array:character
  <span class="Comment"># type one letter in each of them</span>
  assume-console [
    left-click 1, 1
    type <span class="Constant">[0]</span>
    left-click 1, 17
    type <span class="Constant">[1]</span>
  ]
  run [
    event-loop screen:address, console:address, 3:address:programming-environment-data
    4:address:editor-data<span class="Special"> &lt;- </span>get 3:address:programming-environment-data/deref, recipes:offset
    5:number<span class="Special"> &lt;- </span>get 4:address:editor-data/deref, cursor-column:offset
    6:address:editor-data<span class="Special"> &lt;- </span>get 3:address:programming-environment-data/deref, current-sandbox:offset
    7:number<span class="Special"> &lt;- </span>get 6:address:editor-data/deref, cursor-column:offset
  ]
  screen-should-contain [
   <span class="Constant"> .           run (F10)          .  # this line has a different background, but we don't test that yet</span>
   <span class="Constant"> .a0bc           ┊d1ef          .</span>
<span class="Constant">    .┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┊━━━━━━━━━━━━━━.</span>
   <span class="Constant"> .               ┊              .</span>
  ]
  memory-should-contain [
    5<span class="Special"> &lt;- </span>2  <span class="Comment"># cursor column of recipe editor</span>
    7<span class="Special"> &lt;- </span>18  <span class="Comment"># cursor column of sandbox editor</span>
  ]
  <span class="Comment"># show the cursor at the right window</span>
  run [
    screen:address<span class="Special"> &lt;- </span>print-character screen:address, <span class="Constant">9251:literal/␣</span>
  ]
  screen-should-contain [
   <span class="Constant"> .           run (F10)          .</span>
   <span class="Constant"> .a0bc           ┊d1␣f          .</span>
<span class="Constant">    .┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┊━━━━━━━━━━━━━━.</span>
   <span class="Constant"> .               ┊              .</span>
  ]
]

<span class="muScenario">scenario</span> multiple-editors-cover-only-their-own-areas [
<span class="Constant">  $close-trace</span>
  assume-screen <span class="Constant">60:literal/width</span>, <span class="Constant">10:literal/height</span>
  run [
    1:address:array:character<span class="Special"> &lt;- </span>new <span class="Constant">[abc]</span>
    2:address:array:character<span class="Special"> &lt;- </span>new <span class="Constant">[def]</span>
    3:address:programming-environment-data<span class="Special"> &lt;- </span>new-programming-environment screen:address, 1:address:array:character, 2:address:array:character
  ]
  <span class="Comment"># divider isn't messed up</span>
  screen-should-contain [
   <span class="Constant"> .                                         run (F10)          .</span>
   <span class="Constant"> .abc                           ┊def                          .</span>
<span class="Constant">    .┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┊━━━━━━━━━━━━━━━━━━━━━━━━━━━━━.</span>
   <span class="Constant"> .                              ┊                             .</span>
   <span class="Constant"> .                              ┊                             .</span>
  ]
]

<span class="muScenario">scenario</span> editor-in-focus-keeps-cursor [
<span class="Constant">  $close-trace</span>
  assume-screen <span class="Constant">30:literal/width</span>, <span class="Constant">5:literal/height</span>
  1:address:array:character<span class="Special"> &lt;- </span>new <span class="Constant">[abc]</span>
  2:address:array:character<span class="Special"> &lt;- </span>new <span class="Constant">[def]</span>
  <span class="Comment"># initialize programming environment and highlight cursor</span>
  assume-console <span class="Constant">[]</span>
  run [
    3:address:programming-environment-data<span class="Special"> &lt;- </span>new-programming-environment screen:address, 1:address:array:character, 2:address:array:character
    event-loop screen:address, console:address, 3:address:programming-environment-data
    screen:address<span class="Special"> &lt;- </span>print-character screen:address, <span class="Constant">9251:literal/␣</span>
  ]
  <span class="Comment"># is cursor at the right place?</span>
  screen-should-contain [
   <span class="Constant"> .           run (F10)          .</span>
   <span class="Constant"> .␣bc            ┊def           .</span>
<span class="Constant">    .┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┊━━━━━━━━━━━━━━.</span>
   <span class="Constant"> .               ┊              .</span>
  ]
  <span class="Comment"># now try typing a letter</span>
  assume-console [
    type <span class="Constant">[z]</span>
  ]
  run [
    3:address:programming-environment-data<span class="Special"> &lt;- </span>new-programming-environment screen:address, 1:address:array:character, 2:address:array:character
    event-loop screen:address, console:address, 3:address:programming-environment-data
    screen:address<span class="Special"> &lt;- </span>print-character screen:address, <span class="Constant">9251:literal/␣</span>
  ]
  <span class="Comment"># cursor should still be right</span>
  screen-should-contain [
   <span class="Constant"> .           run (F10)          .</span>
   <span class="Constant"> .z␣bc           ┊def           .</span>
<span class="Constant">    .┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┊━━━━━━━━━━━━━━.</span>
   <span class="Constant"> .               ┊              .</span>
  ]
]

<span class="SalientComment">## Running code from the editors</span>

container sandbox-data [
  data:address:array:character
  response:address:array:character
  warnings:address:array:character
  starting-row-on-screen:number  <span class="Comment"># to track clicks on delete</span>
  screen:address:screen  <span class="Comment"># prints in the sandbox go here</span>
  next-sandbox:address:sandbox-data
]

<span class="muScenario">scenario</span> run-and-show-results [
  $close-trace  <span class="Comment"># trace too long for github</span>
  assume-screen <span class="Constant">100:literal/width</span>, <span class="Constant">15:literal/height</span>
  <span class="Comment"># recipe editor is empty</span>
  1:address:array:character<span class="Special"> &lt;- </span>new <span class="Constant">[]</span>
  <span class="Comment"># sandbox editor contains an instruction without storing outputs</span>
  2:address:array:character<span class="Special"> &lt;- </span>new <span class="Constant">[divide-with-remainder 11:literal, 3:literal]</span>
  3:address:programming-environment-data<span class="Special"> &lt;- </span>new-programming-environment screen:address, 1:address:array:character, 2:address:array:character
  <span class="Comment"># run the code in the editors</span>
  assume-console [
    press 65526  <span class="Comment"># F10</span>
  ]
  run [
    event-loop screen:address, console:address, 3:address:programming-environment-data
  ]
  <span class="Comment"># check that screen prints the results</span>
  screen-should-contain [
   <span class="Constant"> .                                                                                 run (F10)          .</span>
   <span class="Constant"> .                                                  ┊                                                 .</span>
<span class="Constant">    .┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┊━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━.</span>
   <span class="Constant"> .                                                  ┊                                                x.</span>
   <span class="Constant"> .                                                  ┊divide-with-remainder 11:literal, 3:literal      .</span>
   <span class="Constant"> .                                                  ┊3                                                .</span>
   <span class="Constant"> .                                                  ┊2                                                .</span>
   <span class="Constant"> .                                                  ┊━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━.</span>
   <span class="Constant"> .                                                  ┊                                                 .</span>
  ]
  screen-should-contain-in-color <span class="Constant">7:literal/white</span>, [
   <span class="Constant"> .                                                                                                    .</span>
   <span class="Constant"> .                                                                                                    .</span>
   <span class="Constant"> .                                                                                                    .</span>
   <span class="Constant"> .                                                                                                    .</span>
   <span class="Constant"> .                                                   divide-with-remainder 11:literal, 3:literal      .</span>
   <span class="Constant"> .                                                                                                    .</span>
   <span class="Constant"> .                                                                                                    .</span>
   <span class="Constant"> .                                                                                                    .</span>
   <span class="Constant"> .                                                                                                    .</span>
  ]
  screen-should-contain-in-color <span class="Constant">245:literal/grey</span>, [
   <span class="Constant"> .                                                                                                    .</span>
   <span class="Constant"> .                                                  ┊                                                 .</span>
<span class="Constant">    .┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┊━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━.</span>
   <span class="Constant"> .                                                  ┊                                                x.</span>
   <span class="Constant"> .                                                  ┊                                                 .</span>
   <span class="Constant"> .                                                  ┊3                                                .</span>
   <span class="Constant"> .                                                  ┊2                                                .</span>
   <span class="Constant"> .                                                  ┊━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━.</span>
   <span class="Constant"> .                                                  ┊                                                 .</span>
  ]
  <span class="Comment"># run another command</span>
  assume-console [
    left-click 1, 80
    type <span class="Constant">[add 2:literal, 2:literal]</span>
    press 65526  <span class="Comment"># F10</span>
  ]
  run [
    event-loop screen:address, console:address, 3:address:programming-environment-data
  ]
  <span class="Comment"># check that screen prints the results</span>
  screen-should-contain [
   <span class="Constant"> .                                                                                 run (F10)          .</span>
   <span class="Constant"> .                                                  ┊                                                 .</span>
<span class="Constant">    .┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┊━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━.</span>
   <span class="Constant"> .                                                  ┊                                                x.</span>
   <span class="Constant"> .                                                  ┊add 2:literal, 2:literal                         .</span>
   <span class="Constant"> .                                                  ┊4                                                .</span>
   <span class="Constant"> .                                                  ┊━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━.</span>
   <span class="Constant"> .                                                  ┊                                                x.</span>
   <span class="Constant"> .                                                  ┊divide-with-remainder 11:literal, 3:literal      .</span>
   <span class="Constant"> .                                                  ┊3                                                .</span>
   <span class="Constant"> .                                                  ┊2                                                .</span>
   <span class="Constant"> .                                                  ┊━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━.</span>
   <span class="Constant"> .                                                  ┊                                                 .</span>
  ]
]

<span class="muRecipe">recipe</span> run-sandboxes [
  <span class="Constant">local-scope</span>
  env:address:programming-environment-data<span class="Special"> &lt;- </span><span class="Constant">next-ingredient</span>
  recipes:address:editor-data<span class="Special"> &lt;- </span>get env:address:programming-environment-data/deref, recipes:offset
  current-sandbox:address:editor-data<span class="Special"> &lt;- </span>get env:address:programming-environment-data/deref, current-sandbox:offset
  <span class="Comment"># copy code from recipe editor, persist, load into mu, save any warnings</span>
  in:address:array:character<span class="Special"> &lt;- </span>editor-contents recipes:address:editor-data
  save <span class="Constant">[recipes.mu]</span>, in:address:array:character
  recipe-warnings:address:address:array:character<span class="Special"> &lt;- </span>get-address env:address:programming-environment-data/deref, recipe-warnings:offset
  recipe-warnings:address:address:array:character/deref<span class="Special"> &lt;- </span>reload in:address:array:character
  <span class="Comment"># if recipe editor has errors, stop</span>
  <span class="muControl">reply-if</span> recipe-warnings:address:address:array:character/deref
  <span class="Comment"># check contents of right editor (sandbox)</span>
  <span class="Delimiter">{</span>
    sandbox-contents:address:array:character<span class="Special"> &lt;- </span>editor-contents current-sandbox:address:editor-data
    <span class="muControl">break-unless</span> sandbox-contents:address:array:character
    <span class="Comment"># if contents exist, first save them</span>
    <span class="Comment"># run them and turn them into a new sandbox-data</span>
    new-sandbox:address:sandbox-data<span class="Special"> &lt;- </span>new sandbox-data:type
    data:address:address:array:character<span class="Special"> &lt;- </span>get-address new-sandbox:address:sandbox-data/deref, data:offset
    data:address:address:array:character/deref<span class="Special"> &lt;- </span>copy sandbox-contents:address:array:character
    <span class="Comment"># push to head of sandbox list</span>
    dest:address:address:sandbox-data<span class="Special"> &lt;- </span>get-address env:address:programming-environment-data/deref, sandbox:offset
    next:address:address:sandbox-data<span class="Special"> &lt;- </span>get-address new-sandbox:address:sandbox-data/deref, next-sandbox:offset
    next:address:address:sandbox-data/deref<span class="Special"> &lt;- </span>copy dest:address:address:sandbox-data/deref
    dest:address:address:sandbox-data/deref<span class="Special"> &lt;- </span>copy new-sandbox:address:sandbox-data
    <span class="Comment"># clear sandbox editor</span>
    init:address:address:duplex-list<span class="Special"> &lt;- </span>get-address current-sandbox:address:editor-data/deref, data:offset
    init:address:address:duplex-list/deref<span class="Special"> &lt;- </span>push-duplex <span class="Constant">167:literal/§</span>, <span class="Constant">0:literal/tail</span>
  <span class="Delimiter">}</span>
  <span class="Comment"># save all sandboxes before running, just in case we die when running</span>
  curr:address:sandbox-data<span class="Special"> &lt;- </span>get env:address:programming-environment-data/deref, sandbox:offset
  filename:number<span class="Special"> &lt;- </span>copy <span class="Constant">0:literal</span>
  <span class="Delimiter">{</span>
    <span class="muControl">break-unless</span> curr:address:sandbox-data
    data:address:address:array:character<span class="Special"> &lt;- </span>get-address curr:address:sandbox-data/deref, data:offset
    save filename:number, data:address:address:array:character/deref
    filename:number<span class="Special"> &lt;- </span>add filename:number, <span class="Constant">1:literal</span>
    curr:address:sandbox-data<span class="Special"> &lt;- </span>get curr:address:sandbox-data/deref, next-sandbox:offset
    <span class="muControl">loop</span>
  <span class="Delimiter">}</span>
  <span class="Comment"># run all sandboxes</span>
  curr:address:sandbox-data<span class="Special"> &lt;- </span>get env:address:programming-environment-data/deref, sandbox:offset
  <span class="Delimiter">{</span>
    <span class="muControl">break-unless</span> curr:address:sandbox-data
    data:address:address:array:character<span class="Special"> &lt;- </span>get-address curr:address:sandbox-data/deref, data:offset
    response:address:address:array:character<span class="Special"> &lt;- </span>get-address curr:address:sandbox-data/deref, response:offset
    warnings:address:address:array:character<span class="Special"> &lt;- </span>get-address curr:address:sandbox-data/deref, warnings:offset
    fake-screen:address:address:screen<span class="Special"> &lt;- </span>get-address curr:address:sandbox-data/deref, screen:offset
    response:address:address:array:character/deref, warnings:address:address:array:character/deref, fake-screen:address:address:screen/deref<span class="Special"> &lt;- </span>run-interactive data:address:address:array:character/deref
<span class="CommentedCode">#?     $print warnings:address:address:array:character/deref, [ ], warnings:address:address:array:character/deref/deref, 10:literal/newline</span>
    curr:address:sandbox-data<span class="Special"> &lt;- </span>get curr:address:sandbox-data/deref, next-sandbox:offset
    <span class="muControl">loop</span>
  <span class="Delimiter">}</span>
]

<span class="muRecipe">recipe</span> render-sandbox-side [
  <span class="Constant">local-scope</span>
  screen:address<span class="Special"> &lt;- </span><span class="Constant">next-ingredient</span>
  env:address:programming-environment-data<span class="Special"> &lt;- </span><span class="Constant">next-ingredient</span>
  clear:boolean<span class="Special"> &lt;- </span><span class="Constant">next-ingredient</span>
  current-sandbox:address:editor-data<span class="Special"> &lt;- </span>get env:address:programming-environment-data/deref, current-sandbox:offset
  left:number<span class="Special"> &lt;- </span>get current-sandbox:address:editor-data/deref, left:offset
  right:number<span class="Special"> &lt;- </span>get current-sandbox:address:editor-data/deref, right:offset
  row:number, screen:address<span class="Special"> &lt;- </span>render screen:address, current-sandbox:address:editor-data
  row:number<span class="Special"> &lt;- </span>add row:number, <span class="Constant">1:literal</span>
  draw-horizontal screen:address, row:number, left:number, right:number, <span class="Constant">9473:literal/horizontal-double</span>
  sandbox:address:sandbox-data<span class="Special"> &lt;- </span>get env:address:programming-environment-data/deref, sandbox:offset
  row:number, screen:address<span class="Special"> &lt;- </span>render-sandboxes screen:address, sandbox:address:sandbox-data, left:number, right:number, row:number
  <span class="Comment"># clear next line, in case we just processed a backspace</span>
  row:number<span class="Special"> &lt;- </span>add row:number, <span class="Constant">1:literal</span>
  move-cursor screen:address, row:number, left:number
  clear-line-delimited screen:address, left:number, right:number
  <span class="muControl">reply-unless</span> clear:boolean, screen:address/same-as-ingredient:0
  screen-height:number<span class="Special"> &lt;- </span>screen-height screen:address
  <span class="Delimiter">{</span>
    at-bottom-of-screen?:boolean<span class="Special"> &lt;- </span>greater-or-equal row:number, screen-height:number
    <span class="muControl">break-if</span> at-bottom-of-screen?:boolean
    move-cursor screen:address, row:number, left:number
    clear-line-delimited screen:address, left:number, right:number
    row:number<span class="Special"> &lt;- </span>add row:number, <span class="Constant">1:literal</span>
    <span class="muControl">loop</span>
  <span class="Delimiter">}</span>
  <span class="muControl">reply</span> screen:address/same-as-ingredient:0
]

<span class="muRecipe">recipe</span> render-sandboxes [
  <span class="Constant">local-scope</span>
  screen:address<span class="Special"> &lt;- </span><span class="Constant">next-ingredient</span>
  sandbox:address:sandbox-data<span class="Special"> &lt;- </span><span class="Constant">next-ingredient</span>
  left:number<span class="Special"> &lt;- </span><span class="Constant">next-ingredient</span>
  right:number<span class="Special"> &lt;- </span><span class="Constant">next-ingredient</span>
  row:number<span class="Special"> &lt;- </span><span class="Constant">next-ingredient</span>
  <span class="muControl">reply-unless</span> sandbox:address:sandbox-data, row:number/same-as-ingredient:4, screen:address/same-as-ingredient:0
  screen-height:number<span class="Special"> &lt;- </span>screen-height screen:address
  at-bottom?:boolean<span class="Special"> &lt;- </span>greater-or-equal row:number screen-height:number
  <span class="muControl">reply-if</span> at-bottom?:boolean, row:number/same-as-ingredient:4, screen:address/same-as-ingredient:0
<span class="CommentedCode">#?   $print [rendering sandbox ], sandbox:address:sandbox-data, 10:literal/newline</span>
  <span class="Comment"># render sandbox menu</span>
  row:number<span class="Special"> &lt;- </span>add row:number, <span class="Constant">1:literal</span>
  move-cursor screen:address, row:number, left:number
  clear-line-delimited screen:address, left:number, right:number
  print-character screen:address, <span class="Constant">120:literal/x</span>, <span class="Constant">245:literal/grey</span>
  <span class="Comment"># save menu row so we can detect clicks to it later</span>
  starting-row:address:number<span class="Special"> &lt;- </span>get-address sandbox:address:sandbox-data/deref, starting-row-on-screen:offset
  starting-row:address:number/deref<span class="Special"> &lt;- </span>copy row:number
  <span class="Comment"># render sandbox contents</span>
  sandbox-data:address:array:character<span class="Special"> &lt;- </span>get sandbox:address:sandbox-data/deref, data:offset
  row:number, screen:address<span class="Special"> &lt;- </span>render-string screen:address, sandbox-data:address:array:character, left:number, right:number, <span class="Constant">7:literal/white</span>, row:number
  <span class="Comment"># render sandbox warnings, screen or response, in that order</span>
  sandbox-response:address:array:character<span class="Special"> &lt;- </span>get sandbox:address:sandbox-data/deref, response:offset
  sandbox-warnings:address:array:character<span class="Special"> &lt;- </span>get sandbox:address:sandbox-data/deref, warnings:offset
  sandbox-screen:address<span class="Special"> &lt;- </span>get sandbox:address:sandbox-data/deref, screen:offset
  <span class="Delimiter">{</span>
    <span class="muControl">break-unless</span> sandbox-warnings:address:array:character
    row:number, screen:address<span class="Special"> &lt;- </span>render-string screen:address, sandbox-warnings:address:array:character, left:number, right:number, <span class="Constant">1:literal/red</span>, row:number
  <span class="Delimiter">}</span>
  <span class="Delimiter">{</span>
    <span class="muControl">break-if</span> sandbox-warnings:address:array:character
    empty-screen?:boolean<span class="Special"> &lt;- </span>fake-screen-is-clear? sandbox-screen:address
    <span class="muControl">break-if</span> empty-screen?:boolean
    row:number, screen:address<span class="Special"> &lt;- </span>render-screen screen:address, sandbox-screen:address, left:number, right:number, row:number
  <span class="Delimiter">}</span>
  <span class="Delimiter">{</span>
    <span class="muControl">break-if</span> sandbox-warnings:address:array:character
    <span class="muControl">break-unless</span> empty-screen?:boolean
    row:number, screen:address<span class="Special"> &lt;- </span>render-string screen:address, sandbox-response:address:array:character, left:number, right:number, <span class="Constant">245:literal/grey</span>, row:number
  <span class="Delimiter">}</span>
  at-bottom?:boolean<span class="Special"> &lt;- </span>greater-or-equal row:number screen-height:number
  <span class="muControl">reply-if</span> at-bottom?:boolean, row:number/same-as-ingredient:4, screen:address/same-as-ingredient:0
  <span class="Comment"># draw solid line after sandbox</span>
  draw-horizontal screen:address, row:number, left:number, right:number, <span class="Constant">9473:literal/horizontal-double</span>
  <span class="Comment"># draw next sandbox</span>
  next-sandbox:address:sandbox-data<span class="Special"> &lt;- </span>get sandbox:address:sandbox-data/deref, next-sandbox:offset
  row:number, screen:address<span class="Special"> &lt;- </span>render-sandboxes screen:address, next-sandbox:address:sandbox-data, left:number, right:number, row:number
  <span class="muControl">reply</span> row:number/same-as-ingredient:4, screen:address/same-as-ingredient:0
]

<span class="Comment"># assumes programming environment has no sandboxes; restores them from previous session</span>
<span class="muRecipe">recipe</span> restore-sandboxes [
  <span class="Constant">local-scope</span>
  env:address:programming-environment-data<span class="Special"> &lt;- </span><span class="Constant">next-ingredient</span>
  <span class="Comment"># read all scenarios, pushing them to end of a list of scenarios</span>
  filename:number<span class="Special"> &lt;- </span>copy <span class="Constant">0:literal</span>
  curr:address:address:sandbox-data<span class="Special"> &lt;- </span>get-address env:address:programming-environment-data/deref, sandbox:offset
  <span class="Delimiter">{</span>
    contents:address:array:character<span class="Special"> &lt;- </span>restore filename:number
    <span class="muControl">break-unless</span> contents:address:array:character  <span class="Comment"># stop at first error; assuming file didn't exist</span>
<span class="CommentedCode">#?     $print contents:address:array:character, 10:literal/newline</span>
    <span class="Comment"># create new sandbox for file</span>
    curr:address:address:sandbox-data/deref<span class="Special"> &lt;- </span>new sandbox-data:type
    data:address:address:array:character<span class="Special"> &lt;- </span>get-address curr:address:address:sandbox-data/deref/deref, data:offset
    data:address:address:array:character/deref<span class="Special"> &lt;- </span>copy contents:address:array:character
    <span class="Comment"># increment loop variables</span>
    filename:number<span class="Special"> &lt;- </span>add filename:number, <span class="Constant">1:literal</span>
    curr:address:address:sandbox-data<span class="Special"> &lt;- </span>get-address curr:address:address:sandbox-data/deref/deref, next-sandbox:offset
    <span class="muControl">loop</span>
  <span class="Delimiter">}</span>
  <span class="muControl">reply</span> env:address:programming-environment-data/same-as-ingredient:0
]

<span class="Comment"># was-deleted?:boolean &lt;- delete-sandbox t:touch-event, env:address:programming-environment-data</span>
<span class="muRecipe">recipe</span> delete-sandbox [
  <span class="Constant">local-scope</span>
  t:touch-event<span class="Special"> &lt;- </span><span class="Constant">next-ingredient</span>
  env:address:programming-environment-data<span class="Special"> &lt;- </span><span class="Constant">next-ingredient</span>
  click-column:number<span class="Special"> &lt;- </span>get t:touch-event, column:offset
  current-sandbox:address:editor-data<span class="Special"> &lt;- </span>get env:address:programming-environment-data/deref, current-sandbox:offset
  right:number<span class="Special"> &lt;- </span>get current-sandbox:address:editor-data/deref, right:offset
<span class="CommentedCode">#?   $print [comparing column ], click-column:number, [ vs ], right:number, 10:literal/newline</span>
  at-right?:boolean<span class="Special"> &lt;- </span>equal click-column:number, right:number
  <span class="muControl">reply-unless</span> at-right?:boolean, <span class="Constant">0:literal/false</span>
<span class="CommentedCode">#?   $print [trying to delete</span>
<span class="CommentedCode">#? ] #? 1</span>
  click-row:number<span class="Special"> &lt;- </span>get t:touch-event, row:offset
  prev:address:address:sandbox-data<span class="Special"> &lt;- </span>get-address env:address:programming-environment-data/deref, sandbox:offset
<span class="CommentedCode">#?   $print [prev: ], prev:address:address:sandbox-data, [ -&gt; ], prev:address:address:sandbox-data/deref, 10:literal/newline</span>
  curr:address:sandbox-data<span class="Special"> &lt;- </span>get env:address:programming-environment-data/deref, sandbox:offset
  <span class="Delimiter">{</span>
<span class="CommentedCode">#?     $print [next sandbox</span>
<span class="CommentedCode">#? ] #? 1</span>
    <span class="muControl">break-unless</span> curr:address:sandbox-data
    <span class="Comment"># more sandboxes to check</span>
    <span class="Delimiter">{</span>
<span class="CommentedCode">#?       $print [checking</span>
<span class="CommentedCode">#? ] #? 1</span>
      target-row:number<span class="Special"> &lt;- </span>get curr:address:sandbox-data/deref, starting-row-on-screen:offset
<span class="CommentedCode">#?       $print [comparing row ], target-row:number, [ vs ], click-row:number, 10:literal/newline</span>
      delete-curr?:boolean<span class="Special"> &lt;- </span>equal target-row:number, click-row:number
      <span class="muControl">break-unless</span> delete-curr?:boolean
<span class="CommentedCode">#?       $print [found!</span>
<span class="CommentedCode">#? ] #? 1</span>
      <span class="Comment"># delete this sandbox, rerender and stop</span>
      prev:address:address:sandbox-data/deref<span class="Special"> &lt;- </span>get curr:address:sandbox-data/deref, next-sandbox:offset
<span class="CommentedCode">#?       $print [setting prev: ], prev:address:address:sandbox-data, [ -&gt; ], prev:address:address:sandbox-data/deref, 10:literal/newline</span>
      <span class="muControl">reply</span> <span class="Constant">1:literal/true</span>
    <span class="Delimiter">}</span>
    prev:address:address:sandbox-data<span class="Special"> &lt;- </span>get-address curr:address:sandbox-data/deref, next-sandbox:offset
<span class="CommentedCode">#?     $print [prev: ], prev:address:address:sandbox-data, [ -&gt; ], prev:address:address:sandbox-data/deref, 10:literal/newline</span>
    curr:address:sandbox-data<span class="Special"> &lt;- </span>get curr:address:sandbox-data/deref, next-sandbox:offset
    <span class="muControl">loop</span>
  <span class="Delimiter">}</span>
  <span class="muControl">reply</span> <span class="Constant">0:literal/false</span>
]

<span class="muScenario">scenario</span> run-updates-results [
  $close-trace  <span class="Comment"># trace too long for github</span>
  assume-screen <span class="Constant">100:literal/width</span>, <span class="Constant">12:literal/height</span>
  <span class="Comment"># define a recipe (no indent for the 'add' line below so column numbers are more obvious)</span>
  1:address:array:character<span class="Special"> &lt;- </span>new <span class="Constant">[ </span>
<span class="Constant">recipe foo [</span>
<span class="Constant">z:number &lt;- add 2:literal, 2:literal</span>
<span class="Constant">]</span>]
  <span class="Comment"># sandbox editor contains an instruction without storing outputs</span>
  2:address:array:character<span class="Special"> &lt;- </span>new <span class="Constant">[foo]</span>
  3:address:programming-environment-data<span class="Special"> &lt;- </span>new-programming-environment screen:address, 1:address:array:character, 2:address:array:character
  <span class="Comment"># run the code in the editors</span>
  assume-console [
    press 65526  <span class="Comment"># F10</span>
  ]
  run [
    event-loop screen:address, console:address, 3:address:programming-environment-data
  ]
  <span class="Comment"># check that screen prints the results</span>
  screen-should-contain [
   <span class="Constant"> .                                                                                 run (F10)          .</span>
   <span class="Constant"> .                                                  ┊                                                 .</span>
   <span class="Constant"> .recipe foo [                                      ┊━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━.</span>
   <span class="Constant"> .z:number &lt;- add 2:literal, 2:literal              ┊                                                x.</span>
   <span class="Constant"> .]                                                 ┊foo                                              .</span>
   <span class="Constant"> .┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┊4                                                .</span>
   <span class="Constant"> .                                                  ┊━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━.</span>
   <span class="Constant"> .                                                  ┊                                                 .</span>
  ]
  <span class="Comment"># make a change (incrementing one of the args to 'add'), then rerun</span>
  assume-console [
    left-click 3, 28  <span class="Comment"># one past the value of the second arg</span>
    type <span class="Constant">[«3]</span>  <span class="Comment"># replace</span>
    press 65526  <span class="Comment"># F10</span>
  ]
  4:event/backspace<span class="Special"> &lt;- </span>merge <span class="Constant">0:literal/text</span>, <span class="Constant">8:literal/backspace</span>, <span class="Constant">0:literal/dummy</span>, <span class="Constant">0:literal/dummy</span>
  replace-in-console <span class="Constant">171:literal/«</span>, 4:event/backspace
  run [
    event-loop screen:address, console:address, 3:address:programming-environment-data
  ]
  <span class="Comment"># check that screen updates the result on the right</span>
  screen-should-contain [
   <span class="Constant"> .                                                                                 run (F10)          .</span>
   <span class="Constant"> .                                                  ┊                                                 .</span>
   <span class="Constant"> .recipe foo [                                      ┊━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━.</span>
   <span class="Constant"> .z:number &lt;- add 2:literal, 3:literal              ┊                                                x.</span>
   <span class="Constant"> .]                                                 ┊foo                                              .</span>
   <span class="Constant"> .┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┊5                                                .</span>
   <span class="Constant"> .                                                  ┊━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━.</span>
   <span class="Constant"> .                                                  ┊                                                 .</span>
  ]
]

<span class="muScenario">scenario</span> run-instruction-and-print-warnings [
  $close-trace  <span class="Comment"># trace too long for github</span>
  assume-screen <span class="Constant">100:literal/width</span>, <span class="Constant">10:literal/height</span>
  <span class="Comment"># left editor is empty</span>
  1:address:array:character<span class="Special"> &lt;- </span>new <span class="Constant">[]</span>
  <span class="Comment"># right editor contains an illegal instruction</span>
  2:address:array:character<span class="Special"> &lt;- </span>new <span class="Constant">[get 1234:number, foo:offset]</span>
  3:address:programming-environment-data<span class="Special"> &lt;- </span>new-programming-environment screen:address, 1:address:array:character, 2:address:array:character
  <span class="Comment"># run the code in the editors</span>
  assume-console [
    press 65526  <span class="Comment"># F10</span>
  ]
  run [
    event-loop screen:address, console:address, 3:address:programming-environment-data
  ]
  <span class="Comment"># check that screen prints error message in red</span>
  screen-should-contain [
   <span class="Constant"> .                                                                                 run (F10)          .</span>
   <span class="Constant"> .                                                  ┊                                                 .</span>
<span class="Constant">    .┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┊━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━.</span>
   <span class="Constant"> .                                                  ┊                                                x.</span>
   <span class="Constant"> .                                                  ┊get 1234:number, foo:offset                      .</span>
   <span class="Constant"> .                                                  ┊unknown element foo in container number          .</span>
   <span class="Constant"> .                                                  ┊━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━.</span>
   <span class="Constant"> .                                                  ┊                                                 .</span>
  ]
  screen-should-contain-in-color <span class="Constant">7:literal/white</span>, [
   <span class="Constant"> .                                                                                                    .</span>
   <span class="Constant"> .                                                                                                    .</span>
   <span class="Constant"> .                                                                                                    .</span>
   <span class="Constant"> .                                                                                                    .</span>
   <span class="Constant"> .                                                   get 1234:number, foo:offset                      .</span>
   <span class="Constant"> .                                                                                                    .</span>
   <span class="Constant"> .                                                                                                    .</span>
   <span class="Constant"> .                                                                                                    .</span>
  ]
  screen-should-contain-in-color <span class="Constant">1:literal/red</span>, [
   <span class="Constant"> .                                                                                                    .</span>
   <span class="Constant"> .                                                                                                    .</span>
   <span class="Constant"> .                                                                                                    .</span>
   <span class="Constant"> .                                                                                                    .</span>
   <span class="Constant"> .                                                                                                    .</span>
   <span class="Constant"> .                                                   unknown element foo in container number          .</span>
   <span class="Constant"> .                                                                                                    .</span>
  ]
  screen-should-contain-in-color <span class="Constant">245:literal/grey</span>, [
   <span class="Constant"> .                                                                                                    .</span>
   <span class="Constant"> .                                                  ┊                                                 .</span>
<span class="Constant">    .┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┊━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━.</span>
   <span class="Constant"> .                                                  ┊                                                x.</span>
   <span class="Constant"> .                                                  ┊                                                 .</span>
   <span class="Constant"> .                                                  ┊                                                 .</span>
   <span class="Constant"> .                                                  ┊━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━.</span>
   <span class="Constant"> .                                                  ┊                                                 .</span>
  ]
]

<span class="muScenario">scenario</span> run-instruction-and-print-warnings-only-once [
  $close-trace  <span class="Comment"># trace too long for github</span>
  assume-screen <span class="Constant">100:literal/width</span>, <span class="Constant">10:literal/height</span>
  <span class="Comment"># left editor is empty</span>
  1:address:array:character<span class="Special"> &lt;- </span>new <span class="Constant">[]</span>
  <span class="Comment"># right editor contains an illegal instruction</span>
  2:address:array:character<span class="Special"> &lt;- </span>new <span class="Constant">[get 1234:number, foo:offset]</span>
  3:address:programming-environment-data<span class="Special"> &lt;- </span>new-programming-environment screen:address, 1:address:array:character, 2:address:array:character
  <span class="Comment"># run the code in the editors multiple times</span>
  assume-console [
    press 65526  <span class="Comment"># F10</span>
    press 65526  <span class="Comment"># F10</span>
  ]
  run [
    event-loop screen:address, console:address, 3:address:programming-environment-data
  ]
  <span class="Comment"># check that screen prints error message just once</span>
  screen-should-contain [
   <span class="Constant"> .                                                                                 run (F10)          .</span>
   <span class="Constant"> .                                                  ┊                                                 .</span>
<span class="Constant">    .┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┊━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━.</span>
   <span class="Constant"> .                                                  ┊                                                x.</span>
   <span class="Constant"> .                                                  ┊get 1234:number, foo:offset                      .</span>
   <span class="Constant"> .                                                  ┊unknown element foo in container number          .</span>
   <span class="Constant"> .                                                  ┊━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━.</span>
   <span class="Constant"> .                                                  ┊                                                 .</span>
  ]
]

<span class="muScenario">scenario</span> deleting-sandboxes [
  $close-trace  <span class="Comment"># trace too long for github</span>
  assume-screen <span class="Constant">100:literal/width</span>, <span class="Constant">15:literal/height</span>
  1:address:array:character<span class="Special"> &lt;- </span>new <span class="Constant">[]</span>
  2:address:array:character<span class="Special"> &lt;- </span>new <span class="Constant">[]</span>
  3:address:programming-environment-data<span class="Special"> &lt;- </span>new-programming-environment screen:address, 1:address:array:character, 2:address:array:character
  <span class="Comment"># run a few commands</span>
  assume-console [
    left-click 1, 80
    type <span class="Constant">[divide-with-remainder 11:literal, 3:literal]</span>
    press 65526  <span class="Comment"># F10</span>
    type <span class="Constant">[add 2:literal, 2:literal]</span>
    press 65526  <span class="Comment"># F10</span>
  ]
  run [
    event-loop screen:address, console:address, 3:address:programming-environment-data
  ]
  screen-should-contain [
   <span class="Constant"> .                                                                                 run (F10)          .</span>
   <span class="Constant"> .                                                  ┊                                                 .</span>
<span class="Constant">    .┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┊━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━.</span>
   <span class="Constant"> .                                                  ┊                                                x.</span>
   <span class="Constant"> .                                                  ┊add 2:literal, 2:literal                         .</span>
   <span class="Constant"> .                                                  ┊4                                                .</span>
   <span class="Constant"> .                                                  ┊━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━.</span>
   <span class="Constant"> .                                                  ┊                                                x.</span>
   <span class="Constant"> .                                                  ┊divide-with-remainder 11:literal, 3:literal      .</span>
   <span class="Constant"> .                                                  ┊3                                                .</span>
   <span class="Constant"> .                                                  ┊2                                                .</span>
   <span class="Constant"> .                                                  ┊━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━.</span>
   <span class="Constant"> .                                                  ┊                                                 .</span>
  ]
  <span class="Comment"># delete second sandbox</span>
  assume-console [
    left-click 7, 99
  ]
  run [
    event-loop screen:address, console:address, 3:address:programming-environment-data
  ]
  screen-should-contain [
   <span class="Constant"> .                                                                                 run (F10)          .</span>
   <span class="Constant"> .                                                  ┊                                                 .</span>
<span class="Constant">    .┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┊━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━.</span>
   <span class="Constant"> .                                                  ┊                                                x.</span>
   <span class="Constant"> .                                                  ┊add 2:literal, 2:literal                         .</span>
   <span class="Constant"> .                                                  ┊4                                                .</span>
   <span class="Constant"> .                                                  ┊━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━.</span>
   <span class="Constant"> .                                                  ┊                                                 .</span>
   <span class="Constant"> .                                                  ┊                                                 .</span>
  ]
  <span class="Comment"># delete first sandbox</span>
  assume-console [
    left-click 3, 99
  ]
  run [
    event-loop screen:address, console:address, 3:address:programming-environment-data
  ]
  screen-should-contain [
   <span class="Constant"> .                                                                                 run (F10)          .</span>
   <span class="Constant"> .                                                  ┊                                                 .</span>
<span class="Constant">    .┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┊━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━.</span>
   <span class="Constant"> .                                                  ┊                                                 .</span>
   <span class="Constant"> .                                                  ┊                                                 .</span>
  ]
]

<span class="muScenario">scenario</span> run-instruction-manages-screen-per-sandbox [
  $close-trace  <span class="Comment"># trace too long for github #? 1</span>
  assume-screen <span class="Constant">100:literal/width</span>, <span class="Constant">20:literal/height</span>
  <span class="Comment"># left editor is empty</span>
  1:address:array:character<span class="Special"> &lt;- </span>new <span class="Constant">[]</span>
  <span class="Comment"># right editor contains an illegal instruction</span>
  2:address:array:character<span class="Special"> &lt;- </span>new <span class="Constant">[print-integer screen:address, 4]</span>
  3:address:programming-environment-data<span class="Special"> &lt;- </span>new-programming-environment screen:address, 1:address:array:character, 2:address:array:character
  <span class="Comment"># run the code in the editor</span>
  assume-console [
    press 65526  <span class="Comment"># F10</span>
  ]
  run [
    event-loop screen:address, console:address, 3:address:programming-environment-data
  ]
  <span class="Comment"># check that it prints a little 5x5 toy screen</span>
  <span class="Comment"># hack: screen address is brittle</span>
  screen-should-contain [
   <span class="Constant"> .                                                                                 run (F10)          .</span>
   <span class="Constant"> .                                                  ┊                                                 .</span>
<span class="Constant">    .┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┊━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━.</span>
   <span class="Constant"> .                                                  ┊                                                x.</span>
   <span class="Constant"> .                                                  ┊print-integer screen:address, 4                  .</span>
   <span class="Constant"> .                                                  ┊screen:                                          .</span>
   <span class="Constant"> .                                                  ┊  .4    .                                        .</span>
   <span class="Constant"> .                                                  ┊  .     .                                        .</span>
   <span class="Constant"> .                                                  ┊  .     .                                        .</span>
   <span class="Constant"> .                                                  ┊  .     .                                        .</span>
   <span class="Constant"> .                                                  ┊  .     .                                        .</span>
   <span class="Constant"> .                                                  ┊━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━.</span>
   <span class="Constant"> .                                                  ┊                                                 .</span>
  ]
]

<span class="muRecipe">recipe</span> editor-contents [
  <span class="Constant">local-scope</span>
  editor:address:editor-data<span class="Special"> &lt;- </span><span class="Constant">next-ingredient</span>
  buf:address:buffer<span class="Special"> &lt;- </span>new-buffer <span class="Constant">80:literal</span>
  curr:address:duplex-list<span class="Special"> &lt;- </span>get editor:address:editor-data/deref, data:offset
  <span class="Comment"># skip § sentinel</span>
  assert curr:address:duplex-list, <span class="Constant">[editor without data is illegal; must have at least a sentinel]</span>
  curr:address:duplex-list<span class="Special"> &lt;- </span>next-duplex curr:address:duplex-list
  <span class="muControl">reply-unless</span> curr:address:duplex-list, <span class="Constant">0:literal</span>
  <span class="Delimiter">{</span>
    <span class="muControl">break-unless</span> curr:address:duplex-list
    c:character<span class="Special"> &lt;- </span>get curr:address:duplex-list/deref, value:offset
    buffer-append buf:address:buffer, c:character
    curr:address:duplex-list<span class="Special"> &lt;- </span>next-duplex curr:address:duplex-list
    <span class="muControl">loop</span>
  <span class="Delimiter">}</span>
  result:address:array:character<span class="Special"> &lt;- </span>buffer-to-array buf:address:buffer
  <span class="muControl">reply</span> result:address:array:character
]

<span class="muScenario">scenario</span> editor-provides-edited-contents [
  assume-screen <span class="Constant">10:literal/width</span>, <span class="Constant">5:literal/height</span>
  1:address:array:character<span class="Special"> &lt;- </span>new <span class="Constant">[abc]</span>
  2:address:editor-data<span class="Special"> &lt;- </span>new-editor 1:address:array:character, screen:address, <span class="Constant">0:literal/left</span>, <span class="Constant">10:literal/right</span>
  assume-console [
    left-click 1, 2
    type <span class="Constant">[def]</span>
  ]
  run [
    editor-event-loop screen:address, console:address, 2:address:editor-data
    3:address:array:character<span class="Special"> &lt;- </span>editor-contents 2:address:editor-data
    4:array:character<span class="Special"> &lt;- </span>copy 3:address:array:character/deref
  ]
  memory-should-contain [
    4:string<span class="Special"> &lt;- </span><span class="Constant">[abdefc]</span>
  ]
]

<span class="SalientComment">## handling malformed programs</span>

<span class="muScenario">scenario</span> run-shows-warnings-in-get [
<span class="Constant">  $close-trace</span>
  assume-screen <span class="Constant">100:literal/width</span>, <span class="Constant">15:literal/height</span>
  assume-console [
    press 65526  <span class="Comment"># F10</span>
  ]
  run [
    x:address:array:character<span class="Special"> &lt;- </span>new <span class="Constant">[ </span>
<span class="Constant">recipe foo [</span>
<span class="Constant">  get 123:number, foo:offset</span>
<span class="Constant">]</span>]
    y:address:array:character<span class="Special"> &lt;- </span>new <span class="Constant">[foo]</span>
    env:address:programming-environment-data<span class="Special"> &lt;- </span>new-programming-environment screen:address, x:address:array:character, y:address:array:character
    event-loop screen:address, console:address, env:address:programming-environment-data
  ]
  screen-should-contain [
   <span class="Constant"> .                                                                                 run (F10)          .</span>
   <span class="Constant"> .                                                  ┊foo                                              .</span>
   <span class="Constant"> .recipe foo [                                      ┊━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━.</span>
   <span class="Constant"> .  get 123:number, foo:offset                      ┊                                                 .</span>
   <span class="Constant"> .]                                                 ┊                                                 .</span>
   <span class="Constant"> .unknown element foo in container number           ┊                                                 .</span>
   <span class="Constant"> .┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┊                                                 .</span>
   <span class="Constant"> .                                                  ┊                                                 .</span>
  ]
  screen-should-contain-in-color <span class="Constant">1:literal/red</span>, [
   <span class="Constant"> .                                                                                                    .</span>
   <span class="Constant"> .                                                                                                    .</span>
   <span class="Constant"> .                                                                                                    .</span>
   <span class="Constant"> .                                                                                                    .</span>
   <span class="Constant"> .                                                                                                    .</span>
   <span class="Constant"> .unknown element foo in container number                                                             .</span>
   <span class="Constant"> .                                                                                                    .</span>
  ]
]

<span class="muScenario">scenario</span> run-shows-missing-type-warnings [
<span class="Constant">  $close-trace</span>
  assume-screen <span class="Constant">100:literal/width</span>, <span class="Constant">15:literal/height</span>
  assume-console [
    press 65526  <span class="Comment"># F10</span>
  ]
  run [
    x:address:array:character<span class="Special"> &lt;- </span>new <span class="Constant">[ </span>
<span class="Constant">recipe foo [</span>
<span class="Constant">  x:number &lt;- copy 0</span>
<span class="Constant">  copy x</span>
<span class="Constant">]</span>]
    y:address:array:character<span class="Special"> &lt;- </span>new <span class="Constant">[foo]</span>
    env:address:programming-environment-data<span class="Special"> &lt;- </span>new-programming-environment screen:address, x:address:array:character, y:address:array:character
    event-loop screen:address, console:address, env:address:programming-environment-data
  ]
  screen-should-contain [
   <span class="Constant"> .                                                                                 run (F10)          .</span>
   <span class="Constant"> .                                                  ┊foo                                              .</span>
   <span class="Constant"> .recipe foo [                                      ┊━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━.</span>
   <span class="Constant"> .  x:number &lt;- copy 0                              ┊                                                 .</span>
   <span class="Constant"> .  copy x                                          ┊                                                 .</span>
   <span class="Constant"> .]                                                 ┊                                                 .</span>
   <span class="Constant"> .missing type in 'copy x'                          ┊                                                 .</span>
   <span class="Constant"> .┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┊                                                 .</span>
   <span class="Constant"> .                                                  ┊                                                 .</span>
  ]
]

<span class="muScenario">scenario</span> run-shows-get-on-non-container-warnings [
<span class="Constant">  $close-trace</span>
  assume-screen <span class="Constant">100:literal/width</span>, <span class="Constant">15:literal/height</span>
  assume-console [
    press 65526  <span class="Comment"># F10</span>
  ]
  run [
    x:address:array:character<span class="Special"> &lt;- </span>new <span class="Constant">[ </span>
<span class="Constant">recipe foo [</span>
<span class="Constant">  x:address:point &lt;- new point:type</span>
<span class="Constant">  get x:address:point, 1:offset</span>
<span class="Constant">]</span>]
    y:address:array:character<span class="Special"> &lt;- </span>new <span class="Constant">[foo]</span>
    env:address:programming-environment-data<span class="Special"> &lt;- </span>new-programming-environment screen:address, x:address:array:character, y:address:array:character
    event-loop screen:address, console:address, env:address:programming-environment-data
  ]
  screen-should-contain [
   <span class="Constant"> .                                                                                 run (F10)          .</span>
   <span class="Constant"> .                                                  ┊                                                 .</span>
   <span class="Constant"> .recipe foo [                                      ┊━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━.</span>
   <span class="Constant"> .  x:address:point &lt;- new point:type               ┊                                                x.</span>
   <span class="Constant"> .  get x:address:point, 1:offset                   ┊foo                                              .</span>
   <span class="Constant"> .]                                                 ┊foo: 'get' on a non-container x:address:point    .</span>
<span class="Constant">    .┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┊━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━.</span>
   <span class="Constant"> .                                                  ┊                                                 .</span>
  ]
]

<span class="muScenario">scenario</span> run-shows-non-literal-get-argument-warnings [
<span class="Constant">  $close-trace</span>
  assume-screen <span class="Constant">100:literal/width</span>, <span class="Constant">15:literal/height</span>
  assume-console [
    press 65526  <span class="Comment"># F10</span>
  ]
  run [
    x:address:array:character<span class="Special"> &lt;- </span>new <span class="Constant">[ </span>
<span class="Constant">recipe foo [</span>
<span class="Constant">  x:number &lt;- copy 0</span>
<span class="Constant">  y:address:point &lt;- new point:type</span>
<span class="Constant">  get y:address:point/deref, x:number</span>
<span class="Constant">]</span>]
    y:address:array:character<span class="Special"> &lt;- </span>new <span class="Constant">[foo]</span>
    env:address:programming-environment-data<span class="Special"> &lt;- </span>new-programming-environment screen:address, x:address:array:character, y:address:array:character
    event-loop screen:address, console:address, env:address:programming-environment-data
  ]
  screen-should-contain [
   <span class="Constant"> .                                                                                 run (F10)          .</span>
   <span class="Constant"> .                                                  ┊foo                                              .</span>
   <span class="Constant"> .recipe foo [                                      ┊━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━.</span>
   <span class="Constant"> .  x:number &lt;- copy 0                              ┊                                                 .</span>
   <span class="Constant"> .  y:address:point &lt;- new point:type               ┊                                                 .</span>
   <span class="Constant"> .  get y:address:point/deref, x:number             ┊                                                 .</span>
   <span class="Constant"> .]                                                 ┊                                                 .</span>
   <span class="Constant"> .foo: expected ingredient 1 of 'get' to have type ↩┊                                                 .</span>
   <span class="Constant"> .'offset'; got x:number                            ┊                                                 .</span>
   <span class="Constant"> .┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┊                                                 .</span>
   <span class="Constant"> .                                                  ┊                                                 .</span>
  ]
]

<span class="SalientComment">## helpers for drawing editor borders</span>

<span class="muRecipe">recipe</span> draw-box [
  <span class="Constant">local-scope</span>
  screen:address<span class="Special"> &lt;- </span><span class="Constant">next-ingredient</span>
  top:number<span class="Special"> &lt;- </span><span class="Constant">next-ingredient</span>
  left:number<span class="Special"> &lt;- </span><span class="Constant">next-ingredient</span>
  bottom:number<span class="Special"> &lt;- </span><span class="Constant">next-ingredient</span>
  right:number<span class="Special"> &lt;- </span><span class="Constant">next-ingredient</span>
  color:number, color-found?:boolean<span class="Special"> &lt;- </span><span class="Constant">next-ingredient</span>
  <span class="Delimiter">{</span>
    <span class="Comment"># default color to white</span>
    <span class="muControl">break-if</span> color-found?:boolean
    color:number<span class="Special"> &lt;- </span>copy <span class="Constant">245:literal/grey</span>
  <span class="Delimiter">}</span>
  <span class="Comment"># top border</span>
  draw-horizontal screen:address, top:number, left:number, right:number, color:number
  draw-horizontal screen:address, bottom:number, left:number, right:number, color:number
  draw-vertical screen:address, left:number, top:number, bottom:number, color:number
  draw-vertical screen:address, right:number, top:number, bottom:number, color:number
  draw-top-left screen:address, top:number, left:number, color:number
  draw-top-right screen:address, top:number, right:number, color:number
  draw-bottom-left screen:address, bottom:number, left:number, color:number
  draw-bottom-right screen:address, bottom:number, right:number, color:number
  <span class="Comment"># position cursor inside box</span>
  move-cursor screen:address, top:number, left:number
  cursor-down screen:address
  cursor-right screen:address
]

<span class="muRecipe">recipe</span> draw-horizontal [
  <span class="Constant">local-scope</span>
  screen:address<span class="Special"> &lt;- </span><span class="Constant">next-ingredient</span>
  row:number<span class="Special"> &lt;- </span><span class="Constant">next-ingredient</span>
  x:number<span class="Special"> &lt;- </span><span class="Constant">next-ingredient</span>
  right:number<span class="Special"> &lt;- </span><span class="Constant">next-ingredient</span>
  style:character, style-found?:boolean<span class="Special"> &lt;- </span><span class="Constant">next-ingredient</span>
  <span class="Delimiter">{</span>
    <span class="muControl">break-if</span> style-found?:boolean
    style:character<span class="Special"> &lt;- </span>copy <span class="Constant">9472:literal/horizontal</span>
  <span class="Delimiter">}</span>
  color:number, color-found?:boolean<span class="Special"> &lt;- </span><span class="Constant">next-ingredient</span>
  <span class="Delimiter">{</span>
    <span class="Comment"># default color to white</span>
    <span class="muControl">break-if</span> color-found?:boolean
    color:number<span class="Special"> &lt;- </span>copy <span class="Constant">245:literal/grey</span>
  <span class="Delimiter">}</span>
  bg-color:number, bg-color-found?:boolean<span class="Special"> &lt;- </span><span class="Constant">next-ingredient</span>
  <span class="Delimiter">{</span>
    <span class="muControl">break-if</span> bg-color-found?:boolean
    bg-color:number<span class="Special"> &lt;- </span>copy <span class="Constant">0:literal/black</span>
  <span class="Delimiter">}</span>
  move-cursor screen:address, row:number, x:number
  <span class="Delimiter">{</span>
    continue?:boolean<span class="Special"> &lt;- </span>lesser-or-equal x:number, right:number  <span class="Comment"># right is inclusive, to match editor-data semantics</span>
    <span class="muControl">break-unless</span> continue?:boolean
    print-character screen:address, style:character, color:number, bg-color:number
    x:number<span class="Special"> &lt;- </span>add x:number, <span class="Constant">1:literal</span>
    <span class="muControl">loop</span>
  <span class="Delimiter">}</span>
]

<span class="muRecipe">recipe</span> draw-vertical [
  <span class="Constant">local-scope</span>
  screen:address<span class="Special"> &lt;- </span><span class="Constant">next-ingredient</span>
  col:number<span class="Special"> &lt;- </span><span class="Constant">next-ingredient</span>
  x:number<span class="Special"> &lt;- </span><span class="Constant">next-ingredient</span>
  bottom:number<span class="Special"> &lt;- </span><span class="Constant">next-ingredient</span>
  style:character, style-found?:boolean<span class="Special"> &lt;- </span><span class="Constant">next-ingredient</span>
  <span class="Delimiter">{</span>
    <span class="muControl">break-if</span> style-found?:boolean
    style:character<span class="Special"> &lt;- </span>copy <span class="Constant">9474:literal/vertical</span>
  <span class="Delimiter">}</span>
  color:number, color-found?:boolean<span class="Special"> &lt;- </span><span class="Constant">next-ingredient</span>
  <span class="Delimiter">{</span>
    <span class="Comment"># default color to white</span>
    <span class="muControl">break-if</span> color-found?:boolean
    color:number<span class="Special"> &lt;- </span>copy <span class="Constant">245:literal/grey</span>
  <span class="Delimiter">}</span>
  <span class="Delimiter">{</span>
    continue?:boolean<span class="Special"> &lt;- </span>lesser-than x:number, bottom:number
    <span class="muControl">break-unless</span> continue?:boolean
    move-cursor screen:address, x:number, col:number
    print-character screen:address, style:character, color:number
    x:number<span class="Special"> &lt;- </span>add x:number, <span class="Constant">1:literal</span>
    <span class="muControl">loop</span>
  <span class="Delimiter">}</span>
]

<span class="muRecipe">recipe</span> draw-top-left [
  <span class="Constant">local-scope</span>
  screen:address<span class="Special"> &lt;- </span><span class="Constant">next-ingredient</span>
  top:number<span class="Special"> &lt;- </span><span class="Constant">next-ingredient</span>
  left:number<span class="Special"> &lt;- </span><span class="Constant">next-ingredient</span>
  color:number, color-found?:boolean<span class="Special"> &lt;- </span><span class="Constant">next-ingredient</span>
  <span class="Delimiter">{</span>
    <span class="Comment"># default color to white</span>
    <span class="muControl">break-if</span> color-found?:boolean
    color:number<span class="Special"> &lt;- </span>copy <span class="Constant">245:literal/grey</span>
  <span class="Delimiter">}</span>
  move-cursor screen:address, top:number, left:number
  print-character screen:address, <span class="Constant">9484:literal/down-right</span>, color:number
]

<span class="muRecipe">recipe</span> draw-top-right [
  <span class="Constant">local-scope</span>
  screen:address<span class="Special"> &lt;- </span><span class="Constant">next-ingredient</span>
  top:number<span class="Special"> &lt;- </span><span class="Constant">next-ingredient</span>
  right:number<span class="Special"> &lt;- </span><span class="Constant">next-ingredient</span>
  color:number, color-found?:boolean<span class="Special"> &lt;- </span><span class="Constant">next-ingredient</span>
  <span class="Delimiter">{</span>
    <span class="Comment"># default color to white</span>
    <span class="muControl">break-if</span> color-found?:boolean
    color:number<span class="Special"> &lt;- </span>copy <span class="Constant">245:literal/grey</span>
  <span class="Delimiter">}</span>
  move-cursor screen:address, top:number, right:number
  print-character screen:address, <span class="Constant">9488:literal/down-left</span>, color:number
]

<span class="muRecipe">recipe</span> draw-bottom-left [
  <span class="Constant">local-scope</span>
  screen:address<span class="Special"> &lt;- </span><span class="Constant">next-ingredient</span>
  bottom:number<span class="Special"> &lt;- </span><span class="Constant">next-ingredient</span>
  left:number<span class="Special"> &lt;- </span><span class="Constant">next-ingredient</span>
  color:number, color-found?:boolean<span class="Special"> &lt;- </span><span class="Constant">next-ingredient</span>
  <span class="Delimiter">{</span>
    <span class="Comment"># default color to white</span>
    <span class="muControl">break-if</span> color-found?:boolean
    color:number<span class="Special"> &lt;- </span>copy <span class="Constant">245:literal/grey</span>
  <span class="Delimiter">}</span>
  move-cursor screen:address, bottom:number, left:number
  print-character screen:address, <span class="Constant">9492:literal/up-right</span>, color:number
]

<span class="muRecipe">recipe</span> draw-bottom-right [
  <span class="Constant">local-scope</span>
  screen:address<span class="Special"> &lt;- </span><span class="Constant">next-ingredient</span>
  bottom:number<span class="Special"> &lt;- </span><span class="Constant">next-ingredient</span>
  right:number<span class="Special"> &lt;- </span><span class="Constant">next-ingredient</span>
  color:number, color-found?:boolean<span class="Special"> &lt;- </span><span class="Constant">next-ingredient</span>
  <span class="Delimiter">{</span>
    <span class="Comment"># default color to white</span>
    <span class="muControl">break-if</span> color-found?:boolean
    color:number<span class="Special"> &lt;- </span>copy <span class="Constant">245:literal/grey</span>
  <span class="Delimiter">}</span>
  move-cursor screen:address, bottom:number, right:number
  print-character screen:address, <span class="Constant">9496:literal/up-left</span>, color:number
]

<span class="muRecipe">recipe</span> print-string-with-gradient-background [
  <span class="Constant">local-scope</span>
  x:address:screen<span class="Special"> &lt;- </span><span class="Constant">next-ingredient</span>
  s:address:array:character<span class="Special"> &lt;- </span><span class="Constant">next-ingredient</span>
  color:number<span class="Special"> &lt;- </span><span class="Constant">next-ingredient</span>
  bg-color1:number<span class="Special"> &lt;- </span><span class="Constant">next-ingredient</span>
  bg-color2:number<span class="Special"> &lt;- </span><span class="Constant">next-ingredient</span>
  len:number<span class="Special"> &lt;- </span>length s:address:array:character/deref
  color-range:number<span class="Special"> &lt;- </span>subtract bg-color2:number, bg-color1:number
  color-quantum:number<span class="Special"> &lt;- </span>divide color-range:number, len:number
<span class="CommentedCode">#?   close-console #? 2</span>
<span class="CommentedCode">#?   $print len:number, [, ], color-range:number, [, ], color-quantum:number, 10:literal/newline</span>
<span class="CommentedCode">#? #?   $exit #? 3</span>
  bg-color:number<span class="Special"> &lt;- </span>copy bg-color1:number
  i:number<span class="Special"> &lt;- </span>copy <span class="Constant">0:literal</span>
  <span class="Delimiter">{</span>
    done?:boolean<span class="Special"> &lt;- </span>greater-or-equal i:number, len:number
    <span class="muControl">break-if</span> done?:boolean
    c:character<span class="Special"> &lt;- </span>index s:address:array:character/deref, i:number
    print-character x:address:screen, c:character, color:number, bg-color:number
    i:number<span class="Special"> &lt;- </span>add i:number, <span class="Constant">1:literal</span>
    bg-color:number<span class="Special"> &lt;- </span>add bg-color:number, color-quantum:number
<span class="CommentedCode">#?     $print [=&gt; ], bg-color:number, 10:literal/newline</span>
    <span class="muControl">loop</span>
  <span class="Delimiter">}</span>
<span class="CommentedCode">#?   $exit #? 1</span>
  <span class="muControl">reply</span> x:address:screen/same-as-ingredient:0
]
</pre>
</body>
</html>
<!-- vim: set foldmethod=manual : -->