about summary refs log blame commit diff stats
path: root/html/edit.mu.html
blob: 98deff235ed1f61cf4765ec44a196a194f4ff08f (plain) (tree)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
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
2529
2530
2531
2532
2533
2534
2535
2536
2537
2538
2539
2540
2541
2542
2543
2544
2545
2546
2547
2548
2549
2550
2551
2552
2553
2554
2555
2556
2557
2558
2559
2560
2561
2562
2563
2564
2565
2566
2567
2568
2569
2570
2571
2572
2573
2574
2575
2576
2577
2578
2579
2580
2581
2582
2583
2584
2585
2586
2587
2588
2589
2590
2591
2592
2593
2594
2595
2596
2597
2598
2599
2600
2601
2602
2603
2604
2605
2606
2607
2608
2609
2610
2611
2612
2613
2614
2615
2616
2617
2618
2619
2620
2621
2622
2623
2624
2625
2626
2627
2628
2629
2630
2631
2632
2633
2634
2635
2636
2637
2638
2639
2640
2641
2642
2643
2644
2645
2646
2647
2648
2649
2650
2651
2652
2653
2654
2655
2656
2657
2658
2659
2660
2661
2662
2663
2664
2665
2666
2667
2668
2669
2670
2671
2672
2673
2674
2675
2676
2677
2678
2679
2680
2681
2682
2683
2684
2685
2686
2687
2688
2689
2690
2691
2692
2693
2694
2695
2696
2697
2698
2699
2700
2701
2702
2703
2704
2705
2706
2707
2708
2709
2710
2711
2712
2713
2714
2715
2716
2717
2718
2719
2720
2721
2722
2723
2724
2725
2726
2727
2728
2729
2730
2731
2732
2733
2734
2735
2736
2737
2738
2739
2740
2741
2742
2743
2744
2745
2746
2747
2748
2749
2750
2751
2752
2753
2754
2755
2756
2757
2758
2759
2760
2761
2762
2763
2764
2765
2766
2767
2768
2769
2770
2771
2772
2773
2774
2775
2776
2777
2778
2779
2780
2781
2782
2783
2784
2785
2786
2787
2788
2789
2790
2791
2792
2793
2794
2795
2796
2797
2798
2799
2800
2801
2802
2803
2804
2805
2806
2807
2808
2809
2810
2811
2812
2813
2814
2815
2816
2817
2818
2819
2820
2821
2822
2823
2824
2825
2826
2827
2828
2829
2830
2831
2832
2833
2834
2835
2836
2837
2838
2839
2840
2841
2842
2843
2844
2845
2846
2847
2848
2849
2850
2851
2852
2853
2854
2855
2856
2857
2858
2859
2860
2861
2862
2863
2864
2865
2866
2867
2868
2869
2870
2871
2872
2873
2874
2875
2876
2877
2878
2879
2880
2881
2882
2883
2884
2885
2886
2887
2888
2889
2890
2891
2892
2893
2894
2895
2896
2897
2898
2899
2900
2901
2902
2903
2904
2905
2906
2907
2908
2909
2910
2911
2912
2913
2914
2915
2916
2917
2918
2919
2920
2921
2922
2923
2924
2925
2926
2927
2928
2929
2930
2931
2932
2933
2934
2935
2936
2937
2938
2939
2940
2941
2942
2943
2944
2945
2946
2947
2948
2949
2950
2951
2952
2953
2954
2955
2956
2957
2958
2959
2960
2961
2962
2963
2964
2965
2966
2967
2968
2969
2970
2971
2972
2973
2974
2975
2976
2977
2978
2979
2980
2981
2982
2983
2984
2985
2986
2987
2988
2989
2990
2991
2992
2993
2994
2995
2996
2997
2998
2999
3000
3001
3002
3003
3004
3005
3006
3007
3008
3009
3010
3011
3012
3013
3014
3015
3016
3017
3018
3019
3020
3021
3022
3023
3024
3025
3026
3027
3028
3029
3030
3031
3032
3033
3034
3035
3036
3037
3038
3039
3040
3041
3042
3043
3044
3045
3046
3047
3048
3049
3050
3051
3052
3053
3054
3055
3056
3057
3058
3059
3060
3061
3062
3063
3064
3065
3066
3067
3068
3069
3070
3071
3072
3073
3074
3075
3076
3077
3078
3079
3080
3081
3082
3083
3084
3085
3086
3087
3088
3089
3090
3091
3092
3093
3094
3095
3096
3097
3098
3099
3100
3101
3102
3103
3104
3105
3106
3107
3108
3109
3110
3111
3112
3113
3114
3115
3116
3117
3118
3119
3120
3121
3122
3123
3124
3125
3126
3127
3128
3129
3130
3131
3132
3133
3134
3135
3136
3137
3138
3139
3140
3141
3142
3143
3144
3145
3146
3147
3148
3149
3150
3151
3152
3153
3154
3155
3156
3157
3158
3159
3160
3161
3162
3163
3164
3165
3166
3167
3168
3169
3170
3171
3172
3173
3174
3175
3176
3177
3178
3179
3180
3181
3182
3183
3184
3185
3186
3187
3188
3189
3190
3191
3192
3193
3194
3195
3196
3197
3198
3199
3200
3201
3202
3203
3204













                                                                                                 
                        
                              
                             
                                   
                                  

                             
                            
                               
                              










                               



                                                                                                                                                     
 
                                           
                                           
              
                                                                                                                              
                                                                                                                 




                                                                                                                                                                                 
                                                

 
                                                                                                              

                                                                                   
                                                                                              
       

                                                                                                                                                                    

                         
                                              




                                              
                       
                                                                                                                   
                          

                                      

                                                                   
 
                                                                     
                                                                                                                         
             





                                                                 
                                                                                                                                                   



                                                                                                        
                                           
                                                                                                            
                                                                                                 
                                                      

                                                                                               
                                                                                          
                                                                                                                  
                                                                 
                                                                                                                    
                                                 
                                                                                                      
                                                  
                                                  
                                                                                                           
                                                                                
                                                                                                              
                                                 
                                                                                                                                    
                                                                                                                                 

                                                                                                                                                      
                                                                                                                                          
                                                  
















                                                                                                               
                                                                                    
                                                                                            
                                                                                                                    
                                  

                                                                              
                                                                   
                         
                                            

                                                                                   

                                       
                                                                                                


                                                                          
                                                                                             
       

                                                                                                                                                                                                                                       

                         
                                                                      






                                                                                                                                                                                       





                                         

 
                                                                                                                    



                                                                                                      
                                             
                                           
                                                                                                 
                                                                                                             
                                                                                                                                                    
                                                                                                       
                                                                              
                                                                                                         
                    
                                                  
                                                                                                                             

                                                                       
                                                  

                                                                                            

                                                                                        


                                                                                                                                                      
                                 
                                  
                                                 


                                                                                              


                                                                                                           
                                    




                                                                                        
                                    

                                                                                                        

                                                                        

                                                                                                           

                                                               





                                                                                                     

                                                                      
                                                
                                                      




                                                                                     


                                                                                             

                                                                                                       

                                                                              
                                                    



                                                                                                                          


                                                                                             



                                                                                         

                                       


                                                                                                                                                            

                                                                                     







                                                                                                                   

                                                                                          





                                                                                                                       
                                    
                                                               
                                  
                                                     
                                            
                                               
                                                                                                     


                                                                                                                                                                            
                                                                
                                                                                          
                                                                                          
                                                    
                                           





                                                                                                            






                                                                                                                                                                  
                                  
                                                 




                                                                                
                                    
                                                    

                                                                              
                                                    



                                                                                                                          
                                                                                                                                     
                                    
                                                                               
                                    
                                                                        

                                                                                                           

                                                                      



                                                                                             

                                           


                                                                                     
                                                                                             
                                    

                                                                                         
                                       
                                  
                                  
                                                             



                                                                                         

                                       
                                                                                                                                                        


                                                           
                                           


                                                                                                 
                                                            
                                  



                                                                                         
                                       
                                  


                                                                                 
                                                                                             


                                                                                                       
                                                                                                                                     

                         
                                         






                                                                           
                                                                                             

                                                                                                        
                                                                                                                                     

                         
                                         
                                         




                                                                                           
                                                                                             


                                                                                                       
                                                                                                                                     

                         
                                         



                                         

 
                                                                            
                                                                                             

                                                                                                            
                                                                                                                                     

                         
                                         



                                           
                                                                         







                                                                                   
                                                                                             

                                                                                                          
                                                                                                                                     








                                                                                                         
                                                                         
                                         





                                           
                                                                        
                                                                                             
       

                                                                                                                                                                                                                                                          

                                                                                                                                                                                          






                                         

                                                                                                                                                    


   
                                                              

                                                                 
                                                                                             



                                                                                                       
                                                                                                                                     







                                         
                                                                              





                                         
                                                                         







                                         





                                                                                                        


                                                                                               
                                                                                              

                                                                                                               

                                                                                                  




                                                                                                            



                                                                                                      





                                                                                                                     



                                                                                                                  



                                                                                                                  



                                                                                                   




                                                                                                                 



                                                                                 
                                            


                                                                   
                                                                                             



                                                                                                       
                                                                                                                                     







                                               
                                                                       







                                               
                                                                                                  
 
                                                        
                                           





                                                                                                             


                                                                                                                 

                                                                                         
                                                                                                                         
                                    

                                                   
                                    





                                                             
                                                                               
                                                                                          

                                                                                                           


                                                                                   



                                       
                                                            
                                           



                                                                                                             
                                                    
                                          
                                  
                                                                                                                      
                                                 


                                                                                                      
                                                       
                                       

                                        
                                                                                  
                                                                                                                          
                                                                                                 


                                                                                                                                                      
                                                                              

                                                                                                         

                                                                           

 

                                                                                       
                                                            
                                           
                                                                                                 
                                                                                                             
                                                                                                
                                                                                           

                                                                                                           

                                                                                              
                                                                                                         

                                                                                               
                                              



                                                                                                                                         
                                           
                                                                           


                                                       
                                           

                                                                                                             
                                                                                                 
                                                                                                                                                      

                                                                              



                                                                                                                                         


                                                                                
                                                                                                       

 












                                                                                                                                                                                                                                                         

 




















                                                                                                                                                                                                                                                         

 















                                                                                                                                                                                                                                                         


                                                                                     

                                                                                                                                   
                                  
                                                                                                                                                                                                                                                         
                  
                                                                                                                                                   

       
                                                                                                          

                                                                                                                                                                                          

                         

                                                                                                                                                    



                                                                                     

                                                                                                                                   
                                  
                                                                                                                                                                                                                                                         
                  
                                                                                                                          

       
                                                                                                          

                                                                                                                                                                                          

                         

                                                                                                                                                    



                                                                                     

                                                                                                                                    
                                                                         
                                                                                                                                                                                                                                                        

                                                                
                                                                               

       
                                                                                                          

                                                                                                                                                                                          

                         
                                              



                                              

                                                                                                                                                              



                                                                                      


                                                                                                                                                                                                                                                        



                                            
                                                                                                          

                         
                                              





                                                                              


                                                                                                                                                                                                                                                         

                                          
                                                                               


                                          
                                                                                                          

                         
                                              





                                                                                


                                                                                                                                                                                                                                                         
                  
                                                                                                                                  


                                                                                        
                                                                                                          

                         
                                              





                                                                                


                                                                                                                                                                                                                                                         
                  
                                                                                                                              


                                                                                        
                                                                                                          

                         
                                              





                                                                                

                                                                                                                                   
                                
                                                                                                                                                                                                                                                         
                  
                                                                                                                              


                                                                                        
                                                                                                          

                         
                                              






                                                                                

                                                                                                                                   
                                
                                                                                                                                                                                                                                                         
                  
                                                                                                                              


                                                                                                                      
                                                                                                          

                         
                                              





                                              


















                                                                                                                                                                                                                                                        
                                                                      


                                                                                                                                                                                                                                                        




                                              
                                                                                                          


                                            


                                         






                                                     
                                                                                                          


                                         
                                         
                                           
                                         



                                         

















                                                                                                          


                                                                                         


                                                                                                                                                                                                                                                        
                  
                                                                                                                                              


                                          
                                                                                                          

                                                                                                                                                                                          

                         
                                              




                                                

                                                                                                                                                    



                                                                                           


                                                                                                                                                                                                                                                        
                  
                                                                                                                                          


                                          
                                                                                                          

                                                                                                                                                                                          

                         
                                              




                                                

                                                                                                                                                    


   

                                                                            
                                                                                           


                                                                                                                                                                                                                                                         




                                         
                                                                                                          

                         
                                              





                                              
























































































                                                                                                                                                                                                                                                         

   






                                                
       
                                                                                                          



                                                             


                                                



                                              













                                                                                                                                                                                                                                                         

                                                                                                                                                                                          







                                                                                                                                                               






                                                                                                       
                                                                                              



                                                                                                                                                                                                                                                        
                  
                                           
   

                                                                                                                                                                                                                                            




                                                                                                          

                                              


   











                                                                                                 
                                                                       


                                                                                                                                                                                                                                                         
                  
                                                                               

                                           

                                                                                                                                                                                                                                                        
       
                                                                                                          

                                                                                                                                                                                          

                         
                                              



                                              

                                                                                                      


   

























































































                                                                                                                                                               
                                                                               
                                                                                              
                                                                 
                                                                                                                                  
                                 
                                                                                                                                                                                                                                                         
                  
                                                                                                                                                      

                                           

                                                                                                                                                                                                                                                        
       
                                                                                                          

                                                                                                                                                                                          

                         
                                              


                                              



                                                                                                      

 


                                                                    
                                                                                              

                                                                                                                                                                                                                                                         
                  
                                                                                    
   




                                                                                                          

                                              
   
                  
                                                                                    
   
       
                                                                                                          

                         
                                              
                                              



                                              












                                                                                                                              
                                                                                              
                                                                                                                                    
                                                                                                                                                                                                                                                         
                  
                                                                                         


                                          
                                                                                                          

                         
                                              
                                              



                                              















































































                                                                                                                                                                                                                                                         


                                          
                                                                                                          

                         


                                              




                                                                                                    


                                                                                                                                                                                                                                                        
                  

                                                                                         

       
                                                                                                          

                                                                                                                                                                                          

                         
                                              




                                                

                                                                                                      


   
                                                                                                      
                                                                                              
                                                          

                                                                                                                                                                                                                                                        
                                                                                                  
                  

                                                                                         

       
                                                                                                          

                                                                                                                                                                                          

                         

                                                                                                      


                                                          
                                             

       
                                                                                                          

                                                                                                                                                                                          

                         

                                                                                                      


   
                                                                                                      


                                                                                                                                                                                                                                                        
                  

                                                                                         

       
                                                                                                          

                                                                                                                                                                                          
   





                                                
                         

                                                                                                      



                                                                                                           

                                                                                                                                   
                                
                                                                                                                                                                                                                                                         
                  

                                                                                                     


                                          
                                                                                                          

                         
                                              





                                              

                                         
                                                                            


                                                                                                                                                                                                                                                         
                  

                                                                                        


                                          
                                                                                                          

                         
                                              




                                              











                                                                                                                                   
                                                                                                                
                                                                                              
                                                                 
                                                                                                                                   
                                
                                                                                                                                                                                                                                                         

                                                                                                         

                                                                                        

       
                                                                                                          

                                                                                                                                                                                          
   
                         

                                                                                                      



                                                                                                                  
                                                                                              
                                                                   
                                                                                                                                   

                                 
                                                                                                                                                                                                                                                         


                                                                                                           

                                                                                        


                                          
                                                                                                          

                         
                                              







                                                                                                                  

                                                                                                                                   

                                 
                                                                                                                                                                                                                                                         

                                                                 

                                                                                                              


                                          
                                                                                                          

                         
                                              







                                                                                                                  
                                                                                              
                                                                                     
                                                                                                                                   

  
                                                                                                                                                                                                                                                         

                                                                       

                                                                                        


                                          
                                                                                                          

                         
                                              







                                                                                                       
                                                                                              
                                                                                     

                                                                                                                                                                                                                                                        
                         
                                              





                                                                       

                                                                                        

       
                                                                                                          

                                                                                                                                                                                          

                         

                                                                                                                                                          


   

                                       
                                                                                      

                                                                                                                                   
                                  
                                                                                                                                                                                                                                                         
                  

                                                                                      

       
                                                                                                          

                                                                                                                                                                                          

                         

                                                                                                      


   



















                                                                                                                               

                                                                                                                                   
                                 
                                                                                                                                                                                                                                                         
                  
                                                                               
                                                                                        

       
                                                                                                          

                                                                                                                                                                                          
   
                         
                                                                                                      
                                                                                                      


   


                                                                                    
                                                                                              
                                                                                                                                   
                                  
                                                                                                                                                                                                                                                         
                                                            
                  
                                                                                        

       
                                                                                                          

                                                                                                                                                                                          
   
                                                     
                         

                                                                                                      


   




















                                                                                                                          
                                                                                              

                                                                                                                                  
                                                                                                                                                                                                                                                         
                  

                                                                                      

       
                                                                                                          

                                                                                                                                                                                          

                         
                                                                                                      
                                                                                                      


   

                                                                         
                                                                                    

                                                                                                                                   
                                  
                                                                                                                                                                                                                                                         
                                                                   
                  
                                                                               
                                                                                 
   

                                                                                                                                                                                                                                                  
       
                                                                                                          

                                                                                                                                                                                          
   
                                                              
                         

                                                                                                      


   








































                                                                                                                                                      
                                                                                      

                                                                                                                                   
                                  
                                                                                                                                                                                                                                                         
                                                                                      
                  
                                                                               
                                                                                 
   

                                                                                                                                                                                                                                                  
       
                                                                                                          

                                                                                                                                                                                          
   
                                                              
                         

                                                                                                      


   
                                                                                  

                                                                                                                                   
                                  
                                                                                                                                                                                                                                                         

                                                                   

                                                                                    

       
                                                                                                          

                                                                                                                                                                                          


                                                              

                                                                                                      



                                                                                    

                                                                                                                                   
                                  
                                                                                                                                                                                                                                                         

                                                                                      

                                                                                    

       
                                                                                                          

                                                                                                                                                                                          


                                                              

                                                                                                      


   

                                                                      
                                                                                    

                                                                                                                                   
                                  
                                                                                                                                                                                                                                                         

                                                                  
                                                                               

                                                                                 

                                                                                                                                                                                                                                                  
       
                                                                                                          

                                                                                                                                                                                          


                                                            

                                                                                                      





                                                                           
                                                                                                          

                                                                                                                                                                                          

                         

                                                                                                      








                                              





































                                                                                                                                                      
                                                                                    

                                                                                                                                   
                                  
                                                                                                                                                                                                                                                         

                                                                                      
                                                                               

                                                                                 

                                                                                                                                                                                                                                                  
       
                                                                                                          

                                                                                                                                                                                          


                                                            

                                                                                                      



                                                                               

                                                                                                                                   
                                  
                                                                                                                                                                                                                                                         

                                                                 

                                                                                   

       
                                                                                                          

                                                                                                                                                                                          


                                                            

                                                                                                      



                                                                                 

                                                                                                                                   
                                  
                                                                                                                                                                                                                                                         

                                                                                     

                                                                                   

       
                                                                                                          

                                                                                                                                                                                          


                                                            

                                                                                                      


   

                                                                                                
                                                                                      

                                                                                                                                   
                                  
                                                                                                                                                                                                                                                         

                                                                   
                                                                               

                                                                                 

                                                                                                                                                                                                                                                   
       
                                                                                                          



                                                                










































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































                                                                                                                                                                                                                                                         
   
                                                                                               
                  
                                                                                       
   
       
                                                                                                          
   

                                              


                                              
   
                                                     
                  
                                                                                      
   
       
                                                                                                          
   
                                                                  

                                              


                                              


   

                                                                                                 
                                                                                              






                                                                                                                                                                                                                                                        
                  
                                                                                       
   
       
                                                                                                          
   

                                              


                                              

                                              
                                                 
                  
                                                                                      
   
       
                                                                                                          
   
                                                                  

                                              



                                              
   
                                                      
                  
                                                                                      
   
       
                                                                                                          
   
                                                                  

                                              



                                                
   
                                                     
                  
                                                                                      
   
       
                                                                                                          
   
                                                                  

                                              



                                                


   










                                                                                                                                                                                                                                                        
                  
                                                                                       
   
       
                                                                                                          
   
                         



                                         
   
                                                     
                  
                                                                                        
   
       
                                                                                                          

                                                                                                                                                                                          
   
                                               
                         







                                                                                                      


   
































































































                                                                                                                                                                                                                             
                                                               


                                                                      
                                                                       










                                                                                        
                                                                    
                                            
                                                                                              
                                                                 


                                                                                                                                                                                                                                                                      

                                                    

                                                                                


                                                            
                                                                                                                    



                                                                                                                                                                                                                          

                         

                                                                                                       



                                                                
                                            
                                                                                              
                                                                 


                                                                                                                                                                                                                                                                      

                                                                
                                                                               
                                          
                                                                                


                                          
                                                                                                                    



                                                                                                                                                                                                                          

                         
                                                                                                                                      




                                                                                                                              

                                                                                                                                                                       


                                                                    
                                                                                                                            

                         
                                                                  






                                                                                                                              
                                            
                                                                                               
       


                                                                                                                                                                                                                                                                        


                                                        
                                                                                                
                                                                                                  
                                                                                                                                                                                                                        

                                                                                                  



                                                                       
                                            


                                                                                                                                    

                                                                                        
       


                                                                                                                                                                                                                                                                        
   
                                                              
                         
                                                                  
                                                                      
                                                                                                                              
                                                                    





                                                        


                                                                                                                                                                                                                                                                        


                                                             
                                                                  





                                                                                                                              



























                                                                                                                                                                                                                                                                        












                                                                                                                                       
 





















                                                                                                                                       

 





















                                                                                                                                               









                                                                                                 










                                                                                                       

























































































                                                                                                                                                                                                                                                                                                                                                



                                                                                                                                          


                                                                                

       
                                                                                                                    


                                                                     
                                                                                                                                        

                                                                                                                                                                                                                                                                                                                                                
                                                                                                                                          
                                                                                                                                          

                                                                                                                                                                                                                                            
                                                                                                                                          
                                                                                                                                          






                                                                                                                                                                                                                                            















                                                                                                           
                                                    
                                           
                                                                                                                           
                                                                                                                       
                                                                                                       

                                                                                       
                                                                                                                                                           
                                                               
                                                                  
                                                          
                                                                         
                                                                                                                                       
                                  

                                                                                                               

                                                                                 

                                                                                                                                               
                                                                  
                                                               

                                                                                                                                                    

                                                             
                                                       
                                                                                                                                               
                                                                                                                                   

                                                                                                                                                                 
                                  
                                                                                                    


                                                                                                                     
                                  
                                                    






                                                                                                                                                

                                       










                                                                                                                                                                                          
                                  
                                                    










                                                                                                                                                    



                                       



                                                                                                                           
                                                                               


                                                                                                                                       


                                                                                                
                                                                                                                        
                                                                                                   
                                                     

                                                                                 
                                                                              
                                  




                                                                                                       

                                       
                                                                                                








                                                                                                               



                                                                                                                                                                               
                                                    



                                                                                                     
                                                                                  
                                                                                                                                                  
                                                           
                                                        
                                                                                                                                 
                                                                                                                                            
                                                                                           




                                                                                                                                                                    
                                  
                                                                
                                                                                                                                              
                                                                                                                                                

                                  



                                                                                                         

                                  

                                                             


                                                                                                      
                                                                                                                                                   
                                  
                                                   

                                                                                                                                                                       
                                                              
                                                                                                
                                                  
                                                                                                                                      

                                                                                                                                                        






                                                                                                                           


                                                                                                                                     
                                  
                                                                                                     

                                                                                                                                        
                                                              

                                                                                                                                         
                                                          







                                                                                                                                                                     
                                           

                                                                                                                 

                                       
                                                                                             

 



                                                                                                                                                           
                                           























                                                                                                                                                                  
                                  










                                                                                                              
                                    



















                                                                                                              
                                    
                                                                                   

                                       
                                                                                                                                                        



                                                                        
                                                                                                
                                                                                                                        
                                                                                                                                 
                                          
                                                     

                                                                                               

                                                                                                                                                                                                                                                                      

                                                            
                                                                                

       
                                                                                                                    


                                                                     
                                                                                                                                        

                                                                                                                                                                                                                                            
                                                                                                                                             


                                                                                                                                                                                                                                              



                                                                                                                                          
                                                                                                                                                     
                                                                                    
                                                                                
   

                                                                                                                                                                                                                                                        
       
                                                                                                                    


                                                                                  
                                                                                                                                        

                                                                                                                                                                                                                                            
                                                                                                                                             


                                                                                                                                                                                                                                              
                                                                                                                                          


   

                                                                             
                                                                                                
                                                     
                                                                                                                                 
                                                                             

                                                                                                                                                                                                                                                                      

                                                            
                                                                                

       
                                                                                                                    


                                                                              
                                                                                                                                        

                                                                                                                                                                                                                                                                                                                                                
                                                                                                                                          




                                                                                                                                                                                                                                            
                                                                         


                                                                                                                                        
                                                                                                                                        




                                                                                                                                        
                                                                       
                                                                                                                                        






                                                                                                                                        
                                                                          


                                                                                                                                                                                                                                                                                                                                                
                                                                                                                                          






                                                                                                                                                                                                                                            

                                                                                       
                                                                                                
                                                     
                                                                                                                                 
                                                                             

                                                                                                                                                                                                                                                                      

                                                                           

                                                                                

       
                                                                                                                    


                                                                                 
                                                                                                                                        









                                                                                                                                                                                                                                                                                                                                                

































                                                                                                                                                                                                                                                                                                                                                



















































































































































                                                                                                                                                                                                                                                                      

                                                                        



                                                                                                                                                                                                                                                                      

                                                   




                                                                                

       
                                                                                                                    

                         
                                                                                                                                        


                                                                                                                                                                                                                                                                                                                                                
                                                                                                                                          


                                                                                                                                                                                                                                            
                                                                                                                                          






                                                                                                                                                                                                                                            
                                                                                

       
                                                                                                                    

                         
                                                                                                                                        


                                                                                                                                                                                                                                                                                                                                                
                                                                                                                                          






                                                                                                                                                                                                                                            
                                                                                

       
                                                                                                                    

                         
                                                                                                                                        






                                                                                                                                                                                                                                                                                                                                                











































                                                                                                                                       

































































































                                                                                                                                                                                                                                                                      
                                           







                                                                                                                           
                                  





                                                                                                                                        

                                       







                                                                                                                                                    

 


































                                                                                                                                                                   
                                                                                                  










                                                                                                                                    
                  















                                                                                                                                                                                                                                                                      

       
                                                                                                                    
   




















































                                                                                                                                                            
   






































































































                                                                                                                                                                                                                                                                      

 



                                                                    
                                                                                                
                  
                                                                                










                                                                                                                                                                                
                                                                                                                                        







                                                                                                                                                                                                                                              
                                                                       











                                                                                                                                        
                                                                                                
                  
                                                                                



                                                                                                     
                                              





                                                                                                                                                                                
                                                                                                                                        

                                                                                                                                                                                                                                            
                                                                                                                                             
                                                                                                                                          
                                                                                                                                             






                                                                                                                                                                                                                                              
                                                                                                
                  
                                                                                











                                                                                                                                                                                
                                                                                                                                        



                                                                                                                                                                                                                                            


                                                                                                                                                                                                                                              





                                                                                                                                          
                                                                                                
                  
                                                                                





                                                                                                     
                                                              





                                                                                                                                                                                
                                                                                                                                        



                                                                                                                                                                                                                                            
                                                                                                                                          







                                                                                                                                                                                                                                              


                                                                         
                                           

                                                                                                 
                                                                                              
                                                                                                
                                                                                               
                                                                                                                     
                                  
                                                         

                                                                                        
                                  
                                           







                                                    
                                                           


                               


                                                      
                                           



                                                                                                 

                                                                                                                        

                                                                                               
                                  
                                                                                                                     
                                  
                                                         

                                                                                        
                                  

                                                                                                                           
                                                           
                                                                                          
                                  
                            
                                  



                                                                                                                                                                    
                                       
                                  


                                                    
                                           

                                                                                                 
                                                                                           
                                                                                                

                                                                                                                        

                                                                                             
                                  


                                                                                                                     

                                                                                        
                                  
                                  




                                                                               
                                       
                                  


                                                    
                                           





                                                                                                                     

                                                                                        
                                  

                                                                              


                                                     
                                           





                                                                                                                     

                                                                                        
                                  

                                                                             


                                                       
                                           





                                                                                                                     

                                                                                        
                                  

                                                                            


                                                        
                                           





                                                                                                                     

                                                                                        
                                  

                                                                           
 

                                                                            
                                           
                                                                                                 



                                                                                                            




                                                                                     
                                  





                                                                               

                                       
                                                                                                
 



                                     
<!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; }
.muControl { color: #c0a020; }
.muRecipe { color: #ff8700; }
.SalientComment { color: #00ffff; }
.CommentedCode { color: #6c6c6c; }
.Comment { color: #9090ff; }
.Constant { color: #00a0a0; }
.Special { color: #ff6060; }
.muScenario { color: #00af00; }
.Delimiter { color: #a04060; }
-->
</style>

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

-->
</script>
</head>
<body>
<pre id='vimCodeElement'>
<span class="Comment"># Environment for learning programming using mu: <a href="http://akkartik.name/post/mu">http://akkartik.name/post/mu</a></span>
<span class="Comment">#</span>
<span class="Comment"># Consists of one editor on the left for recipes and one on the right for the</span>
<span class="Comment"># sandbox.</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/screen</span>, initial-recipe, initial-sandbox
  env<span class="Special"> &lt;- </span>restore-sandboxes env
  render-all <span class="Constant">0/screen</span>, env
  show-screen <span class="Constant">0/screen</span>
  event-loop <span class="Constant">0/screen</span>, <span class="Constant">0/console</span>, env
  <span class="Comment"># never gets here</span>
]

<span class="SalientComment">## the basic editor data structure, and how it displays text to the screen</span>

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

container editor-data [
  <span class="Comment"># editable text: doubly linked list of characters (head contains a special sentinel)</span>
  data:address:duplex-list
  top-of-screen:address:duplex-list
  bottom-of-screen: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 (leaving row 0 for a menu) 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<span class="Special"> &lt;- </span>subtract right, <span class="Constant">1</span>
  result:address:editor-data<span class="Special"> &lt;- </span>new <span class="Constant">editor-data:type</span>
  <span class="Comment"># initialize screen-related fields</span>
  x:address:number<span class="Special"> &lt;- </span>get-address *result, <span class="Constant">left:offset</span>
  *x<span class="Special"> &lt;- </span>copy left
  x<span class="Special"> &lt;- </span>get-address *result, <span class="Constant">right:offset</span>
  *x<span class="Special"> &lt;- </span>copy right
  <span class="Comment"># initialize cursor</span>
  x<span class="Special"> &lt;- </span>get-address *result, <span class="Constant">cursor-row:offset</span>
  *x<span class="Special"> &lt;- </span>copy <span class="Constant">1/top</span>
  x<span class="Special"> &lt;- </span>get-address *result, <span class="Constant">cursor-column:offset</span>
  *x<span class="Special"> &lt;- </span>copy left
  init:address:address:duplex-list<span class="Special"> &lt;- </span>get-address *result, <span class="Constant">data:offset</span>
  *init<span class="Special"> &lt;- </span>push-duplex <span class="Constant">167/§</span>, <span class="Constant">0/tail</span>
  top-of-screen:address:address:duplex-list<span class="Special"> &lt;- </span>get-address *result, <span class="Constant">top-of-screen:offset</span>
  *top-of-screen<span class="Special"> &lt;- </span>copy *init
  y:address:address:duplex-list<span class="Special"> &lt;- </span>get-address *result, <span class="Constant">before-cursor:offset</span>
  *y<span class="Special"> &lt;- </span>copy *init
  result<span class="Special"> &lt;- </span>insert-text result, s
  <span class="Comment"># initialize cursor to top of screen</span>
  y<span class="Special"> &lt;- </span>get-address *result, <span class="Constant">before-cursor:offset</span>
  *y<span class="Special"> &lt;- </span>copy *init
  <span class="Comment"># initial render to screen, just for some old tests</span>
  _, screen<span class="Special"> &lt;- </span>render screen, result
  <span class="muControl">reply</span> result
]

<span class="muRecipe">recipe</span> insert-text [
  <span class="Constant">local-scope</span>
  editor:address:editor-data<span class="Special"> &lt;- </span><span class="Constant">next-ingredient</span>
  text:address:array:character<span class="Special"> &lt;- </span><span class="Constant">next-ingredient</span>
  <span class="Comment"># early exit if text is empty</span>
  <span class="muControl">reply-unless</span> text, editor/same-as-ingredient:<span class="Constant">0</span>
  len:number<span class="Special"> &lt;- </span>length *text
  <span class="muControl">reply-unless</span> len, editor/same-as-ingredient:<span class="Constant">0</span>
  idx:number<span class="Special"> &lt;- </span>copy <span class="Constant">0</span>
  <span class="Comment"># now we can start appending the rest, character by character</span>
  curr:address:duplex-list<span class="Special"> &lt;- </span>get *editor, <span class="Constant">data:offset</span>
  <span class="Delimiter">{</span>
    done?:boolean<span class="Special"> &lt;- </span>greater-or-equal idx, len
    <span class="muControl">break-if</span> done?
    c:character<span class="Special"> &lt;- </span>index *text, idx
    insert-duplex c, curr
    <span class="Comment"># next iter</span>
    curr<span class="Special"> &lt;- </span>next-duplex curr
    idx<span class="Special"> &lt;- </span>add idx, <span class="Constant">1</span>
    <span class="muControl">loop</span>
  <span class="Delimiter">}</span>
  <span class="muControl">reply</span> editor/same-as-ingredient:<span class="Constant">0</span>
]

<span class="muScenario">scenario</span> editor-initializes-without-data [
  assume-screen <span class="Constant">5/width</span>, <span class="Constant">3/height</span>
  run [
    <span class="Constant">1</span>:address:editor-data<span class="Special"> &lt;- </span>new-editor <span class="Constant">0/data</span>, screen:address, <span class="Constant">2/left</span>, <span class="Constant">5/right</span>
    <span class="Constant">2</span>:editor-data<span class="Special"> &lt;- </span>copy *<span class="Constant">1</span>:address:editor-data
  ]
  memory-should-contain [
    <span class="Comment"># 2 (data) &lt;- just the § sentinel</span>
    <span class="Comment"># 3 (top of screen) &lt;- the § sentinel</span>
    <span class="Constant">4</span><span class="Special"> &lt;- </span><span class="Constant">0</span>  <span class="Comment"># bottom-of-screen; null since text fits on screen</span>
    <span class="Comment"># 5 (before cursor) &lt;- the § sentinel</span>
    <span class="Constant">6</span><span class="Special"> &lt;- </span><span class="Constant">2</span>  <span class="Comment"># left</span>
    <span class="Constant">7</span><span class="Special"> &lt;- </span><span class="Constant">4</span>  <span class="Comment"># right  (inclusive)</span>
    <span class="Constant">8</span><span class="Special"> &lt;- </span><span class="Constant">1</span>  <span class="Comment"># cursor row</span>
    <span class="Constant">9</span><span class="Special"> &lt;- </span><span class="Constant">2</span>  <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="Comment">#</span>
<span class="Comment"># Assumes cursor should be at coordinates (cursor-row, cursor-column) and</span>
<span class="Comment"># updates before-cursor to match. Might also move coordinates if they're</span>
<span class="Comment"># outside text.</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, <span class="Constant">1/top</span>, screen/same-as-ingredient:<span class="Constant">0</span>
  left:number<span class="Special"> &lt;- </span>get *editor, <span class="Constant">left:offset</span>
  screen-height:number<span class="Special"> &lt;- </span>screen-height screen
  right:number<span class="Special"> &lt;- </span>get *editor, <span class="Constant">right:offset</span>
  hide-screen screen
  <span class="Comment"># traversing editor</span>
  curr:address:duplex-list<span class="Special"> &lt;- </span>get *editor, <span class="Constant">top-of-screen:offset</span>
  prev:address:duplex-list<span class="Special"> &lt;- </span>copy curr
  curr<span class="Special"> &lt;- </span>next-duplex curr
  <span class="Comment"># traversing screen</span>
<span class="Constant">  +render-loop-initialization</span>
  color:number<span class="Special"> &lt;- </span>copy <span class="Constant">7/white</span>
  row:number<span class="Special"> &lt;- </span>copy <span class="Constant">1/top</span>
  column:number<span class="Special"> &lt;- </span>copy left
  cursor-row:address:number<span class="Special"> &lt;- </span>get-address *editor, <span class="Constant">cursor-row:offset</span>
  cursor-column:address:number<span class="Special"> &lt;- </span>get-address *editor, <span class="Constant">cursor-column:offset</span>
  before-cursor:address:address:duplex-list<span class="Special"> &lt;- </span>get-address *editor, <span class="Constant">before-cursor:offset</span>
  move-cursor screen, row, column
  <span class="Delimiter">{</span>
<span class="Constant">    +next-character</span>
    <span class="muControl">break-unless</span> curr
    off-screen?:boolean<span class="Special"> &lt;- </span>greater-or-equal row, screen-height
    <span class="muControl">break-if</span> off-screen?
    <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, *cursor-row
      <span class="muControl">break-unless</span> at-cursor-row?
      at-cursor?:boolean<span class="Special"> &lt;- </span>equal column, *cursor-column
      <span class="muControl">break-unless</span> at-cursor?
      *before-cursor<span class="Special"> &lt;- </span>prev-duplex curr
    <span class="Delimiter">}</span>
    c:character<span class="Special"> &lt;- </span>get *curr, <span class="Constant">value:offset</span>
<span class="Constant">    +character-c-recived</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, <span class="Constant">10/newline</span>
      <span class="muControl">break-unless</span> newline?
      <span class="Comment"># adjust cursor if necessary</span>
      <span class="Delimiter">{</span>
        at-cursor-row?:boolean<span class="Special"> &lt;- </span>equal row, *cursor-row
        <span class="muControl">break-unless</span> at-cursor-row?
        left-of-cursor?:boolean<span class="Special"> &lt;- </span>lesser-than column, *cursor-column
        <span class="muControl">break-unless</span> left-of-cursor?
        *cursor-column<span class="Special"> &lt;- </span>copy column
        *before-cursor<span class="Special"> &lt;- </span>prev-duplex curr
      <span class="Delimiter">}</span>
      <span class="Comment"># clear rest of line in this window</span>
      clear-line-delimited screen, column, right
      <span class="Comment"># skip to next line</span>
      row<span class="Special"> &lt;- </span>add row, <span class="Constant">1</span>
      column<span class="Special"> &lt;- </span>copy left
      move-cursor screen, row, column
      curr<span class="Special"> &lt;- </span>next-duplex curr
      prev<span class="Special"> &lt;- </span>next-duplex prev
      <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, right
      <span class="muControl">break-unless</span> at-right?
      <span class="Comment"># print wrap icon</span>
      print-character screen, <span class="Constant">8617/loop-back-to-left</span>, <span class="Constant">245/grey</span>
      column<span class="Special"> &lt;- </span>copy left
      row<span class="Special"> &lt;- </span>add row, <span class="Constant">1</span>
      move-cursor screen, row, column
      <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, c, color
    curr<span class="Special"> &lt;- </span>next-duplex curr
    prev<span class="Special"> &lt;- </span>next-duplex prev
    column<span class="Special"> &lt;- </span>add column, <span class="Constant">1</span>
    <span class="muControl">loop</span>
  <span class="Delimiter">}</span>
  <span class="Comment"># save first character off-screen</span>
  bottom-of-screen:address:address:duplex-list<span class="Special"> &lt;- </span>get-address *editor, <span class="Constant">bottom-of-screen:offset</span>
  *bottom-of-screen<span class="Special"> &lt;- </span>copy curr
  <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, *cursor-row
    cursor-outside-line?:boolean<span class="Special"> &lt;- </span>lesser-or-equal column, *cursor-column
    before-cursor-on-same-line?:boolean<span class="Special"> &lt;- </span>and at-cursor-row?, cursor-outside-line?
    above-cursor-row?:boolean<span class="Special"> &lt;- </span>lesser-than row, *cursor-row
    before-cursor?:boolean<span class="Special"> &lt;- </span>or before-cursor-on-same-line?, above-cursor-row?
    <span class="muControl">break-unless</span> before-cursor?
    *cursor-row<span class="Special"> &lt;- </span>copy row
    *cursor-column<span class="Special"> &lt;- </span>copy column
    <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, right
      <span class="muControl">break-unless</span> too-far-right?
      *cursor-column<span class="Special"> &lt;- </span>copy left
      *cursor-row<span class="Special"> &lt;- </span>add *cursor-row, <span class="Constant">1</span>
      above-screen-bottom?:boolean<span class="Special"> &lt;- </span>lesser-than *cursor-row, screen-height
      assert above-screen-bottom?, <span class="Constant">[unimplemented: wrapping cursor past bottom of screen]</span>
    <span class="Delimiter">}</span>
    *before-cursor<span class="Special"> &lt;- </span>copy prev
  <span class="Delimiter">}</span>
  <span class="Comment"># clear rest of screen</span>
  clear-line-delimited screen, column, right
  clear-rest-of-screen screen, row, left, right
  <span class="muControl">reply</span> row, screen/same-as-ingredient:<span class="Constant">0</span>
]

<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<span class="Special"> &lt;- </span>add row, <span class="Constant">1</span>
  <span class="muControl">reply-unless</span> s, row/same-as-ingredient:<span class="Constant">5</span>, screen/same-as-ingredient:<span class="Constant">0</span>
  column:number<span class="Special"> &lt;- </span>copy left
  move-cursor screen, row, column
  screen-height:number<span class="Special"> &lt;- </span>screen-height screen
  i:number<span class="Special"> &lt;- </span>copy <span class="Constant">0</span>
  len:number<span class="Special"> &lt;- </span>length *s
  <span class="Delimiter">{</span>
<span class="Constant">    +next-character</span>
    done?:boolean<span class="Special"> &lt;- </span>greater-or-equal i, len
    <span class="muControl">break-if</span> done?
    done?<span class="Special"> &lt;- </span>greater-or-equal row, screen-height
    <span class="muControl">break-if</span> done?
    c:character<span class="Special"> &lt;- </span>index *s, i
    <span class="Delimiter">{</span>
      <span class="Comment"># at right? wrap.</span>
      at-right?:boolean<span class="Special"> &lt;- </span>equal column, right
      <span class="muControl">break-unless</span> at-right?
      <span class="Comment"># print wrap icon</span>
      print-character screen, <span class="Constant">8617/loop-back-to-left</span>, <span class="Constant">245/grey</span>
      column<span class="Special"> &lt;- </span>copy left
      row<span class="Special"> &lt;- </span>add row, <span class="Constant">1</span>
      move-cursor screen, row, column
      <span class="muControl">loop</span> <span class="Constant">+next-character:label</span>  <span class="Comment"># retry i</span>
    <span class="Delimiter">}</span>
    i<span class="Special"> &lt;- </span>add i, <span class="Constant">1</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, <span class="Constant">10/newline</span>
      <span class="muControl">break-unless</span> newline?
      <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, right
        <span class="muControl">break-if</span> done?
        print-character screen, <span class="Constant">32/space</span>
        column<span class="Special"> &lt;- </span>add column, <span class="Constant">1</span>
        <span class="muControl">loop</span>
      <span class="Delimiter">}</span>
      row<span class="Special"> &lt;- </span>add row, <span class="Constant">1</span>
      column<span class="Special"> &lt;- </span>copy left
      move-cursor screen, row, column
      <span class="muControl">loop</span> <span class="Constant">+next-character:label</span>
    <span class="Delimiter">}</span>
    print-character screen, c, color
    column<span class="Special"> &lt;- </span>add column, <span class="Constant">1</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, right
    <span class="muControl">break-if</span> line-done?
    print-character screen, <span class="Constant">32/space</span>
    column<span class="Special"> &lt;- </span>add column, <span class="Constant">1</span>
    <span class="muControl">loop</span>
  <span class="Delimiter">}</span>
  <span class="muControl">reply</span> row/same-as-ingredient:<span class="Constant">5</span>, screen/same-as-ingredient:<span class="Constant">0</span>
]

<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
  <span class="Delimiter">{</span>
    done?:boolean<span class="Special"> &lt;- </span>greater-than column, right
    <span class="muControl">break-if</span> done?
    print-character screen, <span class="Constant">32/space</span>
    column<span class="Special"> &lt;- </span>add column, <span class="Constant">1</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/width</span>, <span class="Constant">5/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/left</span>, <span class="Constant">5/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/width</span>, <span class="Constant">5/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/left</span>, <span class="Constant">5/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/width</span>, <span class="Constant">5/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/left</span>, <span class="Constant">5/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/width</span>, <span class="Constant">5/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/left</span>, <span class="Constant">5/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/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/width</span>, <span class="Constant">5/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/left</span>, <span class="Constant">5/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/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/width</span>, <span class="Constant">5/height</span>
  run [
    <span class="Constant">1</span>:address:array:character<span class="Special"> &lt;- </span>new <span class="Constant">[]</span>
    <span class="Constant">2</span>:address:editor-data<span class="Special"> &lt;- </span>new-editor <span class="Constant">1</span>:address:array:character, screen:address, <span class="Constant">0/left</span>, <span class="Constant">5/right</span>
    <span class="Constant">3</span>:number<span class="Special"> &lt;- </span>get *<span class="Constant">2</span>:address:editor-data, <span class="Constant">cursor-row:offset</span>
    <span class="Constant">4</span>:number<span class="Special"> &lt;- </span>get *<span class="Constant">2</span>:address:editor-data, <span class="Constant">cursor-column:offset</span>
  ]
  screen-should-contain [
   <span class="Constant"> .     .</span>
   <span class="Constant"> .     .</span>
   <span class="Constant"> .     .</span>
  ]
  memory-should-contain [
    <span class="Constant">3</span><span class="Special"> &lt;- </span><span class="Constant">1</span>  <span class="Comment"># cursor row</span>
    <span class="Constant">4</span><span class="Special"> &lt;- </span><span class="Constant">0</span>  <span class="Comment"># cursor column</span>
  ]
]

<span class="Comment"># just a little color for mu code</span>

<span class="muScenario">scenario</span> render-colors-comments [
  assume-screen <span class="Constant">5/width</span>, <span class="Constant">5/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/left</span>, <span class="Constant">5/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/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/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="muRecipe">after</span> +character-c-recived [
  color<span class="Special"> &lt;- </span>get-color color, c
]

<span class="Comment"># color:number &lt;- get-color color:number, c:character</span>
<span class="Comment"># so far the previous color is all the information we need; that may change</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>
  c:character<span class="Special"> &lt;- </span><span class="Constant">next-ingredient</span>
  color-is-white?:boolean<span class="Special"> &lt;- </span>equal color, <span class="Constant">7/white</span>
<span class="CommentedCode">#?   $print [character: ], c, 10/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?
    starting-comment?:boolean<span class="Special"> &lt;- </span>equal c, <span class="Constant">35/#</span>
    <span class="muControl">break-unless</span> starting-comment?
<span class="CommentedCode">#?     $print [switch color back to blue], 10/newline #? 1</span>
    color<span class="Special"> &lt;- </span>copy <span class="Constant">12/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, <span class="Constant">12/lightblue</span>
    <span class="muControl">break-unless</span> color-is-blue?
    ending-comment?:boolean<span class="Special"> &lt;- </span>equal c, <span class="Constant">10/newline</span>
    <span class="muControl">break-unless</span> ending-comment?
<span class="CommentedCode">#?     $print [switch color back to white], 10/newline #? 1</span>
    color<span class="Special"> &lt;- </span>copy <span class="Constant">7/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?
    starting-assignment?:boolean<span class="Special"> &lt;- </span>equal c, <span class="Constant">60/&lt;</span>
    <span class="muControl">break-unless</span> starting-assignment?
    color<span class="Special"> &lt;- </span>copy <span class="Constant">1/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, <span class="Constant">1/red</span>
    <span class="muControl">break-unless</span> color-is-red?
    ending-assignment?:boolean<span class="Special"> &lt;- </span>equal c, <span class="Constant">32/space</span>
    <span class="muControl">break-unless</span> ending-assignment?
    color<span class="Special"> &lt;- </span>copy <span class="Constant">7/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
]

<span class="muScenario">scenario</span> render-colors-assignment [
  assume-screen <span class="Constant">8/width</span>, <span class="Constant">5/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/left</span>, <span class="Constant">8/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/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> 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
    <span class="muControl">loop-unless</span> found?
    <span class="muControl">break-if</span> quit?  <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>
    t:address:touch-event<span class="Special"> &lt;- </span>maybe-convert e, <span class="Constant">touch:variant</span>
    <span class="Delimiter">{</span>
      <span class="muControl">break-unless</span> t
      move-cursor-in-editor screen, editor, *t
    <span class="Delimiter">}</span>
    <span class="Comment"># keyboard events</span>
    <span class="Delimiter">{</span>
      <span class="muControl">break-if</span> t
      handle-keyboard-event screen, console, editor, e
    <span class="Delimiter">}</span>
    <span class="Comment"># send any changes to screen</span>
    row:number, screen<span class="Special"> &lt;- </span>render screen, editor
    <span class="Comment"># clear final line, in case we just processed a backspace</span>
    left:number<span class="Special"> &lt;- </span>get *editor, <span class="Constant">left:offset</span>
    right:number<span class="Special"> &lt;- </span>get *editor, <span class="Constant">right:offset</span>
    row<span class="Special"> &lt;- </span>add row, <span class="Constant">1</span>
    move-cursor screen, row, left
    clear-line-delimited screen, left, right
    <span class="muControl">loop</span>
  <span class="Delimiter">}</span>
]

<span class="muRecipe">recipe</span> handle-keyboard-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
  <span class="Comment"># character</span>
  <span class="Delimiter">{</span>
    c:address:character<span class="Special"> &lt;- </span>maybe-convert e, <span class="Constant">text:variant</span>
    <span class="muControl">break-unless</span> c
<span class="CommentedCode">#?     trace [app], [handle-keyboard-event: special character] #? 1</span>
    <span class="Comment"># exceptions for special characters go here</span>
<span class="Constant">    +handle-special-character</span>
    <span class="Comment"># otherwise type it in</span>
    insert-at-cursor editor, *c, screen
    <span class="muControl">reply</span>
  <span class="Delimiter">}</span>
  <span class="Comment"># special key to modify the text or move the cursor</span>
  k:address:number<span class="Special"> &lt;- </span>maybe-convert e:event, <span class="Constant">keycode:variant</span>
  assert k, <span class="Constant">[event was of unknown type; neither keyboard nor mouse]</span>
  before-cursor:address:address:duplex-list<span class="Special"> &lt;- </span>get-address *editor, <span class="Constant">before-cursor:offset</span>
  cursor-row:address:number<span class="Special"> &lt;- </span>get-address *editor, <span class="Constant">cursor-row:offset</span>
  cursor-column:address:number<span class="Special"> &lt;- </span>get-address *editor, <span class="Constant">cursor-column:offset</span>
  screen-height:number<span class="Special"> &lt;- </span>screen-height screen
  left:number<span class="Special"> &lt;- </span>get *editor, <span class="Constant">left:offset</span>
  right:number<span class="Special"> &lt;- </span>get *editor, <span class="Constant">right:offset</span>
  <span class="Comment"># handlers for each special key will go here</span>
<span class="Constant">  +handle-special-key</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, <span class="Constant">0/false</span>
  click-column:number<span class="Special"> &lt;- </span>get t, <span class="Constant">column:offset</span>
  left:number<span class="Special"> &lt;- </span>get *editor, <span class="Constant">left:offset</span>
  too-far-left?:boolean<span class="Special"> &lt;- </span>lesser-than click-column, left
  <span class="muControl">reply-if</span> too-far-left?, <span class="Constant">0/false</span>
  right:number<span class="Special"> &lt;- </span>get *editor, <span class="Constant">right:offset</span>
  too-far-right?:boolean<span class="Special"> &lt;- </span>greater-than click-column, right
  <span class="muControl">reply-if</span> too-far-right?, <span class="Constant">0/false</span>
  <span class="Comment"># update cursor</span>
  cursor-row:address:number<span class="Special"> &lt;- </span>get-address *editor, <span class="Constant">cursor-row:offset</span>
  *cursor-row<span class="Special"> &lt;- </span>get t, <span class="Constant">row:offset</span>
  cursor-column:address:number<span class="Special"> &lt;- </span>get-address *editor, <span class="Constant">cursor-column:offset</span>
  *cursor-column<span class="Special"> &lt;- </span>get t, <span class="Constant">column:offset</span>
  <span class="Comment"># gain focus</span>
  <span class="muControl">reply</span> <span class="Constant">1/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>
  before-cursor:address:address:duplex-list<span class="Special"> &lt;- </span>get-address *editor, <span class="Constant">before-cursor:offset</span>
  insert-duplex c, *before-cursor
  *before-cursor<span class="Special"> &lt;- </span>next-duplex *before-cursor
  cursor-row:address:number<span class="Special"> &lt;- </span>get-address *editor, <span class="Constant">cursor-row:offset</span>
  cursor-column:address:number<span class="Special"> &lt;- </span>get-address *editor, <span class="Constant">cursor-column:offset</span>
  left:number<span class="Special"> &lt;- </span>get *editor, <span class="Constant">left:offset</span>
  right:number<span class="Special"> &lt;- </span>get *editor, <span class="Constant">right:offset</span>
  <span class="Comment"># occasionally we'll need to mess with the cursor</span>
<span class="Constant">  +insert-character-special-case</span>
  <span class="Comment"># but mostly we'll just move the cursor right</span>
  *cursor-column<span class="Special"> &lt;- </span>add *cursor-column, <span class="Constant">1</span>
]

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

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

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

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

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

<span class="muScenario">scenario</span> editor-inserts-characters-into-empty-editor [
  assume-screen <span class="Constant">10/width</span>, <span class="Constant">5/height</span>
  <span class="Constant">1</span>:address:array:character<span class="Special"> &lt;- </span>new <span class="Constant">[]</span>
  <span class="Constant">2</span>:address:editor-data<span class="Special"> &lt;- </span>new-editor <span class="Constant">1</span>:address:array:character, screen:address, <span class="Constant">0/left</span>, <span class="Constant">5/right</span>
  assume-console [
    type <span class="Constant">[abc]</span>
  ]
  run [
    editor-event-loop screen:address, console:address, <span class="Constant">2</span>: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/width</span>, <span class="Constant">5/height</span>
  <span class="Constant">1</span>:address:array:character<span class="Special"> &lt;- </span>new <span class="Constant">[abc]</span>
  <span class="Constant">2</span>:address:editor-data<span class="Special"> &lt;- </span>new-editor <span class="Constant">1</span>:address:array:character, screen:address, <span class="Constant">0/left</span>, <span class="Constant">10/right</span>
  assume-console [
    type <span class="Constant">[0]</span>
    left-click <span class="Constant">1</span>, <span class="Constant">2</span>
    type <span class="Constant">[d]</span>
  ]
  run [
    editor-event-loop screen:address, console:address, <span class="Constant">2</span>: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/width</span>, <span class="Constant">5/height</span>
  <span class="Constant">1</span>:address:array:character<span class="Special"> &lt;- </span>new <span class="Constant">[abc]</span>
  <span class="Constant">2</span>:address:editor-data<span class="Special"> &lt;- </span>new-editor <span class="Constant">1</span>:address:array:character, screen:address, <span class="Constant">0/left</span>, <span class="Constant">10/right</span>
  assume-console [
    left-click <span class="Constant">1</span>, <span class="Constant">5</span>  <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, <span class="Constant">2</span>: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/width</span>, <span class="Constant">5/height</span>
  <span class="Constant">1</span>:address:array:character<span class="Special"> &lt;- </span>new <span class="Constant">[abc]</span>
  <span class="Constant">2</span>:address:editor-data<span class="Special"> &lt;- </span>new-editor <span class="Constant">1</span>:address:array:character, screen:address, <span class="Constant">0/left</span>, <span class="Constant">10/right</span>
  assume-console [
    left-click <span class="Constant">3</span>, <span class="Constant">5</span>  <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, <span class="Constant">2</span>: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/width</span>, <span class="Constant">5/height</span>
  <span class="Constant">1</span>:address:array:character<span class="Special"> &lt;- </span>new <span class="Constant">[abc</span>
<span class="Constant">d]</span>
  <span class="Constant">2</span>:address:editor-data<span class="Special"> &lt;- </span>new-editor <span class="Constant">1</span>:address:array:character, screen:address, <span class="Constant">0/left</span>, <span class="Constant">10/right</span>
  assume-console [
    left-click <span class="Constant">3</span>, <span class="Constant">5</span>  <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, <span class="Constant">2</span>: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/width</span>, <span class="Constant">5/height</span>
  <span class="Constant">1</span>:address:array:character<span class="Special"> &lt;- </span>new <span class="Constant">[abc</span>
<span class="Constant">d]</span>
  <span class="Constant">2</span>:address:editor-data<span class="Special"> &lt;- </span>new-editor <span class="Constant">1</span>:address:array:character, screen:address, <span class="Constant">0/left</span>, <span class="Constant">10/right</span>
  assume-console [
    left-click <span class="Constant">3</span>, <span class="Constant">5</span>  <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, <span class="Constant">2</span>: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-moves-cursor-after-inserting-characters [
  assume-screen <span class="Constant">10/width</span>, <span class="Constant">5/height</span>
  <span class="Constant">1</span>:address:array:character<span class="Special"> &lt;- </span>new <span class="Constant">[ab]</span>
  <span class="Constant">2</span>:address:editor-data<span class="Special"> &lt;- </span>new-editor <span class="Constant">1</span>:address:array:character, screen:address, <span class="Constant">0/left</span>, <span class="Constant">5/right</span>
  assume-console [
    type <span class="Constant">[01]</span>
  ]
  run [
    editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data
  ]
  screen-should-contain [
   <span class="Constant"> .          .</span>
   <span class="Constant"> .01ab      .</span>
   <span class="Constant"> .          .</span>
  ]
]

<span class="Comment"># if the cursor reaches the right margin, wrap the line</span>

<span class="muScenario">scenario</span> editor-wraps-line-on-insert [
  assume-screen <span class="Constant">5/width</span>, <span class="Constant">5/height</span>
  <span class="Constant">1</span>:address:array:character<span class="Special"> &lt;- </span>new <span class="Constant">[abc]</span>
  <span class="Constant">2</span>:address:editor-data<span class="Special"> &lt;- </span>new-editor <span class="Constant">1</span>:address:array:character, screen:address, <span class="Constant">0/left</span>, <span class="Constant">5/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, <span class="Constant">2</span>: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, <span class="Constant">2</span>: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="muRecipe">after</span> +insert-character-special-case [
  <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, <span class="Constant">1</span>
    at-wrap?:boolean<span class="Special"> &lt;- </span>greater-or-equal *cursor-column, wrap-column
    <span class="muControl">break-unless</span> at-wrap?
    *cursor-column<span class="Special"> &lt;- </span>subtract *cursor-column, wrap-column
    *cursor-row<span class="Special"> &lt;- </span>add *cursor-row, <span class="Constant">1</span>
    <span class="Comment"># if we're out of the screen, scroll down</span>
    <span class="Delimiter">{</span>
      screen-height:number<span class="Special"> &lt;- </span>screen-height screen
      below-screen?:boolean<span class="Special"> &lt;- </span>greater-or-equal *cursor-row, screen-height
      <span class="muControl">break-unless</span> below-screen?
<span class="Constant">      +scroll-down</span>
    <span class="Delimiter">}</span>
    <span class="muControl">reply</span>
  <span class="Delimiter">}</span>
]

<span class="muScenario">scenario</span> editor-wraps-cursor-after-inserting-characters [
  assume-screen <span class="Constant">10/width</span>, <span class="Constant">5/height</span>
  <span class="Constant">1</span>:address:array:character<span class="Special"> &lt;- </span>new <span class="Constant">[abcde]</span>
  <span class="Constant">2</span>:address:editor-data<span class="Special"> &lt;- </span>new-editor <span class="Constant">1</span>:address:array:character, screen:address, <span class="Constant">0/left</span>, <span class="Constant">5/right</span>
  assume-console [
    left-click <span class="Constant">1</span>, <span class="Constant">4</span>  <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, <span class="Constant">2</span>:address:editor-data
    <span class="Constant">3</span>:number<span class="Special"> &lt;- </span>get *<span class="Constant">2</span>:address:editor-data, <span class="Constant">cursor-row:offset</span>
    <span class="Constant">4</span>:number<span class="Special"> &lt;- </span>get *<span class="Constant">2</span>:address:editor-data, <span class="Constant">cursor-column:offset</span>
  ]
  screen-should-contain [
   <span class="Constant"> .          .</span>
   <span class="Constant"> .abcd↩     .</span>
   <span class="Constant"> .fe        .</span>
   <span class="Constant"> .          .</span>
  ]
  memory-should-contain [
    <span class="Constant">3</span><span class="Special"> &lt;- </span><span class="Constant">2</span>  <span class="Comment"># cursor row</span>
    <span class="Constant">4</span><span class="Special"> &lt;- </span><span class="Constant">1</span>  <span class="Comment"># cursor column</span>
  ]
]

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

<span class="Comment"># if newline, move cursor to start of next line</span>

<span class="muScenario">scenario</span> editor-moves-cursor-down-after-inserting-newline [
  assume-screen <span class="Constant">10/width</span>, <span class="Constant">5/height</span>
  <span class="Constant">1</span>:address:array:character<span class="Special"> &lt;- </span>new <span class="Constant">[abc]</span>
  <span class="Constant">2</span>:address:editor-data<span class="Special"> &lt;- </span>new-editor <span class="Constant">1</span>:address:array:character, screen:address, <span class="Constant">0/left</span>, <span class="Constant">10/right</span>
  assume-console [
    type <span class="Constant">[0</span>
<span class="Constant">1]</span>
  ]
  run [
    editor-event-loop screen:address, console:address, <span class="Constant">2</span>: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="muRecipe">after</span> +insert-character-special-case [
  <span class="Delimiter">{</span>
    newline?:boolean<span class="Special"> &lt;- </span>equal c, <span class="Constant">10/newline</span>
    <span class="muControl">break-unless</span> newline?
    *cursor-row<span class="Special"> &lt;- </span>add *cursor-row, <span class="Constant">1</span>
    *cursor-column<span class="Special"> &lt;- </span>copy left
    <span class="Delimiter">{</span>
      screen-height:number<span class="Special"> &lt;- </span>screen-height screen
      below-screen?:boolean<span class="Special"> &lt;- </span>greater-or-equal *cursor-row, screen-height  <span class="Comment"># must be equal, never greater</span>
      <span class="muControl">break-unless</span> below-screen?
<span class="Constant">      +scroll-down</span>
      *cursor-row<span class="Special"> &lt;- </span>subtract *cursor-row, <span class="Constant">1</span>  <span class="Comment"># bring back into screen range</span>
    <span class="Delimiter">}</span>
    <span class="Comment"># indent if necessary</span>
    d:address:duplex-list<span class="Special"> &lt;- </span>get *editor, <span class="Constant">data:offset</span>
    end-of-previous-line:address:duplex-list<span class="Special"> &lt;- </span>prev-duplex *before-cursor
    indent:number<span class="Special"> &lt;- </span>line-indent end-of-previous-line, d
    i:number<span class="Special"> &lt;- </span>copy <span class="Constant">0</span>
    <span class="Delimiter">{</span>
      indent-done?:boolean<span class="Special"> &lt;- </span>greater-or-equal i, indent
      <span class="muControl">break-if</span> indent-done?
      insert-at-cursor editor, <span class="Constant">32/space</span>, screen
      i<span class="Special"> &lt;- </span>add i, <span class="Constant">1</span>
      <span class="muControl">loop</span>
    <span class="Delimiter">}</span>
    <span class="muControl">reply</span>
  <span class="Delimiter">}</span>
]

<span class="Comment"># takes a pointer 'curr' into the doubly-linked list and its sentinel, counts</span>
<span class="Comment"># the number of spaces at the start of the line containing 'curr'.</span>
<span class="muRecipe">recipe</span> line-indent [
  <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</span>
  <span class="muControl">reply-unless</span> curr, result
  at-start?:boolean<span class="Special"> &lt;- </span>equal curr, start
  <span class="muControl">reply-if</span> at-start?, result
  <span class="Delimiter">{</span>
    curr<span class="Special"> &lt;- </span>prev-duplex curr
    <span class="muControl">break-unless</span> curr
    at-start?:boolean<span class="Special"> &lt;- </span>equal curr, start
    <span class="muControl">break-if</span> at-start?
    c:character<span class="Special"> &lt;- </span>get *curr, <span class="Constant">value:offset</span>
    at-newline?:boolean<span class="Special"> &lt;- </span>equal c, <span class="Constant">10/newline</span>
    <span class="muControl">break-if</span> at-newline?
    <span class="Comment"># if c is a space, increment result</span>
    is-space?:boolean<span class="Special"> &lt;- </span>equal c, <span class="Constant">32/space</span>
    <span class="Delimiter">{</span>
      <span class="muControl">break-unless</span> is-space?
      result<span class="Special"> &lt;- </span>add result, <span class="Constant">1</span>
    <span class="Delimiter">}</span>
    <span class="Comment"># if c is not a space, reset result</span>
    <span class="Delimiter">{</span>
      <span class="muControl">break-if</span> is-space?
      result<span class="Special"> &lt;- </span>copy <span class="Constant">0</span>
    <span class="Delimiter">}</span>
    <span class="muControl">loop</span>
  <span class="Delimiter">}</span>
  <span class="muControl">reply</span> result
]

<span class="muScenario">scenario</span> editor-moves-cursor-down-after-inserting-newline-2 [
  assume-screen <span class="Constant">10/width</span>, <span class="Constant">5/height</span>
  <span class="Constant">1</span>:address:array:character<span class="Special"> &lt;- </span>new <span class="Constant">[abc]</span>
  <span class="Constant">2</span>:address:editor-data<span class="Special"> &lt;- </span>new-editor <span class="Constant">1</span>:address:array:character, screen:address, <span class="Constant">1/left</span>, <span class="Constant">10/right</span>
  assume-console [
    type <span class="Constant">[0</span>
<span class="Constant">1]</span>
  ]
  run [
    editor-event-loop screen:address, console:address, <span class="Constant">2</span>: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/width</span>, <span class="Constant">5/height</span>
  <span class="Constant">1</span>:address:array:character<span class="Special"> &lt;- </span>new <span class="Constant">[abcde]</span>
  <span class="Constant">2</span>:address:editor-data<span class="Special"> &lt;- </span>new-editor <span class="Constant">1</span>:address:array:character, screen:address, <span class="Constant">0/left</span>, <span class="Constant">5/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, <span class="Constant">2</span>: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-inserts-indent-after-newline [
  assume-screen <span class="Constant">10/width</span>, <span class="Constant">10/height</span>
  <span class="Constant">1</span>:address:array:character<span class="Special"> &lt;- </span>new <span class="Constant">[ab</span>
<span class="Constant">  cd</span>
<span class="Constant">ef]</span>
  <span class="Constant">2</span>:address:editor-data<span class="Special"> &lt;- </span>new-editor <span class="Constant">1</span>:address:array:character, screen:address, <span class="Constant">0/left</span>, <span class="Constant">10/right</span>
  <span class="Comment"># position cursor after 'cd' and hit 'newline'</span>
  assume-console [
    left-click <span class="Constant">2</span>, <span class="Constant">8</span>
    type [
]
  ]
  run [
    editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data
    <span class="Constant">3</span>:number<span class="Special"> &lt;- </span>get *<span class="Constant">2</span>:address:editor-data, <span class="Constant">cursor-row:offset</span>
    <span class="Constant">4</span>:number<span class="Special"> &lt;- </span>get *<span class="Constant">2</span>:address:editor-data, <span class="Constant">cursor-column:offset</span>
  ]
  <span class="Comment"># cursor should be below start of previous line</span>
  memory-should-contain [
    <span class="Constant">3</span><span class="Special"> &lt;- </span><span class="Constant">3</span>  <span class="Comment"># cursor row</span>
    <span class="Constant">4</span><span class="Special"> &lt;- </span><span class="Constant">2</span>  <span class="Comment"># cursor column (indented)</span>
  ]
]

<span class="SalientComment">## special shortcuts for manipulating the editor</span>
<span class="Comment"># Some keys on the keyboard generate unicode characters, others generate</span>
<span class="Comment"># terminfo key codes. We need to modify different places in the two cases.</span>

<span class="Comment"># tab - insert two spaces</span>

<span class="muScenario">scenario</span> editor-inserts-two-spaces-on-tab [
  assume-screen <span class="Constant">10/width</span>, <span class="Constant">5/height</span>
  <span class="Comment"># just one character in final line</span>
  <span class="Constant">1</span>:address:array:character<span class="Special"> &lt;- </span>new <span class="Constant">[ab</span>
<span class="Constant">cd]</span>
  <span class="Constant">2</span>:address:editor-data<span class="Special"> &lt;- </span>new-editor <span class="Constant">1</span>:address:array:character, screen:address, <span class="Constant">0/left</span>, <span class="Constant">5/right</span>
  assume-console [
    type <span class="Constant">[»]</span>
  ]
  <span class="Constant">3</span>:event/tab<span class="Special"> &lt;- </span>merge <span class="Constant">0/text</span>, <span class="Constant">9/tab</span>, <span class="Constant">0/dummy</span>, <span class="Constant">0/dummy</span>
  replace-in-console <span class="Constant">187/»</span>, <span class="Constant">3</span>:event/tab
  run [
    editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data
  ]
  screen-should-contain [
   <span class="Constant"> .          .</span>
   <span class="Constant"> .  ab      .</span>
   <span class="Constant"> .cd        .</span>
  ]
]

<span class="muRecipe">after</span> +handle-special-character [
  <span class="Delimiter">{</span>
    tab?:boolean<span class="Special"> &lt;- </span>equal *c, <span class="Constant">9/tab</span>
    <span class="muControl">break-unless</span> tab?
    insert-at-cursor editor, <span class="Constant">32/space</span>, screen
    insert-at-cursor editor, <span class="Constant">32/space</span>, screen
    <span class="muControl">reply</span>
  <span class="Delimiter">}</span>
]

<span class="Comment"># backspace - delete character before cursor</span>

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

<span class="muRecipe">after</span> +handle-special-character [
  <span class="Delimiter">{</span>
    backspace?:boolean<span class="Special"> &lt;- </span>equal *c, <span class="Constant">8/backspace</span>
    <span class="muControl">break-unless</span> backspace?
    delete-before-cursor editor
    <span class="muControl">reply</span>
  <span class="Delimiter">}</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, <span class="Constant">before-cursor:offset</span>
  <span class="Comment"># if at start of text (before-cursor at § sentinel), return</span>
  prev:address:duplex-list<span class="Special"> &lt;- </span>prev-duplex *before-cursor
  <span class="muControl">reply-unless</span> prev
<span class="CommentedCode">#?   trace [app], [delete-before-cursor] #? 1</span>
  editor<span class="Special"> &lt;- </span>move-cursor-coordinates-left editor
  remove-duplex *before-cursor
  *before-cursor<span class="Special"> &lt;- </span>copy prev
]

<span class="muRecipe">recipe</span> move-cursor-coordinates-left [
  <span class="Constant">local-scope</span>
  editor:address:editor-data<span class="Special"> &lt;- </span><span class="Constant">next-ingredient</span>
  before-cursor:address:duplex-list<span class="Special"> &lt;- </span>get *editor, <span class="Constant">before-cursor:offset</span>
  cursor-row:address:number<span class="Special"> &lt;- </span>get-address *editor, <span class="Constant">cursor-row:offset</span>
  cursor-column:address:number<span class="Special"> &lt;- </span>get-address *editor, <span class="Constant">cursor-column:offset</span>
  left:number<span class="Special"> &lt;- </span>get *editor, <span class="Constant">left:offset</span>
  <span class="Comment"># if 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, left
    <span class="muControl">break-if</span> at-left-margin?
<span class="CommentedCode">#?     trace [app], [decrementing cursor column] #? 1</span>
    *cursor-column<span class="Special"> &lt;- </span>subtract *cursor-column, <span class="Constant">1</span>
    <span class="muControl">reply</span> editor/same-as-ingredient:<span class="Constant">0</span>
  <span class="Delimiter">}</span>
  <span class="Comment"># if at left margin, we must move to previous row:</span>
  top-of-screen?:boolean<span class="Special"> &lt;- </span>equal *cursor-row, <span class="Constant">1</span>  <span class="Comment"># exclude menu bar</span>
  <span class="Delimiter">{</span>
    <span class="muControl">break-if</span> top-of-screen?
    *cursor-row<span class="Special"> &lt;- </span>subtract *cursor-row, <span class="Constant">1</span>
  <span class="Delimiter">}</span>
  <span class="Delimiter">{</span>
    <span class="muControl">break-unless</span> top-of-screen?
<span class="Constant">    +scroll-up</span>
  <span class="Delimiter">}</span>
  <span class="Delimiter">{</span>
    <span class="Comment"># case 1: if previous character was newline, figure out how long the previous line is</span>
    previous-character:character<span class="Special"> &lt;- </span>get *before-cursor, <span class="Constant">value:offset</span>
    previous-character-is-newline?:boolean<span class="Special"> &lt;- </span>equal previous-character, <span class="Constant">10/newline</span>
    <span class="muControl">break-unless</span> previous-character-is-newline?
    <span class="Comment"># compute length of previous line</span>
<span class="CommentedCode">#?     trace [app], [switching to previous line] #? 1</span>
    d:address:duplex-list<span class="Special"> &lt;- </span>get *editor, <span class="Constant">data:offset</span>
    end-of-line:number<span class="Special"> &lt;- </span>previous-line-length before-cursor, d
    *cursor-column<span class="Special"> &lt;- </span>add left, end-of-line
    <span class="muControl">reply</span> editor/same-as-ingredient:<span class="Constant">0</span>
  <span class="Delimiter">}</span>
  <span class="Comment"># case 2: if previous-character was not newline, we're just at a wrapped line</span>
<span class="CommentedCode">#?   trace [app], [wrapping to previous line] #? 1</span>
  right:number<span class="Special"> &lt;- </span>get *editor, <span class="Constant">right:offset</span>
  *cursor-column<span class="Special"> &lt;- </span>subtract right, <span class="Constant">1</span>  <span class="Comment"># leave room for wrap icon</span>
  <span class="muControl">reply</span> editor/same-as-ingredient:<span class="Constant">0</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</span>
  <span class="muControl">reply-unless</span> curr, result
  at-start?:boolean<span class="Special"> &lt;- </span>equal curr, start
  <span class="muControl">reply-if</span> at-start?, result
  <span class="Delimiter">{</span>
    curr<span class="Special"> &lt;- </span>prev-duplex curr
    <span class="muControl">break-unless</span> curr
    at-start?:boolean<span class="Special"> &lt;- </span>equal curr, start
    <span class="muControl">break-if</span> at-start?
    c:character<span class="Special"> &lt;- </span>get *curr, <span class="Constant">value:offset</span>
    at-newline?:boolean<span class="Special"> &lt;- </span>equal c, <span class="Constant">10/newline</span>
    <span class="muControl">break-if</span> at-newline?
    result<span class="Special"> &lt;- </span>add result, <span class="Constant">1</span>
    <span class="muControl">loop</span>
  <span class="Delimiter">}</span>
  <span class="muControl">reply</span> result
]

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

<span class="Comment"># delete - delete character at cursor</span>

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

<span class="muRecipe">after</span> +handle-special-key [
  <span class="Delimiter">{</span>
    delete?:boolean<span class="Special"> &lt;- </span>equal *k, <span class="Constant">65522/delete</span>
    <span class="muControl">break-unless</span> delete?
    curr:address:duplex-list<span class="Special"> &lt;- </span>get **before-cursor, <span class="Constant">next:offset</span>
    _<span class="Special"> &lt;- </span>remove-duplex curr
    <span class="muControl">reply</span>
  <span class="Delimiter">}</span>
]

<span class="Comment"># right arrow</span>

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

<span class="muRecipe">after</span> +handle-special-key [
  <span class="Delimiter">{</span>
    move-to-next-character?:boolean<span class="Special"> &lt;- </span>equal *k, <span class="Constant">65514/right-arrow</span>
    <span class="muControl">break-unless</span> move-to-next-character?
    <span class="Comment"># if not at end of text</span>
    old-cursor:address:duplex-list<span class="Special"> &lt;- </span>next-duplex *before-cursor
    <span class="muControl">break-unless</span> old-cursor
    <span class="Comment"># scan to next character</span>
    *before-cursor<span class="Special"> &lt;- </span>copy old-cursor
    <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, <span class="Constant">value:offset</span>
      was-at-newline?:boolean<span class="Special"> &lt;- </span>equal old-cursor-character, <span class="Constant">10/newline</span>
      <span class="muControl">break-unless</span> was-at-newline?
      *cursor-row<span class="Special"> &lt;- </span>add *cursor-row, <span class="Constant">1</span>
      *cursor-column<span class="Special"> &lt;- </span>copy left
      below-screen?:boolean<span class="Special"> &lt;- </span>greater-or-equal *cursor-row, screen-height  <span class="Comment"># must be equal</span>
      <span class="muControl">reply-unless</span> below-screen?
<span class="Constant">      +scroll-down</span>
      *cursor-row<span class="Special"> &lt;- </span>subtract *cursor-row, <span class="Constant">1</span>  <span class="Comment"># bring back into screen range</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, <span class="Constant">1</span>
      at-wrap?:boolean<span class="Special"> &lt;- </span>equal *cursor-column, wrap-column
      <span class="muControl">break-unless</span> at-wrap?
      <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
      <span class="muControl">break-unless</span> new-cursor
      next-character:character<span class="Special"> &lt;- </span>get *new-cursor, <span class="Constant">value:offset</span>
      newline?:boolean<span class="Special"> &lt;- </span>equal next-character, <span class="Constant">10/newline</span>
      <span class="muControl">break-if</span> newline?
      *cursor-row<span class="Special"> &lt;- </span>add *cursor-row, <span class="Constant">1</span>
      *cursor-column<span class="Special"> &lt;- </span>copy left
      below-screen?:boolean<span class="Special"> &lt;- </span>greater-or-equal *cursor-row, screen-height  <span class="Comment"># must be equal</span>
      <span class="muControl">reply-unless</span> below-screen?
<span class="Constant">      +scroll-down</span>
      *cursor-row<span class="Special"> &lt;- </span>subtract *cursor-row, <span class="Constant">1</span>  <span class="Comment"># bring back into screen range</span>
      <span class="muControl">reply</span>
    <span class="Delimiter">}</span>
    <span class="Comment"># otherwise move cursor one character right</span>
    *cursor-column<span class="Special"> &lt;- </span>add *cursor-column, <span class="Constant">1</span>
  <span class="Delimiter">}</span>
]

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

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

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

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

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

<span class="muRecipe">after</span> +handle-special-key [
  <span class="Delimiter">{</span>
    move-to-previous-character?:boolean<span class="Special"> &lt;- </span>equal *k, <span class="Constant">65515/left-arrow</span>
    <span class="muControl">break-unless</span> move-to-previous-character?
<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
    <span class="muControl">break-unless</span> prev
    editor<span class="Special"> &lt;- </span>move-cursor-coordinates-left editor
  <span class="Delimiter">}</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/width</span>, <span class="Constant">5/height</span>
  <span class="Comment"># initialize editor with two lines</span>
  <span class="Constant">1</span>:address:array:character<span class="Special"> &lt;- </span>new <span class="Constant">[abc</span>
<span class="Constant">d]</span>
  <span class="Constant">2</span>:address:editor-data<span class="Special"> &lt;- </span>new-editor <span class="Constant">1</span>:address:array:character, screen:address, <span class="Constant">0/left</span>, <span class="Constant">10/right</span>
  <span class="Comment"># position cursor at start of second line (so there's no previous newline)</span>
  assume-console [
    left-click <span class="Constant">2</span>, <span class="Constant">0</span>
    press <span class="Constant">65515</span>  <span class="Comment"># left arrow</span>
  ]
  run [
    editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data
    <span class="Constant">3</span>:number<span class="Special"> &lt;- </span>get *<span class="Constant">2</span>:address:editor-data, <span class="Constant">cursor-row:offset</span>
    <span class="Constant">4</span>:number<span class="Special"> &lt;- </span>get *<span class="Constant">2</span>:address:editor-data, <span class="Constant">cursor-column:offset</span>
  ]
  memory-should-contain [
    <span class="Constant">3</span><span class="Special"> &lt;- </span><span class="Constant">1</span>
    <span class="Constant">4</span><span class="Special"> &lt;- </span><span class="Constant">3</span>
  ]
]

<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/width</span>, <span class="Constant">5/height</span>
  <span class="Comment"># initialize editor with three lines</span>
  <span class="Constant">1</span>:address:array:character<span class="Special"> &lt;- </span>new <span class="Constant">[abc</span>
<span class="Constant">def</span>
<span class="Constant">g]</span>
  <span class="Constant">2</span>:address:editor-data<span class="Special"> &lt;- </span>new-editor <span class="Constant">1</span>:address:array:character, screen:address, <span class="Constant">0/left</span>, <span class="Constant">10/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 <span class="Constant">3</span>, <span class="Constant">0</span>
    press <span class="Constant">65515</span>  <span class="Comment"># left arrow</span>
    type <span class="Constant">[0]</span>
  ]
  run [
    editor-event-loop screen:address, console:address, <span class="Constant">2</span>: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/width</span>, <span class="Constant">5/height</span>
  <span class="Constant">1</span>:address:array:character<span class="Special"> &lt;- </span>new <span class="Constant">[abc</span>
<span class="Constant">def</span>
<span class="Constant">g]</span>
  <span class="Constant">2</span>:address:editor-data<span class="Special"> &lt;- </span>new-editor <span class="Constant">1</span>:address:array:character, screen:address, <span class="Constant">0/left</span>, <span class="Constant">10/right</span>
  <span class="Comment"># position cursor at start of text</span>
  assume-console [
    left-click <span class="Constant">1</span>, <span class="Constant">0</span>
    press <span class="Constant">65515</span>  <span class="Comment"># left arrow should have no effect</span>
    type <span class="Constant">[0]</span>
  ]
  run [
    editor-event-loop screen:address, console:address, <span class="Constant">2</span>: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/width</span>, <span class="Constant">5/height</span>
  <span class="Comment"># initialize editor with text containing an empty line</span>
  <span class="Constant">1</span>:address:array:character<span class="Special"> &lt;- </span>new <span class="Constant">[abc</span>

d]
  <span class="Constant">2</span>:address:editor-data<span class="Special"> &lt;- </span>new-editor <span class="Constant">1</span>:address:array:character, screen:address, <span class="Constant">0/left</span>, <span class="Constant">10/right</span>
  <span class="Comment"># position cursor right after empty line</span>
  assume-console [
    left-click <span class="Constant">3</span>, <span class="Constant">0</span>
    press <span class="Constant">65515</span>  <span class="Comment"># left arrow</span>
    type <span class="Constant">[0]</span>
  ]
  run [
    editor-event-loop screen:address, console:address, <span class="Constant">2</span>: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/width</span>, <span class="Constant">5/height</span>
  <span class="Comment"># initialize editor with text containing an empty line</span>
  <span class="Constant">1</span>:address:array:character<span class="Special"> &lt;- </span>new <span class="Constant">[abcdef]</span>
  <span class="Constant">2</span>:address:editor-data<span class="Special"> &lt;- </span>new-editor <span class="Constant">1</span>:address:array:character, screen:address, <span class="Constant">0/left</span>, <span class="Constant">5/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 <span class="Constant">2</span>, <span class="Constant">0</span>
    press <span class="Constant">65515</span>  <span class="Comment"># left arrow</span>
  ]
  run [
    editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data
    <span class="Constant">3</span>:number<span class="Special"> &lt;- </span>get *<span class="Constant">2</span>:address:editor-data, <span class="Constant">cursor-row:offset</span>
    <span class="Constant">4</span>:number<span class="Special"> &lt;- </span>get *<span class="Constant">2</span>:address:editor-data, <span class="Constant">cursor-column:offset</span>
  ]
  memory-should-contain [
    <span class="Constant">3</span><span class="Special"> &lt;- </span><span class="Constant">1</span>  <span class="Comment"># previous row</span>
    <span class="Constant">4</span><span class="Special"> &lt;- </span><span class="Constant">3</span>  <span class="Comment"># end of wrapped line</span>
  ]
]

<span class="Comment"># up arrow</span>

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

<span class="muRecipe">after</span> +handle-special-key [
  <span class="Delimiter">{</span>
    move-to-previous-line?:boolean<span class="Special"> &lt;- </span>equal *k, <span class="Constant">65517/up-arrow</span>
    <span class="muControl">break-unless</span> move-to-previous-line?
    already-at-top?:boolean<span class="Special"> &lt;- </span>lesser-or-equal *cursor-row, <span class="Constant">1/top</span>
    <span class="Delimiter">{</span>
      <span class="Comment"># if cursor not at top, move it</span>
      <span class="muControl">break-if</span> already-at-top?
      *cursor-row<span class="Special"> &lt;- </span>subtract *cursor-row, <span class="Constant">1</span>
    <span class="Delimiter">}</span>
    <span class="Delimiter">{</span>
      <span class="Comment"># if cursor already at top, scroll up</span>
      <span class="muControl">break-unless</span> already-at-top?
<span class="Constant">      +scroll-up</span>
    <span class="Delimiter">}</span>
    <span class="Comment"># that's it; render will adjust cursor-column as necessary</span>
  <span class="Delimiter">}</span>
]

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

<span class="Comment"># down arrow</span>

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

<span class="muRecipe">after</span> +handle-special-key [
  <span class="Delimiter">{</span>
    move-to-next-line?:boolean<span class="Special"> &lt;- </span>equal *k, <span class="Constant">65516/down-arrow</span>
    <span class="muControl">break-unless</span> move-to-next-line?
    last-line:number<span class="Special"> &lt;- </span>subtract screen-height, <span class="Constant">1</span>
    already-at-bottom?:boolean<span class="Special"> &lt;- </span>greater-or-equal *cursor-row, last-line
    <span class="Delimiter">{</span>
      <span class="Comment"># if cursor not at top, move it</span>
      <span class="muControl">break-if</span> already-at-bottom?
      *cursor-row<span class="Special"> &lt;- </span>add *cursor-row, <span class="Constant">1</span>
    <span class="Delimiter">}</span>
    <span class="Delimiter">{</span>
      <span class="Comment"># if cursor already at top, scroll up</span>
      <span class="muControl">break-unless</span> already-at-bottom?
<span class="Constant">      +scroll-down</span>
    <span class="Delimiter">}</span>
    <span class="Comment"># that's it; render will adjust cursor-column as necessary</span>
  <span class="Delimiter">}</span>
]

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

<span class="Comment"># ctrl-a/home - move cursor to start of line</span>

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

<span class="muRecipe">after</span> +handle-special-character [
  <span class="Delimiter">{</span>
    ctrl-a?:boolean<span class="Special"> &lt;- </span>equal *c, <span class="Constant">1/ctrl-a</span>
    <span class="muControl">break-unless</span> ctrl-a?
    move-to-start-of-line editor
    <span class="muControl">reply</span>
  <span class="Delimiter">}</span>
]

<span class="muRecipe">after</span> +handle-special-key [
  <span class="Delimiter">{</span>
    home?:boolean<span class="Special"> &lt;- </span>equal *k, <span class="Constant">65521/home</span>
    <span class="muControl">break-unless</span> home?
    move-to-start-of-line editor
    <span class="muControl">reply</span>
  <span class="Delimiter">}</span>
]

<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, <span class="Constant">left:offset</span>
  cursor-column:address:number<span class="Special"> &lt;- </span>get-address *editor, <span class="Constant">cursor-column:offset</span>
  *cursor-column<span class="Special"> &lt;- </span>copy left
  <span class="Comment"># update before-cursor</span>
  before-cursor:address:address:duplex-list<span class="Special"> &lt;- </span>get-address *editor, <span class="Constant">before-cursor:offset</span>
  init:address:duplex-list<span class="Special"> &lt;- </span>get *editor, <span class="Constant">data:offset</span>
  <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, init
    <span class="muControl">break-if</span> at-start-of-text?
    prev:character<span class="Special"> &lt;- </span>get **before-cursor, <span class="Constant">value:offset</span>
    at-start-of-line?:boolean<span class="Special"> &lt;- </span>equal prev, <span class="Constant">10/newline</span>
    <span class="muControl">break-if</span> at-start-of-line?
    *before-cursor<span class="Special"> &lt;- </span>prev-duplex *before-cursor
    assert *before-cursor, <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="muScenario">scenario</span> editor-moves-to-start-of-line-with-ctrl-a-2 [
  assume-screen <span class="Constant">10/width</span>, <span class="Constant">5/height</span>
  <span class="Constant">1</span>:address:array:character<span class="Special"> &lt;- </span>new <span class="Constant">[123</span>
<span class="Constant">456]</span>
  <span class="Constant">2</span>:address:editor-data<span class="Special"> &lt;- </span>new-editor <span class="Constant">1</span>:address:array:character, screen:address, <span class="Constant">0/left</span>, <span class="Constant">10/right</span>
  <span class="Comment"># start on first line (no newline before), press ctrl-a</span>
  assume-console [
    left-click <span class="Constant">1</span>, <span class="Constant">3</span>
    type <span class="Constant">[a]</span>  <span class="Comment"># ctrl-a</span>
  ]
  <span class="Constant">3</span>:event/ctrl-a<span class="Special"> &lt;- </span>merge <span class="Constant">0/text</span>, <span class="Constant">1/ctrl-a</span>, <span class="Constant">0/dummy</span>, <span class="Constant">0/dummy</span>
  replace-in-console <span class="Constant">97/a</span>, <span class="Constant">3</span>:event/ctrl-a
  run [
    editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data
    <span class="Constant">4</span>:number<span class="Special"> &lt;- </span>get *<span class="Constant">2</span>:address:editor-data, <span class="Constant">cursor-row:offset</span>
    <span class="Constant">5</span>:number<span class="Special"> &lt;- </span>get *<span class="Constant">2</span>:address:editor-data, <span class="Constant">cursor-column:offset</span>
  ]
  <span class="Comment"># cursor moves to start of line</span>
  memory-should-contain [
    <span class="Constant">4</span><span class="Special"> &lt;- </span><span class="Constant">1</span>
    <span class="Constant">5</span><span class="Special"> &lt;- </span><span class="Constant">0</span>
  ]
]

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

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

<span class="Comment"># ctrl-e/end - move cursor to end of line</span>

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

<span class="muRecipe">after</span> +handle-special-character [
  <span class="Delimiter">{</span>
    ctrl-e?:boolean<span class="Special"> &lt;- </span>equal *c, <span class="Constant">5/ctrl-e</span>
    <span class="muControl">break-unless</span> ctrl-e?
    move-to-end-of-line editor
    <span class="muControl">reply</span>
  <span class="Delimiter">}</span>
]

<span class="muRecipe">after</span> +handle-special-key [
  <span class="Delimiter">{</span>
    end?:boolean<span class="Special"> &lt;- </span>equal *k, <span class="Constant">65520/end</span>
    <span class="muControl">break-unless</span> end?
    move-to-end-of-line editor
    <span class="muControl">reply</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, <span class="Constant">before-cursor:offset</span>
  cursor-column:address:number<span class="Special"> &lt;- </span>get-address *editor, <span class="Constant">cursor-column:offset</span>
  <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
    <span class="muControl">break-unless</span> next  <span class="Comment"># end of text</span>
    nextc:character<span class="Special"> &lt;- </span>get *next, <span class="Constant">value:offset</span>
    at-end-of-line?:boolean<span class="Special"> &lt;- </span>equal nextc, <span class="Constant">10/newline</span>
    <span class="muControl">break-if</span> at-end-of-line?
    *before-cursor<span class="Special"> &lt;- </span>copy next
    *cursor-column<span class="Special"> &lt;- </span>add *cursor-column, <span class="Constant">1</span>
    <span class="muControl">loop</span>
  <span class="Delimiter">}</span>
  <span class="Comment"># move one past final character</span>
  *cursor-column<span class="Special"> &lt;- </span>add *cursor-column, <span class="Constant">1</span>
]

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

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

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

<span class="Comment"># ctrl-u - delete text from start of line until (but not at) cursor</span>

<span class="muScenario">scenario</span> editor-deletes-to-start-of-line-with-ctrl-u [
  assume-screen <span class="Constant">10/width</span>, <span class="Constant">5/height</span>
  <span class="Constant">1</span>:address:array:character<span class="Special"> &lt;- </span>new <span class="Constant">[123</span>
<span class="Constant">456]</span>
  <span class="Constant">2</span>:address:editor-data<span class="Special"> &lt;- </span>new-editor <span class="Constant">1</span>:address:array:character, screen:address, <span class="Constant">0/left</span>, <span class="Constant">10/right</span>
  <span class="Comment"># start on second line, press ctrl-u</span>
  assume-console [
    left-click <span class="Constant">2</span>, <span class="Constant">2</span>
    type <span class="Constant">[u]</span>  <span class="Comment"># ctrl-u</span>
  ]
  <span class="Constant">3</span>:event/ctrl-a<span class="Special"> &lt;- </span>merge <span class="Constant">0/text</span>, <span class="Constant">21/ctrl-u</span>, <span class="Constant">0/dummy</span>, <span class="Constant">0/dummy</span>
  replace-in-console <span class="Constant">117/u</span>, <span class="Constant">3</span>:event/ctrl-u
  run [
    editor-event-loop screen:address, console:address, <span class="Constant">2</span>: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="muRecipe">after</span> +handle-special-character [
  <span class="Delimiter">{</span>
    ctrl-u?:boolean<span class="Special"> &lt;- </span>equal *c, <span class="Constant">21/ctrl-u</span>
    <span class="muControl">break-unless</span> ctrl-u?
    delete-to-start-of-line editor
    <span class="muControl">reply</span>
  <span class="Delimiter">}</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, <span class="Constant">data:offset</span>
  before-cursor:address:address:duplex-list<span class="Special"> &lt;- </span>get-address *editor, <span class="Constant">before-cursor:offset</span>
  start:address:duplex-list<span class="Special"> &lt;- </span>copy *before-cursor
  end:address:duplex-list<span class="Special"> &lt;- </span>next-duplex *before-cursor
  <span class="Delimiter">{</span>
    at-start-of-text?:boolean<span class="Special"> &lt;- </span>equal start, init
    <span class="muControl">break-if</span> at-start-of-text?
    curr:character<span class="Special"> &lt;- </span>get *start, <span class="Constant">value:offset</span>
    at-start-of-line?:boolean<span class="Special"> &lt;- </span>equal curr, <span class="Constant">10/newline</span>
    <span class="muControl">break-if</span> at-start-of-line?
    start<span class="Special"> &lt;- </span>prev-duplex start
    assert start, <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, <span class="Constant">next:offset</span>
  *start-next<span class="Special"> &lt;- </span>copy end
  <span class="Delimiter">{</span>
    <span class="muControl">break-unless</span> end
    end-prev:address:address:duplex-list<span class="Special"> &lt;- </span>get-address *end, <span class="Constant">prev:offset</span>
    *end-prev<span class="Special"> &lt;- </span>copy start
  <span class="Delimiter">}</span>
  <span class="Comment"># adjust cursor</span>
  *before-cursor<span class="Special"> &lt;- </span>prev-duplex end
  left:number<span class="Special"> &lt;- </span>get *editor, <span class="Constant">left:offset</span>
  cursor-column:address:number<span class="Special"> &lt;- </span>get-address *editor, <span class="Constant">cursor-column:offset</span>
  *cursor-column<span class="Special"> &lt;- </span>copy left
]

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

<span class="Comment"># ctrl-k - delete text from cursor to end of line (but not the newline)</span>

<span class="muScenario">scenario</span> editor-deletes-to-end-of-line-with-ctrl-k [
  assume-screen <span class="Constant">10/width</span>, <span class="Constant">5/height</span>
  <span class="Constant">1</span>:address:array:character<span class="Special"> &lt;- </span>new <span class="Constant">[123</span>
<span class="Constant">456]</span>
  <span class="Constant">2</span>:address:editor-data<span class="Special"> &lt;- </span>new-editor <span class="Constant">1</span>:address:array:character, screen:address, <span class="Constant">0/left</span>, <span class="Constant">10/right</span>
  <span class="Comment"># start on first line, press ctrl-k</span>
  assume-console [
    left-click <span class="Constant">1</span>, <span class="Constant">1</span>
    type <span class="Constant">[k]</span>  <span class="Comment"># ctrl-k</span>
  ]
  <span class="Constant">3</span>:event/ctrl-k<span class="Special"> &lt;- </span>merge <span class="Constant">0/text</span>, <span class="Constant">11/ctrl-k</span>, <span class="Constant">0/dummy</span>, <span class="Constant">0/dummy</span>
  replace-in-console <span class="Constant">107/k</span>, <span class="Constant">3</span>:event/ctrl-k
  run [
    editor-event-loop screen:address, console:address, <span class="Constant">2</span>: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="muRecipe">after</span> +handle-special-character [
  <span class="Delimiter">{</span>
    ctrl-k?:boolean<span class="Special"> &lt;- </span>equal *c, <span class="Constant">11/ctrl-k</span>
    <span class="muControl">break-unless</span> ctrl-k?
    delete-to-end-of-line editor
    <span class="muControl">reply</span>
  <span class="Delimiter">}</span>
]

<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, <span class="Constant">before-cursor:offset</span>
  end:address:duplex-list<span class="Special"> &lt;- </span>next-duplex start
  <span class="Delimiter">{</span>
    at-end-of-text?:boolean<span class="Special"> &lt;- </span>equal end, <span class="Constant">0/null</span>
    <span class="muControl">break-if</span> at-end-of-text?
    curr:character<span class="Special"> &lt;- </span>get *end, <span class="Constant">value:offset</span>
    at-end-of-line?:boolean<span class="Special"> &lt;- </span>equal curr, <span class="Constant">10/newline</span>
    <span class="muControl">break-if</span> at-end-of-line?
    end<span class="Special"> &lt;- </span>next-duplex end
    <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, <span class="Constant">next:offset</span>
  *start-next<span class="Special"> &lt;- </span>copy end
  <span class="Delimiter">{</span>
    <span class="muControl">break-unless</span> end
    end-prev:address:address:duplex-list<span class="Special"> &lt;- </span>get-address *end, <span class="Constant">prev:offset</span>
    *end-prev<span class="Special"> &lt;- </span>copy start
  <span class="Delimiter">}</span>
]

<span class="muScenario">scenario</span> editor-deletes-to-end-of-line-with-ctrl-k-2 [
  assume-screen <span class="Constant">10/width</span>, <span class="Constant">5/height</span>
  <span class="Constant">1</span>:address:array:character<span class="Special"> &lt;- </span>new <span class="Constant">[123</span>
<span class="Constant">456]</span>
  <span class="Constant">2</span>:address:editor-data<span class="Special"> &lt;- </span>new-editor <span class="Constant">1</span>:address:array:character, screen:address, <span class="Constant">0/left</span>, <span class="Constant">10/right</span>
  <span class="Comment"># start on second line (no newline after), press ctrl-k</span>
  assume-console [
    left-click <span class="Constant">2</span>, <span class="Constant">1</span>
    type <span class="Constant">[k]</span>  <span class="Comment"># ctrl-k</span>
  ]
  <span class="Constant">3</span>:event/ctrl-k<span class="Special"> &lt;- </span>merge <span class="Constant">0/text</span>, <span class="Constant">11/ctrl-k</span>, <span class="Constant">0/dummy</span>, <span class="Constant">0/dummy</span>
  replace-in-console <span class="Constant">107/k</span>, <span class="Constant">3</span>:event/ctrl-k
  run [
    editor-event-loop screen:address, console:address, <span class="Constant">2</span>: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/width</span>, <span class="Constant">5/height</span>
  <span class="Constant">1</span>:address:array:character<span class="Special"> &lt;- </span>new <span class="Constant">[123</span>
<span class="Constant">456]</span>
  <span class="Constant">2</span>:address:editor-data<span class="Special"> &lt;- </span>new-editor <span class="Constant">1</span>:address:array:character, screen:address, <span class="Constant">0/left</span>, <span class="Constant">10/right</span>
  <span class="Comment"># start at end of line</span>
  assume-console [
    left-click <span class="Constant">1</span>, <span class="Constant">2</span>
    type <span class="Constant">[k]</span>  <span class="Comment"># ctrl-k</span>
  ]
  <span class="Constant">3</span>:event/ctrl-k<span class="Special"> &lt;- </span>merge <span class="Constant">0/text</span>, <span class="Constant">11/ctrl-k</span>, <span class="Constant">0/dummy</span>, <span class="Constant">0/dummy</span>
  replace-in-console <span class="Constant">107/k</span>, <span class="Constant">3</span>:event/ctrl-k
  run [
    editor-event-loop screen:address, console:address, <span class="Constant">2</span>: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/width</span>, <span class="Constant">5/height</span>
  <span class="Constant">1</span>:address:array:character<span class="Special"> &lt;- </span>new <span class="Constant">[123</span>
<span class="Constant">456]</span>
  <span class="Constant">2</span>:address:editor-data<span class="Special"> &lt;- </span>new-editor <span class="Constant">1</span>:address:array:character, screen:address, <span class="Constant">0/left</span>, <span class="Constant">10/right</span>
  <span class="Comment"># start past end of line</span>
  assume-console [
    left-click <span class="Constant">1</span>, <span class="Constant">3</span>
    type <span class="Constant">[k]</span>  <span class="Comment"># ctrl-k</span>
  ]
  <span class="Constant">3</span>:event/ctrl-k<span class="Special"> &lt;- </span>merge <span class="Constant">0/text</span>, <span class="Constant">11/ctrl-k</span>, <span class="Constant">0/dummy</span>, <span class="Constant">0/dummy</span>
  replace-in-console <span class="Constant">107/k</span>, <span class="Constant">3</span>:event/ctrl-k
  run [
    editor-event-loop screen:address, console:address, <span class="Constant">2</span>: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/width</span>, <span class="Constant">5/height</span>
  <span class="Constant">1</span>:address:array:character<span class="Special"> &lt;- </span>new <span class="Constant">[123</span>
<span class="Constant">456]</span>
  <span class="Constant">2</span>:address:editor-data<span class="Special"> &lt;- </span>new-editor <span class="Constant">1</span>:address:array:character, screen:address, <span class="Constant">0/left</span>, <span class="Constant">10/right</span>
  <span class="Comment"># start at end of text</span>
  assume-console [
    left-click <span class="Constant">2</span>, <span class="Constant">2</span>
    type <span class="Constant">[k]</span>  <span class="Comment"># ctrl-k</span>
  ]
  <span class="Constant">3</span>:event/ctrl-k<span class="Special"> &lt;- </span>merge <span class="Constant">0/text</span>, <span class="Constant">11/ctrl-k</span>, <span class="Constant">0/dummy</span>, <span class="Constant">0/dummy</span>
  replace-in-console <span class="Constant">107/k</span>, <span class="Constant">3</span>:event/ctrl-k
  run [
    editor-event-loop screen:address, console:address, <span class="Constant">2</span>: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/width</span>, <span class="Constant">5/height</span>
  <span class="Constant">1</span>:address:array:character<span class="Special"> &lt;- </span>new <span class="Constant">[123</span>
<span class="Constant">456]</span>
  <span class="Constant">2</span>:address:editor-data<span class="Special"> &lt;- </span>new-editor <span class="Constant">1</span>:address:array:character, screen:address, <span class="Constant">0/left</span>, <span class="Constant">10/right</span>
  <span class="Comment"># start past end of text</span>
  assume-console [
    left-click <span class="Constant">2</span>, <span class="Constant">3</span>
    type <span class="Constant">[k]</span>  <span class="Comment"># ctrl-k</span>
  ]
  <span class="Constant">3</span>:event/ctrl-k<span class="Special"> &lt;- </span>merge <span class="Constant">0/text</span>, <span class="Constant">11/ctrl-k</span>, <span class="Constant">0/dummy</span>, <span class="Constant">0/dummy</span>
  replace-in-console <span class="Constant">107/k</span>, <span class="Constant">3</span>:event/ctrl-k
  run [
    editor-event-loop screen:address, console:address, <span class="Constant">2</span>: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="Comment"># ctrl-f/page-down - render next page if it exists</span>

<span class="muScenario">scenario</span> editor-can-scroll [
  assume-screen <span class="Constant">10/width</span>, <span class="Constant">4/height</span>
  <span class="Constant">1</span>:address:array:character<span class="Special"> &lt;- </span>new <span class="Constant">[a</span>
<span class="Constant">b</span>
<span class="Constant">c</span>
<span class="Constant">d]</span>
  <span class="Constant">2</span>:address:editor-data<span class="Special"> &lt;- </span>new-editor <span class="Constant">1</span>:address:array:character, screen:address, <span class="Constant">0/left</span>, <span class="Constant">10/right</span>
  screen-should-contain [
   <span class="Constant"> .          .</span>
   <span class="Constant"> .a         .</span>
   <span class="Constant"> .b         .</span>
   <span class="Constant"> .c         .</span>
  ]
  <span class="Comment"># scroll down</span>
  assume-console [
    press <span class="Constant">65518</span>  <span class="Comment"># page-down</span>
  ]
  run [
    editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data
  ]
  <span class="Comment"># screen shows next page</span>
  screen-should-contain [
   <span class="Constant"> .          .</span>
   <span class="Constant"> .c         .</span>
   <span class="Constant"> .d         .</span>
   <span class="Constant"> .          .</span>
  ]
]

<span class="muRecipe">after</span> +handle-special-character [
  <span class="Delimiter">{</span>
    ctrl-f?:boolean<span class="Special"> &lt;- </span>equal *c, <span class="Constant">6/ctrl-f</span>
    <span class="muControl">break-unless</span> ctrl-f?
    page-down editor
    <span class="muControl">reply</span>
  <span class="Delimiter">}</span>
]

<span class="muRecipe">after</span> +handle-special-key [
  <span class="Delimiter">{</span>
    page-down?:boolean<span class="Special"> &lt;- </span>equal *k, <span class="Constant">65518/page-down</span>
    <span class="muControl">break-unless</span> page-down?
    page-down editor
    <span class="muControl">reply</span>
  <span class="Delimiter">}</span>
]

<span class="Comment"># Cache old pointers to top-of-page in a list as you scroll past them, so that</span>
<span class="Comment"># page-up later doesn't have to recompute them.</span>
<span class="Comment"># This only works because we can never ever have edits outside the current</span>
<span class="Comment"># page. Any edits outside the current page might invalidate pointers to old</span>
<span class="Comment"># pages.</span>
container editor-data [
  previous-page:address:list:address:duplex-list:character
]

<span class="Comment"># page-down skips entire wrapped lines, so it can't scroll past lines</span>
<span class="Comment"># taking up the entire screen</span>
<span class="muRecipe">recipe</span> page-down [
  <span class="Constant">local-scope</span>
  editor:address:editor-data<span class="Special"> &lt;- </span><span class="Constant">next-ingredient</span>
  <span class="Comment"># if editor contents don't overflow screen, do nothing</span>
  bottom-of-screen:address:duplex-list<span class="Special"> &lt;- </span>get *editor, <span class="Constant">bottom-of-screen:offset</span>
  <span class="muControl">reply-unless</span> bottom-of-screen, editor/same-as-ingredient:<span class="Constant">0</span>
  <span class="Comment"># if not, position cursor at final character</span>
  before-cursor:address:address:duplex-list<span class="Special"> &lt;- </span>get-address *editor, <span class="Constant">before-cursor:offset</span>
  *before-cursor<span class="Special"> &lt;- </span>prev-duplex bottom-of-screen
  <span class="Comment"># keep one line in common with previous page</span>
  <span class="Delimiter">{</span>
    last:character<span class="Special"> &lt;- </span>get **before-cursor, <span class="Constant">value:offset</span>
    newline?:boolean<span class="Special"> &lt;- </span>equal last, <span class="Constant">10/newline</span>
    <span class="muControl">break-unless</span> newline?:boolean
    *before-cursor<span class="Special"> &lt;- </span>prev-duplex *before-cursor
  <span class="Delimiter">}</span>
  <span class="Comment"># save top-of-screen to previous-page list</span>
  top-of-screen:address:address:duplex-list<span class="Special"> &lt;- </span>get-address *editor, <span class="Constant">top-of-screen:offset</span>
  previous-page:address:address:list:address:duplex-list:character<span class="Special"> &lt;- </span>get-address *editor, <span class="Constant">previous-page:offset</span>
  *previous-page<span class="Special"> &lt;- </span>push *top-of-screen, *previous-page
  <span class="Comment"># move cursor and top-of-screen to start of that line</span>
  move-to-start-of-line editor
  *top-of-screen<span class="Special"> &lt;- </span>copy *before-cursor
  <span class="muControl">reply</span> editor/same-as-ingredient:<span class="Constant">0</span>
]

<span class="muScenario">scenario</span> editor-does-not-scroll-past-end [
  assume-screen <span class="Constant">10/width</span>, <span class="Constant">4/height</span>
  <span class="Constant">1</span>:address:array:character<span class="Special"> &lt;- </span>new <span class="Constant">[a</span>
<span class="Constant">b]</span>
  <span class="Constant">2</span>:address:editor-data<span class="Special"> &lt;- </span>new-editor <span class="Constant">1</span>:address:array:character, screen:address, <span class="Constant">0/left</span>, <span class="Constant">10/right</span>
  screen-should-contain [
   <span class="Constant"> .          .</span>
   <span class="Constant"> .a         .</span>
   <span class="Constant"> .b         .</span>
   <span class="Constant"> .          .</span>
  ]
  <span class="Comment"># scroll down</span>
  assume-console [
    press <span class="Constant">65518</span>  <span class="Comment"># page-down</span>
  ]
  run [
    editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data
  ]
  <span class="Comment"># screen remains unmodified</span>
  screen-should-contain [
   <span class="Constant"> .          .</span>
   <span class="Constant"> .a         .</span>
   <span class="Constant"> .b         .</span>
   <span class="Constant"> .          .</span>
  ]
]

<span class="muScenario">scenario</span> editor-starts-next-page-at-start-of-wrapped-line [
  <span class="Comment"># screen has 1 line for menu + 3 lines for text</span>
  assume-screen <span class="Constant">10/width</span>, <span class="Constant">4/height</span>
  <span class="Comment"># editor contains a long last line</span>
  <span class="Constant">1</span>:address:array:character<span class="Special"> &lt;- </span>new <span class="Constant">[a</span>
<span class="Constant">b</span>
<span class="Constant">cdefgh]</span>
  <span class="Comment"># editor screen triggers wrap of last line</span>
  <span class="Constant">2</span>:address:editor-data<span class="Special"> &lt;- </span>new-editor <span class="Constant">1</span>:address:array:character, screen:address, <span class="Constant">0/left</span>, <span class="Constant">4/right</span>
  <span class="Comment"># some part of last line is not displayed</span>
  screen-should-contain [
   <span class="Constant"> .          .</span>
   <span class="Constant"> .a         .</span>
   <span class="Constant"> .b         .</span>
   <span class="Constant"> .cde↩      .</span>
  ]
  <span class="Comment"># scroll down</span>
  assume-console [
    press <span class="Constant">65518</span>  <span class="Comment"># page-down</span>
  ]
  run [
    editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data
  ]
  <span class="Comment"># screen shows entire wrapped line</span>
  screen-should-contain [
   <span class="Constant"> .          .</span>
   <span class="Constant"> .cde↩      .</span>
   <span class="Constant"> .fgh       .</span>
   <span class="Constant"> .          .</span>
  ]
]

<span class="muScenario">scenario</span> editor-starts-next-page-at-start-of-wrapped-line-2 [
  <span class="Comment"># screen has 1 line for menu + 3 lines for text</span>
  assume-screen <span class="Constant">10/width</span>, <span class="Constant">4/height</span>
  <span class="Comment"># editor contains a very long line that occupies last two lines of screen</span>
  <span class="Comment"># and still has something left over</span>
  <span class="Constant">1</span>:address:array:character<span class="Special"> &lt;- </span>new <span class="Constant">[a</span>
<span class="Constant">bcdefgh]</span>
  <span class="Constant">2</span>:address:editor-data<span class="Special"> &lt;- </span>new-editor <span class="Constant">1</span>:address:array:character, screen:address, <span class="Constant">0/left</span>, <span class="Constant">4/right</span>
  <span class="Comment"># some part of last line is not displayed</span>
  screen-should-contain [
   <span class="Constant"> .          .</span>
   <span class="Constant"> .a         .</span>
   <span class="Constant"> .bcd↩      .</span>
   <span class="Constant"> .efg↩      .</span>
  ]
  <span class="Comment"># scroll down</span>
  assume-console [
    press <span class="Constant">65518</span>  <span class="Comment"># page-down</span>
  ]
  run [
    editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data
  ]
  <span class="Comment"># screen shows entire wrapped line</span>
  screen-should-contain [
   <span class="Constant"> .          .</span>
   <span class="Constant"> .bcd↩      .</span>
   <span class="Constant"> .efg↩      .</span>
   <span class="Constant"> .h         .</span>
  ]
]

<span class="Comment"># ctrl-b/page-up - render previous page if it exists</span>

<span class="muScenario">scenario</span> editor-can-scroll-up [
  assume-screen <span class="Constant">10/width</span>, <span class="Constant">4/height</span>
  <span class="Constant">1</span>:address:array:character<span class="Special"> &lt;- </span>new <span class="Constant">[a</span>
<span class="Constant">b</span>
<span class="Constant">c</span>
<span class="Constant">d]</span>
  <span class="Constant">2</span>:address:editor-data<span class="Special"> &lt;- </span>new-editor <span class="Constant">1</span>:address:array:character, screen:address, <span class="Constant">0/left</span>, <span class="Constant">10/right</span>
  screen-should-contain [
   <span class="Constant"> .          .</span>
   <span class="Constant"> .a         .</span>
   <span class="Constant"> .b         .</span>
   <span class="Constant"> .c         .</span>
  ]
  <span class="Comment"># scroll down</span>
  assume-console [
    press <span class="Constant">65518</span>  <span class="Comment"># page-down</span>
  ]
  run [
    editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data
  ]
  <span class="Comment"># screen shows next page</span>
  screen-should-contain [
   <span class="Constant"> .          .</span>
   <span class="Constant"> .c         .</span>
   <span class="Constant"> .d         .</span>
   <span class="Constant"> .          .</span>
  ]
  <span class="Comment"># scroll back up</span>
  assume-console [
    press <span class="Constant">65519</span>  <span class="Comment"># page-up</span>
  ]
  run [
    editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data
  ]
  <span class="Comment"># screen shows original page again</span>
  screen-should-contain [
   <span class="Constant"> .          .</span>
   <span class="Constant"> .a         .</span>
   <span class="Constant"> .b         .</span>
   <span class="Constant"> .c         .</span>
  ]
]

<span class="muRecipe">after</span> +handle-special-character [
  <span class="Delimiter">{</span>
    ctrl-b?:boolean<span class="Special"> &lt;- </span>equal *c, <span class="Constant">2/ctrl-f</span>
    <span class="muControl">break-unless</span> ctrl-b?
    page-up editor
    <span class="muControl">reply</span>
  <span class="Delimiter">}</span>
]

<span class="muRecipe">after</span> +handle-special-key [
  <span class="Delimiter">{</span>
    page-up?:boolean<span class="Special"> &lt;- </span>equal *k, <span class="Constant">65519/page-up</span>
    <span class="muControl">break-unless</span> page-up?
    page-up editor
    <span class="muControl">reply</span>
  <span class="Delimiter">}</span>
]

<span class="muRecipe">recipe</span> page-up [
  <span class="Constant">local-scope</span>
  editor:address:editor-data<span class="Special"> &lt;- </span><span class="Constant">next-ingredient</span>
  previous-page:address:address:list:address:duplex-list:character<span class="Special"> &lt;- </span>get-address *editor, <span class="Constant">previous-page:offset</span>
  <span class="muControl">reply-unless</span> *previous-page, editor/same-as-ingredient:<span class="Constant">0</span>
  top-of-screen:address:address:duplex-list<span class="Special"> &lt;- </span>get-address *editor, <span class="Constant">top-of-screen:offset</span>
  *top-of-screen<span class="Special"> &lt;- </span>first *previous-page
  *previous-page<span class="Special"> &lt;- </span>rest *previous-page
  <span class="muControl">reply</span> editor/same-as-ingredient:<span class="Constant">0</span>
]

<span class="muScenario">scenario</span> editor-can-scroll-up-multiple-pages [
  <span class="Comment"># screen has 1 line for menu + 3 lines</span>
  assume-screen <span class="Constant">10/width</span>, <span class="Constant">4/height</span>
  <span class="Comment"># initialize editor with 8 lines</span>
  <span class="Constant">1</span>:address:array:character<span class="Special"> &lt;- </span>new <span class="Constant">[a</span>
<span class="Constant">b</span>
<span class="Constant">c</span>
<span class="Constant">d</span>
<span class="Constant">e</span>
<span class="Constant">f</span>
<span class="Constant">g</span>
<span class="Constant">h]</span>
  <span class="Constant">2</span>:address:editor-data<span class="Special"> &lt;- </span>new-editor <span class="Constant">1</span>:address:array:character, screen:address, <span class="Constant">0/left</span>, <span class="Constant">10/right</span>
  screen-should-contain [
   <span class="Constant"> .          .</span>
   <span class="Constant"> .a         .</span>
   <span class="Constant"> .b         .</span>
   <span class="Constant"> .c         .</span>
  ]
  <span class="Comment"># scroll down two pages</span>
  assume-console [
    press <span class="Constant">65518</span>  <span class="Comment"># page-down</span>
    press <span class="Constant">65518</span>  <span class="Comment"># page-down</span>
  ]
  run [
    editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data
  ]
  <span class="Comment"># screen shows third page</span>
  screen-should-contain [
   <span class="Constant"> .          .</span>
   <span class="Constant"> .e         .</span>
   <span class="Constant"> .f         .</span>
   <span class="Constant"> .g         .</span>
  ]
  <span class="Comment"># scroll up</span>
  assume-console [
    press <span class="Constant">65519</span>  <span class="Comment"># page-up</span>
  ]
  run [
    editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data
  ]
  <span class="Comment"># screen shows second page</span>
  screen-should-contain [
   <span class="Constant"> .          .</span>
   <span class="Constant"> .c         .</span>
   <span class="Constant"> .d         .</span>
   <span class="Constant"> .e         .</span>
  ]
  <span class="Comment"># scroll up again</span>
  assume-console [
    press <span class="Constant">65519</span>  <span class="Comment"># page-up</span>
  ]
  run [
    editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data
  ]
  <span class="Comment"># screen shows original page again</span>
  screen-should-contain [
   <span class="Constant"> .          .</span>
   <span class="Constant"> .a         .</span>
   <span class="Constant"> .b         .</span>
   <span class="Constant"> .c         .</span>
  ]
]

<span class="Comment"># cursor-down can scroll if necessary</span>

<span class="muScenario">scenario</span> editor-can-scroll-down-using-arrow-keys [
  <span class="Comment"># screen has 1 line for menu + 3 lines</span>
  assume-screen <span class="Constant">10/width</span>, <span class="Constant">4/height</span>
  <span class="Comment"># initialize editor with &gt;3 lines</span>
  <span class="Constant">1</span>:address:array:character<span class="Special"> &lt;- </span>new <span class="Constant">[a</span>
<span class="Constant">b</span>
<span class="Constant">c</span>
<span class="Constant">d]</span>
  <span class="Constant">2</span>:address:editor-data<span class="Special"> &lt;- </span>new-editor <span class="Constant">1</span>:address:array:character, screen:address, <span class="Constant">0/left</span>, <span class="Constant">10/right</span>
  screen-should-contain [
   <span class="Constant"> .          .</span>
   <span class="Constant"> .a         .</span>
   <span class="Constant"> .b         .</span>
   <span class="Constant"> .c         .</span>
  ]
  <span class="Comment"># position cursor at last line, then try to move further down</span>
  assume-console [
    left-click <span class="Constant">3</span>, <span class="Constant">0</span>
    press <span class="Constant">65516</span>  <span class="Comment"># down-arrow</span>
  ]
  run [
    editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data
  ]
  <span class="Comment"># screen slides by one line</span>
  screen-should-contain [
   <span class="Constant"> .          .</span>
   <span class="Constant"> .b         .</span>
   <span class="Constant"> .c         .</span>
   <span class="Constant"> .d         .</span>
  ]
]

<span class="muRecipe">after</span> +scroll-down [
<span class="CommentedCode">#?   $print [scroll down], 10/newline #? 1</span>
  top-of-screen:address:address:duplex-list<span class="Special"> &lt;- </span>get-address *editor, <span class="Constant">top-of-screen:offset</span>
  left:number<span class="Special"> &lt;- </span>get *editor, <span class="Constant">left:offset</span>
  right:number<span class="Special"> &lt;- </span>get *editor, <span class="Constant">right:offset</span>
  max:number<span class="Special"> &lt;- </span>subtract right, left
  *top-of-screen<span class="Special"> &lt;- </span>start-of-next-line *top-of-screen, max
]

<span class="Comment"># takes a pointer into the doubly-linked list, scans ahead at most 'max'</span>
<span class="Comment"># positions until just past the next newline</span>
<span class="muRecipe">recipe</span> start-of-next-line [
  <span class="Constant">local-scope</span>
  original:address:duplex-list<span class="Special"> &lt;- </span><span class="Constant">next-ingredient</span>
  max:number<span class="Special"> &lt;- </span><span class="Constant">next-ingredient</span>
  count:number<span class="Special"> &lt;- </span>copy <span class="Constant">0</span>
  curr:address:duplex-list<span class="Special"> &lt;- </span>copy original
  <span class="Delimiter">{</span>
    <span class="muControl">reply-unless</span> curr, original
    done?:boolean<span class="Special"> &lt;- </span>greater-or-equal count, max
    <span class="muControl">break-if</span> done?
    c:character<span class="Special"> &lt;- </span>get *curr, <span class="Constant">value:offset</span>
    at-newline?:boolean<span class="Special"> &lt;- </span>equal c, <span class="Constant">10/newline</span>
    <span class="muControl">break-if</span> at-newline?
    curr<span class="Special"> &lt;- </span>next-duplex curr
    count<span class="Special"> &lt;- </span>add count, <span class="Constant">1</span>
    <span class="muControl">loop</span>
  <span class="Delimiter">}</span>
  <span class="muControl">reply-unless</span> curr, original
  <span class="muControl">reply</span> curr
]

<span class="muScenario">scenario</span> editor-scrolls-down-past-wrapped-line-using-arrow-keys [
  <span class="Comment"># screen has 1 line for menu + 3 lines</span>
  assume-screen <span class="Constant">10/width</span>, <span class="Constant">4/height</span>
  <span class="Comment"># initialize editor with a long, wrapped line and more than a screen of</span>
  <span class="Comment"># other lines</span>
  <span class="Constant">1</span>:address:array:character<span class="Special"> &lt;- </span>new <span class="Constant">[abcdef</span>
<span class="Constant">g</span>
<span class="Constant">h</span>
<span class="Constant">i]</span>
  <span class="Constant">2</span>:address:editor-data<span class="Special"> &lt;- </span>new-editor <span class="Constant">1</span>:address:array:character, screen:address, <span class="Constant">0/left</span>, <span class="Constant">5/right</span>
  screen-should-contain [
   <span class="Constant"> .          .</span>
   <span class="Constant"> .abcd↩     .</span>
   <span class="Constant"> .ef        .</span>
   <span class="Constant"> .g         .</span>
  ]
  <span class="Comment"># position cursor at last line, then try to move further down</span>
  assume-console [
    left-click <span class="Constant">3</span>, <span class="Constant">0</span>
    press <span class="Constant">65516</span>  <span class="Comment"># down-arrow</span>
  ]
  run [
    editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data
  ]
  <span class="Comment"># screen shows partial wrapped line</span>
  screen-should-contain [
   <span class="Constant"> .          .</span>
   <span class="Constant"> .ef        .</span>
   <span class="Constant"> .g         .</span>
   <span class="Constant"> .h         .</span>
  ]
]

<span class="muScenario">scenario</span> editor-scrolls-down-past-wrapped-line-using-arrow-keys-2 [
  <span class="Comment"># screen has 1 line for menu + 3 lines</span>
  assume-screen <span class="Constant">10/width</span>, <span class="Constant">4/height</span>
  <span class="Comment"># editor starts with a long line wrapping twice</span>
  <span class="Constant">1</span>:address:array:character<span class="Special"> &lt;- </span>new <span class="Constant">[abcdefghij</span>
<span class="Constant">k</span>
<span class="Constant">l</span>
<span class="Constant">m]</span>
  <span class="Constant">2</span>:address:editor-data<span class="Special"> &lt;- </span>new-editor <span class="Constant">1</span>:address:array:character, screen:address, <span class="Constant">0/left</span>, <span class="Constant">5/right</span>
  <span class="Comment"># position cursor at last line, then try to move further down</span>
  assume-console [
    left-click <span class="Constant">3</span>, <span class="Constant">0</span>
    press <span class="Constant">65516</span>  <span class="Comment"># down-arrow</span>
  ]
  run [
    editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data
  ]
  <span class="Comment"># screen shows partial wrapped line containing a wrap icon</span>
  screen-should-contain [
   <span class="Constant"> .          .</span>
   <span class="Constant"> .efgh↩     .</span>
   <span class="Constant"> .ij        .</span>
   <span class="Constant"> .k         .</span>
  ]
  <span class="Comment"># scroll down again</span>
  assume-console [
    press <span class="Constant">65516</span>  <span class="Comment"># down-arrow</span>
  ]
  run [
    editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data
  ]
  <span class="Comment"># screen shows partial wrapped line</span>
  screen-should-contain [
   <span class="Constant"> .          .</span>
   <span class="Constant"> .ij        .</span>
   <span class="Constant"> .k         .</span>
   <span class="Constant"> .l         .</span>
  ]
]

<span class="muScenario">scenario</span> editor-scrolls-down-when-line-wraps [
  <span class="Comment"># screen has 1 line for menu + 3 lines</span>
  assume-screen <span class="Constant">5/width</span>, <span class="Constant">4/height</span>
  <span class="Comment"># editor contains a long line in the third line</span>
  <span class="Constant">1</span>:address:array:character<span class="Special"> &lt;- </span>new <span class="Constant">[a</span>
<span class="Constant">b</span>
<span class="Constant">cdef]</span>
  <span class="Constant">2</span>:address:editor-data<span class="Special"> &lt;- </span>new-editor <span class="Constant">1</span>:address:array:character, screen:address, <span class="Constant">0/left</span>, <span class="Constant">5/right</span>
  <span class="Comment"># position cursor at end, type a character</span>
  assume-console [
    left-click <span class="Constant">3</span>, <span class="Constant">4</span>
    type <span class="Constant">[g]</span>
  ]
  run [
    editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data
    <span class="Constant">3</span>:number<span class="Special"> &lt;- </span>get *<span class="Constant">2</span>:address:editor-data, <span class="Constant">cursor-row:offset</span>
    <span class="Constant">4</span>:number<span class="Special"> &lt;- </span>get *<span class="Constant">2</span>:address:editor-data, <span class="Constant">cursor-column:offset</span>
  ]
  <span class="Comment"># screen scrolls</span>
  screen-should-contain [
   <span class="Constant"> .     .</span>
   <span class="Constant"> .b    .</span>
<span class="Constant">    .cdef↩.</span>
   <span class="Constant"> .g    .</span>
  ]
  memory-should-contain [
    <span class="Constant">3</span><span class="Special"> &lt;- </span><span class="Constant">3</span>
    <span class="Constant">4</span><span class="Special"> &lt;- </span><span class="Constant">1</span>
  ]
]

<span class="muScenario">scenario</span> editor-scrolls-down-on-newline [
  assume-screen <span class="Constant">5/width</span>, <span class="Constant">4/height</span>
  <span class="Comment"># position cursor after last line and type newline</span>
  <span class="Constant">1</span>:address:array:character<span class="Special"> &lt;- </span>new <span class="Constant">[a</span>
<span class="Constant">b</span>
<span class="Constant">c]</span>
  <span class="Constant">2</span>:address:editor-data<span class="Special"> &lt;- </span>new-editor <span class="Constant">1</span>:address:array:character, screen:address, <span class="Constant">0/left</span>, <span class="Constant">5/right</span>
  assume-console [
    left-click <span class="Constant">3</span>, <span class="Constant">4</span>
    type [
]
  ]
  run [
    editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data
    <span class="Constant">3</span>:number<span class="Special"> &lt;- </span>get *<span class="Constant">2</span>:address:editor-data, <span class="Constant">cursor-row:offset</span>
    <span class="Constant">4</span>:number<span class="Special"> &lt;- </span>get *<span class="Constant">2</span>:address:editor-data, <span class="Constant">cursor-column:offset</span>
  ]
  <span class="Comment"># screen scrolls</span>
  screen-should-contain [
   <span class="Constant"> .     .</span>
   <span class="Constant"> .b    .</span>
   <span class="Constant"> .c    .</span>
   <span class="Constant"> .     .</span>
  ]
  memory-should-contain [
    <span class="Constant">3</span><span class="Special"> &lt;- </span><span class="Constant">3</span>
    <span class="Constant">4</span><span class="Special"> &lt;- </span><span class="Constant">0</span>
  ]
]

<span class="muScenario">scenario</span> editor-scrolls-down-on-right-arrow [
  <span class="Comment"># screen has 1 line for menu + 3 lines</span>
  assume-screen <span class="Constant">5/width</span>, <span class="Constant">4/height</span>
  <span class="Comment"># editor contains a wrapped line</span>
  <span class="Constant">1</span>:address:array:character<span class="Special"> &lt;- </span>new <span class="Constant">[a</span>
<span class="Constant">b</span>
<span class="Constant">cdefgh]</span>
  <span class="Constant">2</span>:address:editor-data<span class="Special"> &lt;- </span>new-editor <span class="Constant">1</span>:address:array:character, screen:address, <span class="Constant">0/left</span>, <span class="Constant">5/right</span>
  <span class="Comment"># position cursor at end of screen and try to move right</span>
  assume-console [
    left-click <span class="Constant">3</span>, <span class="Constant">3</span>
    press <span class="Constant">65514</span>  <span class="Comment"># right arrow</span>
  ]
  run [
    editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data
    <span class="Constant">3</span>:number<span class="Special"> &lt;- </span>get *<span class="Constant">2</span>:address:editor-data, <span class="Constant">cursor-row:offset</span>
    <span class="Constant">4</span>:number<span class="Special"> &lt;- </span>get *<span class="Constant">2</span>:address:editor-data, <span class="Constant">cursor-column:offset</span>
  ]
  <span class="Comment"># screen scrolls</span>
  screen-should-contain [
   <span class="Constant"> .     .</span>
   <span class="Constant"> .b    .</span>
<span class="Constant">    .cdef↩.</span>
   <span class="Constant"> .gh   .</span>
  ]
  memory-should-contain [
    <span class="Constant">3</span><span class="Special"> &lt;- </span><span class="Constant">3</span>
    <span class="Constant">4</span><span class="Special"> &lt;- </span><span class="Constant">0</span>
  ]
]

<span class="muScenario">scenario</span> editor-scrolls-down-on-right-arrow-2 [
  <span class="Comment"># screen has 1 line for menu + 3 lines</span>
  assume-screen <span class="Constant">5/width</span>, <span class="Constant">4/height</span>
  <span class="Comment"># editor contains more lines than can fit on screen</span>
  <span class="Constant">1</span>:address:array:character<span class="Special"> &lt;- </span>new <span class="Constant">[a</span>
<span class="Constant">b</span>
<span class="Constant">c</span>
<span class="Constant">d]</span>
  <span class="Constant">2</span>:address:editor-data<span class="Special"> &lt;- </span>new-editor <span class="Constant">1</span>:address:array:character, screen:address, <span class="Constant">0/left</span>, <span class="Constant">5/right</span>
  <span class="Comment"># position cursor at end of screen and try to move right</span>
  assume-console [
    left-click <span class="Constant">3</span>, <span class="Constant">3</span>
    press <span class="Constant">65514</span>  <span class="Comment"># right arrow</span>
  ]
  run [
    editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data
    <span class="Constant">3</span>:number<span class="Special"> &lt;- </span>get *<span class="Constant">2</span>:address:editor-data, <span class="Constant">cursor-row:offset</span>
    <span class="Constant">4</span>:number<span class="Special"> &lt;- </span>get *<span class="Constant">2</span>:address:editor-data, <span class="Constant">cursor-column:offset</span>
  ]
  <span class="Comment"># screen scrolls</span>
  screen-should-contain [
   <span class="Constant"> .     .</span>
   <span class="Constant"> .b    .</span>
   <span class="Constant"> .c    .</span>
   <span class="Constant"> .d    .</span>
  ]
  memory-should-contain [
    <span class="Constant">3</span><span class="Special"> &lt;- </span><span class="Constant">3</span>
    <span class="Constant">4</span><span class="Special"> &lt;- </span><span class="Constant">0</span>
  ]
]

<span class="Comment"># cursor-up can scroll if necessary</span>

<span class="muScenario">scenario</span> editor-can-scroll-up-using-arrow-keys [
  <span class="Comment"># screen has 1 line for menu + 3 lines</span>
  assume-screen <span class="Constant">10/width</span>, <span class="Constant">4/height</span>
  <span class="Comment"># initialize editor with &gt;3 lines</span>
  <span class="Constant">1</span>:address:array:character<span class="Special"> &lt;- </span>new <span class="Constant">[a</span>
<span class="Constant">b</span>
<span class="Constant">c</span>
<span class="Constant">d]</span>
  <span class="Constant">2</span>:address:editor-data<span class="Special"> &lt;- </span>new-editor <span class="Constant">1</span>:address:array:character, screen:address, <span class="Constant">0/left</span>, <span class="Constant">10/right</span>
  screen-should-contain [
   <span class="Constant"> .          .</span>
   <span class="Constant"> .a         .</span>
   <span class="Constant"> .b         .</span>
   <span class="Constant"> .c         .</span>
  ]
  <span class="Comment"># position cursor at top of second page, then try to move up</span>
  assume-console [
    press <span class="Constant">65518</span>  <span class="Comment"># page-down</span>
    press <span class="Constant">65517</span>  <span class="Comment"># up-arrow</span>
  ]
  run [
    editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data
  ]
  <span class="Comment"># screen slides by one line</span>
  screen-should-contain [
   <span class="Constant"> .          .</span>
   <span class="Constant"> .b         .</span>
   <span class="Constant"> .c         .</span>
   <span class="Constant"> .d         .</span>
  ]
]

<span class="muRecipe">after</span> +scroll-up [
<span class="CommentedCode">#?   $print [scroll up], 10/newline #? 1</span>
  top-of-screen:address:address:duplex-list<span class="Special"> &lt;- </span>get-address *editor, <span class="Constant">top-of-screen:offset</span>
  left:number<span class="Special"> &lt;- </span>get *editor, <span class="Constant">left:offset</span>
  right:number<span class="Special"> &lt;- </span>get *editor, <span class="Constant">right:offset</span>
  max:number<span class="Special"> &lt;- </span>subtract right, left
  *top-of-screen<span class="Special"> &lt;- </span>start-of-previous-line *top-of-screen, max
]

<span class="Comment"># takes a pointer into the doubly-linked list, scans back at most 'max'</span>
<span class="Comment"># positions to previous newline. Returns original pointer if falls off edge of</span>
<span class="Comment"># list.</span>
<span class="muRecipe">recipe</span> start-of-previous-line [
  <span class="Constant">local-scope</span>
  original:address:duplex-list<span class="Special"> &lt;- </span><span class="Constant">next-ingredient</span>
  max:number<span class="Special"> &lt;- </span><span class="Constant">next-ingredient</span>
  count:number<span class="Special"> &lt;- </span>copy <span class="Constant">0</span>
  curr:address:duplex-list<span class="Special"> &lt;- </span>copy original
  <span class="muControl">reply-unless</span> curr, original
  <span class="Comment"># if top is at start of line, don't count the previous newline</span>
  <span class="Delimiter">{</span>
    c:character<span class="Special"> &lt;- </span>get *curr, <span class="Constant">value:offset</span>
    at-newline?:boolean<span class="Special"> &lt;- </span>equal c, <span class="Constant">10/newline</span>
    <span class="muControl">break-unless</span> at-newline?
    max<span class="Special"> &lt;- </span>subtract max, <span class="Constant">1</span>
  <span class="Delimiter">}</span>
  <span class="Comment"># skip newline at original</span>
  curr<span class="Special"> &lt;- </span>prev-duplex curr
  count<span class="Special"> &lt;- </span>add count, <span class="Constant">1</span>
  <span class="Comment"># now skip before until previous newline</span>
  <span class="Delimiter">{</span>
    <span class="muControl">reply-unless</span> curr, original
    done?:boolean<span class="Special"> &lt;- </span>greater-or-equal count, max
    <span class="muControl">break-if</span> done?
    c:character<span class="Special"> &lt;- </span>get *curr, <span class="Constant">value:offset</span>
    at-newline?:boolean<span class="Special"> &lt;- </span>equal c, <span class="Constant">10/newline</span>
    <span class="muControl">break-if</span> at-newline?
    curr<span class="Special"> &lt;- </span>prev-duplex curr
    count<span class="Special"> &lt;- </span>add count, <span class="Constant">1</span>
    <span class="muControl">loop</span>
  <span class="Delimiter">}</span>
  <span class="muControl">reply-unless</span> curr, original
  <span class="muControl">reply</span> curr
]

<span class="muScenario">scenario</span> editor-scrolls-up-past-wrapped-line-using-arrow-keys [
  <span class="Comment"># screen has 1 line for menu + 3 lines</span>
  assume-screen <span class="Constant">10/width</span>, <span class="Constant">4/height</span>
  <span class="Comment"># initialize editor with a long, wrapped line and more than a screen of</span>
  <span class="Comment"># other lines</span>
  <span class="Constant">1</span>:address:array:character<span class="Special"> &lt;- </span>new <span class="Constant">[abcdef</span>
<span class="Constant">g</span>
<span class="Constant">h</span>
<span class="Constant">i]</span>
  <span class="Constant">2</span>:address:editor-data<span class="Special"> &lt;- </span>new-editor <span class="Constant">1</span>:address:array:character, screen:address, <span class="Constant">0/left</span>, <span class="Constant">5/right</span>
  screen-should-contain [
   <span class="Constant"> .          .</span>
   <span class="Constant"> .abcd↩     .</span>
   <span class="Constant"> .ef        .</span>
   <span class="Constant"> .g         .</span>
  ]
  <span class="Comment"># position cursor at top of second page, just below wrapped line</span>
  assume-console [
    press <span class="Constant">65518</span>  <span class="Comment"># page-down</span>
  ]
  run [
    editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data
  ]
  screen-should-contain [
   <span class="Constant"> .          .</span>
   <span class="Constant"> .g         .</span>
   <span class="Constant"> .h         .</span>
   <span class="Constant"> .i         .</span>
  ]
  <span class="Comment"># now move up one line</span>
  assume-console [
    press <span class="Constant">65517</span>  <span class="Comment"># up-arrow</span>
  ]
  run [
    editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data
  ]
  <span class="Comment"># screen shows partial wrapped line</span>
  screen-should-contain [
   <span class="Constant"> .          .</span>
   <span class="Constant"> .ef        .</span>
   <span class="Constant"> .g         .</span>
   <span class="Constant"> .h         .</span>
  ]
]

<span class="muScenario">scenario</span> editor-scrolls-up-past-wrapped-line-using-arrow-keys-2 [
  <span class="Comment"># screen has 1 line for menu + 4 lines</span>
  assume-screen <span class="Constant">10/width</span>, <span class="Constant">5/height</span>
  <span class="Comment"># editor starts with a long line wrapping twice, occupying 3 of the 4 lines</span>
  <span class="Constant">1</span>:address:array:character<span class="Special"> &lt;- </span>new <span class="Constant">[abcdefghij</span>
<span class="Constant">k</span>
<span class="Constant">l</span>
<span class="Constant">m]</span>
  <span class="Constant">2</span>:address:editor-data<span class="Special"> &lt;- </span>new-editor <span class="Constant">1</span>:address:array:character, screen:address, <span class="Constant">0/left</span>, <span class="Constant">5/right</span>
  <span class="Comment"># position cursor at top of second page</span>
  assume-console [
    press <span class="Constant">65518</span>  <span class="Comment"># page-down</span>
  ]
  run [
    editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data
  ]
  screen-should-contain [
   <span class="Constant"> .          .</span>
   <span class="Constant"> .k         .</span>
   <span class="Constant"> .l         .</span>
   <span class="Constant"> .m         .</span>
   <span class="Constant"> .          .</span>
  ]
  <span class="Comment"># move up one line</span>
  assume-console [
    press <span class="Constant">65517</span>  <span class="Comment"># up-arrow</span>
  ]
  run [
    editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data
  ]
  <span class="Comment"># screen shows partial wrapped line</span>
  screen-should-contain [
   <span class="Constant"> .          .</span>
   <span class="Constant"> .ij        .</span>
   <span class="Constant"> .k         .</span>
   <span class="Constant"> .l         .</span>
   <span class="Constant"> .m         .</span>
  ]
  <span class="Comment"># move up a second line</span>
  assume-console [
    press <span class="Constant">65517</span>  <span class="Comment"># up-arrow</span>
  ]
  run [
    editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data
  ]
  <span class="Comment"># screen shows partial wrapped line</span>
  screen-should-contain [
   <span class="Constant"> .          .</span>
   <span class="Constant"> .efgh↩     .</span>
   <span class="Constant"> .ij        .</span>
   <span class="Constant"> .k         .</span>
   <span class="Constant"> .l         .</span>
  ]
  <span class="Comment"># move up a third line</span>
  assume-console [
    press <span class="Constant">65517</span>  <span class="Comment"># up-arrow</span>
  ]
  run [
    editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data
  ]
  <span class="Comment"># screen shows partial wrapped line</span>
  screen-should-contain [
   <span class="Constant"> .          .</span>
   <span class="Constant"> .abcd↩     .</span>
   <span class="Constant"> .efgh↩     .</span>
   <span class="Constant"> .ij        .</span>
   <span class="Constant"> .k         .</span>
  ]
]

<span class="muScenario">scenario</span> editor-scrolls-up-on-left-arrow [
  <span class="Comment"># screen has 1 line for menu + 3 lines</span>
  assume-screen <span class="Constant">5/width</span>, <span class="Constant">4/height</span>
  <span class="Comment"># editor contains &gt;3 lines</span>
  <span class="Constant">1</span>:address:array:character<span class="Special"> &lt;- </span>new <span class="Constant">[a</span>
<span class="Constant">b</span>
<span class="Constant">c</span>
<span class="Constant">d</span>
<span class="Constant">e]</span>
  <span class="Constant">2</span>:address:editor-data<span class="Special"> &lt;- </span>new-editor <span class="Constant">1</span>:address:array:character, screen:address, <span class="Constant">0/left</span>, <span class="Constant">5/right</span>
  <span class="Comment"># position cursor at top of second page</span>
  assume-console [
    press <span class="Constant">65518</span>  <span class="Comment"># page-down</span>
  ]
  run [
    editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data
  ]
  screen-should-contain [
   <span class="Constant"> .     .</span>
   <span class="Constant"> .c    .</span>
   <span class="Constant"> .d    .</span>
   <span class="Constant"> .e    .</span>
  ]
  <span class="Comment"># now try to move left</span>
  assume-console [
    press <span class="Constant">65515</span>  <span class="Comment"># left arrow</span>
  ]
  run [
    editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data
    <span class="Constant">3</span>:number<span class="Special"> &lt;- </span>get *<span class="Constant">2</span>:address:editor-data, <span class="Constant">cursor-row:offset</span>
    <span class="Constant">4</span>:number<span class="Special"> &lt;- </span>get *<span class="Constant">2</span>:address:editor-data, <span class="Constant">cursor-column:offset</span>
  ]
  <span class="Comment"># screen scrolls</span>
  screen-should-contain [
   <span class="Constant"> .     .</span>
   <span class="Constant"> .b    .</span>
   <span class="Constant"> .c    .</span>
   <span class="Constant"> .d    .</span>
  ]
  memory-should-contain [
    <span class="Constant">3</span><span class="Special"> &lt;- </span><span class="Constant">1</span>
    <span class="Constant">4</span><span class="Special"> &lt;- </span><span class="Constant">1</span>
  ]
]

<span class="SalientComment">## putting the environment together out of editors</span>

container programming-environment-data [
  recipes:address:editor-data
  recipe-warnings:address:array:character
  current-sandbox:address:editor-data
  sandbox:address:sandbox-data  <span class="Comment"># list of sandboxes, from top to bottom</span>
  sandbox-in-focus?:boolean  <span class="Comment"># false =&gt; cursor in recipes; true =&gt; cursor 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
  height:number<span class="Special"> &lt;- </span>screen-height screen
  <span class="Comment"># top menu</span>
  result:address:programming-environment-data<span class="Special"> &lt;- </span>new <span class="Constant">programming-environment-data:type</span>
  draw-horizontal screen, <span class="Constant">0</span>, <span class="Constant">0/left</span>, width, <span class="Constant">32/space</span>, <span class="Constant">0/black</span>, <span class="Constant">238/grey</span>
  button-start:number<span class="Special"> &lt;- </span>subtract width, <span class="Constant">20</span>
  button-on-screen?:boolean<span class="Special"> &lt;- </span>greater-or-equal button-start, <span class="Constant">0</span>
  assert button-on-screen?, <span class="Constant">[screen too narrow for menu]</span>
  move-cursor screen, <span class="Constant">0/row</span>, button-start
  run-button:address:array:character<span class="Special"> &lt;- </span>new <span class="Constant">[ run (F4) ]</span>
  print-string screen, run-button, <span class="Constant">255/white</span>, <span class="Constant">161/reddish</span>
  <span class="Comment"># dotted line down the middle</span>
  divider:number, _<span class="Special"> &lt;- </span>divide-with-remainder width, <span class="Constant">2</span>
  draw-vertical screen, divider, <span class="Constant">1/top</span>, height, <span class="Constant">9482/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, <span class="Constant">recipes:offset</span>
  *recipes<span class="Special"> &lt;- </span>new-editor initial-recipe-contents, screen, <span class="Constant">0/left</span>, divider/right
  <span class="Comment"># sandbox editor on the right</span>
  new-left:number<span class="Special"> &lt;- </span>add divider, <span class="Constant">1</span>
  new-right:number<span class="Special"> &lt;- </span>add new-left, <span class="Constant">5</span>
  current-sandbox:address:address:editor-data<span class="Special"> &lt;- </span>get-address *result, <span class="Constant">current-sandbox:offset</span>
  *current-sandbox<span class="Special"> &lt;- </span>new-editor initial-sandbox-contents, screen, new-left, width/right
  screen<span class="Special"> &lt;- </span>render-all screen, result
  <span class="muControl">reply</span> result
]

<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, <span class="Constant">recipes:offset</span>
  current-sandbox:address:editor-data<span class="Special"> &lt;- </span>get *env, <span class="Constant">current-sandbox:offset</span>
  sandbox-in-focus?:address:boolean<span class="Special"> &lt;- </span>get-address *env, <span class="Constant">sandbox-in-focus?:offset</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, found?:boolean, quit?:boolean<span class="Special"> &lt;- </span>read-event console
    <span class="muControl">loop-unless</span> found?
    <span class="muControl">break-if</span> quit?  <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, <span class="Constant">keycode:variant</span>
      <span class="muControl">break-unless</span> k
<span class="Constant">      +global-keypress</span>
    <span class="Delimiter">}</span>
    <span class="Delimiter">{</span>
      c:address:character<span class="Special"> &lt;- </span>maybe-convert e:event, <span class="Constant">text:variant</span>
      <span class="muControl">break-unless</span> c
<span class="Constant">      +global-type</span>
      <span class="Comment"># ctrl-n? - switch focus</span>
      <span class="Delimiter">{</span>
        ctrl-n?:boolean<span class="Special"> &lt;- </span>equal *c, <span class="Constant">14/ctrl-n</span>
        <span class="muControl">break-unless</span> ctrl-n?
        *sandbox-in-focus?<span class="Special"> &lt;- </span>not *sandbox-in-focus?
        update-cursor screen, recipes, current-sandbox, *sandbox-in-focus?
        show-screen screen
        <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 - send to both sides, see what picks it up</span>
    <span class="Delimiter">{</span>
      t:address:touch-event<span class="Special"> &lt;- </span>maybe-convert e:event, <span class="Constant">touch:variant</span>
      <span class="muControl">break-unless</span> t
      <span class="Comment"># ignore all but 'left-click' events for now</span>
      <span class="Comment"># todo: test this</span>
      touch-type:number<span class="Special"> &lt;- </span>get *t, <span class="Constant">type:offset</span>
      is-left-click?:boolean<span class="Special"> &lt;- </span>equal touch-type, <span class="Constant">65513/mouse-left</span>
      <span class="muControl">loop-unless</span> is-left-click?, <span class="Constant">+next-event:label</span>
      <span class="Comment"># later exceptions for non-editor touches will go here</span>
<span class="Constant">      +global-touch</span>
      <span class="Comment"># send to both editors</span>
      _<span class="Special"> &lt;- </span>move-cursor-in-editor screen, recipes, *t
      *sandbox-in-focus?<span class="Special"> &lt;- </span>move-cursor-in-editor screen, current-sandbox, *t
      render-minimal screen, env
      <span class="muControl">loop</span> <span class="Constant">+next-event:label</span>
    <span class="Delimiter">}</span>
    <span class="Comment"># if it's not global and not a touch event, send to appropriate editor</span>
    <span class="Delimiter">{</span>
      <span class="Delimiter">{</span>
        <span class="muControl">break-if</span> *sandbox-in-focus?
        handle-keyboard-event screen, console, recipes, e:event
      <span class="Delimiter">}</span>
      <span class="Delimiter">{</span>
        <span class="muControl">break-unless</span> *sandbox-in-focus?
        handle-keyboard-event screen, console, current-sandbox, e:event
      <span class="Delimiter">}</span>
      <span class="Comment"># optimization: refresh screen only if no more events</span>
      <span class="Comment"># todo: test this</span>
      more-events?:boolean<span class="Special"> &lt;- </span>has-more-events? console
      <span class="muControl">break-if</span> more-events?
      render-minimal screen, env
    <span class="Delimiter">}</span>
    <span class="muControl">loop</span>
  <span class="Delimiter">}</span>
]

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

<span class="muScenario">scenario</span> edit-multiple-editors [
<span class="Constant">  $close-trace</span>
  assume-screen <span class="Constant">30/width</span>, <span class="Constant">5/height</span>
  <span class="Comment"># initialize both halves of screen</span>
  <span class="Constant">1</span>:address:array:character<span class="Special"> &lt;- </span>new <span class="Constant">[abc]</span>
  <span class="Constant">2</span>:address:array:character<span class="Special"> &lt;- </span>new <span class="Constant">[def]</span>
  <span class="Constant">3</span>:address:programming-environment-data<span class="Special"> &lt;- </span>new-programming-environment screen:address, <span class="Constant">1</span>:address:array:character, <span class="Constant">2</span>:address:array:character
  <span class="Comment"># type one letter in each of them</span>
  assume-console [
    left-click <span class="Constant">1</span>, <span class="Constant">1</span>
    type <span class="Constant">[0]</span>
    left-click <span class="Constant">1</span>, <span class="Constant">17</span>
    type <span class="Constant">[1]</span>
  ]
  run [
    event-loop screen:address, console:address, <span class="Constant">3</span>:address:programming-environment-data
    <span class="Constant">4</span>:address:editor-data<span class="Special"> &lt;- </span>get *<span class="Constant">3</span>:address:programming-environment-data, <span class="Constant">recipes:offset</span>
    <span class="Constant">5</span>:number<span class="Special"> &lt;- </span>get *<span class="Constant">4</span>:address:editor-data, <span class="Constant">cursor-column:offset</span>
    <span class="Constant">6</span>:address:editor-data<span class="Special"> &lt;- </span>get *<span class="Constant">3</span>:address:programming-environment-data, <span class="Constant">current-sandbox:offset</span>
    <span class="Constant">7</span>:number<span class="Special"> &lt;- </span>get *<span class="Constant">6</span>:address:editor-data, <span class="Constant">cursor-column:offset</span>
  ]
  screen-should-contain [
   <span class="Constant"> .           run (F4)           .  # 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 [
    <span class="Constant">5</span><span class="Special"> &lt;- </span><span class="Constant">2</span>  <span class="Comment"># cursor column of recipe editor</span>
    <span class="Constant">7</span><span class="Special"> &lt;- </span><span class="Constant">18</span>  <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/␣</span>
  ]
  screen-should-contain [
   <span class="Constant"> .           run (F4)           .</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/width</span>, <span class="Constant">10/height</span>
  run [
    <span class="Constant">1</span>:address:array:character<span class="Special"> &lt;- </span>new <span class="Constant">[abc]</span>
    <span class="Constant">2</span>:address:array:character<span class="Special"> &lt;- </span>new <span class="Constant">[def]</span>
    <span class="Constant">3</span>:address:programming-environment-data<span class="Special"> &lt;- </span>new-programming-environment screen:address, <span class="Constant">1</span>:address:array:character, <span class="Constant">2</span>:address:array:character
  ]
  <span class="Comment"># divider isn't messed up</span>
  screen-should-contain [
   <span class="Constant"> .                                         run (F4)           .</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/width</span>, <span class="Constant">5/height</span>
  <span class="Constant">1</span>:address:array:character<span class="Special"> &lt;- </span>new <span class="Constant">[abc]</span>
  <span class="Constant">2</span>: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 [
    <span class="Constant">3</span>:address:programming-environment-data<span class="Special"> &lt;- </span>new-programming-environment screen:address, <span class="Constant">1</span>:address:array:character, <span class="Constant">2</span>:address:array:character
    event-loop screen:address, console:address, <span class="Constant">3</span>:address:programming-environment-data
    screen:address<span class="Special"> &lt;- </span>print-character screen:address, <span class="Constant">9251/␣</span>
  ]
  <span class="Comment"># is cursor at the right place?</span>
  screen-should-contain [
   <span class="Constant"> .           run (F4)           .</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 [
    <span class="Constant">3</span>:address:programming-environment-data<span class="Special"> &lt;- </span>new-programming-environment screen:address, <span class="Constant">1</span>:address:array:character, <span class="Constant">2</span>:address:array:character
    event-loop screen:address, console:address, <span class="Constant">3</span>:address:programming-environment-data
    screen:address<span class="Special"> &lt;- </span>print-character screen:address, <span class="Constant">9251/␣</span>
  ]
  <span class="Comment"># cursor should still be right</span>
  screen-should-contain [
   <span class="Constant"> .           run (F4)           .</span>
   <span class="Constant"> .z␣bc           ┊def           .</span>
<span class="Constant">    .┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┊━━━━━━━━━━━━━━.</span>
   <span class="Constant"> .               ┊              .</span>
  ]
]

<span class="muScenario">scenario</span> backspace-in-sandbox-editor-joins-lines [
<span class="Constant">  $close-trace</span>
  assume-screen <span class="Constant">30/width</span>, <span class="Constant">5/height</span>
  <span class="Comment"># initialize sandbox side with two lines</span>
  <span class="Constant">1</span>:address:array:character<span class="Special"> &lt;- </span>new <span class="Constant">[]</span>
  <span class="Constant">2</span>:address:array:character<span class="Special"> &lt;- </span>new <span class="Constant">[abc</span>
<span class="Constant">def]</span>
  <span class="Comment"># position cursor at start of second line and hit backspace</span>
  assume-console [
    left-click <span class="Constant">2</span>, <span class="Constant">16</span>
    type <span class="Constant">[«]</span>
  ]
  <span class="Constant">3</span>:event/backspace<span class="Special"> &lt;- </span>merge <span class="Constant">0/text</span>, <span class="Constant">8/backspace</span>, <span class="Constant">0/dummy</span>, <span class="Constant">0/dummy</span>
  replace-in-console <span class="Constant">171/«</span>, <span class="Constant">3</span>:event/backspace
  run [
    <span class="Constant">4</span>:address:programming-environment-data<span class="Special"> &lt;- </span>new-programming-environment screen:address, <span class="Constant">1</span>:address:array:character, <span class="Constant">2</span>:address:array:character
    event-loop screen:address, console:address, <span class="Constant">4</span>:address:programming-environment-data
    screen:address<span class="Special"> &lt;- </span>print-character screen:address, <span class="Constant">9251/␣</span>
  ]
  <span class="Comment"># cursor moves to end of old line</span>
  screen-should-contain [
   <span class="Constant"> .           run (F4)           .</span>
   <span class="Constant"> .               ┊abc␣ef        .</span>
<span class="Constant">    .┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┊━━━━━━━━━━━━━━.</span>
   <span class="Constant"> .               ┊              .</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<span class="Special"> &lt;- </span>render-recipes screen, env
  screen<span class="Special"> &lt;- </span>render-sandbox-side screen, env
  recipes:address:editor-data<span class="Special"> &lt;- </span>get *env, <span class="Constant">recipes:offset</span>
  current-sandbox:address:editor-data<span class="Special"> &lt;- </span>get *env, <span class="Constant">current-sandbox:offset</span>
  sandbox-in-focus?:boolean<span class="Special"> &lt;- </span>get *env, <span class="Constant">sandbox-in-focus?:offset</span>
  update-cursor screen, recipes, current-sandbox, sandbox-in-focus?
  show-screen screen
  <span class="muControl">reply</span> screen/same-as-ingredient:<span class="Constant">0</span>
]

<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, <span class="Constant">recipes:offset</span>
  current-sandbox:address:editor-data<span class="Special"> &lt;- </span>get *env, <span class="Constant">current-sandbox:offset</span>
  sandbox-in-focus?:boolean<span class="Special"> &lt;- </span>get *env, <span class="Constant">sandbox-in-focus?:offset</span>
  <span class="Delimiter">{</span>
    <span class="muControl">break-if</span> sandbox-in-focus?
    screen<span class="Special"> &lt;- </span>render-recipes screen, env
    cursor-row:number<span class="Special"> &lt;- </span>get *recipes, <span class="Constant">cursor-row:offset</span>
    cursor-column:number<span class="Special"> &lt;- </span>get *recipes, <span class="Constant">cursor-column:offset</span>
  <span class="Delimiter">}</span>
  <span class="Delimiter">{</span>
    <span class="muControl">break-unless</span> sandbox-in-focus?
    screen<span class="Special"> &lt;- </span>render-sandbox-side screen, env
    cursor-row:number<span class="Special"> &lt;- </span>get *current-sandbox, <span class="Constant">cursor-row:offset</span>
    cursor-column:number<span class="Special"> &lt;- </span>get *current-sandbox, <span class="Constant">cursor-column:offset</span>
  <span class="Delimiter">}</span>
  move-cursor screen, cursor-row, cursor-column
  show-screen screen
  <span class="muControl">reply</span> screen/same-as-ingredient:<span class="Constant">0</span>
]

<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>
  recipes:address:editor-data<span class="Special"> &lt;- </span>get *env, <span class="Constant">recipes:offset</span>
  <span class="Comment"># render recipes</span>
  left:number<span class="Special"> &lt;- </span>get *recipes, <span class="Constant">left:offset</span>
  right:number<span class="Special"> &lt;- </span>get *recipes, <span class="Constant">right:offset</span>
  row:number, screen<span class="Special"> &lt;- </span>render screen, recipes
  recipe-warnings:address:array:character<span class="Special"> &lt;- </span>get *env, <span class="Constant">recipe-warnings:offset</span>
  <span class="Delimiter">{</span>
    <span class="Comment"># print any warnings</span>
    <span class="muControl">break-unless</span> recipe-warnings
    row, screen<span class="Special"> &lt;- </span>render-string screen, recipe-warnings, left, right, <span class="Constant">1/red</span>, row
  <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
    row<span class="Special"> &lt;- </span>add row, <span class="Constant">1</span>
  <span class="Delimiter">}</span>
  <span class="Comment"># draw dotted line after recipes</span>
  draw-horizontal screen, row, left, right, <span class="Constant">9480/horizontal-dotted</span>
  clear-rest-of-screen screen, row, left, right
  <span class="muControl">reply</span> screen/same-as-ingredient:<span class="Constant">0</span>
]

<span class="muRecipe">recipe</span> clear-rest-of-screen [
  <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>
  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<span class="Special"> &lt;- </span>add row, <span class="Constant">1</span>
  move-cursor screen, row, left
  screen-height:number<span class="Special"> &lt;- </span>screen-height screen
  <span class="Delimiter">{</span>
    at-bottom-of-screen?:boolean<span class="Special"> &lt;- </span>greater-or-equal row, screen-height
    <span class="muControl">break-if</span> at-bottom-of-screen?
    move-cursor screen, row, left
    clear-line-delimited screen, left, right
    row<span class="Special"> &lt;- </span>add row, <span class="Constant">1</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> 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?
<span class="CommentedCode">#?     $print [recipes in focus</span>
<span class="CommentedCode">#? ] #? 1</span>
    cursor-row:number<span class="Special"> &lt;- </span>get *recipes, <span class="Constant">cursor-row:offset</span>
    cursor-column:number<span class="Special"> &lt;- </span>get *recipes, <span class="Constant">cursor-column:offset</span>
  <span class="Delimiter">}</span>
  <span class="Delimiter">{</span>
    <span class="muControl">break-unless</span> sandbox-in-focus?
<span class="CommentedCode">#?     $print [sandboxes in focus</span>
<span class="CommentedCode">#? ] #? 1</span>
    cursor-row:number<span class="Special"> &lt;- </span>get *current-sandbox, <span class="Constant">cursor-row:offset</span>
    cursor-column:number<span class="Special"> &lt;- </span>get *current-sandbox, <span class="Constant">cursor-column:offset</span>
  <span class="Delimiter">}</span>
  move-cursor screen, cursor-row, cursor-column
]

<span class="SalientComment">## running code from the editor and creating sandboxes</span>

container sandbox-data [
  data:address:array:character
  response:address:array:character
  warnings:address:array:character
  trace:address:array:character
  expected-response:address:array:character
  <span class="Comment"># coordinates to track clicks</span>
  starting-row-on-screen:number
  response-starting-row-on-screen:number
  display-trace?:boolean
  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/width</span>, <span class="Constant">15/height</span>
  <span class="Comment"># recipe editor is empty</span>
  <span class="Constant">1</span>: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>
  <span class="Constant">2</span>:address:array:character<span class="Special"> &lt;- </span>new <span class="Constant">[divide-with-remainder 11, 3]</span>
  <span class="Constant">3</span>:address:programming-environment-data<span class="Special"> &lt;- </span>new-programming-environment screen:address, <span class="Constant">1</span>:address:array:character, <span class="Constant">2</span>:address:array:character
  <span class="Comment"># run the code in the editors</span>
  assume-console [
    press <span class="Constant">65532</span>  <span class="Comment"># F4</span>
  ]
  run [
    event-loop screen:address, console:address, <span class="Constant">3</span>:address:programming-environment-data
  ]
  <span class="Comment"># check that screen prints the results</span>
  screen-should-contain [
   <span class="Constant"> .                                                                                 run (F4)           .</span>
   <span class="Constant"> .                                                  ┊                                                 .</span>
<span class="Constant">    .┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┊━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━.</span>
   <span class="Constant"> .                                                  ┊                                                x.</span>
   <span class="Constant"> .                                                  ┊divide-with-remainder 11, 3                      .</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/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, 3                      .</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/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 <span class="Constant">1</span>, <span class="Constant">80</span>
    type <span class="Constant">[add 2, 2]</span>
    press <span class="Constant">65532</span>  <span class="Comment"># F4</span>
  ]
  run [
    event-loop screen:address, console:address, <span class="Constant">3</span>:address:programming-environment-data
  ]
  <span class="Comment"># check that screen prints the results</span>
  screen-should-contain [
   <span class="Constant"> .                                                                                 run (F4)           .</span>
   <span class="Constant"> .                                                  ┊                                                 .</span>
<span class="Constant">    .┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┊━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━.</span>
   <span class="Constant"> .                                                  ┊                                                x.</span>
   <span class="Constant"> .                                                  ┊add 2, 2                                         .</span>
   <span class="Constant"> .                                                  ┊4                                                .</span>
   <span class="Constant"> .                                                  ┊━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━.</span>
   <span class="Constant"> .                                                  ┊                                                x.</span>
   <span class="Constant"> .                                                  ┊divide-with-remainder 11, 3                      .</span>
   <span class="Constant"> .                                                  ┊3                                                .</span>
   <span class="Constant"> .                                                  ┊2                                                .</span>
   <span class="Constant"> .                                                  ┊━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━.</span>
   <span class="Constant"> .                                                  ┊                                                 .</span>
  ]
]

<span class="Comment"># hook into event-loop recipe: read non-unicode keypress from k, process it if</span>
<span class="Comment"># necessary, then go to next level</span>
<span class="muRecipe">after</span> +global-keypress [
  <span class="Comment"># F4? load all code and run all sandboxes.</span>
  <span class="Delimiter">{</span>
    do-run?:boolean<span class="Special"> &lt;- </span>equal *k, <span class="Constant">65532/F4</span>
    <span class="muControl">break-unless</span> do-run?
    run-sandboxes env
    <span class="Comment"># F4 might update warnings and results on both sides</span>
    screen<span class="Special"> &lt;- </span>render-all screen, env
    update-cursor screen, recipes, current-sandbox, *sandbox-in-focus?
    show-screen screen
    <span class="muControl">loop</span> <span class="Constant">+next-event:label</span>
  <span class="Delimiter">}</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, <span class="Constant">recipes:offset</span>
  <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
  save <span class="Constant">[recipes.mu]</span>, in
  recipe-warnings:address:address:array:character<span class="Special"> &lt;- </span>get-address *env, <span class="Constant">recipe-warnings:offset</span>
  *recipe-warnings<span class="Special"> &lt;- </span>reload in
  <span class="Comment"># if recipe editor has errors, stop</span>
  <span class="muControl">reply-if</span> *recipe-warnings
  <span class="Comment"># check contents of right editor (sandbox)</span>
  current-sandbox:address:editor-data<span class="Special"> &lt;- </span>get *env, <span class="Constant">current-sandbox:offset</span>
  <span class="Delimiter">{</span>
    sandbox-contents:address:array:character<span class="Special"> &lt;- </span>editor-contents current-sandbox
    <span class="muControl">break-unless</span> sandbox-contents
    <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 <span class="Constant">sandbox-data:type</span>
    data:address:address:array:character<span class="Special"> &lt;- </span>get-address *new-sandbox, <span class="Constant">data:offset</span>
    *data<span class="Special"> &lt;- </span>copy sandbox-contents
    <span class="Comment"># push to head of sandbox list</span>
    dest:address:address:sandbox-data<span class="Special"> &lt;- </span>get-address *env, <span class="Constant">sandbox:offset</span>
    next:address:address:sandbox-data<span class="Special"> &lt;- </span>get-address *new-sandbox, <span class="Constant">next-sandbox:offset</span>
    *next<span class="Special"> &lt;- </span>copy *dest
    *dest<span class="Special"> &lt;- </span>copy new-sandbox
    <span class="Comment"># clear sandbox editor</span>
    init:address:address:duplex-list<span class="Special"> &lt;- </span>get-address *current-sandbox, <span class="Constant">data:offset</span>
    *init<span class="Special"> &lt;- </span>push-duplex <span class="Constant">167/§</span>, <span class="Constant">0/tail</span>
    top-of-screen:address:address:duplex-list<span class="Special"> &lt;- </span>get-address *current-sandbox, <span class="Constant">top-of-screen:offset</span>
    *top-of-screen<span class="Special"> &lt;- </span>copy *init
  <span class="Delimiter">}</span>
  <span class="Comment"># save all sandboxes before running, just in case we die when running</span>
  save-sandboxes env
  <span class="Comment"># run all sandboxes</span>
  curr:address:sandbox-data<span class="Special"> &lt;- </span>get *env, <span class="Constant">sandbox:offset</span>
  <span class="Delimiter">{</span>
    <span class="muControl">break-unless</span> curr
    data<span class="Special"> &lt;- </span>get-address *curr, <span class="Constant">data:offset</span>
    response:address:address:array:character<span class="Special"> &lt;- </span>get-address *curr, <span class="Constant">response:offset</span>
    warnings:address:address:array:character<span class="Special"> &lt;- </span>get-address *curr, <span class="Constant">warnings:offset</span>
    trace:address:address:array:character<span class="Special"> &lt;- </span>get-address *curr, <span class="Constant">trace:offset</span>
    fake-screen:address:address:screen<span class="Special"> &lt;- </span>get-address *curr, <span class="Constant">screen:offset</span>
    *response, *warnings, *fake-screen, *trace<span class="Special"> &lt;- </span>run-interactive *data
    curr<span class="Special"> &lt;- </span>get *curr, <span class="Constant">next-sandbox:offset</span>
    <span class="muControl">loop</span>
  <span class="Delimiter">}</span>
]

<span class="muRecipe">recipe</span> save-sandboxes [
  <span class="Constant">local-scope</span>
  env:address:programming-environment-data<span class="Special"> &lt;- </span><span class="Constant">next-ingredient</span>
  current-sandbox:address:editor-data<span class="Special"> &lt;- </span>get *env, <span class="Constant">current-sandbox:offset</span>
  <span class="Comment"># first clear previous versions, in case we deleted some sandbox</span>
  $system <span class="Constant">[rm lesson/[0-9]</span>* &gt;/dev/null <span class="Constant">2</span>&gt;/dev/null]  <span class="Comment"># some shells can't handle '&gt;&amp;'</span>
  curr:address:sandbox-data<span class="Special"> &lt;- </span>get *env, <span class="Constant">sandbox:offset</span>
  suffix:address:array:character<span class="Special"> &lt;- </span>new <span class="Constant">[.out]</span>
  idx:number<span class="Special"> &lt;- </span>copy <span class="Constant">0</span>
  <span class="Delimiter">{</span>
    <span class="muControl">break-unless</span> curr
    data:address:array:character<span class="Special"> &lt;- </span>get *curr, <span class="Constant">data:offset</span>
    filename:address:array:character<span class="Special"> &lt;- </span>integer-to-decimal-string idx
    save filename, data
    <span class="Delimiter">{</span>
      expected-response:address:array:character<span class="Special"> &lt;- </span>get *curr, <span class="Constant">expected-response:offset</span>
      <span class="muControl">break-unless</span> expected-response
      filename<span class="Special"> &lt;- </span>string-append filename, suffix
      save filename, expected-response
    <span class="Delimiter">}</span>
    idx<span class="Special"> &lt;- </span>add idx, <span class="Constant">1</span>
    curr<span class="Special"> &lt;- </span>get *curr, <span class="Constant">next-sandbox:offset</span>
    <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>
<span class="CommentedCode">#?   trace [app], [render sandbox side] #? 1</span>
  current-sandbox:address:editor-data<span class="Special"> &lt;- </span>get *env, <span class="Constant">current-sandbox:offset</span>
  left:number<span class="Special"> &lt;- </span>get *current-sandbox, <span class="Constant">left:offset</span>
  right:number<span class="Special"> &lt;- </span>get *current-sandbox, <span class="Constant">right:offset</span>
  row:number, screen<span class="Special"> &lt;- </span>render screen, current-sandbox
  row<span class="Special"> &lt;- </span>add row, <span class="Constant">1</span>
  draw-horizontal screen, row, left, right, <span class="Constant">9473/horizontal-double</span>
  sandbox:address:sandbox-data<span class="Special"> &lt;- </span>get *env, <span class="Constant">sandbox:offset</span>
  row, screen<span class="Special"> &lt;- </span>render-sandboxes screen, sandbox, left, right, row
  <span class="Comment"># clear rest of screen</span>
  row<span class="Special"> &lt;- </span>add row, <span class="Constant">1</span>
  move-cursor screen, row, left
  screen-height:number<span class="Special"> &lt;- </span>screen-height screen
  <span class="Delimiter">{</span>
    at-bottom-of-screen?:boolean<span class="Special"> &lt;- </span>greater-or-equal row, screen-height
    <span class="muControl">break-if</span> at-bottom-of-screen?
    move-cursor screen, row, left
    clear-line-delimited screen, left, right
    row<span class="Special"> &lt;- </span>add row, <span class="Constant">1</span>
    <span class="muControl">loop</span>
  <span class="Delimiter">}</span>
  <span class="muControl">reply</span> screen/same-as-ingredient:<span class="Constant">0</span>
]

<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, row/same-as-ingredient:<span class="Constant">4</span>, screen/same-as-ingredient:<span class="Constant">0</span>
  screen-height:number<span class="Special"> &lt;- </span>screen-height screen
  at-bottom?:boolean<span class="Special"> &lt;- </span>greater-or-equal row, screen-height
  <span class="muControl">reply-if</span> at-bottom?:boolean, row/same-as-ingredient:<span class="Constant">4</span>, screen/same-as-ingredient:<span class="Constant">0</span>
  <span class="Comment"># render sandbox menu</span>
  row<span class="Special"> &lt;- </span>add row, <span class="Constant">1</span>
  move-cursor screen, row, left
  clear-line-delimited screen, left, right
  print-character screen, <span class="Constant">120/x</span>, <span class="Constant">245/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, <span class="Constant">starting-row-on-screen:offset</span>
  *starting-row<span class="Special"> &lt;- </span>copy row
  <span class="Comment"># render sandbox contents</span>
  sandbox-data:address:array:character<span class="Special"> &lt;- </span>get *sandbox, <span class="Constant">data:offset</span>
  row, screen<span class="Special"> &lt;- </span>render-string screen, sandbox-data, left, right, <span class="Constant">7/white</span>, row
  <span class="Comment"># render sandbox warnings, screen or response, in that order</span>
  response-starting-row:address:number<span class="Special"> &lt;- </span>get-address *sandbox, <span class="Constant">response-starting-row-on-screen:offset</span>
  sandbox-response:address:array:character<span class="Special"> &lt;- </span>get *sandbox, <span class="Constant">response:offset</span>
  sandbox-warnings:address:array:character<span class="Special"> &lt;- </span>get *sandbox, <span class="Constant">warnings:offset</span>
  sandbox-screen:address<span class="Special"> &lt;- </span>get *sandbox, <span class="Constant">screen:offset</span>
<span class="Constant">  +render-sandbox-results</span>
  <span class="Delimiter">{</span>
    <span class="muControl">break-unless</span> sandbox-warnings
    *response-starting-row<span class="Special"> &lt;- </span>copy <span class="Constant">0</span>  <span class="Comment"># no response</span>
    row, screen<span class="Special"> &lt;- </span>render-string screen, sandbox-warnings, left, right, <span class="Constant">1/red</span>, row
  <span class="Delimiter">}</span>
  <span class="Delimiter">{</span>
    <span class="muControl">break-if</span> sandbox-warnings
    empty-screen?:boolean<span class="Special"> &lt;- </span>fake-screen-is-empty? sandbox-screen
    <span class="muControl">break-if</span> empty-screen?
    row, screen<span class="Special"> &lt;- </span>render-screen screen, sandbox-screen, left, right, row
  <span class="Delimiter">}</span>
  <span class="Delimiter">{</span>
    <span class="muControl">break-if</span> sandbox-warnings
    <span class="muControl">break-unless</span> empty-screen?
<span class="CommentedCode">#?     $print [display response from ], row, 10/newline #? 1</span>
    *response-starting-row<span class="Special"> &lt;- </span>add row, <span class="Constant">1</span>
<span class="Constant">    +render-sandbox-response</span>
    row, screen<span class="Special"> &lt;- </span>render-string screen, sandbox-response, left, right, <span class="Constant">245/grey</span>, row
  <span class="Delimiter">}</span>
<span class="Constant">  +render-sandbox-end</span>
  at-bottom?:boolean<span class="Special"> &lt;- </span>greater-or-equal row, screen-height
  <span class="muControl">reply-if</span> at-bottom?, row/same-as-ingredient:<span class="Constant">4</span>, screen/same-as-ingredient:<span class="Constant">0</span>
  <span class="Comment"># draw solid line after sandbox</span>
  draw-horizontal screen, row, left, right, <span class="Constant">9473/horizontal-double</span>
  <span class="Comment"># draw next sandbox</span>
  next-sandbox:address:sandbox-data<span class="Special"> &lt;- </span>get *sandbox, <span class="Constant">next-sandbox:offset</span>
  row, screen<span class="Special"> &lt;- </span>render-sandboxes screen, next-sandbox, left, right, row
  <span class="muControl">reply</span> row/same-as-ingredient:<span class="Constant">4</span>, screen/same-as-ingredient:<span class="Constant">0</span>
]

<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>
  suffix:address:array:character<span class="Special"> &lt;- </span>new <span class="Constant">[.out]</span>
  idx:number<span class="Special"> &lt;- </span>copy <span class="Constant">0</span>
  curr:address:address:sandbox-data<span class="Special"> &lt;- </span>get-address *env, <span class="Constant">sandbox:offset</span>
  <span class="Delimiter">{</span>
    filename:address:array:character<span class="Special"> &lt;- </span>integer-to-decimal-string idx
    contents:address:array:character<span class="Special"> &lt;- </span>restore filename
    <span class="muControl">break-unless</span> contents  <span class="Comment"># stop at first error; assuming file didn't exist</span>
    <span class="Comment"># create new sandbox for file</span>
    *curr<span class="Special"> &lt;- </span>new <span class="Constant">sandbox-data:type</span>
    data:address:address:array:character<span class="Special"> &lt;- </span>get-address **curr, <span class="Constant">data:offset</span>
    *data<span class="Special"> &lt;- </span>copy contents
    <span class="Comment"># restore expected output for sandbox if it exists</span>
    <span class="Delimiter">{</span>
      filename<span class="Special"> &lt;- </span>string-append filename, suffix
      contents<span class="Special"> &lt;- </span>restore filename
      <span class="muControl">break-unless</span> contents
      expected-response:address:address:array:character<span class="Special"> &lt;- </span>get-address **curr, <span class="Constant">expected-response:offset</span>
      *expected-response<span class="Special"> &lt;- </span>copy contents
    <span class="Delimiter">}</span>
<span class="Constant">    +continue</span>
    idx<span class="Special"> &lt;- </span>add idx, <span class="Constant">1</span>
    curr<span class="Special"> &lt;- </span>get-address **curr, <span class="Constant">next-sandbox:offset</span>
    <span class="muControl">loop</span>
  <span class="Delimiter">}</span>
  <span class="muControl">reply</span> env/same-as-ingredient:<span class="Constant">0</span>
]

<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<span class="Special"> &lt;- </span>add row, <span class="Constant">1</span>
  <span class="muControl">reply-unless</span> s, row/same-as-ingredient:<span class="Constant">4</span>, screen/same-as-ingredient:<span class="Constant">0</span>
  <span class="Comment"># print 'screen:'</span>
  header:address:array:character<span class="Special"> &lt;- </span>new <span class="Constant">[screen:]</span>
  row<span class="Special"> &lt;- </span>subtract row, <span class="Constant">1</span>  <span class="Comment"># compensate for render-string below</span>
  row<span class="Special"> &lt;- </span>render-string screen, header, left, right, <span class="Constant">245/grey</span>, row
  <span class="Comment"># newline</span>
  row<span class="Special"> &lt;- </span>add row, <span class="Constant">1</span>
  move-cursor screen, row, left
  <span class="Comment"># start printing s</span>
  column:number<span class="Special"> &lt;- </span>copy left
  s-width:number<span class="Special"> &lt;- </span>screen-width s
  s-height:number<span class="Special"> &lt;- </span>screen-height s
  buf:address:array:screen-cell<span class="Special"> &lt;- </span>get *s, <span class="Constant">data:offset</span>
  stop-printing:number<span class="Special"> &lt;- </span>add left, s-width, <span class="Constant">3</span>
  max-column:number<span class="Special"> &lt;- </span>min stop-printing, right
  i:number<span class="Special"> &lt;- </span>copy <span class="Constant">0</span>
  len:number<span class="Special"> &lt;- </span>length *buf
  screen-height:number<span class="Special"> &lt;- </span>screen-height screen
  <span class="Delimiter">{</span>
    done?:boolean<span class="Special"> &lt;- </span>greater-or-equal i, len
    <span class="muControl">break-if</span> done?
    done?<span class="Special"> &lt;- </span>greater-or-equal row, screen-height
    <span class="muControl">break-if</span> done?
    column<span class="Special"> &lt;- </span>copy left
    move-cursor screen, row, column
    <span class="Comment"># initial leader for each row: two spaces and a '.'</span>
    print-character screen, <span class="Constant">32/space</span>, <span class="Constant">245/grey</span>
    print-character screen, <span class="Constant">32/space</span>, <span class="Constant">245/grey</span>
    print-character screen, <span class="Constant">46/full-stop</span>, <span class="Constant">245/grey</span>
    column<span class="Special"> &lt;- </span>add left, <span class="Constant">3</span>
    <span class="Delimiter">{</span>
      <span class="Comment"># print row</span>
      row-done?:boolean<span class="Special"> &lt;- </span>greater-or-equal column, max-column
      <span class="muControl">break-if</span> row-done?
      curr:screen-cell<span class="Special"> &lt;- </span>index *buf, i
      c:character<span class="Special"> &lt;- </span>get curr, <span class="Constant">contents:offset</span>
      print-character screen, c, <span class="Constant">245/grey</span>
      column<span class="Special"> &lt;- </span>add column, <span class="Constant">1</span>
      i<span class="Special"> &lt;- </span>add i, <span class="Constant">1</span>
      <span class="muControl">loop</span>
    <span class="Delimiter">}</span>
    <span class="Comment"># print final '.'</span>
    print-character screen, <span class="Constant">46/full-stop</span>, <span class="Constant">245/grey</span>
    column<span class="Special"> &lt;- </span>add column, <span class="Constant">1</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, right
      <span class="muControl">break-if</span> line-done?
      print-character screen, <span class="Constant">32/space</span>
      column<span class="Special"> &lt;- </span>add column, <span class="Constant">1</span>
      <span class="muControl">loop</span>
    <span class="Delimiter">}</span>
    row<span class="Special"> &lt;- </span>add row, <span class="Constant">1</span>
    <span class="muControl">loop</span>
  <span class="Delimiter">}</span>
  <span class="muControl">reply</span> row/same-as-ingredient:<span class="Constant">4</span>, screen/same-as-ingredient:<span class="Constant">0</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/width</span>, <span class="Constant">12/height</span>
  <span class="Comment"># define a recipe (no indent for the 'add' line below so column numbers are more obvious)</span>
  <span class="Constant">1</span>: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, 2</span>
<span class="Constant">]</span>]
  <span class="Comment"># sandbox editor contains an instruction without storing outputs</span>
  <span class="Constant">2</span>:address:array:character<span class="Special"> &lt;- </span>new <span class="Constant">[foo]</span>
  <span class="Constant">3</span>:address:programming-environment-data<span class="Special"> &lt;- </span>new-programming-environment screen:address, <span class="Constant">1</span>:address:array:character, <span class="Constant">2</span>:address:array:character
  <span class="Comment"># run the code in the editors</span>
  assume-console [
    press <span class="Constant">65532</span>  <span class="Comment"># F4</span>
  ]
  run [
    event-loop screen:address, console:address, <span class="Constant">3</span>:address:programming-environment-data
  ]
  <span class="Comment"># check that screen prints the results</span>
  screen-should-contain [
   <span class="Constant"> .                                                                                 run (F4)           .</span>
   <span class="Constant"> .                                                  ┊                                                 .</span>
   <span class="Constant"> .recipe foo [                                      ┊━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━.</span>
   <span class="Constant"> .z:number &lt;- add 2, 2                              ┊                                                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 <span class="Constant">3</span>, <span class="Constant">28</span>  <span class="Comment"># one past the value of the second arg</span>
    type <span class="Constant">[«3]</span>  <span class="Comment"># replace</span>
    press <span class="Constant">65532</span>  <span class="Comment"># F4</span>
  ]
  <span class="Constant">4</span>:event/backspace<span class="Special"> &lt;- </span>merge <span class="Constant">0/text</span>, <span class="Constant">8/backspace</span>, <span class="Constant">0/dummy</span>, <span class="Constant">0/dummy</span>
  replace-in-console <span class="Constant">171/«</span>, <span class="Constant">4</span>:event/backspace
  run [
    event-loop screen:address, console:address, <span class="Constant">3</span>:address:programming-environment-data
  ]
  <span class="Comment"># check that screen updates the result on the right</span>
  screen-should-contain [
   <span class="Constant"> .                                                                                 run (F4)           .</span>
   <span class="Constant"> .                                                  ┊                                                 .</span>
   <span class="Constant"> .recipe foo [                                      ┊━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━.</span>
   <span class="Constant"> .z:number &lt;- add 2, 3                              ┊                                                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/width</span>, <span class="Constant">10/height</span>
  <span class="Comment"># left editor is empty</span>
  <span class="Constant">1</span>:address:array:character<span class="Special"> &lt;- </span>new <span class="Constant">[]</span>
  <span class="Comment"># right editor contains an illegal instruction</span>
  <span class="Constant">2</span>:address:array:character<span class="Special"> &lt;- </span>new <span class="Constant">[get 1234:number, foo:offset]</span>
  <span class="Constant">3</span>:address:programming-environment-data<span class="Special"> &lt;- </span>new-programming-environment screen:address, <span class="Constant">1</span>:address:array:character, <span class="Constant">2</span>:address:array:character
  <span class="Comment"># run the code in the editors</span>
  assume-console [
    press <span class="Constant">65532</span>  <span class="Comment"># F4</span>
  ]
  run [
    event-loop screen:address, console:address, <span class="Constant">3</span>:address:programming-environment-data
  ]
  <span class="Comment"># check that screen prints error message in red</span>
  screen-should-contain [
   <span class="Constant"> .                                                                                 run (F4)           .</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/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/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/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/width</span>, <span class="Constant">10/height</span>
  <span class="Comment"># left editor is empty</span>
  <span class="Constant">1</span>:address:array:character<span class="Special"> &lt;- </span>new <span class="Constant">[]</span>
  <span class="Comment"># right editor contains an illegal instruction</span>
  <span class="Constant">2</span>:address:array:character<span class="Special"> &lt;- </span>new <span class="Constant">[get 1234:number, foo:offset]</span>
  <span class="Constant">3</span>:address:programming-environment-data<span class="Special"> &lt;- </span>new-programming-environment screen:address, <span class="Constant">1</span>:address:array:character, <span class="Constant">2</span>:address:array:character
  <span class="Comment"># run the code in the editors multiple times</span>
  assume-console [
    press <span class="Constant">65532</span>  <span class="Comment"># F4</span>
    press <span class="Constant">65532</span>  <span class="Comment"># F4</span>
  ]
  run [
    event-loop screen:address, console:address, <span class="Constant">3</span>:address:programming-environment-data
  ]
  <span class="Comment"># check that screen prints error message just once</span>
  screen-should-contain [
   <span class="Constant"> .                                                                                 run (F4)           .</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> run-instruction-manages-screen-per-sandbox [
  $close-trace  <span class="Comment"># trace too long for github #? 1</span>
  assume-screen <span class="Constant">100/width</span>, <span class="Constant">20/height</span>
  <span class="Comment"># left editor is empty</span>
  <span class="Constant">1</span>:address:array:character<span class="Special"> &lt;- </span>new <span class="Constant">[]</span>
  <span class="Comment"># right editor contains an illegal instruction</span>
  <span class="Constant">2</span>:address:array:character<span class="Special"> &lt;- </span>new <span class="Constant">[print-integer screen:address, 4]</span>
  <span class="Constant">3</span>:address:programming-environment-data<span class="Special"> &lt;- </span>new-programming-environment screen:address, <span class="Constant">1</span>:address:array:character, <span class="Constant">2</span>:address:array:character
  <span class="Comment"># run the code in the editor</span>
  assume-console [
    press <span class="Constant">65532</span>  <span class="Comment"># F4</span>
  ]
  run [
    event-loop screen:address, console:address, <span class="Constant">3</span>: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 (F4)           .</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</span>
  curr:address:duplex-list<span class="Special"> &lt;- </span>get *editor, <span class="Constant">data:offset</span>
  <span class="Comment"># skip § sentinel</span>
  assert curr, <span class="Constant">[editor without data is illegal; must have at least a sentinel]</span>
  curr<span class="Special"> &lt;- </span>next-duplex curr
  <span class="muControl">reply-unless</span> curr, <span class="Constant">0</span>
  <span class="Delimiter">{</span>
    <span class="muControl">break-unless</span> curr
    c:character<span class="Special"> &lt;- </span>get *curr, <span class="Constant">value:offset</span>
    buffer-append buf, c
    curr<span class="Special"> &lt;- </span>next-duplex curr
    <span class="muControl">loop</span>
  <span class="Delimiter">}</span>
  result:address:array:character<span class="Special"> &lt;- </span>buffer-to-array buf
  <span class="muControl">reply</span> result
]

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

<span class="SalientComment">## editing sandboxes after they've been created</span>

<span class="muScenario">scenario</span> clicking-on-a-sandbox-moves-it-to-editor [
<span class="Constant">  $close-trace</span>
  assume-screen <span class="Constant">40/width</span>, <span class="Constant">10/height</span>
  <span class="Comment"># basic recipe</span>
  <span class="Constant">1</span>:address:array:character<span class="Special"> &lt;- </span>new <span class="Constant">[ </span>
<span class="Constant">recipe foo [</span>
<span class="Constant">  add 2, 2</span>
<span class="Constant">]</span>]
  <span class="Comment"># run it</span>
  <span class="Constant">2</span>:address:array:character<span class="Special"> &lt;- </span>new <span class="Constant">[foo]</span>
  assume-console [
    press <span class="Constant">65532</span>  <span class="Comment"># F4</span>
  ]
  <span class="Constant">3</span>:address:programming-environment-data<span class="Special"> &lt;- </span>new-programming-environment screen:address, <span class="Constant">1</span>:address:array:character, <span class="Constant">2</span>:address:array:character
  event-loop screen:address, console:address, <span class="Constant">3</span>:address:programming-environment-data
  screen-should-contain [
   <span class="Constant"> .                     run (F4)           .</span>
   <span class="Constant"> .                    ┊                   .</span>
   <span class="Constant"> .recipe foo [        ┊━━━━━━━━━━━━━━━━━━━.</span>
   <span class="Constant"> .  add 2, 2          ┊                  x.</span>
   <span class="Constant"> .]                   ┊foo                .</span>
   <span class="Constant"> .┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┊4                  .</span>
   <span class="Constant"> .                    ┊━━━━━━━━━━━━━━━━━━━.</span>
   <span class="Constant"> .                    ┊                   .</span>
  ]
  <span class="Comment"># click somewhere on the sandbox</span>
  assume-console [
    left-click <span class="Constant">3</span>, <span class="Constant">30</span>
  ]
  run [
    event-loop screen:address, console:address, <span class="Constant">3</span>:address:programming-environment-data
  ]
  <span class="Comment"># it pops back into editor</span>
  screen-should-contain [
   <span class="Constant"> .                     run (F4)           .</span>
   <span class="Constant"> .                    ┊foo                .</span>
   <span class="Constant"> .recipe foo [        ┊━━━━━━━━━━━━━━━━━━━.</span>
   <span class="Constant"> .  add 2, 2          ┊                   .</span>
   <span class="Constant"> .]                   ┊                   .</span>
   <span class="Constant"> .┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┊                   .</span>
   <span class="Constant"> .                    ┊                   .</span>
   <span class="Constant"> .                    ┊                   .</span>
  ]
]

<span class="muRecipe">after</span> +global-touch [
  <span class="Comment"># right side of screen and below sandbox editor? pop appropriate sandbox</span>
  <span class="Comment"># contents back into sandbox editor provided it's empty</span>
  <span class="Delimiter">{</span>
    sandbox-left-margin:number<span class="Special"> &lt;- </span>get *current-sandbox, <span class="Constant">left:offset</span>
    click-column:number<span class="Special"> &lt;- </span>get *t, <span class="Constant">column:offset</span>
    on-sandbox-side?:boolean<span class="Special"> &lt;- </span>greater-or-equal click-column, sandbox-left-margin
    <span class="muControl">break-unless</span> on-sandbox-side?
    first-sandbox:address:sandbox-data<span class="Special"> &lt;- </span>get *env, <span class="Constant">sandbox:offset</span>
    <span class="muControl">break-unless</span> first-sandbox
    first-sandbox-begins:number<span class="Special"> &lt;- </span>get *first-sandbox, <span class="Constant">starting-row-on-screen:offset</span>
    click-row:number<span class="Special"> &lt;- </span>get *t, <span class="Constant">row:offset</span>
    below-sandbox-editor?:boolean<span class="Special"> &lt;- </span>greater-or-equal click-row, first-sandbox-begins
    <span class="muControl">break-unless</span> below-sandbox-editor?
    empty-sandbox-editor?:boolean<span class="Special"> &lt;- </span>empty-editor? current-sandbox
    <span class="muControl">break-unless</span> empty-sandbox-editor?  <span class="Comment"># make the user hit F4 before editing a new sandbox</span>
    <span class="Comment"># identify the sandbox to edit and remove it from the sandbox list</span>
    sandbox:address:sandbox-data<span class="Special"> &lt;- </span>extract-sandbox env, click-row
    text:address:array:character<span class="Special"> &lt;- </span>get *sandbox, <span class="Constant">data:offset</span>
    current-sandbox<span class="Special"> &lt;- </span>insert-text current-sandbox, text
    screen<span class="Special"> &lt;- </span>render-sandbox-side screen, env
    update-cursor screen, recipes, current-sandbox, *sandbox-in-focus?
    show-screen screen
    <span class="muControl">loop</span> <span class="Constant">+next-event:label</span>
  <span class="Delimiter">}</span>
]

<span class="muRecipe">recipe</span> empty-editor? [
  <span class="Constant">local-scope</span>
  editor:address:editor-data<span class="Special"> &lt;- </span><span class="Constant">next-ingredient</span>
  head:address:duplex-list<span class="Special"> &lt;- </span>get *editor, <span class="Constant">data:offset</span>
  first:address:duplex-list<span class="Special"> &lt;- </span>next-duplex head
  result:boolean<span class="Special"> &lt;- </span>not first
  <span class="muControl">reply</span> result
]

<span class="muRecipe">recipe</span> extract-sandbox [
  <span class="Constant">local-scope</span>
  env:address:programming-environment-data<span class="Special"> &lt;- </span><span class="Constant">next-ingredient</span>
  click-row:number<span class="Special"> &lt;- </span><span class="Constant">next-ingredient</span>
  <span class="Comment"># assert click-row &gt;= sandbox.starting-row-on-screen</span>
  sandbox:address:address:sandbox-data<span class="Special"> &lt;- </span>get-address *env, <span class="Constant">sandbox:offset</span>
  start:number<span class="Special"> &lt;- </span>get **sandbox, <span class="Constant">starting-row-on-screen:offset</span>
  clicked-on-sandboxes?:boolean<span class="Special"> &lt;- </span>greater-or-equal click-row, start
  assert clicked-on-sandboxes?, <span class="Constant">[extract-sandbox called on click to sandbox editor]</span>
  <span class="Delimiter">{</span>
    next-sandbox:address:sandbox-data<span class="Special"> &lt;- </span>get **sandbox, <span class="Constant">next-sandbox:offset</span>
    <span class="muControl">break-unless</span> next-sandbox
    <span class="Comment"># if click-row &lt; sandbox.next-sandbox.starting-row-on-screen, break</span>
    next-start:number<span class="Special"> &lt;- </span>get *next-sandbox, <span class="Constant">starting-row-on-screen:offset</span>
    found?:boolean<span class="Special"> &lt;- </span>lesser-than click-row, next-start
    <span class="muControl">break-if</span> found?
    sandbox<span class="Special"> &lt;- </span>get-address **sandbox, <span class="Constant">next-sandbox:offset</span>
    <span class="muControl">loop</span>
  <span class="Delimiter">}</span>
  <span class="Comment"># snip sandbox out of its list</span>
  result:address:sandbox-data<span class="Special"> &lt;- </span>copy *sandbox
  *sandbox<span class="Special"> &lt;- </span>copy next-sandbox
  <span class="muControl">reply</span> result
]

<span class="SalientComment">## deleting sandboxes</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/width</span>, <span class="Constant">15/height</span>
  <span class="Constant">1</span>:address:array:character<span class="Special"> &lt;- </span>new <span class="Constant">[]</span>
  <span class="Constant">2</span>:address:array:character<span class="Special"> &lt;- </span>new <span class="Constant">[]</span>
  <span class="Constant">3</span>:address:programming-environment-data<span class="Special"> &lt;- </span>new-programming-environment screen:address, <span class="Constant">1</span>:address:array:character, <span class="Constant">2</span>:address:array:character
  <span class="Comment"># run a few commands</span>
  assume-console [
    left-click <span class="Constant">1</span>, <span class="Constant">80</span>
    type <span class="Constant">[divide-with-remainder 11, 3]</span>
    press <span class="Constant">65532</span>  <span class="Comment"># F4</span>
    type <span class="Constant">[add 2, 2]</span>
    press <span class="Constant">65532</span>  <span class="Comment"># F4</span>
  ]
  run [
    event-loop screen:address, console:address, <span class="Constant">3</span>:address:programming-environment-data
  ]
  screen-should-contain [
   <span class="Constant"> .                                                                                 run (F4)           .</span>
   <span class="Constant"> .                                                  ┊                                                 .</span>
<span class="Constant">    .┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┊━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━.</span>
   <span class="Constant"> .                                                  ┊                                                x.</span>
   <span class="Constant"> .                                                  ┊add 2, 2                                         .</span>
   <span class="Constant"> .                                                  ┊4                                                .</span>
   <span class="Constant"> .                                                  ┊━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━.</span>
   <span class="Constant"> .                                                  ┊                                                x.</span>
   <span class="Constant"> .                                                  ┊divide-with-remainder 11, 3                      .</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 <span class="Constant">7</span>, <span class="Constant">99</span>
  ]
  run [
    event-loop screen:address, console:address, <span class="Constant">3</span>:address:programming-environment-data
  ]
  screen-should-contain [
   <span class="Constant"> .                                                                                 run (F4)           .</span>
   <span class="Constant"> .                                                  ┊                                                 .</span>
<span class="Constant">    .┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┊━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━.</span>
   <span class="Constant"> .                                                  ┊                                                x.</span>
   <span class="Constant"> .                                                  ┊add 2, 2                                         .</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 <span class="Constant">3</span>, <span class="Constant">99</span>
  ]
  run [
    event-loop screen:address, console:address, <span class="Constant">3</span>:address:programming-environment-data
  ]
  screen-should-contain [
   <span class="Constant"> .                                                                                 run (F4)           .</span>
   <span class="Constant"> .                                                  ┊                                                 .</span>
<span class="Constant">    .┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┊━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━.</span>
   <span class="Constant"> .                                                  ┊                                                 .</span>
   <span class="Constant"> .                                                  ┊                                                 .</span>
  ]
]

<span class="muRecipe">after</span> +global-touch [
  <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, env
    <span class="muControl">break-unless</span> was-delete?
<span class="CommentedCode">#?     trace [app], [delete clicked] #? 1</span>
    screen<span class="Special"> &lt;- </span>render-sandbox-side screen, env
    update-cursor screen, recipes, current-sandbox, *sandbox-in-focus?
    show-screen screen
    <span class="muControl">loop</span> <span class="Constant">+next-event:label</span>
  <span class="Delimiter">}</span>
]

<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, <span class="Constant">column:offset</span>
  current-sandbox:address:editor-data<span class="Special"> &lt;- </span>get *env, <span class="Constant">current-sandbox:offset</span>
  right:number<span class="Special"> &lt;- </span>get *current-sandbox, <span class="Constant">right:offset</span>
  at-right?:boolean<span class="Special"> &lt;- </span>equal click-column, right
  <span class="muControl">reply-unless</span> at-right?, <span class="Constant">0/false</span>
  click-row:number<span class="Special"> &lt;- </span>get t, <span class="Constant">row:offset</span>
  prev:address:address:sandbox-data<span class="Special"> &lt;- </span>get-address *env, <span class="Constant">sandbox:offset</span>
  curr:address:sandbox-data<span class="Special"> &lt;- </span>get *env, <span class="Constant">sandbox:offset</span>
  <span class="Delimiter">{</span>
    <span class="muControl">break-unless</span> curr
    <span class="Comment"># more sandboxes to check</span>
    <span class="Delimiter">{</span>
      target-row:number<span class="Special"> &lt;- </span>get *curr, <span class="Constant">starting-row-on-screen:offset</span>
      delete-curr?:boolean<span class="Special"> &lt;- </span>equal target-row, click-row
      <span class="muControl">break-unless</span> delete-curr?
      <span class="Comment"># delete this sandbox, rerender and stop</span>
      *prev<span class="Special"> &lt;- </span>get *curr, <span class="Constant">next-sandbox:offset</span>
      <span class="muControl">reply</span> <span class="Constant">1/true</span>
    <span class="Delimiter">}</span>
    prev<span class="Special"> &lt;- </span>get-address *curr, <span class="Constant">next-sandbox:offset</span>
    curr<span class="Special"> &lt;- </span>get *curr, <span class="Constant">next-sandbox:offset</span>
    <span class="muControl">loop</span>
  <span class="Delimiter">}</span>
  <span class="muControl">reply</span> <span class="Constant">0/false</span>
]

<span class="SalientComment">## clicking on sandbox results to 'fix' them and turn sandboxes into tests</span>

<span class="muScenario">scenario</span> sandbox-click-on-result-toggles-color-to-green [
<span class="Constant">  $close-trace</span>
  assume-screen <span class="Constant">40/width</span>, <span class="Constant">10/height</span>
  <span class="Comment"># basic recipe</span>
  <span class="Constant">1</span>:address:array:character<span class="Special"> &lt;- </span>new <span class="Constant">[ </span>
<span class="Constant">recipe foo [</span>
<span class="Constant">  add 2, 2</span>
<span class="Constant">]</span>]
  <span class="Comment"># run it</span>
  <span class="Constant">2</span>:address:array:character<span class="Special"> &lt;- </span>new <span class="Constant">[foo]</span>
  assume-console [
    press <span class="Constant">65532</span>  <span class="Comment"># F4</span>
  ]
  <span class="Constant">3</span>:address:programming-environment-data<span class="Special"> &lt;- </span>new-programming-environment screen:address, <span class="Constant">1</span>:address:array:character, <span class="Constant">2</span>:address:array:character
  event-loop screen:address, console:address, <span class="Constant">3</span>:address:programming-environment-data
  screen-should-contain [
   <span class="Constant"> .                     run (F4)           .</span>
   <span class="Constant"> .                    ┊                   .</span>
   <span class="Constant"> .recipe foo [        ┊━━━━━━━━━━━━━━━━━━━.</span>
   <span class="Constant"> .  add 2, 2          ┊                  x.</span>
   <span class="Constant"> .]                   ┊foo                .</span>
   <span class="Constant"> .┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┊4                  .</span>
   <span class="Constant"> .                    ┊━━━━━━━━━━━━━━━━━━━.</span>
   <span class="Constant"> .                    ┊                   .</span>
  ]
  <span class="Comment"># click on the '4' in the result</span>
  assume-console [
    left-click <span class="Constant">5</span>, <span class="Constant">21</span>
  ]
  run [
    event-loop screen:address, console:address, <span class="Constant">3</span>:address:programming-environment-data
  ]
  <span class="Comment"># color toggles to green</span>
  screen-should-contain-in-color <span class="Constant">2/green</span>, [
   <span class="Constant"> .                                        .</span>
   <span class="Constant"> .                                        .</span>
   <span class="Constant"> .                                        .</span>
   <span class="Constant"> .                                        .</span>
   <span class="Constant"> .                                        .</span>
   <span class="Constant"> .                     4                  .</span>
   <span class="Constant"> .                                        .</span>
   <span class="Constant"> .                                        .</span>
  ]
  <span class="Comment"># now change the second arg of the 'add'</span>
  <span class="Comment"># then rerun</span>
  assume-console [
    left-click <span class="Constant">3</span>, <span class="Constant">11</span>  <span class="Comment"># cursor to end of line</span>
    type <span class="Constant">[«3]</span>  <span class="Comment"># turn '2' into '3'</span>
    press <span class="Constant">65532</span>  <span class="Comment"># F4</span>
  ]
  <span class="Constant">4</span>:event/backspace<span class="Special"> &lt;- </span>merge <span class="Constant">0/text</span>, <span class="Constant">8/backspace</span>, <span class="Constant">0/dummy</span>, <span class="Constant">0/dummy</span>
  replace-in-console <span class="Constant">171/«</span>, <span class="Constant">4</span>:event/backspace
  run [
    event-loop screen:address, console:address, <span class="Constant">3</span>:address:programming-environment-data
  ]
  <span class="Comment"># result turns red</span>
  screen-should-contain-in-color <span class="Constant">1/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"> .                     5                  .</span>
   <span class="Constant"> .                                        .</span>
   <span class="Constant"> .                                        .</span>
  ]
]

<span class="Comment"># clicks on sandbox responses save it as 'expected'</span>
<span class="muRecipe">after</span> +global-touch [
  <span class="Comment"># right side of screen? check if it's inside the output of any sandbox</span>
  <span class="Delimiter">{</span>
    sandbox-left-margin:number<span class="Special"> &lt;- </span>get *current-sandbox, <span class="Constant">left:offset</span>
    click-column:number<span class="Special"> &lt;- </span>get *t, <span class="Constant">column:offset</span>
    on-sandbox-side?:boolean<span class="Special"> &lt;- </span>greater-or-equal click-column, sandbox-left-margin
    <span class="muControl">break-unless</span> on-sandbox-side?
    first-sandbox:address:sandbox-data<span class="Special"> &lt;- </span>get *env, <span class="Constant">sandbox:offset</span>
    <span class="muControl">break-unless</span> first-sandbox
    first-sandbox-begins:number<span class="Special"> &lt;- </span>get *first-sandbox, <span class="Constant">starting-row-on-screen:offset</span>
    click-row:number<span class="Special"> &lt;- </span>get *t, <span class="Constant">row:offset</span>
    below-sandbox-editor?:boolean<span class="Special"> &lt;- </span>greater-or-equal click-row, first-sandbox-begins
    <span class="muControl">break-unless</span> below-sandbox-editor?
    <span class="Comment"># identify the sandbox whose output is being clicked on</span>
    sandbox:address:sandbox-data<span class="Special"> &lt;- </span>find-click-in-sandbox-output env, click-row
    <span class="muControl">break-unless</span> sandbox
    <span class="Comment"># toggle its expected-response, and save session</span>
    sandbox<span class="Special"> &lt;- </span>toggle-expected-response sandbox
    save-sandboxes env
    screen<span class="Special"> &lt;- </span>render-sandbox-side screen, env, <span class="Constant">1/clear</span>
    <span class="Comment"># no change in cursor</span>
    show-screen screen
    <span class="muControl">loop</span> <span class="Constant">+next-event:label</span>
  <span class="Delimiter">}</span>
]

<span class="muRecipe">recipe</span> find-click-in-sandbox-output [
  <span class="Constant">local-scope</span>
  env:address:programming-environment-data<span class="Special"> &lt;- </span><span class="Constant">next-ingredient</span>
  click-row:number<span class="Special"> &lt;- </span><span class="Constant">next-ingredient</span>
  <span class="Comment"># assert click-row &gt;= sandbox.starting-row-on-screen</span>
  sandbox:address:sandbox-data<span class="Special"> &lt;- </span>get *env, <span class="Constant">sandbox:offset</span>
  start:number<span class="Special"> &lt;- </span>get *sandbox, <span class="Constant">starting-row-on-screen:offset</span>
  clicked-on-sandboxes?:boolean<span class="Special"> &lt;- </span>greater-or-equal click-row, start
  assert clicked-on-sandboxes?, <span class="Constant">[extract-sandbox called on click to sandbox editor]</span>
  <span class="Comment"># while click-row &lt; sandbox.next-sandbox.starting-row-on-screen</span>
  <span class="Delimiter">{</span>
    next-sandbox:address:sandbox-data<span class="Special"> &lt;- </span>get *sandbox, <span class="Constant">next-sandbox:offset</span>
    <span class="muControl">break-unless</span> next-sandbox
    next-start:number<span class="Special"> &lt;- </span>get *next-sandbox, <span class="Constant">starting-row-on-screen:offset</span>
    found?:boolean<span class="Special"> &lt;- </span>lesser-than click-row, next-start
    <span class="muControl">break-if</span> found?
    sandbox<span class="Special"> &lt;- </span>copy next-sandbox
    <span class="muControl">loop</span>
  <span class="Delimiter">}</span>
  <span class="Comment"># return sandbox if click is in its output region</span>
  response-starting-row:number<span class="Special"> &lt;- </span>get *sandbox, <span class="Constant">response-starting-row-on-screen:offset</span>
  click-in-response?:boolean<span class="Special"> &lt;- </span>greater-or-equal click-row, response-starting-row
  <span class="Delimiter">{</span>
    <span class="muControl">break-if</span> click-in-response?
    <span class="muControl">reply</span> <span class="Constant">0/no-click-in-sandbox-output</span>
  <span class="Delimiter">}</span>
  <span class="muControl">reply</span> sandbox
]

<span class="muRecipe">recipe</span> toggle-expected-response [
  <span class="Constant">local-scope</span>
  sandbox:address:sandbox-data<span class="Special"> &lt;- </span><span class="Constant">next-ingredient</span>
  expected-response:address:address:array:character<span class="Special"> &lt;- </span>get-address *sandbox, <span class="Constant">expected-response:offset</span>
  <span class="Delimiter">{</span>
    <span class="Comment"># if expected-response is set, reset</span>
    <span class="muControl">break-unless</span> *expected-response
    *expected-response<span class="Special"> &lt;- </span>copy <span class="Constant">0</span>
    <span class="muControl">reply</span> sandbox/same-as-ingredient:<span class="Constant">0</span>
  <span class="Delimiter">}</span>
  <span class="Comment"># if not, current response is the expected response</span>
  response:address:array:character<span class="Special"> &lt;- </span>get *sandbox, <span class="Constant">response:offset</span>
  *expected-response<span class="Special"> &lt;- </span>copy response
  <span class="muControl">reply</span> sandbox/same-as-ingredient:<span class="Constant">0</span>
]

<span class="Comment"># when rendering a sandbox, color it in red/green if expected response exists</span>
<span class="muRecipe">after</span> +render-sandbox-response [
  <span class="Delimiter">{</span>
    <span class="muControl">break-unless</span> sandbox-response
    expected-response:address:array:character<span class="Special"> &lt;- </span>get *sandbox, <span class="Constant">expected-response:offset</span>
    <span class="muControl">break-unless</span> expected-response  <span class="Comment"># fall-through to print in grey</span>
    response-is-expected?:boolean<span class="Special"> &lt;- </span>string-equal expected-response, sandbox-response
    <span class="Delimiter">{</span>
      <span class="muControl">break-if</span> response-is-expected?:boolean
      row, screen<span class="Special"> &lt;- </span>render-string screen, sandbox-response, left, right, <span class="Constant">1/red</span>, row
    <span class="Delimiter">}</span>
    <span class="Delimiter">{</span>
      <span class="muControl">break-unless</span> response-is-expected?:boolean
      row, screen<span class="Special"> &lt;- </span>render-string screen, sandbox-response, left, right, <span class="Constant">2/green</span>, row
    <span class="Delimiter">}</span>
    <span class="muControl">jump</span> <span class="Constant">+render-sandbox-end:label</span>
  <span class="Delimiter">}</span>
]

<span class="SalientComment">## clicking on the code typed into a sandbox toggles its trace</span>

<span class="muScenario">scenario</span> sandbox-click-on-code-toggles-app-trace [
<span class="Constant">  $close-trace</span>
  assume-screen <span class="Constant">40/width</span>, <span class="Constant">10/height</span>
  <span class="Comment"># basic recipe</span>
  <span class="Constant">1</span>:address:array:character<span class="Special"> &lt;- </span>new <span class="Constant">[ </span>
<span class="Constant">recipe foo [</span>
<span class="Constant">  trace [abc]</span>
]]
  <span class="Comment"># run it</span>
  <span class="Constant">2</span>:address:array:character<span class="Special"> &lt;- </span>new <span class="Constant">[foo]</span>
  assume-console [
    press <span class="Constant">65532</span>  <span class="Comment"># F4</span>
  ]
  <span class="Constant">3</span>:address:programming-environment-data<span class="Special"> &lt;- </span>new-programming-environment screen:address, <span class="Constant">1</span>:address:array:character, <span class="Constant">2</span>:address:array:character
  event-loop screen:address, console:address, <span class="Constant">3</span>:address:programming-environment-data
  screen-should-contain [
   <span class="Constant"> .                     run (F4)           .</span>
   <span class="Constant"> .                    ┊                   .</span>
   <span class="Constant"> .recipe foo [        ┊━━━━━━━━━━━━━━━━━━━.</span>
   <span class="Constant"> .  trace [abc]       ┊                  x.</span>
   <span class="Constant"> .]                   ┊foo                .</span>
<span class="Constant">    .┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┊━━━━━━━━━━━━━━━━━━━.</span>
   <span class="Constant"> .                    ┊                   .</span>
  ]
  <span class="Comment"># click on the 'foo' line in the sandbox</span>
  assume-console [
    left-click <span class="Constant">4</span>, <span class="Constant">21</span>
  ]
  run [
    event-loop screen:address, console:address, <span class="Constant">3</span>:address:programming-environment-data
  ]
  <span class="Comment"># trace now printed</span>
  screen-should-contain [
   <span class="Constant"> .                     run (F4)           .</span>
   <span class="Constant"> .                    ┊                   .</span>
   <span class="Constant"> .recipe foo [        ┊━━━━━━━━━━━━━━━━━━━.</span>
   <span class="Constant"> .  trace [abc]       ┊                  x.</span>
   <span class="Constant"> .]                   ┊foo                .</span>
   <span class="Constant"> .┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┊abc                .</span>
   <span class="Constant"> .                    ┊━━━━━━━━━━━━━━━━━━━.</span>
   <span class="Constant"> .                    ┊                   .</span>
  ]
  screen-should-contain-in-color <span class="Constant">245/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"> .┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┊abc                .</span>
   <span class="Constant"> .                    ┊━━━━━━━━━━━━━━━━━━━.</span>
   <span class="Constant"> .                    ┊                   .</span>
  ]
  <span class="Comment"># click again on the same region</span>
  assume-console [
    left-click <span class="Constant">4</span>, <span class="Constant">25</span>
  ]
  run [
    event-loop screen:address, console:address, <span class="Constant">3</span>:address:programming-environment-data
  ]
  <span class="Comment"># trace hidden again</span>
  screen-should-contain [
   <span class="Constant"> .                     run (F4)           .</span>
   <span class="Constant"> .                    ┊                   .</span>
   <span class="Constant"> .recipe foo [        ┊━━━━━━━━━━━━━━━━━━━.</span>
   <span class="Constant"> .  trace [abc]       ┊                  x.</span>
   <span class="Constant"> .]                   ┊foo                .</span>
<span class="Constant">    .┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┊━━━━━━━━━━━━━━━━━━━.</span>
   <span class="Constant"> .                    ┊                   .</span>
  ]
]

<span class="muScenario">scenario</span> sandbox-shows-app-trace-and-result [
<span class="Constant">  $close-trace</span>
  assume-screen <span class="Constant">40/width</span>, <span class="Constant">10/height</span>
  <span class="Comment"># basic recipe</span>
  <span class="Constant">1</span>:address:array:character<span class="Special"> &lt;- </span>new <span class="Constant">[ </span>
<span class="Constant">recipe foo [</span>
<span class="Constant">  trace [abc]</span>
  add <span class="Constant">2</span>, <span class="Constant">2</span>
]]
  <span class="Comment"># run it</span>
  <span class="Constant">2</span>:address:array:character<span class="Special"> &lt;- </span>new <span class="Constant">[foo]</span>
  assume-console [
    press <span class="Constant">65532</span>  <span class="Comment"># F4</span>
  ]
  <span class="Constant">3</span>:address:programming-environment-data<span class="Special"> &lt;- </span>new-programming-environment screen:address, <span class="Constant">1</span>:address:array:character, <span class="Constant">2</span>:address:array:character
  event-loop screen:address, console:address, <span class="Constant">3</span>:address:programming-environment-data
  screen-should-contain [
   <span class="Constant"> .                     run (F4)           .</span>
   <span class="Constant"> .                    ┊                   .</span>
   <span class="Constant"> .recipe foo [        ┊━━━━━━━━━━━━━━━━━━━.</span>
   <span class="Constant"> .  trace [abc]       ┊                  x.</span>
   <span class="Constant"> .  add 2, 2          ┊foo                .</span>
   <span class="Constant"> .]                   ┊4                  .</span>
<span class="Constant">    .┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┊━━━━━━━━━━━━━━━━━━━.</span>
   <span class="Constant"> .                    ┊                   .</span>
  ]
  <span class="Comment"># click on the 'foo' line in the sandbox</span>
  assume-console [
    left-click <span class="Constant">4</span>, <span class="Constant">21</span>
  ]
  run [
    event-loop screen:address, console:address, <span class="Constant">3</span>:address:programming-environment-data
  ]
  <span class="Comment"># trace now printed</span>
  screen-should-contain [
   <span class="Constant"> .                     run (F4)           .</span>
   <span class="Constant"> .                    ┊                   .</span>
   <span class="Constant"> .recipe foo [        ┊━━━━━━━━━━━━━━━━━━━.</span>
   <span class="Constant"> .  trace [abc]       ┊                  x.</span>
   <span class="Constant"> .  add 2, 2          ┊foo                .</span>
   <span class="Constant"> .]                   ┊abc                .</span>
   <span class="Constant"> .┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┊4                  .</span>
   <span class="Constant"> .                    ┊━━━━━━━━━━━━━━━━━━━.</span>
   <span class="Constant"> .                    ┊                   .</span>
  ]
]

<span class="Comment"># clicks on sandbox code toggle its display-trace? flag</span>
<span class="muRecipe">after</span> +global-touch [
  <span class="Comment"># right side of screen? check if it's inside the code of any sandbox</span>
  <span class="Delimiter">{</span>
    sandbox-left-margin:number<span class="Special"> &lt;- </span>get *current-sandbox, <span class="Constant">left:offset</span>
    click-column:number<span class="Special"> &lt;- </span>get *t, <span class="Constant">column:offset</span>
    on-sandbox-side?:boolean<span class="Special"> &lt;- </span>greater-or-equal click-column, sandbox-left-margin
    <span class="muControl">break-unless</span> on-sandbox-side?
    first-sandbox:address:sandbox-data<span class="Special"> &lt;- </span>get *env, <span class="Constant">sandbox:offset</span>
    <span class="muControl">break-unless</span> first-sandbox
    first-sandbox-begins:number<span class="Special"> &lt;- </span>get *first-sandbox, <span class="Constant">starting-row-on-screen:offset</span>
    click-row:number<span class="Special"> &lt;- </span>get *t, <span class="Constant">row:offset</span>
    below-sandbox-editor?:boolean<span class="Special"> &lt;- </span>greater-or-equal click-row, first-sandbox-begins
    <span class="muControl">break-unless</span> below-sandbox-editor?
    <span class="Comment"># identify the sandbox whose code is being clicked on</span>
    sandbox:address:sandbox-data<span class="Special"> &lt;- </span>find-click-in-sandbox-code env, click-row
    <span class="muControl">break-unless</span> sandbox
    <span class="Comment"># toggle its display-trace? property</span>
    x:address:boolean<span class="Special"> &lt;- </span>get-address *sandbox, <span class="Constant">display-trace?:offset</span>
    *x<span class="Special"> &lt;- </span>not *x
    screen<span class="Special"> &lt;- </span>render-sandbox-side screen, env, <span class="Constant">1/clear</span>
    <span class="Comment"># no change in cursor</span>
    show-screen screen
    <span class="muControl">loop</span> <span class="Constant">+next-event:label</span>
  <span class="Delimiter">}</span>
]

<span class="muRecipe">recipe</span> find-click-in-sandbox-code [
  <span class="Constant">local-scope</span>
  env:address:programming-environment-data<span class="Special"> &lt;- </span><span class="Constant">next-ingredient</span>
  click-row:number<span class="Special"> &lt;- </span><span class="Constant">next-ingredient</span>
  <span class="Comment"># assert click-row &gt;= sandbox.starting-row-on-screen</span>
  sandbox:address:sandbox-data<span class="Special"> &lt;- </span>get *env, <span class="Constant">sandbox:offset</span>
  start:number<span class="Special"> &lt;- </span>get *sandbox, <span class="Constant">starting-row-on-screen:offset</span>
  clicked-on-sandboxes?:boolean<span class="Special"> &lt;- </span>greater-or-equal click-row, start
  assert clicked-on-sandboxes?, <span class="Constant">[extract-sandbox called on click to sandbox editor]</span>
  <span class="Comment"># while click-row &lt; sandbox.next-sandbox.starting-row-on-screen</span>
  <span class="Delimiter">{</span>
    next-sandbox:address:sandbox-data<span class="Special"> &lt;- </span>get *sandbox, <span class="Constant">next-sandbox:offset</span>
    <span class="muControl">break-unless</span> next-sandbox
    next-start:number<span class="Special"> &lt;- </span>get *next-sandbox, <span class="Constant">starting-row-on-screen:offset</span>
    found?:boolean<span class="Special"> &lt;- </span>lesser-than click-row, next-start
    <span class="muControl">break-if</span> found?
    sandbox<span class="Special"> &lt;- </span>copy next-sandbox
    <span class="muControl">loop</span>
  <span class="Delimiter">}</span>
  <span class="Comment"># return sandbox if click is in its code region</span>
  response-starting-row:number<span class="Special"> &lt;- </span>get *sandbox, <span class="Constant">response-starting-row-on-screen:offset</span>
  click-above-response?:boolean<span class="Special"> &lt;- </span>lesser-than click-row, response-starting-row
  start:number<span class="Special"> &lt;- </span>get *sandbox, <span class="Constant">starting-row-on-screen:offset</span>
  click-below-menu?:boolean<span class="Special"> &lt;- </span>greater-than click-row, start
  click-on-sandbox-code?:boolean<span class="Special"> &lt;- </span>and click-above-response?, click-below-menu?
  <span class="Delimiter">{</span>
    <span class="muControl">break-if</span> click-on-sandbox-code?
    <span class="muControl">reply</span> <span class="Constant">0/no-click-in-sandbox-output</span>
  <span class="Delimiter">}</span>
  <span class="muControl">reply</span> sandbox
]

<span class="Comment"># when rendering a sandbox, dump its trace before response/warning if display-trace? property is set</span>
<span class="muRecipe">after</span> +render-sandbox-results [
  <span class="Delimiter">{</span>
    display-trace?:boolean<span class="Special"> &lt;- </span>get *sandbox, <span class="Constant">display-trace?:offset</span>
    <span class="muControl">break-unless</span> display-trace?
    sandbox-trace:address:array:character<span class="Special"> &lt;- </span>get *sandbox, <span class="Constant">trace:offset</span>
    <span class="muControl">break-unless</span> sandbox-trace  <span class="Comment"># nothing to print; move on</span>
<span class="CommentedCode">#?     $print [display trace from ], row, 10/newline #? 1</span>
    row, screen<span class="Special"> &lt;- </span>render-string, screen, sandbox-trace, left, right, <span class="Constant">245/grey</span>, row
    row<span class="Special"> &lt;- </span>subtract row, <span class="Constant">1</span>  <span class="Comment"># trim the trailing newline that's always present</span>
  <span class="Delimiter">}</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/width</span>, <span class="Constant">15/height</span>
  assume-console [
    press <span class="Constant">65532</span>  <span class="Comment"># F4</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 (F4)           .</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/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/width</span>, <span class="Constant">15/height</span>
  assume-console [
    press <span class="Constant">65532</span>  <span class="Comment"># F4</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 &lt;- copy 0</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 (F4)           .</span>
   <span class="Constant"> .                                                  ┊foo                                              .</span>
   <span class="Constant"> .recipe foo [                                      ┊━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━.</span>
   <span class="Constant"> .  x &lt;- copy 0                                     ┊                                                 .</span>
   <span class="Constant"> .]                                                 ┊                                                 .</span>
   <span class="Constant"> .missing type in 'x &lt;- copy 0'                     ┊                                                 .</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/width</span>, <span class="Constant">15/height</span>
  assume-console [
    press <span class="Constant">65532</span>  <span class="Comment"># F4</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 (F4)           .</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: first ingredient of 'get' should be a conta↩.</span>
   <span class="Constant"> .┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┊iner, but got 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/width</span>, <span class="Constant">15/height</span>
  assume-console [
    press <span class="Constant">65532</span>  <span class="Comment"># F4</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, 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 (F4)           .</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, 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?
    color<span class="Special"> &lt;- </span>copy <span class="Constant">245/grey</span>
  <span class="Delimiter">}</span>
  <span class="Comment"># top border</span>
  draw-horizontal screen, top, left, right, color
  draw-horizontal screen, bottom, left, right, color
  draw-vertical screen, left, top, bottom, color
  draw-vertical screen, right, top, bottom, color
  draw-top-left screen, top, left, color
  draw-top-right screen, top, right, color
  draw-bottom-left screen, bottom, left, color
  draw-bottom-right screen, bottom, right, color
  <span class="Comment"># position cursor inside box</span>
  move-cursor screen, top, left
  cursor-down screen
  cursor-right screen
]

<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?
    style<span class="Special"> &lt;- </span>copy <span class="Constant">9472/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?
    color<span class="Special"> &lt;- </span>copy <span class="Constant">245/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?
    bg-color<span class="Special"> &lt;- </span>copy <span class="Constant">0/black</span>
  <span class="Delimiter">}</span>
  move-cursor screen, row, x
  <span class="Delimiter">{</span>
    continue?:boolean<span class="Special"> &lt;- </span>lesser-or-equal x, right  <span class="Comment"># right is inclusive, to match editor-data semantics</span>
    <span class="muControl">break-unless</span> continue?
    print-character screen, style, color, bg-color
    x<span class="Special"> &lt;- </span>add x, <span class="Constant">1</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>
  y: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?
    style<span class="Special"> &lt;- </span>copy <span class="Constant">9474/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?
    color<span class="Special"> &lt;- </span>copy <span class="Constant">245/grey</span>
  <span class="Delimiter">}</span>
  <span class="Delimiter">{</span>
    continue?:boolean<span class="Special"> &lt;- </span>lesser-than y, bottom
    <span class="muControl">break-unless</span> continue?
    move-cursor screen, y, col
    print-character screen, style, color
    y<span class="Special"> &lt;- </span>add y, <span class="Constant">1</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?
    color<span class="Special"> &lt;- </span>copy <span class="Constant">245/grey</span>
  <span class="Delimiter">}</span>
  move-cursor screen, top, left
  print-character screen, <span class="Constant">9484/down-right</span>, color
]

<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?
    color<span class="Special"> &lt;- </span>copy <span class="Constant">245/grey</span>
  <span class="Delimiter">}</span>
  move-cursor screen, top, right
  print-character screen, <span class="Constant">9488/down-left</span>, color
]

<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?
    color<span class="Special"> &lt;- </span>copy <span class="Constant">245/grey</span>
  <span class="Delimiter">}</span>
  move-cursor screen, bottom, left
  print-character screen, <span class="Constant">9492/up-right</span>, color
]

<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?
    color<span class="Special"> &lt;- </span>copy <span class="Constant">245/grey</span>
  <span class="Delimiter">}</span>
  move-cursor screen, bottom, right
  print-character screen, <span class="Constant">9496/up-left</span>, color
]

<span class="muRecipe">recipe</span> print-string-with-gradient-background [
  <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>
  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
  color-range:number<span class="Special"> &lt;- </span>subtract bg-color2, bg-color1
  color-quantum:number<span class="Special"> &lt;- </span>divide color-range, len
  bg-color:number<span class="Special"> &lt;- </span>copy bg-color1
  i:number<span class="Special"> &lt;- </span>copy <span class="Constant">0</span>
  <span class="Delimiter">{</span>
    done?:boolean<span class="Special"> &lt;- </span>greater-or-equal i, len
    <span class="muControl">break-if</span> done?
    c:character<span class="Special"> &lt;- </span>index *s, i
    print-character screen, c, color, bg-color
    i<span class="Special"> &lt;- </span>add i, <span class="Constant">1</span>
    bg-color<span class="Special"> &lt;- </span>add bg-color, color-quantum
    <span class="muControl">loop</span>
  <span class="Delimiter">}</span>
  <span class="muControl">reply</span> screen/same-as-ingredient:<span class="Constant">0</span>
]
</pre>
</body>
</html>
<!-- vim: set foldmethod=manual : -->