about summary refs log blame commit diff stats
path: root/html/edit/003-shortcuts.mu.html
blob: 8a6f0fbc488a0575204fe81acfe3bdc016bd6eb9 (plain) (tree)
1
2
3
4
5
6
7
8
9
10




                                                                                          

                                                
                                   

                                                                                         

                       
                                                                                                 
                                                                                            


                                      
                              
                             
                            
                             
                                   
                              

        





                               

       
                         








                                                                                                       
                                                                                                               
                                 
                                                                                                                                                                                                                                   



                  
                                                                                                              









                                                                                                    
                                                                                             

                                                                

                                                                                                                                              
                                                              
                                                                                           
                                         






                                                                                              
                                                                                                                 

                                                                                                                                                                                                                                    





                                                                               


                                                                                                                                                                                















                                                                                                                                                                                   
                                                                                                                         

                                                                          
                                                                                                                                                  
                                                                 
                                         


                                  


                                                                                                                               
                                                                                                                                                                                                                                       
                                           
                                                

                                                                                                                                         
                                                                                           
                                                                                   
                                                                                                                                                                     
                                                   
                                                                                                                                   


                                                                                                                  


                                                                                                                                                                              
                                                                                         
                                                  


                                                                                                                      
                                                                      
                                                                                  
                                                                                         
                                                        


                                                                                                      
                                                                                         
                                                                       

                                                                                  
                                                                                         
                                                                                           
                                                      

                                                    

                                                                                                             
                                                       
                                                                 
                                                                                                   
                                                     


                                                                               
                                                                                           
                                                               
                                                                                          

 
                                                                                                                                                             
                                           
                                                



                                                                                                                                         

                                                                               
                                                                                     

                                                                                                                                           

                                                                                                                             
                                                                                            
                                         

                                                                                 

                                                                                                                                                           

                                                          

                                                                                                                       







                                                                                                                      

                                                                                                                                             


                                                                                                                                           




                                                                                                                      

                                                       
                                                                                                      

                                                                                                                               


                                                   

                                                                                                                               
                                    
                                         


                                                                                                                                        
                                                                                                      

                                                                                                                                                           



                                                                                                          
                                                                                                                                                                 
                                           
                                                
                                                                                    
                                                   
                                                                     
                                                    
                                  
                                                     
                                                    
                                                                       
                                                     

                                                                                                         



                                                                                         




                                                                                              
                                                                                                               
                                 
                                                                                                                                                                                                                                    




                                                                                                                                                      


                                                                                                                                                                                












                                                                                                      


                                                                                              
                                                                                                                    
                                      

                                                                                                                                                                                                                                    






                                                                                                 
                                                                                                              













                                                                                              
                                                                                                                          

                                                                                                                                                                                                                                   













                                                                                                                     
                                                                                                              










                                                                                                        



                                                                                              
                                                                                                                 

                                                                                                                                                                                                                                    




                                            
                                                                                                              












                                                                                                                                                                                   
                                                                                                              











                                                                                                                                                                      
                                                                                                                      

                                                                      
                                                                                                                                           
                                                              
                                         


                                  
                                                                                                                                                                                                                                
                                           
                                                


                                                                                                                                         
                                                                                          
                                                           
                                                                                                             
                                                                   
                                                                                                                
                                                                                         
                                                           
                                                                      


                                                                                                                                              
                                                                                         

                                                                         

                                                                                  
                                                                                                
                                                                                           
                                                      

                                                    

                                                                                                             
                                                       
                                                                 
                                                                                                   
                                                     


                                                                               
                                                                                           
                                                               
                                                                                          





                                                                                              
                                                                                                                 

                                                                                                                                                                                                                                    





                                            
                                                                                                              











                                                                                                                                                                         
                                                                                                                            

                                                                       
                                                                                            


                                                           

                                                                                                                             
                                                                                                                  
                                                                                           
                                                                                                             
                                                         
                                         


                                  
                                                                                                                                                                                 
                                           
                                                




                                                                                                                                        

                                                                                       

                                                                                                                                
                                                               



                                                                                                                             
                                                                                                                                                  
                                                                                            
                                                              
                                                     

                                                                                                                                                                   
                                                                                           
                                         



                                                                                        

                                                                                                      

                                                                      
                                                                                     
                                                    

                                                                                                                   
                                                    



                                                                                                                             
                                                                                                                                                  
                                                                                                                                                                         
                                                     

                                                                                                                                                                   
                                                                                           
                                         

                                                                          

                                                                                                                           
                                                                                          



                                                                                              
                                                                                                                
                                

                                                                                                                                                                                                                                    








                                                                                            
                                                                                                              






                                                                                                              
                                                                                                              












                                                                                                                                                                        
                                                                                                                
                                

                                                                                                                                                                                                                                    







                                                               
                                                                                                              











                                                                                                    
                                                                                                                    

                                                                                                                                                                                                                                   





                                                                               


                                                                                                                                                                                

















                                                                                                              
                                                                                                                   

                                                                                                                                                                                                                                   






                                                                                                  


                                                                                                                                                                                









                                                                                                      


                                                                                                                                                                                









                                                                                                              
                                                                                                                    

                                                                                                                                                                                                                                   





                                                                               


                                                                                                                                                                                
















                                                                                                              
                                                                                                                
                                

                                                                                                                                                                                                                                    







                                                                                         
                                                                                                              

















                                                                                                              
                                                                                                                 

                                                                                                                                                                                                                                    






                                                                               
                                                                                                              











                                                                                                              
                                                                                                                               


                                                                                                                           
                                                                                     
                                                                                            
                                                     

                                                                                             

                                                                                                                             
                                                                                                            
                                                         
                                         





                                                                                                                
                                                                                                                
                                

                                                                                                                                                                                                                                    






                                                                                                         


                                                                                                                                                                                










                                                                                                                  
                                                                                                                

                                 

                                                                                                                                                                                                                                    








                                                                                                           
                                                                                                              












                                                                                                                                                           
                                                                                                                

                                 

                                                                                                                                                                                                                                    







                                                                                                          
                                                                                                              














                                                                                                                                                                   
                                                                                                                

  

                                                                                                                                                                                                                                    







                                                                               
                                                                                                              












                                                                                                                                                           
                                                                       
                                                                                                                    

                                                                                                                                                                                                                                   













                                                                               


                                                                                                                                                                                


                                                                                                                                                   







                                                                                                                                                                    
                                                                                                                   
                                

                                                                                                                                                                                                                                   













                                                                               


                                                                                                                                                                                










                                                                                                                                                          
                                                                                                                 
                                

                                                                                                                                                                                                                                   













                                                                               


                                                                                                                                                                                



                                                                                                                                                          









                                                                                                              
                                                                                                                
                                  

                                                                                                                                                                                                                                    





                                                                               


                                                                                                                                                                                









                                                                                                              
                                                                                                              











                                                                                              
                                                                                                                        


                                                                                      
                                                                                                          
                                                         
                                         


                                  
                                                                                                                                                      
                                           
                                                





                                                                                                                                         





                                                                                                        
                                                                                     
                                    


                                                                                                            
                                                         

                                                                                                      
                                                                                              
                                                         



                                                                               
                                                                        
                                                                                              
                                                         
                                    



                                                                                                                             
                                                                                  
                                                                           

                                                                                                                             
                                    
                                                                                                 
                                                   
                                                                                       
                                                      

                                                                                                               

                                                         



                                                                                                                               

                                         
                                                                                            
                                         




                                                                      
                                                                                           
                                         




                                                                                              
                                                                                                               
                                  

                                                                                                                                                                                                                                    





                                                                               


                                                                                                                                                                                









                                                                                                              
                                                                                                              











                                                                                              
                                                                               
                                  

                                                                                                                                                                                                                                    





                                                                               


                                                                                                                                                                                









                                                                                                              
                                                                                                              












                                                                                              
                                                                                                                

                                  

                                                                                                                                                                                                                                    






                                                                                                             


                                                                                                                                                                                









                                                                                                              
                                                                                                              













                                                                                              
                                                                                                                
                                  

                                                                                                                                                                                                                                    





                                                            


                                                                                                                                                                                










                                                                                                              
                                                                                                              











                                                                                              
                                                                                                                      


                                                                                                 
                                                                                                            
                                                         
                                         


                                  
                                                                                                                                                                     
                                           
                                                






                                                                                                                                         



                                                                                                        

                                                                                                                    


                                                                                                   
                                                                                       
                                                            
                                                                                                              
                                                                                                         
                                                                                              
                                           
                                    



                                                                                                                             
                                                                           

                                                                                                                             
                                    
                                                                                                 
                                                   
                                                                                       
                                                      

                                                                                                               

                                                         



                                                                                                                               

                                         
                                                                                            
                                         


                                                   
                                                                                         



                                                                                              
                                                                                                                
                                 

                                                                                                                                                                                                                                    





                                                                               


                                                                                                                                                                                









                                                                                                              
                                                                                                              









                                                                  



                                                                                              
                                                                                                                
                                  

                                                                                                                                                                                                                                    






                                                                               


                                                                                                                                                                                










                                                                                                              
                                                                                                                  


                                                                      
                                                                                                       
                                                         
                                                                                            
                                         




                                                                                              
                                                                                                                    


                                                                      
                                                                                                       
                                                         
                                                                                            
                                         


                                  
                                                                                                                                     
                                           
                                                
                                                     

                                                                                                    
                                                                                                                           
                                                     

                                                                                                                                         

                                                                  
                                                                                       
                                                             

                                                                                                                  
                                                             


                                                                                                                             





                                                                                              
                                                                                                                
                                  

                                                                                                                                                                                                                                    






                                                                                      


                                                                                                                                                                                










                                                                                                              
                                                                                                                
                                  
                                                                                                                                                                                                                                    






                                                                               


                                                                                                                                                                                










                                                                                                              
                                                                                                                
                                  

                                                                                                                                                                                                                                    






                                                                                      


                                                                                                                                                                                












                                                                                                              
                                                                                                                
                                  

                                                                                                                                                                                                                                    






                                                                               


                                                                                                                                                                                











                                                                                                              


                                                                                                                                                                                
















                                                                                                              
                                                                                                                


                                                                    
                                                                                                       
                                                         
                                                                                            
                                         




                                                                                              
                                                                                                                 


                                                                    
                                                                                                       
                                                         
                                                                                            
                                         


                                  
                                                                                                                                   
                                           
                                                

                                                                                                                                         

                                                                  
                                                                                     
                                                                                                

                                                                                                                 
                                                           



                                                                                                                             





                                                                                              
                                                                                                                
                                  

                                                                                                                                                                                                                                    






                                                                                      


                                                                                                                                                                                










                                                                                                              
                                                                                                                
                                  

                                                                                                                                                                                                                                    






                                                                               


                                                                                                                                                                                










                                                                                                              
                                                                                                                
                                  

                                                                                                                                                                                                                                    






                                                                                     


                                                                                                                                                                                












                                                                                                              
                                                                                                                
                                  
                                                                                                                                                                                                                                    





                                                                               
                                                                                                              












                                                                                                    
                                                                                                                     

                                                                        
                                                                                                          
                                                                     
                                                                                           
                                         


                                  
                                                                                                                                                                      
                                           
                                                
                                                        



                                                                                                                                         
                                  
                                                                               
                                                             

                                                                                                                  
                                                             
                                                       



                                                                                                            
                                                                             
                           
                                              

                                                                                                                           
                                                                                                    
                                                                                                                  



                                                                                              
                                                                                                                
                                  
                                                                                                                                                                                                                                    





                                                                                      
                                                                                                              












                                                                                              
                                                                                                                
                                  
                                                                                                                                                                                                                                    





                                                                               
                                                                                                              












                                                                                              
                                                                                                                
                                  
                                                                                                                                                                                                                                    





                                                                               
                                                                                                              














                                                                                                    
                                                                                                                
                                  
                                                                                                                                                                                                                                    





                                                                               
                                                                                                              












                                                                                                    
                                                                                                                   

                                                                      
                                                                                                        
                                                                   
                                                                                           
                                         


                                  
                                                                                                                                                                    
                                           
                                                
                                                        

                                                                                                                                 
                                  
                                                                                                           
                                                           

                                                                                                                
                                                           
                                                   


                                            

                                                      



                                                                                              
                                                                                                                
                                  
                                                                                                                                                                                                                                    





                                                                                      
                                                                                                              












                                                                                              
                                                                                                                
                                  
                                                                                                                                                                                                                                    





                                                                               
                                                                                                              












                                                                                              
                                                                                                                
                                  
                                                                                                                                                                                                                                    





                                                                               
                                                                                                              












                                                                                              
                                                                                                                
                                  
                                                                                                                                                                                                                                    





                                                                               
                                                                                                              












                                                                                              
                                                                                                                
                                  
                                                                                                                                                                                                                                    





                                                                               
                                                                                                              
















                                                                                              
                                                                                                              


                                
                                                                                                                                                                                                                                    











                                                                                            
                                                                                                              











                                                                                                                          




                                                                                                                                         

                                                                                                                           
                                                                                   
                                                                                          
                                                       




                                                                                                     
                                                                                                                                                                      
                                           
                                                

                                                                                   

                                                                      

                                                                                                         
                                                           
                                                     


                                                                                       
                                                               
                                                                             
                                                 

                                                                                                         
                                                       
                                                     


                                                                                       

                                                             






                                                                                                      
                                                                                                                   


                                
                                                                                                                                                                                                                                   











                                                                                            
                                                                                                              













                                                                                                   
                                                                                                                       


                                
                                                                                                                                                                                                                                   





                                                                                            
                                                                                                              












                                                                                         
                                                                                                              













                                                                                             
                                                                                                              

                                   
                                                                                                                                                                                                                                   





                                                                               


                                                                                                                                                                                
















                                                                                                      
                                                                                                              

                                
                                                                                                                                                                                                                                   





                                                                               


                                                                                                                                                                                

















                                                                                                      
                                                                                                              

                                     
                                                                                                                                                                                                                                   





                                                                                       


                                                                                                                                                                                

















                                                                                                      
                                                                                                              


                                
                                                                                                                                                                                                                                   





                                                                                       


                                                                                                                                                                                













                                                                                                      

                                                                                              
                                                                                                                
                                 

                                                                                                                                                                                                                                    






                                                                               


                                                                                                                                                                                









                                                                                                      
                                                                                                              













                                                                               


                                                                                                                                                                                










                                                                                                              
                                                                                                              








                                                                  



                                                                                              
                                                                                                              





                                
                                                                                                                                                                                                                                   






                                                                               
                                                                                                              















                                                                                              
                                                                                                              


                                
                                                                                                                                                                                                                                    











                                                                                           
                                                                                                              











                                                                                                                        

                                                                                                                                         

                                                                                                                           
                                                                                   
                                                                                          
                                                       




                                                                                                         
                                                                                                                                                                      
                                           
                                                

                                                                                                 


                                                                                                               




                                                                                                                                                                          


                                                                     
                                                                            

                                                           
                                  
                                                                                          





                                                                                 
                                                                                   

                                                      
                                                                             
                                                 
                                                                            




                                                                                       
                                            






                                                                                                      
                                                                                                                   


                                
                                                                                                                                                                                                                                   










                                                                                               
                                                                                                              











                                                     
                                                                                                              













                                                                                                          
                                                                                                                       


                                
                                                                                                                                                                                                                                   




                                                                      
                                                                                                              












                                                        
                                                                                                              













                                                                  
                                                                                                              













                                                                  
                                                                                                              

















                                                                                                      
                                                                                                                   


                                
                                                                                                                                                                                                                                   










                                                                                               
                                                                                                              











                                                     
                                                                                                              













                                                                                                 
                                                                                                              




                               
                                                                                                                                                                                                                                   



                   
                                                                                                              










                                              
                                                                                                              










                                                          
                                                                                                              












                                                                                             
                                                                                                              



                                
                                                                                                                                                                                                                                   




                                                                      
                                                                                                              











                                                     


                                                                                                                                                                                

















                                                                                                      
                                                                                                              


                                
                                                                                                                                                                                                                                    













                                                                                                       
                                                                                                              












                                                          
                                                                                                              













                                                                                              
                                                                                                              


                                
                                                                                                                                                                                                                                    










                                              
                                                                                                              











                                                                                                    
                                                                                                      
                                                          
                                                                                                                                     

                                                           
                                                                                                       
                                                         

                                                                                                                                           
                                                                  
                                         




                                                                                              
                                                                                                             
                                                          
                                                                                                                                     

                                                           
                                                                                                       
                                                         

                                                                                                                                           
                                                                  
                                         




                                                                                                  
                                                                                                                         
                                           
                                                
                                                                                     
                                                                                                                                               
                                                               
                                                                           

                                                                                                                                         
                                                                                                                           

                                                                           


                                                                                                               

                                                                                                                             


                                                                                    

                                                                                                                           



                                                                                              
                                                                                                              
                                

                                                                                                                                                                                                                                    










                                                                  
                                                                                                              













                                                                                              
                                                                                                              


                                                                         
                                                                                                                                                                                                                                   











                                                                        
                                                                                                              














                                                                                                        
                                                                                                              
                                      
                                                                                                                                                                                                                                   











                                                                        
                                                                                                              













                                                                                              
                                                                                                              


                                
                                                                                                                                                                                                                                    










                                              
                                                                                                              












                                                                  
                                                                                                              











                                                                                                    
                                                                                                    
                                                        
                                                                                                                                     

                                                                           
                                                                                                       
                                                         

                                                                                                                                           
                                                                  
                                         




                                                                                              
                                                                                                         
                                                        
                                                                                                                                     

                                                                           
                                                                                                       
                                                         

                                                                                                                                           
                                                                                                
                                                                  
                                         


                                  
                                                                                                                                          
                                           
                                                


                                                                                                                                                               
                                  
                                                                             
                                                 
                                                                                                             
                                                    

                                                                                                                             


                                                                                       





                                                                                              
                                                                                                              






                                
                                                                                                                                                                                                                                    











                                                      
                                                                                                              












                                                        
                                                                                                              












                                                         
                                                                                                              













                                                                                              
                                                                                                              









                                                                         
                                                                                                                                                                                                                                   















                                                                               
                                                                                                              














                                                                 
                                                                                                              
















                                                                                                        
                                                                                                              
                                      
                                                                                                                                                                                                                                   











                                                                        
                                                                                                              












                                                                 
                                                                                                              












                                                                                              
                                                                                                                







                                 
                                                                                                                                                                                                                                   









                                              
                                                                                                              










                                              
                                                                                                              











                                                               
                                                                                                              











                                                                                              
                                                                                                                







                                 
                                                                                                                                                                                                                                   









                                              
                                                                                                              










                                              
                                                                                                              











                                                               
                                                                                                              










                                              
                                     
<!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/003-shortcuts.mu</title>
<meta name="Generator" content="Vim/7.4">
<meta name="plugin-version" content="vim7.4_v2">
<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-size: 12pt; font-family: monospace; color: #eeeeee; background-color: #080808; }
* { font-size: 12pt; font-size: 1em; }
.muScenario { color: #00af00; }
.Special { color: #c00000; }
.Delimiter { color: #800080; }
.muRecipe { color: #ff8700; }
.Comment { color: #9090ff; }
.Constant { color: #00a0a0; }
.SalientComment { color: #00ffff; }
.muControl { color: #c0a020; }
-->
</style>

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

-->
</script>
</head>
<body>
<pre id='vimCodeElement'>
<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>:text<span class="Special"> &lt;- </span>new <span class="Constant">[ab</span>
<span class="Constant">cd]</span>
  <span class="Constant">2</span>:&amp;:editor<span class="Special"> &lt;- </span>new-editor <span class="Constant">1</span>:text, screen:&amp;:screen, <span class="Constant">0/left</span>, <span class="Constant">5/right</span>
  assume-console [
    press tab
  ]
  run [
    editor-event-loop screen:&amp;:screen, console:&amp;:console, <span class="Constant">2</span>:&amp;:editor
  ]
  screen-should-contain [
   <span class="Constant"> .          .</span>
   <span class="Constant"> .  ab      .</span>
   <span class="Constant"> .cd        .</span>
  ]
]

<span class="muRecipe">after</span> <span class="Constant">&lt;handle-special-character&gt;</span> [
  <span class="Delimiter">{</span>
    tab?:bool<span class="Special"> &lt;- </span>equal c, <span class="Constant">9/tab</span>
    <span class="muControl">break-unless</span> tab?
<span class="Constant">    &lt;insert-character-begin&gt;</span>
    editor, screen, go-render?:bool<span class="Special"> &lt;- </span>insert-at-cursor editor, <span class="Constant">32/space</span>, screen
    editor, screen, go-render?:bool<span class="Special"> &lt;- </span>insert-at-cursor editor, <span class="Constant">32/space</span>, screen
<span class="Constant">    &lt;insert-character-end&gt;</span>
    go-render?<span class="Special"> &lt;- </span>copy <span class="Constant">1/true</span>
    <span class="muControl">return</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>:text<span class="Special"> &lt;- </span>new <span class="Constant">[abc]</span>
  <span class="Constant">2</span>:&amp;:editor<span class="Special"> &lt;- </span>new-editor <span class="Constant">1</span>:text, screen:&amp;:screen, <span class="Constant">0/left</span>, <span class="Constant">10/right</span>
  editor-render screen, <span class="Constant">2</span>:&amp;:editor
<span class="Constant">  $clear-trace</span>
  assume-console [
    left-click <span class="Constant">1</span>, <span class="Constant">1</span>
    press backspace
  ]
  run [
    editor-event-loop screen:&amp;:screen, console:&amp;:console, <span class="Constant">2</span>:&amp;:editor
    <span class="Constant">4</span>:num<span class="Special"> &lt;- </span>get *<span class="Constant">2</span>:&amp;:editor, <span class="Constant">cursor-row:offset</span>
    <span class="Constant">5</span>:num<span class="Special"> &lt;- </span>get *<span class="Constant">2</span>:&amp;:editor, <span class="Constant">cursor-column:offset</span>
  ]
  screen-should-contain [
   <span class="Constant"> .          .</span>
   <span class="Constant"> .bc        .</span>
<span class="Constant">    .┈┈┈┈┈┈┈┈┈┈.</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>
  ]
  check-trace-count-for-label <span class="Constant">3</span>, <span class="Constant">[print-character]</span>  <span class="Comment"># length of original line to overwrite</span>
]

<span class="muRecipe">after</span> <span class="Constant">&lt;handle-special-character&gt;</span> [
  <span class="Delimiter">{</span>
    delete-previous-character?:bool<span class="Special"> &lt;- </span>equal c, <span class="Constant">8/backspace</span>
    <span class="muControl">break-unless</span> delete-previous-character?
<span class="Constant">    &lt;backspace-character-begin&gt;</span>
    editor, screen, go-render?:bool, backspaced-cell:&amp;:duplex-list:char<span class="Special"> &lt;- </span>delete-before-cursor editor, screen
<span class="Constant">    &lt;backspace-character-end&gt;</span>
    <span class="muControl">return</span>
  <span class="Delimiter">}</span>
]

<span class="Comment"># return values:</span>
<span class="Comment">#   go-render? - whether caller needs to update the screen</span>
<span class="Comment">#   backspaced-cell - value deleted (or 0 if nothing was deleted) so we can save it for undo, etc.</span>
<span class="muRecipe">def</span> delete-before-cursor editor:&amp;:editor, screen:&amp;:screen<span class="muRecipe"> -&gt; </span>editor:&amp;:editor, screen:&amp;:screen, go-render?:bool, backspaced-cell:&amp;:duplex-list:char [
  <span class="Constant">local-scope</span>
  <span class="Constant">load-ingredients</span>
  before-cursor:&amp;:duplex-list:char<span class="Special"> &lt;- </span>get *editor, <span class="Constant">before-cursor:offset</span>
  data:&amp;:duplex-list:char<span class="Special"> &lt;- </span>get *editor, <span class="Constant">data:offset</span>
  <span class="Comment"># if at start of text (before-cursor at § sentinel), return</span>
  prev:&amp;:duplex-list:char<span class="Special"> &lt;- </span>prev before-cursor
  go-render?, backspaced-cell<span class="Special"> &lt;- </span>copy <span class="Constant">0/no-more-render</span>, <span class="Constant">0/nothing-deleted</span>
  <span class="muControl">return-unless</span> prev
  trace <span class="Constant">10</span>, <span class="Constant">[app]</span>, <span class="Constant">[delete-before-cursor]</span>
  original-row:num<span class="Special"> &lt;- </span>get *editor, <span class="Constant">cursor-row:offset</span>
  editor, scroll?:bool<span class="Special"> &lt;- </span>move-cursor-coordinates-left editor
  backspaced-cell:&amp;:duplex-list:char<span class="Special"> &lt;- </span>copy before-cursor
  data<span class="Special"> &lt;- </span>remove before-cursor, data  <span class="Comment"># will also neatly trim next/prev pointers in backspaced-cell/before-cursor</span>
  before-cursor<span class="Special"> &lt;- </span>copy prev
  *editor<span class="Special"> &lt;- </span>put *editor, <span class="Constant">before-cursor:offset</span>, before-cursor
  go-render?<span class="Special"> &lt;- </span>copy <span class="Constant">1/true</span>
  <span class="muControl">return-if</span> scroll?
  screen-width:num<span class="Special"> &lt;- </span>screen-width screen
  cursor-row:num<span class="Special"> &lt;- </span>get *editor, <span class="Constant">cursor-row:offset</span>
  cursor-column:num<span class="Special"> &lt;- </span>get *editor, <span class="Constant">cursor-column:offset</span>
  <span class="Comment"># did we just backspace over a newline?</span>
  same-row?:bool<span class="Special"> &lt;- </span>equal cursor-row, original-row
  go-render?<span class="Special"> &lt;- </span>copy <span class="Constant">1/true</span>
  <span class="muControl">return-unless</span> same-row?
  left:num<span class="Special"> &lt;- </span>get *editor, <span class="Constant">left:offset</span>
  right:num<span class="Special"> &lt;- </span>get *editor, <span class="Constant">right:offset</span>
  curr:&amp;:duplex-list:char<span class="Special"> &lt;- </span>next before-cursor
  screen<span class="Special"> &lt;- </span>move-cursor screen, cursor-row, cursor-column
  curr-column:num<span class="Special"> &lt;- </span>copy cursor-column
  <span class="Delimiter">{</span>
    <span class="Comment"># hit right margin? give up and let caller render</span>
    at-right?:bool<span class="Special"> &lt;- </span>greater-or-equal curr-column, right
    go-render?<span class="Special"> &lt;- </span>copy <span class="Constant">1/true</span>
    <span class="muControl">return-if</span> at-right?
    <span class="muControl">break-unless</span> curr
    <span class="Comment"># newline? done.</span>
    currc:char<span class="Special"> &lt;- </span>get *curr, <span class="Constant">value:offset</span>
    at-newline?:bool<span class="Special"> &lt;- </span>equal currc, <span class="Constant">10/newline</span>
    <span class="muControl">break-if</span> at-newline?
    screen<span class="Special"> &lt;- </span>print screen, currc
    curr-column<span class="Special"> &lt;- </span>add curr-column, <span class="Constant">1</span>
    curr<span class="Special"> &lt;- </span>next curr
    <span class="muControl">loop</span>
  <span class="Delimiter">}</span>
  <span class="Comment"># we're guaranteed not to be at the right margin</span>
  space:char<span class="Special"> &lt;- </span>copy <span class="Constant">32/space</span>
  screen<span class="Special"> &lt;- </span>print screen, space
  go-render?<span class="Special"> &lt;- </span>copy <span class="Constant">0/false</span>
]

<span class="muRecipe">def</span> move-cursor-coordinates-left editor:&amp;:editor<span class="muRecipe"> -&gt; </span>editor:&amp;:editor, go-render?:bool [
  <span class="Constant">local-scope</span>
  <span class="Constant">load-ingredients</span>
  before-cursor:&amp;:duplex-list:char<span class="Special"> &lt;- </span>get *editor, <span class="Constant">before-cursor:offset</span>
  cursor-row:num<span class="Special"> &lt;- </span>get *editor, <span class="Constant">cursor-row:offset</span>
  cursor-column:num<span class="Special"> &lt;- </span>get *editor, <span class="Constant">cursor-column:offset</span>
  left:num<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?:bool<span class="Special"> &lt;- </span>equal cursor-column, left
    <span class="muControl">break-if</span> at-left-margin?
    trace <span class="Constant">10</span>, <span class="Constant">[app]</span>, <span class="Constant">[decrementing cursor column]</span>
    cursor-column<span class="Special"> &lt;- </span>subtract cursor-column, <span class="Constant">1</span>
    *editor<span class="Special"> &lt;- </span>put *editor, <span class="Constant">cursor-column:offset</span>, cursor-column
    go-render?<span class="Special"> &lt;- </span>copy <span class="Constant">0/false</span>
    <span class="muControl">return</span>
  <span class="Delimiter">}</span>
  <span class="Comment"># if at left margin, we must move to previous row:</span>
  top-of-screen?:bool<span class="Special"> &lt;- </span>equal cursor-row, <span class="Constant">1</span>  <span class="Comment"># exclude menu bar</span>
  go-render?:bool<span class="Special"> &lt;- </span>copy <span class="Constant">0/false</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>
    *editor<span class="Special"> &lt;- </span>put *editor, <span class="Constant">cursor-row:offset</span>, cursor-row
  <span class="Delimiter">}</span>
  <span class="Delimiter">{</span>
    <span class="muControl">break-unless</span> top-of-screen?
<span class="Constant">    &lt;scroll-up&gt;</span>
    go-render?<span class="Special"> &lt;- </span>copy <span class="Constant">1/true</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:char<span class="Special"> &lt;- </span>get *before-cursor, <span class="Constant">value:offset</span>
    previous-character-is-newline?:bool<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>
    trace <span class="Constant">10</span>, <span class="Constant">[app]</span>, <span class="Constant">[switching to previous line]</span>
    d:&amp;:duplex-list:char<span class="Special"> &lt;- </span>get *editor, <span class="Constant">data:offset</span>
    end-of-line:num<span class="Special"> &lt;- </span>previous-line-length before-cursor, d
    right:num<span class="Special"> &lt;- </span>get *editor, <span class="Constant">right:offset</span>
    width:num<span class="Special"> &lt;- </span>subtract right, left
    wrap?:bool<span class="Special"> &lt;- </span>greater-than end-of-line, width
    <span class="Delimiter">{</span>
      <span class="muControl">break-unless</span> wrap?
      _, column-offset:num<span class="Special"> &lt;- </span>divide-with-remainder end-of-line, width
      cursor-column<span class="Special"> &lt;- </span>add left, column-offset
      *editor<span class="Special"> &lt;- </span>put *editor, <span class="Constant">cursor-column:offset</span>, cursor-column
    <span class="Delimiter">}</span>
    <span class="Delimiter">{</span>
      <span class="muControl">break-if</span> wrap?
      cursor-column<span class="Special"> &lt;- </span>add left, end-of-line
      *editor<span class="Special"> &lt;- </span>put *editor, <span class="Constant">cursor-column:offset</span>, cursor-column
    <span class="Delimiter">}</span>
    <span class="muControl">return</span>
  <span class="Delimiter">}</span>
  <span class="Comment"># case 2: if previous-character was not newline, we're just at a wrapped line</span>
  trace <span class="Constant">10</span>, <span class="Constant">[app]</span>, <span class="Constant">[wrapping to previous line]</span>
  right:num<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>
  *editor<span class="Special"> &lt;- </span>put *editor, <span class="Constant">cursor-column:offset</span>, cursor-column
]

<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">def</span> previous-line-length curr:&amp;:duplex-list:char, start:&amp;:duplex-list:char<span class="muRecipe"> -&gt; </span>result:num [
  <span class="Constant">local-scope</span>
  <span class="Constant">load-ingredients</span>
  result:num<span class="Special"> &lt;- </span>copy <span class="Constant">0</span>
  <span class="muControl">return-unless</span> curr
  at-start?:bool<span class="Special"> &lt;- </span>equal curr, start
  <span class="muControl">return-if</span> at-start?
  <span class="Delimiter">{</span>
    curr<span class="Special"> &lt;- </span>prev curr
    <span class="muControl">break-unless</span> curr
    at-start?:bool<span class="Special"> &lt;- </span>equal curr, start
    <span class="muControl">break-if</span> at-start?
    c:char<span class="Special"> &lt;- </span>get *curr, <span class="Constant">value:offset</span>
    at-newline?:bool<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="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>:text<span class="Special"> &lt;- </span>new <span class="Constant">[ab</span>
<span class="Constant">cd]</span>
  <span class="Constant">2</span>:&amp;:editor<span class="Special"> &lt;- </span>new-editor <span class="Constant">1</span>:text, screen:&amp;:screen, <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>
    press backspace
  ]
  run [
    editor-event-loop screen:&amp;:screen, console:&amp;:console, <span class="Constant">2</span>:&amp;:editor
    <span class="Constant">4</span>:num<span class="Special"> &lt;- </span>get *<span class="Constant">2</span>:&amp;:editor, <span class="Constant">cursor-row:offset</span>
    <span class="Constant">5</span>:num<span class="Special"> &lt;- </span>get *<span class="Constant">2</span>:&amp;:editor, <span class="Constant">cursor-column:offset</span>
  ]
  screen-should-contain [
   <span class="Constant"> .          .</span>
   <span class="Constant"> .abcd      .</span>
<span class="Constant">    .┈┈┈┈┈┈┈┈┈┈.</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="muScenario">scenario</span> editor-joins-and-wraps-lines-on-backspace [
  assume-screen <span class="Constant">10/width</span>, <span class="Constant">5/height</span>
  <span class="Comment"># initialize editor with two long-ish but non-wrapping lines</span>
  <span class="Constant">1</span>:text<span class="Special"> &lt;- </span>new <span class="Constant">[abc def</span>
<span class="Constant">ghi jkl]</span>
  <span class="Constant">2</span>:&amp;:editor<span class="Special"> &lt;- </span>new-editor <span class="Constant">1</span>:text, screen:&amp;:screen, <span class="Constant">0/left</span>, <span class="Constant">10/right</span>
  editor-render screen, <span class="Constant">2</span>:&amp;:editor
<span class="Constant">  $clear-trace</span>
  <span class="Comment"># position the cursor at the start of the second and hit backspace</span>
  assume-console [
    left-click <span class="Constant">2</span>, <span class="Constant">0</span>
    press backspace
  ]
  run [
    editor-event-loop screen:&amp;:screen, console:&amp;:console, <span class="Constant">2</span>:&amp;:editor
  ]
  <span class="Comment"># resulting single line should wrap correctly</span>
  screen-should-contain [
   <span class="Constant"> .          .</span>
   <span class="Constant"> .abc defgh↩.</span>
   <span class="Constant"> .i jkl     .</span>
<span class="Constant">    .┈┈┈┈┈┈┈┈┈┈.</span>
   <span class="Constant"> .          .</span>
  ]
]

<span class="muScenario">scenario</span> editor-wraps-long-lines-on-backspace [
  assume-screen <span class="Constant">10/width</span>, <span class="Constant">5/height</span>
  <span class="Comment"># initialize editor in part of the screen with a long line</span>
  <span class="Constant">1</span>:text<span class="Special"> &lt;- </span>new <span class="Constant">[abc def ghij]</span>
  <span class="Constant">2</span>:&amp;:editor<span class="Special"> &lt;- </span>new-editor <span class="Constant">1</span>:text, screen:&amp;:screen, <span class="Constant">0/left</span>, <span class="Constant">8/right</span>
  editor-render screen, <span class="Constant">2</span>:&amp;:editor
  <span class="Comment"># confirm that it wraps</span>
  screen-should-contain [
   <span class="Constant"> .          .</span>
   <span class="Constant"> .abc def↩  .</span>
   <span class="Constant"> . ghij     .</span>
   <span class="Constant"> .┈┈┈┈┈┈┈┈  .</span>
  ]
<span class="Constant">  $clear-trace</span>
  <span class="Comment"># position the cursor somewhere in the middle of the top screen line and hit backspace</span>
  assume-console [
    left-click <span class="Constant">1</span>, <span class="Constant">4</span>
    press backspace
  ]
  run [
    editor-event-loop screen:&amp;:screen, console:&amp;:console, <span class="Constant">2</span>:&amp;:editor
  ]
  <span class="Comment"># resulting single line should wrap correctly and not overflow its bounds</span>
  screen-should-contain [
   <span class="Constant"> .          .</span>
   <span class="Constant"> .abcdef ↩  .</span>
   <span class="Constant"> .ghij      .</span>
   <span class="Constant"> .┈┈┈┈┈┈┈┈  .</span>
   <span class="Constant"> .          .</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>:text<span class="Special"> &lt;- </span>new <span class="Constant">[abc]</span>
  <span class="Constant">2</span>:&amp;:editor<span class="Special"> &lt;- </span>new-editor <span class="Constant">1</span>:text, screen:&amp;:screen, <span class="Constant">0/left</span>, <span class="Constant">10/right</span>
  editor-render screen, <span class="Constant">2</span>:&amp;:editor
<span class="Constant">  $clear-trace</span>
  assume-console [
    press delete
  ]
  run [
    editor-event-loop screen:&amp;:screen, console:&amp;:console, <span class="Constant">2</span>:&amp;:editor
  ]
  screen-should-contain [
   <span class="Constant"> .          .</span>
   <span class="Constant"> .bc        .</span>
<span class="Constant">    .┈┈┈┈┈┈┈┈┈┈.</span>
   <span class="Constant"> .          .</span>
  ]
  check-trace-count-for-label <span class="Constant">3</span>, <span class="Constant">[print-character]</span>  <span class="Comment"># length of original line to overwrite</span>
<span class="Constant">  $clear-trace</span>
  assume-console [
    press delete
  ]
  run [
    editor-event-loop screen:&amp;:screen, console:&amp;:console, <span class="Constant">2</span>:&amp;:editor
  ]
  screen-should-contain [
   <span class="Constant"> .          .</span>
   <span class="Constant"> .c         .</span>
<span class="Constant">    .┈┈┈┈┈┈┈┈┈┈.</span>
   <span class="Constant"> .          .</span>
  ]
  check-trace-count-for-label <span class="Constant">2</span>, <span class="Constant">[print-character]</span>  <span class="Comment"># new length to overwrite</span>
]

<span class="muRecipe">after</span> <span class="Constant">&lt;handle-special-key&gt;</span> [
  <span class="Delimiter">{</span>
    delete-next-character?:bool<span class="Special"> &lt;- </span>equal k, <span class="Constant">65522/delete</span>
    <span class="muControl">break-unless</span> delete-next-character?
<span class="Constant">    &lt;delete-character-begin&gt;</span>
    editor, screen, go-render?:bool, deleted-cell:&amp;:duplex-list:char<span class="Special"> &lt;- </span>delete-at-cursor editor, screen
<span class="Constant">    &lt;delete-character-end&gt;</span>
    <span class="muControl">return</span>
  <span class="Delimiter">}</span>
]

<span class="muRecipe">def</span> delete-at-cursor editor:&amp;:editor, screen:&amp;:screen<span class="muRecipe"> -&gt; </span>editor:&amp;:editor, screen:&amp;:screen, go-render?:bool, deleted-cell:&amp;:duplex-list:char [
  <span class="Constant">local-scope</span>
  <span class="Constant">load-ingredients</span>
  before-cursor:&amp;:duplex-list:char<span class="Special"> &lt;- </span>get *editor, <span class="Constant">before-cursor:offset</span>
  data:&amp;:duplex-list:char<span class="Special"> &lt;- </span>get *editor, <span class="Constant">data:offset</span>
  deleted-cell:&amp;:duplex-list:char<span class="Special"> &lt;- </span>next before-cursor
  go-render?<span class="Special"> &lt;- </span>copy <span class="Constant">0/false</span>
  <span class="muControl">return-unless</span> deleted-cell
  currc:char<span class="Special"> &lt;- </span>get *deleted-cell, <span class="Constant">value:offset</span>
  data<span class="Special"> &lt;- </span>remove deleted-cell, data
  deleted-newline?:bool<span class="Special"> &lt;- </span>equal currc, <span class="Constant">10/newline</span>
  go-render?<span class="Special"> &lt;- </span>copy <span class="Constant">1/true</span>
  <span class="muControl">return-if</span> deleted-newline?
  <span class="Comment"># wasn't a newline? render rest of line</span>
  curr:&amp;:duplex-list:char<span class="Special"> &lt;- </span>next before-cursor  <span class="Comment"># refresh after remove above</span>
  cursor-row:num<span class="Special"> &lt;- </span>get *editor, <span class="Constant">cursor-row:offset</span>
  cursor-column:num<span class="Special"> &lt;- </span>get *editor, <span class="Constant">cursor-column:offset</span>
  screen<span class="Special"> &lt;- </span>move-cursor screen, cursor-row, cursor-column
  curr-column:num<span class="Special"> &lt;- </span>copy cursor-column
  screen-width:num<span class="Special"> &lt;- </span>screen-width screen
  <span class="Delimiter">{</span>
    <span class="Comment"># hit right margin? give up and let caller render</span>
    at-right?:bool<span class="Special"> &lt;- </span>greater-or-equal curr-column, screen-width
    go-render?<span class="Special"> &lt;- </span>copy <span class="Constant">1/true</span>
    <span class="muControl">return-if</span> at-right?
    <span class="muControl">break-unless</span> curr
    <span class="Comment"># newline? done.</span>
    currc:char<span class="Special"> &lt;- </span>get *curr, <span class="Constant">value:offset</span>
    at-newline?:bool<span class="Special"> &lt;- </span>equal currc, <span class="Constant">10/newline</span>
    <span class="muControl">break-if</span> at-newline?
    screen<span class="Special"> &lt;- </span>print screen, currc
    curr-column<span class="Special"> &lt;- </span>add curr-column, <span class="Constant">1</span>
    curr<span class="Special"> &lt;- </span>next curr
    <span class="muControl">loop</span>
  <span class="Delimiter">}</span>
  <span class="Comment"># we're guaranteed not to be at the right margin</span>
  space:char<span class="Special"> &lt;- </span>copy <span class="Constant">32/space</span>
  screen<span class="Special"> &lt;- </span>print screen, space
  go-render?<span class="Special"> &lt;- </span>copy <span class="Constant">0/false</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>:text<span class="Special"> &lt;- </span>new <span class="Constant">[abc]</span>
  <span class="Constant">2</span>:&amp;:editor<span class="Special"> &lt;- </span>new-editor <span class="Constant">1</span>:text, screen:&amp;:screen, <span class="Constant">0/left</span>, <span class="Constant">10/right</span>
  editor-render screen, <span class="Constant">2</span>:&amp;:editor
<span class="Constant">  $clear-trace</span>
  assume-console [
    press right-arrow
    type <span class="Constant">[0]</span>
  ]
  run [
    editor-event-loop screen:&amp;:screen, console:&amp;:console, <span class="Constant">2</span>:&amp;:editor
  ]
  screen-should-contain [
   <span class="Constant"> .          .</span>
   <span class="Constant"> .a0bc      .</span>
<span class="Constant">    .┈┈┈┈┈┈┈┈┈┈.</span>
   <span class="Constant"> .          .</span>
  ]
  check-trace-count-for-label <span class="Constant">3</span>, <span class="Constant">[print-character]</span>  <span class="Comment"># 0 and following characters</span>
]

<span class="muRecipe">after</span> <span class="Constant">&lt;handle-special-key&gt;</span> [
  <span class="Delimiter">{</span>
    move-to-next-character?:bool<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>
    next-cursor:&amp;:duplex-list:char<span class="Special"> &lt;- </span>next before-cursor
    <span class="muControl">break-unless</span> next-cursor
    <span class="Comment"># scan to next character</span>
<span class="Constant">    &lt;move-cursor-begin&gt;</span>
    before-cursor<span class="Special"> &lt;- </span>copy next-cursor
    *editor<span class="Special"> &lt;- </span>put *editor, <span class="Constant">before-cursor:offset</span>, before-cursor
    editor, go-render?:bool<span class="Special"> &lt;- </span>move-cursor-coordinates-right editor, screen-height
    screen<span class="Special"> &lt;- </span>move-cursor screen, cursor-row, cursor-column
    undo-coalesce-tag:num<span class="Special"> &lt;- </span>copy <span class="Constant">2/right-arrow</span>
<span class="Constant">    &lt;move-cursor-end&gt;</span>
    <span class="muControl">return</span>
  <span class="Delimiter">}</span>
]

<span class="muRecipe">def</span> move-cursor-coordinates-right editor:&amp;:editor, screen-height:num<span class="muRecipe"> -&gt; </span>editor:&amp;:editor, go-render?:bool [
  <span class="Constant">local-scope</span>
  <span class="Constant">load-ingredients</span>
  before-cursor:&amp;:duplex-list:char<span class="Special"> &lt;- </span>get *editor <span class="Constant">before-cursor:offset</span>
  cursor-row:num<span class="Special"> &lt;- </span>get *editor, <span class="Constant">cursor-row:offset</span>
  cursor-column:num<span class="Special"> &lt;- </span>get *editor, <span class="Constant">cursor-column:offset</span>
  left:num<span class="Special"> &lt;- </span>get *editor, <span class="Constant">left:offset</span>
  right:num<span class="Special"> &lt;- </span>get *editor, <span class="Constant">right:offset</span>
  <span class="Comment"># if crossed a newline, move cursor to start of next row</span>
  <span class="Delimiter">{</span>
    old-cursor-character:char<span class="Special"> &lt;- </span>get *before-cursor, <span class="Constant">value:offset</span>
    was-at-newline?:bool<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>
    *editor<span class="Special"> &lt;- </span>put *editor, <span class="Constant">cursor-row:offset</span>, cursor-row
    cursor-column<span class="Special"> &lt;- </span>copy left
    *editor<span class="Special"> &lt;- </span>put *editor, <span class="Constant">cursor-column:offset</span>, cursor-column
    below-screen?:bool<span class="Special"> &lt;- </span>greater-or-equal cursor-row, screen-height  <span class="Comment"># must be equal</span>
    go-render?<span class="Special"> &lt;- </span>copy <span class="Constant">0/false</span>
    <span class="muControl">return-unless</span> below-screen?
<span class="Constant">    &lt;scroll-down&gt;</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>
    *editor<span class="Special"> &lt;- </span>put *editor, <span class="Constant">cursor-row:offset</span>, cursor-row
    go-render?<span class="Special"> &lt;- </span>copy <span class="Constant">1/true</span>
    <span class="muControl">return</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:num<span class="Special"> &lt;- </span>subtract right, <span class="Constant">1</span>
    at-wrap?:bool<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>
    next:&amp;:duplex-list:char<span class="Special"> &lt;- </span>next before-cursor
    <span class="muControl">break-unless</span> next
    next-character:char<span class="Special"> &lt;- </span>get *next, <span class="Constant">value:offset</span>
    newline?:bool<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>
    *editor<span class="Special"> &lt;- </span>put *editor, <span class="Constant">cursor-row:offset</span>, cursor-row
    cursor-column<span class="Special"> &lt;- </span>copy left
    *editor<span class="Special"> &lt;- </span>put *editor, <span class="Constant">cursor-column:offset</span>, cursor-column
    below-screen?:bool<span class="Special"> &lt;- </span>greater-or-equal cursor-row, screen-height  <span class="Comment"># must be equal</span>
    <span class="muControl">return-unless</span> below-screen?, editor/same-as-ingredient:<span class="Constant">0</span>, <span class="Constant">0/no-more-render</span>
<span class="Constant">    &lt;scroll-down&gt;</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>
    *editor<span class="Special"> &lt;- </span>put *editor, <span class="Constant">cursor-row:offset</span>, cursor-row
    go-render?<span class="Special"> &lt;- </span>copy <span class="Constant">1/true</span>
    <span class="muControl">return</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>
  *editor<span class="Special"> &lt;- </span>put *editor, <span class="Constant">cursor-column:offset</span>, cursor-column
  go-render?<span class="Special"> &lt;- </span>copy <span class="Constant">0/false</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>:text<span class="Special"> &lt;- </span>new <span class="Constant">[abc</span>
<span class="Constant">d]</span>
  <span class="Constant">2</span>:&amp;:editor<span class="Special"> &lt;- </span>new-editor <span class="Constant">1</span>:text, screen:&amp;:screen, <span class="Constant">0/left</span>, <span class="Constant">10/right</span>
  editor-render screen, <span class="Constant">2</span>:&amp;:editor
<span class="Constant">  $clear-trace</span>
  <span class="Comment"># type right-arrow a few times to get to start of second line</span>
  assume-console [
    press right-arrow
    press right-arrow
    press right-arrow
    press right-arrow  <span class="Comment"># next line</span>
  ]
  run [
    editor-event-loop screen:&amp;:screen, console:&amp;:console, <span class="Constant">2</span>:&amp;:editor
  ]
  check-trace-count-for-label <span class="Constant">0</span>, <span class="Constant">[print-character]</span>
  <span class="Comment"># type something and ensure it goes where it should</span>
  assume-console [
    type <span class="Constant">[0]</span>
  ]
  run [
    editor-event-loop screen:&amp;:screen, console:&amp;:console, <span class="Constant">2</span>:&amp;:editor
  ]
  screen-should-contain [
   <span class="Constant"> .          .</span>
   <span class="Constant"> .abc       .</span>
   <span class="Constant"> .0d        .</span>
<span class="Constant">    .┈┈┈┈┈┈┈┈┈┈.</span>
   <span class="Constant"> .          .</span>
  ]
  check-trace-count-for-label <span class="Constant">2</span>, <span class="Constant">[print-character]</span>  <span class="Comment"># new length of second line</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>:text<span class="Special"> &lt;- </span>new <span class="Constant">[abc</span>
<span class="Constant">d]</span>
  <span class="Constant">2</span>:&amp;:editor<span class="Special"> &lt;- </span>new-editor <span class="Constant">1</span>:text, screen:&amp;:screen, <span class="Constant">1/left</span>, <span class="Constant">10/right</span>
  editor-render screen, <span class="Constant">2</span>:&amp;:editor
  assume-console [
    press right-arrow
    press right-arrow
    press right-arrow
    press right-arrow  <span class="Comment"># next line</span>
    type <span class="Constant">[0]</span>
  ]
  run [
    editor-event-loop screen:&amp;:screen, console:&amp;:console, <span class="Constant">2</span>:&amp;:editor
  ]
  screen-should-contain [
   <span class="Constant"> .          .</span>
   <span class="Constant"> . abc      .</span>
   <span class="Constant"> . 0d       .</span>
   <span class="Constant"> . ┈┈┈┈┈┈┈┈┈.</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>:text<span class="Special"> &lt;- </span>new <span class="Constant">[abcdef]</span>
  <span class="Constant">2</span>:&amp;:editor<span class="Special"> &lt;- </span>new-editor <span class="Constant">1</span>:text, screen:&amp;:screen, <span class="Constant">0/left</span>, <span class="Constant">5/right</span>
  editor-render screen, <span class="Constant">2</span>:&amp;:editor
<span class="Constant">  $clear-trace</span>
  assume-console [
    left-click <span class="Constant">1</span>, <span class="Constant">3</span>
    press right-arrow
  ]
  run [
    editor-event-loop screen:&amp;:screen, console:&amp;:console, <span class="Constant">2</span>:&amp;:editor
    <span class="Constant">3</span>:num<span class="Special"> &lt;- </span>get *<span class="Constant">2</span>:&amp;:editor, <span class="Constant">cursor-row:offset</span>
    <span class="Constant">4</span>:num<span class="Special"> &lt;- </span>get *<span class="Constant">2</span>:&amp;:editor, <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>
   <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>
  ]
  check-trace-count-for-label <span class="Constant">0</span>, <span class="Constant">[print-character]</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>:text<span class="Special"> &lt;- </span>new <span class="Constant">[abcde]</span>
  <span class="Constant">2</span>:&amp;:editor<span class="Special"> &lt;- </span>new-editor <span class="Constant">1</span>:text, screen:&amp;:screen, <span class="Constant">0/left</span>, <span class="Constant">5/right</span>
  editor-render screen, <span class="Constant">2</span>:&amp;:editor
<span class="Constant">  $clear-trace</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 right-arrow
  ]
  run [
    editor-event-loop screen:&amp;:screen, console:&amp;:console, <span class="Constant">2</span>:&amp;:editor
    <span class="Constant">3</span>:num<span class="Special"> &lt;- </span>get *<span class="Constant">2</span>:&amp;:editor, <span class="Constant">cursor-row:offset</span>
    <span class="Constant">4</span>:num<span class="Special"> &lt;- </span>get *<span class="Constant">2</span>:&amp;:editor, <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 right-arrow
  ]
  run [
    editor-event-loop screen:&amp;:screen, console:&amp;:console, <span class="Constant">2</span>:&amp;:editor
    <span class="Constant">3</span>:num<span class="Special"> &lt;- </span>get *<span class="Constant">2</span>:&amp;:editor, <span class="Constant">cursor-row:offset</span>
    <span class="Constant">4</span>:num<span class="Special"> &lt;- </span>get *<span class="Constant">2</span>:&amp;:editor, <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>
  ]
  check-trace-count-for-label <span class="Constant">0</span>, <span class="Constant">[print-character]</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>:text<span class="Special"> &lt;- </span>new <span class="Constant">[abcdef]</span>
  <span class="Constant">2</span>:&amp;:editor<span class="Special"> &lt;- </span>new-editor <span class="Constant">1</span>:text, screen:&amp;:screen, <span class="Constant">1/left</span>, <span class="Constant">6/right</span>
  editor-render screen, <span class="Constant">2</span>:&amp;:editor
<span class="Constant">  $clear-trace</span>
  assume-console [
    left-click <span class="Constant">1</span>, <span class="Constant">4</span>
    press right-arrow
  ]
  run [
    editor-event-loop screen:&amp;:screen, console:&amp;:console, <span class="Constant">2</span>:&amp;:editor
    <span class="Constant">3</span>:num<span class="Special"> &lt;- </span>get *<span class="Constant">2</span>:&amp;:editor, <span class="Constant">cursor-row:offset</span>
    <span class="Constant">4</span>:num<span class="Special"> &lt;- </span>get *<span class="Constant">2</span>:&amp;:editor, <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>
   <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>
  ]
  check-trace-count-for-label <span class="Constant">0</span>, <span class="Constant">[print-character]</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>:text<span class="Special"> &lt;- </span>new <span class="Constant">[abc</span>
<span class="Constant">d]</span>
  <span class="Constant">2</span>:&amp;:editor<span class="Special"> &lt;- </span>new-editor <span class="Constant">1</span>:text, screen:&amp;:screen, <span class="Constant">0/left</span>, <span class="Constant">10/right</span>
  editor-render screen, <span class="Constant">2</span>:&amp;:editor
<span class="Constant">  $clear-trace</span>
  <span class="Comment"># move to end of line, press right-arrow, type a character</span>
  assume-console [
    left-click <span class="Constant">1</span>, <span class="Constant">3</span>
    press right-arrow
    type <span class="Constant">[0]</span>
  ]
  run [
    editor-event-loop screen:&amp;:screen, console:&amp;:console, <span class="Constant">2</span>:&amp;:editor
  ]
  <span class="Comment"># new character should be in next line</span>
  screen-should-contain [
   <span class="Constant"> .          .</span>
   <span class="Constant"> .abc       .</span>
   <span class="Constant"> .0d        .</span>
<span class="Constant">    .┈┈┈┈┈┈┈┈┈┈.</span>
   <span class="Constant"> .          .</span>
  ]
  check-trace-count-for-label <span class="Constant">2</span>, <span class="Constant">[print-character]</span>
]

<span class="Comment"># todo: ctrl-right: next word-end</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>:text<span class="Special"> &lt;- </span>new <span class="Constant">[abc]</span>
  <span class="Constant">2</span>:&amp;:editor<span class="Special"> &lt;- </span>new-editor <span class="Constant">1</span>:text, screen:&amp;:screen, <span class="Constant">0/left</span>, <span class="Constant">10/right</span>
  editor-render screen, <span class="Constant">2</span>:&amp;:editor
<span class="Constant">  $clear-trace</span>
  assume-console [
    left-click <span class="Constant">1</span>, <span class="Constant">2</span>
    press left-arrow
    type <span class="Constant">[0]</span>
  ]
  run [
    editor-event-loop screen:&amp;:screen, console:&amp;:console, <span class="Constant">2</span>:&amp;:editor
  ]
  screen-should-contain [
   <span class="Constant"> .          .</span>
   <span class="Constant"> .a0bc      .</span>
<span class="Constant">    .┈┈┈┈┈┈┈┈┈┈.</span>
   <span class="Constant"> .          .</span>
  ]
  check-trace-count-for-label <span class="Constant">3</span>, <span class="Constant">[print-character]</span>
]

<span class="muRecipe">after</span> <span class="Constant">&lt;handle-special-key&gt;</span> [
  <span class="Delimiter">{</span>
    move-to-previous-character?:bool<span class="Special"> &lt;- </span>equal k, <span class="Constant">65515/left-arrow</span>
    <span class="muControl">break-unless</span> move-to-previous-character?
    trace <span class="Constant">10</span>, <span class="Constant">[app]</span>, <span class="Constant">[left arrow]</span>
    <span class="Comment"># if not at start of text (before-cursor at § sentinel)</span>
    prev:&amp;:duplex-list:char<span class="Special"> &lt;- </span>prev before-cursor
    go-render?<span class="Special"> &lt;- </span>copy <span class="Constant">0/false</span>
    <span class="muControl">return-unless</span> prev
<span class="Constant">    &lt;move-cursor-begin&gt;</span>
    editor, go-render?<span class="Special"> &lt;- </span>move-cursor-coordinates-left editor
    before-cursor<span class="Special"> &lt;- </span>copy prev
    *editor<span class="Special"> &lt;- </span>put *editor, <span class="Constant">before-cursor:offset</span>, before-cursor
    undo-coalesce-tag:num<span class="Special"> &lt;- </span>copy <span class="Constant">1/left-arrow</span>
<span class="Constant">    &lt;move-cursor-end&gt;</span>
    <span class="muControl">return</span>
  <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>:text<span class="Special"> &lt;- </span>new <span class="Constant">[abc</span>
<span class="Constant">d]</span>
  <span class="Constant">2</span>:&amp;:editor<span class="Special"> &lt;- </span>new-editor <span class="Constant">1</span>:text, screen:&amp;:screen, <span class="Constant">0/left</span>, <span class="Constant">10/right</span>
  editor-render screen, <span class="Constant">2</span>:&amp;:editor
<span class="Constant">  $clear-trace</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 left-arrow
  ]
  run [
    editor-event-loop screen:&amp;:screen, console:&amp;:console, <span class="Constant">2</span>:&amp;:editor
    <span class="Constant">3</span>:num<span class="Special"> &lt;- </span>get *<span class="Constant">2</span>:&amp;:editor, <span class="Constant">cursor-row:offset</span>
    <span class="Constant">4</span>:num<span class="Special"> &lt;- </span>get *<span class="Constant">2</span>:&amp;:editor, <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>
  ]
  check-trace-count-for-label <span class="Constant">0</span>, <span class="Constant">[print-character]</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>:text<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>:&amp;:editor<span class="Special"> &lt;- </span>new-editor <span class="Constant">1</span>:text, screen:&amp;:screen, <span class="Constant">0/left</span>, <span class="Constant">10/right</span>
  editor-render screen, <span class="Constant">2</span>:&amp;:editor
<span class="Constant">  $clear-trace</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 left-arrow
    type <span class="Constant">[0]</span>
  ]
  run [
    editor-event-loop screen:&amp;:screen, console:&amp;:console, <span class="Constant">2</span>:&amp;:editor
  ]
  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>
  ]
  check-trace-count-for-label <span class="Constant">1</span>, <span class="Constant">[print-character]</span>  <span class="Comment"># just the '0'</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>:text<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>:&amp;:editor<span class="Special"> &lt;- </span>new-editor <span class="Constant">1</span>:text, screen:&amp;:screen, <span class="Constant">0/left</span>, <span class="Constant">10/right</span>
  editor-render screen, <span class="Constant">2</span>:&amp;:editor
<span class="Constant">  $clear-trace</span>
  <span class="Comment"># position cursor at start of text, press left-arrow, then type a character</span>
  assume-console [
    left-click <span class="Constant">1</span>, <span class="Constant">0</span>
    press left-arrow
    type <span class="Constant">[0]</span>
  ]
  run [
    editor-event-loop screen:&amp;:screen, console:&amp;:console, <span class="Constant">2</span>:&amp;:editor
  ]
  <span class="Comment"># left-arrow should have had no effect</span>
  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>
  ]
  check-trace-count-for-label <span class="Constant">4</span>, <span class="Constant">[print-character]</span>  <span class="Comment"># length of first line</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>:text<span class="Special"> &lt;- </span>new <span class="Constant">[abc</span>

d]
  <span class="Constant">2</span>:&amp;:editor<span class="Special"> &lt;- </span>new-editor <span class="Constant">1</span>:text, screen:&amp;:screen, <span class="Constant">0/left</span>, <span class="Constant">10/right</span>
  editor-render screen, <span class="Constant">2</span>:&amp;:editor
<span class="Constant">  $clear-trace</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 left-arrow
    type <span class="Constant">[0]</span>
  ]
  run [
    editor-event-loop screen:&amp;:screen, console:&amp;:console, <span class="Constant">2</span>:&amp;:editor
  ]
  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>
  ]
  check-trace-count-for-label <span class="Constant">1</span>, <span class="Constant">[print-character]</span>  <span class="Comment"># just the '0'</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 a wrapping line</span>
  <span class="Constant">1</span>:text<span class="Special"> &lt;- </span>new <span class="Constant">[abcdef]</span>
  <span class="Constant">2</span>:&amp;:editor<span class="Special"> &lt;- </span>new-editor <span class="Constant">1</span>:text, screen:&amp;:screen, <span class="Constant">0/left</span>, <span class="Constant">5/right</span>
  editor-render screen, <span class="Constant">2</span>:&amp;:editor
<span class="Constant">  $clear-trace</span>
  screen-should-contain [
   <span class="Constant"> .          .</span>
   <span class="Constant"> .abcd↩     .</span>
   <span class="Constant"> .ef        .</span>
   <span class="Constant"> .┈┈┈┈┈     .</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 left-arrow
  ]
  run [
    editor-event-loop screen:&amp;:screen, console:&amp;:console, <span class="Constant">2</span>:&amp;:editor
    <span class="Constant">3</span>:num<span class="Special"> &lt;- </span>get *<span class="Constant">2</span>:&amp;:editor, <span class="Constant">cursor-row:offset</span>
    <span class="Constant">4</span>:num<span class="Special"> &lt;- </span>get *<span class="Constant">2</span>:&amp;:editor, <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"># right margin except wrap icon</span>
  ]
  check-trace-count-for-label <span class="Constant">0</span>, <span class="Constant">[print-character]</span>
]

<span class="muScenario">scenario</span> editor-moves-across-screen-lines-to-wrapping-line-with-left-arrow [
  assume-screen <span class="Constant">10/width</span>, <span class="Constant">5/height</span>
  <span class="Comment"># initialize editor with a wrapping line followed by a second line</span>
  <span class="Constant">1</span>:text<span class="Special"> &lt;- </span>new <span class="Constant">[abcdef</span>
<span class="Constant">g]</span>
  <span class="Constant">2</span>:&amp;:editor<span class="Special"> &lt;- </span>new-editor <span class="Constant">1</span>:text, screen:&amp;:screen, <span class="Constant">0/left</span>, <span class="Constant">5/right</span>
  editor-render screen, <span class="Constant">2</span>:&amp;:editor
<span class="Constant">  $clear-trace</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="Constant"> .┈┈┈┈┈     .</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 left-arrow
  ]
  run [
    editor-event-loop screen:&amp;:screen, console:&amp;:console, <span class="Constant">2</span>:&amp;:editor
    <span class="Constant">3</span>:num<span class="Special"> &lt;- </span>get *<span class="Constant">2</span>:&amp;:editor, <span class="Constant">cursor-row:offset</span>
    <span class="Constant">4</span>:num<span class="Special"> &lt;- </span>get *<span class="Constant">2</span>:&amp;:editor, <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"># previous row</span>
    <span class="Constant">4</span><span class="Special"> &lt;- </span><span class="Constant">2</span>  <span class="Comment"># end of wrapped line</span>
  ]
  check-trace-count-for-label <span class="Constant">0</span>, <span class="Constant">[print-character]</span>
]

<span class="muScenario">scenario</span> editor-moves-across-screen-lines-to-non-wrapping-line-with-left-arrow [
  assume-screen <span class="Constant">10/width</span>, <span class="Constant">5/height</span>
  <span class="Comment"># initialize editor with a line on the verge of wrapping, followed by a second line</span>
  <span class="Constant">1</span>:text<span class="Special"> &lt;- </span>new <span class="Constant">[abcd</span>
<span class="Constant">e]</span>
  <span class="Constant">2</span>:&amp;:editor<span class="Special"> &lt;- </span>new-editor <span class="Constant">1</span>:text, screen:&amp;:screen, <span class="Constant">0/left</span>, <span class="Constant">5/right</span>
  editor-render screen, <span class="Constant">2</span>:&amp;:editor
<span class="Constant">  $clear-trace</span>
  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>
  ]
  <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 left-arrow
  ]
  run [
    editor-event-loop screen:&amp;:screen, console:&amp;:console, <span class="Constant">2</span>:&amp;:editor
    <span class="Constant">3</span>:num<span class="Special"> &lt;- </span>get *<span class="Constant">2</span>:&amp;:editor, <span class="Constant">cursor-row:offset</span>
    <span class="Constant">4</span>:num<span class="Special"> &lt;- </span>get *<span class="Constant">2</span>:&amp;:editor, <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">4</span>  <span class="Comment"># end of wrapped line</span>
  ]
  check-trace-count-for-label <span class="Constant">0</span>, <span class="Constant">[print-character]</span>
]

<span class="Comment"># todo: ctrl-left: previous word-start</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>:text<span class="Special"> &lt;- </span>new <span class="Constant">[abc</span>
<span class="Constant">def]</span>
  <span class="Constant">2</span>:&amp;:editor<span class="Special"> &lt;- </span>new-editor <span class="Constant">1</span>:text, screen:&amp;:screen, <span class="Constant">0/left</span>, <span class="Constant">10/right</span>
  editor-render screen, <span class="Constant">2</span>:&amp;:editor
<span class="Constant">  $clear-trace</span>
  assume-console [
    left-click <span class="Constant">2</span>, <span class="Constant">1</span>
    press up-arrow
  ]
  run [
    editor-event-loop screen:&amp;:screen, console:&amp;:console, <span class="Constant">2</span>:&amp;:editor
    <span class="Constant">3</span>:num<span class="Special"> &lt;- </span>get *<span class="Constant">2</span>:&amp;:editor, <span class="Constant">cursor-row:offset</span>
    <span class="Constant">4</span>:num<span class="Special"> &lt;- </span>get *<span class="Constant">2</span>:&amp;:editor, <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>
  ]
  check-trace-count-for-label <span class="Constant">0</span>, <span class="Constant">[print-character]</span>
  assume-console [
    type <span class="Constant">[0]</span>
  ]
  run [
    editor-event-loop screen:&amp;:screen, console:&amp;:console, <span class="Constant">2</span>:&amp;:editor
  ]
  screen-should-contain [
   <span class="Constant"> .          .</span>
   <span class="Constant"> .a0bc      .</span>
   <span class="Constant"> .def       .</span>
<span class="Constant">    .┈┈┈┈┈┈┈┈┈┈.</span>
   <span class="Constant"> .          .</span>
  ]
]

<span class="muRecipe">after</span> <span class="Constant">&lt;handle-special-key&gt;</span> [
  <span class="Delimiter">{</span>
    move-to-previous-line?:bool<span class="Special"> &lt;- </span>equal k, <span class="Constant">65517/up-arrow</span>
    <span class="muControl">break-unless</span> move-to-previous-line?
<span class="Constant">    &lt;move-cursor-begin&gt;</span>
    editor, go-render?<span class="Special"> &lt;- </span>move-to-previous-line editor
    undo-coalesce-tag:num<span class="Special"> &lt;- </span>copy <span class="Constant">3/up-arrow</span>
<span class="Constant">    &lt;move-cursor-end&gt;</span>
    <span class="muControl">return</span>
  <span class="Delimiter">}</span>
]

<span class="muRecipe">def</span> move-to-previous-line editor:&amp;:editor<span class="muRecipe"> -&gt; </span>editor:&amp;:editor, go-render?:bool [
  <span class="Constant">local-scope</span>
  <span class="Constant">load-ingredients</span>
  cursor-row:num<span class="Special"> &lt;- </span>get *editor, <span class="Constant">cursor-row:offset</span>
  cursor-column:num<span class="Special"> &lt;- </span>get *editor, <span class="Constant">cursor-column:offset</span>
  before-cursor:&amp;:duplex-list:char<span class="Special"> &lt;- </span>get *editor, <span class="Constant">before-cursor:offset</span>
  left:num<span class="Special"> &lt;- </span>get *editor, <span class="Constant">left:offset</span>
  right:num<span class="Special"> &lt;- </span>get *editor, <span class="Constant">right:offset</span>
  already-at-top?:bool<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?
    <span class="Comment"># if not at newline, move to start of line (previous newline)</span>
    <span class="Comment"># then scan back another line</span>
    <span class="Comment"># if either step fails, give up without modifying cursor or coordinates</span>
    curr:&amp;:duplex-list:char<span class="Special"> &lt;- </span>copy before-cursor
    <span class="Delimiter">{</span>
      old:&amp;:duplex-list:char<span class="Special"> &lt;- </span>copy curr
      c2:char<span class="Special"> &lt;- </span>get *curr, <span class="Constant">value:offset</span>
      at-newline?:bool<span class="Special"> &lt;- </span>equal c2, <span class="Constant">10/newline</span>
      <span class="muControl">break-if</span> at-newline?
      curr:&amp;:duplex-list:char<span class="Special"> &lt;- </span>before-previous-line curr, editor
      no-motion?:bool<span class="Special"> &lt;- </span>equal curr, old
      go-render?<span class="Special"> &lt;- </span>copy <span class="Constant">0/false</span>
      <span class="muControl">return-if</span> no-motion?
    <span class="Delimiter">}</span>
    <span class="Delimiter">{</span>
      old<span class="Special"> &lt;- </span>copy curr
      curr<span class="Special"> &lt;- </span>before-previous-line curr, editor
      no-motion?:bool<span class="Special"> &lt;- </span>equal curr, old
      go-render?<span class="Special"> &lt;- </span>copy <span class="Constant">0/false</span>
      <span class="muControl">return-if</span> no-motion?
    <span class="Delimiter">}</span>
    before-cursor<span class="Special"> &lt;- </span>copy curr
    *editor<span class="Special"> &lt;- </span>put *editor, <span class="Constant">before-cursor:offset</span>, before-cursor
    cursor-row<span class="Special"> &lt;- </span>subtract cursor-row, <span class="Constant">1</span>
    *editor<span class="Special"> &lt;- </span>put *editor, <span class="Constant">cursor-row:offset</span>, cursor-row
    <span class="Comment"># scan ahead to right column or until end of line</span>
    target-column:num<span class="Special"> &lt;- </span>copy cursor-column
    cursor-column<span class="Special"> &lt;- </span>copy left
    *editor<span class="Special"> &lt;- </span>put *editor, <span class="Constant">cursor-column:offset</span>, cursor-column
    <span class="Delimiter">{</span>
      done?:bool<span class="Special"> &lt;- </span>greater-or-equal cursor-column, target-column
      <span class="muControl">break-if</span> done?
      curr:&amp;:duplex-list:char<span class="Special"> &lt;- </span>next before-cursor
      <span class="muControl">break-unless</span> curr
      currc:char<span class="Special"> &lt;- </span>get *curr, <span class="Constant">value:offset</span>
      at-newline?:bool<span class="Special"> &lt;- </span>equal currc, <span class="Constant">10/newline</span>
      <span class="muControl">break-if</span> at-newline?
      <span class="Comment">#</span>
      before-cursor<span class="Special"> &lt;- </span>copy curr
      *editor<span class="Special"> &lt;- </span>put *editor, <span class="Constant">before-cursor:offset</span>, before-cursor
      cursor-column<span class="Special"> &lt;- </span>add cursor-column, <span class="Constant">1</span>
      *editor<span class="Special"> &lt;- </span>put *editor, <span class="Constant">cursor-column:offset</span>, cursor-column
      <span class="muControl">loop</span>
    <span class="Delimiter">}</span>
    go-render?<span class="Special"> &lt;- </span>copy <span class="Constant">0/false</span>
    <span class="muControl">return</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">    &lt;scroll-up&gt;</span>
    go-render?<span class="Special"> &lt;- </span>copy <span class="Constant">1/true</span>
    <span class="muControl">return</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>:text<span class="Special"> &lt;- </span>new <span class="Constant">[ab</span>
<span class="Constant">def]</span>
  <span class="Constant">2</span>:&amp;:editor<span class="Special"> &lt;- </span>new-editor <span class="Constant">1</span>:text, screen:&amp;:screen, <span class="Constant">0/left</span>, <span class="Constant">10/right</span>
  editor-render screen, <span class="Constant">2</span>:&amp;:editor
<span class="Constant">  $clear-trace</span>
  assume-console [
    left-click <span class="Constant">2</span>, <span class="Constant">3</span>
    press up-arrow
  ]
  run [
    editor-event-loop screen:&amp;:screen, console:&amp;:console, <span class="Constant">2</span>:&amp;:editor
    <span class="Constant">3</span>:num<span class="Special"> &lt;- </span>get *<span class="Constant">2</span>:&amp;:editor, <span class="Constant">cursor-row:offset</span>
    <span class="Constant">4</span>:num<span class="Special"> &lt;- </span>get *<span class="Constant">2</span>:&amp;:editor, <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>
  ]
  check-trace-count-for-label <span class="Constant">0</span>, <span class="Constant">[print-character]</span>
  assume-console [
    type <span class="Constant">[0]</span>
  ]
  run [
    editor-event-loop screen:&amp;:screen, console:&amp;:console, <span class="Constant">2</span>:&amp;:editor
  ]
  screen-should-contain [
   <span class="Constant"> .          .</span>
   <span class="Constant"> .ab0       .</span>
   <span class="Constant"> .def       .</span>
<span class="Constant">    .┈┈┈┈┈┈┈┈┈┈.</span>
   <span class="Constant"> .          .</span>
  ]
]

<span class="muScenario">scenario</span> editor-adjusts-column-at-empty-line [
  assume-screen <span class="Constant">10/width</span>, <span class="Constant">5/height</span>
  <span class="Constant">1</span>:text<span class="Special"> &lt;- </span>new [
<span class="muRecipe">def</span>]
  <span class="Constant">2</span>:&amp;:editor<span class="Special"> &lt;- </span>new-editor <span class="Constant">1</span>:text, screen:&amp;:screen, <span class="Constant">0/left</span>, <span class="Constant">10/right</span>
  editor-render screen, <span class="Constant">2</span>:&amp;:editor
<span class="Constant">  $clear-trace</span>
  assume-console [
    left-click <span class="Constant">2</span>, <span class="Constant">3</span>
    press up-arrow
  ]
  run [
    editor-event-loop screen:&amp;:screen, console:&amp;:console, <span class="Constant">2</span>:&amp;:editor
    <span class="Constant">3</span>:num<span class="Special"> &lt;- </span>get *<span class="Constant">2</span>:&amp;:editor, <span class="Constant">cursor-row:offset</span>
    <span class="Constant">4</span>:num<span class="Special"> &lt;- </span>get *<span class="Constant">2</span>:&amp;:editor, <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">0</span>
  ]
  check-trace-count-for-label <span class="Constant">0</span>, <span class="Constant">[print-character]</span>
  assume-console [
    type <span class="Constant">[0]</span>
  ]
  run [
    editor-event-loop screen:&amp;:screen, console:&amp;:console, <span class="Constant">2</span>:&amp;:editor
  ]
  screen-should-contain [
   <span class="Constant"> .          .</span>
   <span class="Constant"> .0         .</span>
   <span class="Constant"> .def       .</span>
<span class="Constant">    .┈┈┈┈┈┈┈┈┈┈.</span>
   <span class="Constant"> .          .</span>
  ]
]

<span class="muScenario">scenario</span> editor-moves-to-previous-line-from-left-margin [
  assume-screen <span class="Constant">10/width</span>, <span class="Constant">5/height</span>
  <span class="Comment"># start out with three lines</span>
  <span class="Constant">1</span>:text<span class="Special"> &lt;- </span>new <span class="Constant">[abc</span>
<span class="Constant">def</span>
<span class="Constant">ghi]</span>
  <span class="Constant">2</span>:&amp;:editor<span class="Special"> &lt;- </span>new-editor <span class="Constant">1</span>:text, screen:&amp;:screen, <span class="Constant">0/left</span>, <span class="Constant">10/right</span>
  editor-render screen, <span class="Constant">2</span>:&amp;:editor
<span class="Constant">  $clear-trace</span>
  <span class="Comment"># click on the third line and hit up-arrow, so you end up just after a newline</span>
  assume-console [
    left-click <span class="Constant">3</span>, <span class="Constant">0</span>
    press up-arrow
  ]
  run [
    editor-event-loop screen:&amp;:screen, console:&amp;:console, <span class="Constant">2</span>:&amp;:editor
    <span class="Constant">3</span>:num<span class="Special"> &lt;- </span>get *<span class="Constant">2</span>:&amp;:editor, <span class="Constant">cursor-row:offset</span>
    <span class="Constant">4</span>:num<span class="Special"> &lt;- </span>get *<span class="Constant">2</span>:&amp;:editor, <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>
  ]
  check-trace-count-for-label <span class="Constant">0</span>, <span class="Constant">[print-character]</span>
  assume-console [
    type <span class="Constant">[0]</span>
  ]
  run [
    editor-event-loop screen:&amp;:screen, console:&amp;:console, <span class="Constant">2</span>:&amp;:editor
  ]
  screen-should-contain [
   <span class="Constant"> .          .</span>
   <span class="Constant"> .abc       .</span>
   <span class="Constant"> .0def      .</span>
   <span class="Constant"> .ghi       .</span>
<span class="Constant">    .┈┈┈┈┈┈┈┈┈┈.</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>:text<span class="Special"> &lt;- </span>new <span class="Constant">[abc</span>
<span class="Constant">def]</span>
  <span class="Constant">2</span>:&amp;:editor<span class="Special"> &lt;- </span>new-editor <span class="Constant">1</span>:text, screen:&amp;:screen, <span class="Constant">0/left</span>, <span class="Constant">10/right</span>
  editor-render screen, <span class="Constant">2</span>:&amp;:editor
<span class="Constant">  $clear-trace</span>
  <span class="Comment"># cursor starts out at (1, 0)</span>
  assume-console [
    press down-arrow
  ]
  run [
    editor-event-loop screen:&amp;:screen, console:&amp;:console, <span class="Constant">2</span>:&amp;:editor
    <span class="Constant">3</span>:num<span class="Special"> &lt;- </span>get *<span class="Constant">2</span>:&amp;:editor, <span class="Constant">cursor-row:offset</span>
    <span class="Constant">4</span>:num<span class="Special"> &lt;- </span>get *<span class="Constant">2</span>:&amp;:editor, <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>
  ]
  check-trace-count-for-label <span class="Constant">0</span>, <span class="Constant">[print-character]</span>
  assume-console [
    type <span class="Constant">[0]</span>
  ]
  run [
    editor-event-loop screen:&amp;:screen, console:&amp;:console, <span class="Constant">2</span>:&amp;:editor
  ]
  screen-should-contain [
   <span class="Constant"> .          .</span>
   <span class="Constant"> .abc       .</span>
   <span class="Constant"> .0def      .</span>
<span class="Constant">    .┈┈┈┈┈┈┈┈┈┈.</span>
   <span class="Constant"> .          .</span>
  ]
]

<span class="muRecipe">after</span> <span class="Constant">&lt;handle-special-key&gt;</span> [
  <span class="Delimiter">{</span>
    move-to-next-line?:bool<span class="Special"> &lt;- </span>equal k, <span class="Constant">65516/down-arrow</span>
    <span class="muControl">break-unless</span> move-to-next-line?
<span class="Constant">    &lt;move-cursor-begin&gt;</span>
    editor, go-render?<span class="Special"> &lt;- </span>move-to-next-line editor, screen-height
    undo-coalesce-tag:num<span class="Special"> &lt;- </span>copy <span class="Constant">4/down-arrow</span>
<span class="Constant">    &lt;move-cursor-end&gt;</span>
    <span class="muControl">return</span>
  <span class="Delimiter">}</span>
]

<span class="muRecipe">def</span> move-to-next-line editor:&amp;:editor, screen-height:num<span class="muRecipe"> -&gt; </span>editor:&amp;:editor, go-render?:bool [
  <span class="Constant">local-scope</span>
  <span class="Constant">load-ingredients</span>
  cursor-row:num<span class="Special"> &lt;- </span>get *editor, <span class="Constant">cursor-row:offset</span>
  cursor-column:num<span class="Special"> &lt;- </span>get *editor, <span class="Constant">cursor-column:offset</span>
  before-cursor:&amp;:duplex-list:char<span class="Special"> &lt;- </span>get *editor, <span class="Constant">before-cursor:offset</span>
  left:num<span class="Special"> &lt;- </span>get *editor, <span class="Constant">left:offset</span>
  right:num<span class="Special"> &lt;- </span>get *editor, <span class="Constant">right:offset</span>
  last-line:num<span class="Special"> &lt;- </span>subtract screen-height, <span class="Constant">1</span>
  already-at-bottom?:bool<span class="Special"> &lt;- </span>greater-or-equal cursor-row, last-line
  <span class="Delimiter">{</span>
    <span class="Comment"># if cursor not at bottom, move it</span>
    <span class="muControl">break-if</span> already-at-bottom?
    <span class="Comment"># scan to start of next line, then to right column or until end of line</span>
    max:num<span class="Special"> &lt;- </span>subtract right, left
    next-line:&amp;:duplex-list:char<span class="Special"> &lt;- </span>before-start-of-next-line before-cursor, max
    <span class="Delimiter">{</span>
      <span class="Comment"># already at end of buffer? try to scroll up (so we can see more</span>
      <span class="Comment"># warnings or sandboxes below)</span>
      no-motion?:bool<span class="Special"> &lt;- </span>equal next-line, before-cursor
      <span class="muControl">break-unless</span> no-motion?
      scroll?:bool<span class="Special"> &lt;- </span>greater-than cursor-row, <span class="Constant">1</span>
      <span class="muControl">break-if</span> scroll?, <span class="Constant">+try-to-scroll:label</span>
      go-render?<span class="Special"> &lt;- </span>copy <span class="Constant">0/false</span>
      <span class="muControl">return</span>
    <span class="Delimiter">}</span>
    cursor-row<span class="Special"> &lt;- </span>add cursor-row, <span class="Constant">1</span>
    *editor<span class="Special"> &lt;- </span>put *editor, <span class="Constant">cursor-row:offset</span>, cursor-row
    before-cursor<span class="Special"> &lt;- </span>copy next-line
    *editor<span class="Special"> &lt;- </span>put *editor, <span class="Constant">before-cursor:offset</span>, before-cursor
    target-column:num<span class="Special"> &lt;- </span>copy cursor-column
    cursor-column<span class="Special"> &lt;- </span>copy left
    *editor<span class="Special"> &lt;- </span>put *editor, <span class="Constant">cursor-column:offset</span>, cursor-column
    <span class="Delimiter">{</span>
      done?:bool<span class="Special"> &lt;- </span>greater-or-equal cursor-column, target-column
      <span class="muControl">break-if</span> done?
      curr:&amp;:duplex-list:char<span class="Special"> &lt;- </span>next before-cursor
      <span class="muControl">break-unless</span> curr
      currc:char<span class="Special"> &lt;- </span>get *curr, <span class="Constant">value:offset</span>
      at-newline?:bool<span class="Special"> &lt;- </span>equal currc, <span class="Constant">10/newline</span>
      <span class="muControl">break-if</span> at-newline?
      <span class="Comment">#</span>
      before-cursor<span class="Special"> &lt;- </span>copy curr
      *editor<span class="Special"> &lt;- </span>put *editor, <span class="Constant">before-cursor:offset</span>, before-cursor
      cursor-column<span class="Special"> &lt;- </span>add cursor-column, <span class="Constant">1</span>
      *editor<span class="Special"> &lt;- </span>put *editor, <span class="Constant">cursor-column:offset</span>, cursor-column
      <span class="muControl">loop</span>
    <span class="Delimiter">}</span>
    go-render?<span class="Special"> &lt;- </span>copy <span class="Constant">0/false</span>
    <span class="muControl">return</span>
  <span class="Delimiter">}</span>
<span class="Constant">  +try-to-scroll</span>
<span class="Constant">  &lt;scroll-down&gt;</span>
  go-render?<span class="Special"> &lt;- </span>copy <span class="Constant">1/true</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>:text<span class="Special"> &lt;- </span>new <span class="Constant">[abc</span>
<span class="Constant">de]</span>
  <span class="Constant">2</span>:&amp;:editor<span class="Special"> &lt;- </span>new-editor <span class="Constant">1</span>:text, screen:&amp;:screen, <span class="Constant">0/left</span>, <span class="Constant">10/right</span>
  editor-render screen, <span class="Constant">2</span>:&amp;:editor
<span class="Constant">  $clear-trace</span>
  assume-console [
    left-click <span class="Constant">1</span>, <span class="Constant">3</span>
    press down-arrow
  ]
  run [
    editor-event-loop screen:&amp;:screen, console:&amp;:console, <span class="Constant">2</span>:&amp;:editor
    <span class="Constant">3</span>:num<span class="Special"> &lt;- </span>get *<span class="Constant">2</span>:&amp;:editor, <span class="Constant">cursor-row:offset</span>
    <span class="Constant">4</span>:num<span class="Special"> &lt;- </span>get *<span class="Constant">2</span>:&amp;:editor, <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>
  ]
  check-trace-count-for-label <span class="Constant">0</span>, <span class="Constant">[print-character]</span>
  assume-console [
    type <span class="Constant">[0]</span>
  ]
  run [
    editor-event-loop screen:&amp;:screen, console:&amp;:console, <span class="Constant">2</span>:&amp;:editor
  ]
  screen-should-contain [
   <span class="Constant"> .          .</span>
   <span class="Constant"> .abc       .</span>
   <span class="Constant"> .de0       .</span>
<span class="Constant">    .┈┈┈┈┈┈┈┈┈┈.</span>
   <span class="Constant"> .          .</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>:text<span class="Special"> &lt;- </span>new <span class="Constant">[123</span>
<span class="Constant">456]</span>
  <span class="Constant">2</span>:&amp;:editor<span class="Special"> &lt;- </span>new-editor <span class="Constant">1</span>:text, screen:&amp;:screen, <span class="Constant">0/left</span>, <span class="Constant">10/right</span>
  editor-render screen, <span class="Constant">2</span>:&amp;:editor
<span class="Constant">  $clear-trace</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>
    press ctrl-a
  ]
  run [
    editor-event-loop screen:&amp;:screen, console:&amp;:console, <span class="Constant">2</span>:&amp;:editor
    <span class="Constant">4</span>:num<span class="Special"> &lt;- </span>get *<span class="Constant">2</span>:&amp;:editor, <span class="Constant">cursor-row:offset</span>
    <span class="Constant">5</span>:num<span class="Special"> &lt;- </span>get *<span class="Constant">2</span>:&amp;:editor, <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>
  ]
  check-trace-count-for-label <span class="Constant">0</span>, <span class="Constant">[print-character]</span>
]

<span class="muRecipe">after</span> <span class="Constant">&lt;handle-special-character&gt;</span> [
  <span class="Delimiter">{</span>
    move-to-start-of-line?:bool<span class="Special"> &lt;- </span>equal c, <span class="Constant">1/ctrl-a</span>
    <span class="muControl">break-unless</span> move-to-start-of-line?
<span class="Constant">    &lt;move-cursor-begin&gt;</span>
    move-to-start-of-line editor
    undo-coalesce-tag:num<span class="Special"> &lt;- </span>copy <span class="Constant">0/never</span>
<span class="Constant">    &lt;move-cursor-end&gt;</span>
    go-render?<span class="Special"> &lt;- </span>copy <span class="Constant">0/false</span>
    <span class="muControl">return</span>
  <span class="Delimiter">}</span>
]

<span class="muRecipe">after</span> <span class="Constant">&lt;handle-special-key&gt;</span> [
  <span class="Delimiter">{</span>
    move-to-start-of-line?:bool<span class="Special"> &lt;- </span>equal k, <span class="Constant">65521/home</span>
    <span class="muControl">break-unless</span> move-to-start-of-line?
<span class="Constant">    &lt;move-cursor-begin&gt;</span>
    move-to-start-of-line editor
    undo-coalesce-tag:num<span class="Special"> &lt;- </span>copy <span class="Constant">0/never</span>
<span class="Constant">    &lt;move-cursor-end&gt;</span>
    go-render?<span class="Special"> &lt;- </span>copy <span class="Constant">0/false</span>
    <span class="muControl">return</span>
  <span class="Delimiter">}</span>
]

<span class="muRecipe">def</span> move-to-start-of-line editor:&amp;:editor<span class="muRecipe"> -&gt; </span>editor:&amp;:editor [
  <span class="Constant">local-scope</span>
  <span class="Constant">load-ingredients</span>
  <span class="Comment"># update cursor column</span>
  left:num<span class="Special"> &lt;- </span>get *editor, <span class="Constant">left:offset</span>
  cursor-column:num<span class="Special"> &lt;- </span>copy left
  *editor<span class="Special"> &lt;- </span>put *editor, <span class="Constant">cursor-column:offset</span>, cursor-column
  <span class="Comment"># update before-cursor</span>
  before-cursor:&amp;:duplex-list:char<span class="Special"> &lt;- </span>get *editor, <span class="Constant">before-cursor:offset</span>
  init:&amp;:duplex-list:char<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?:bool<span class="Special"> &lt;- </span>equal before-cursor, init
    <span class="muControl">break-if</span> at-start-of-text?
    prev:char<span class="Special"> &lt;- </span>get *before-cursor, <span class="Constant">value:offset</span>
    at-start-of-line?:bool<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 before-cursor
    *editor<span class="Special"> &lt;- </span>put *editor, <span class="Constant">before-cursor:offset</span>, 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>:text<span class="Special"> &lt;- </span>new <span class="Constant">[123</span>
<span class="Constant">456]</span>
  <span class="Constant">2</span>:&amp;:editor<span class="Special"> &lt;- </span>new-editor <span class="Constant">1</span>:text, screen:&amp;:screen, <span class="Constant">0/left</span>, <span class="Constant">10/right</span>
  editor-render screen, <span class="Constant">2</span>:&amp;:editor
<span class="Constant">  $clear-trace</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>
    press ctrl-a
  ]
  run [
    editor-event-loop screen:&amp;:screen, console:&amp;:console, <span class="Constant">2</span>:&amp;:editor
    <span class="Constant">4</span>:num<span class="Special"> &lt;- </span>get *<span class="Constant">2</span>:&amp;:editor, <span class="Constant">cursor-row:offset</span>
    <span class="Constant">5</span>:num<span class="Special"> &lt;- </span>get *<span class="Constant">2</span>:&amp;:editor, <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>
  ]
  check-trace-count-for-label <span class="Constant">0</span>, <span class="Constant">[print-character]</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>:text<span class="Special"> &lt;- </span>new <span class="Constant">[123</span>
<span class="Constant">456]</span>
  <span class="Constant">2</span>:&amp;:editor<span class="Special"> &lt;- </span>new-editor <span class="Constant">1</span>:text, screen:&amp;:screen, <span class="Constant">0/left</span>, <span class="Constant">10/right</span>
<span class="Constant">  $clear-trace</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 home
  ]
  run [
    editor-event-loop screen:&amp;:screen, console:&amp;:console, <span class="Constant">2</span>:&amp;:editor
    <span class="Constant">3</span>:num<span class="Special"> &lt;- </span>get *<span class="Constant">2</span>:&amp;:editor, <span class="Constant">cursor-row:offset</span>
    <span class="Constant">4</span>:num<span class="Special"> &lt;- </span>get *<span class="Constant">2</span>:&amp;:editor, <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>
  ]
  check-trace-count-for-label <span class="Constant">0</span>, <span class="Constant">[print-character]</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>:text<span class="Special"> &lt;- </span>new <span class="Constant">[123</span>
<span class="Constant">456]</span>
  <span class="Constant">2</span>:&amp;:editor<span class="Special"> &lt;- </span>new-editor <span class="Constant">1</span>:text, screen:&amp;:screen, <span class="Constant">0/left</span>, <span class="Constant">10/right</span>
  editor-render screen, <span class="Constant">2</span>:&amp;:editor
<span class="Constant">  $clear-trace</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 home
  ]
  run [
    editor-event-loop screen:&amp;:screen, console:&amp;:console, <span class="Constant">2</span>:&amp;:editor
    <span class="Constant">3</span>:num<span class="Special"> &lt;- </span>get *<span class="Constant">2</span>:&amp;:editor, <span class="Constant">cursor-row:offset</span>
    <span class="Constant">4</span>:num<span class="Special"> &lt;- </span>get *<span class="Constant">2</span>:&amp;:editor, <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>
  ]
  check-trace-count-for-label <span class="Constant">0</span>, <span class="Constant">[print-character]</span>
]

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

<span class="muScenario">scenario</span> editor-moves-to-end-of-line-with-ctrl-e [
  assume-screen <span class="Constant">10/width</span>, <span class="Constant">5/height</span>
  <span class="Constant">1</span>:text<span class="Special"> &lt;- </span>new <span class="Constant">[123</span>
<span class="Constant">456]</span>
  <span class="Constant">2</span>:&amp;:editor<span class="Special"> &lt;- </span>new-editor <span class="Constant">1</span>:text, screen:&amp;:screen, <span class="Constant">0/left</span>, <span class="Constant">10/right</span>
  editor-render screen, <span class="Constant">2</span>:&amp;:editor
<span class="Constant">  $clear-trace</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>
    press ctrl-e
  ]
  run [
    editor-event-loop screen:&amp;:screen, console:&amp;:console, <span class="Constant">2</span>:&amp;:editor
    <span class="Constant">4</span>:num<span class="Special"> &lt;- </span>get *<span class="Constant">2</span>:&amp;:editor, <span class="Constant">cursor-row:offset</span>
    <span class="Constant">5</span>:num<span class="Special"> &lt;- </span>get *<span class="Constant">2</span>:&amp;:editor, <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>
  ]
  check-trace-count-for-label <span class="Constant">0</span>, <span class="Constant">[print-character]</span>
  <span class="Comment"># editor inserts future characters at cursor</span>
  assume-console [
    type <span class="Constant">[z]</span>
  ]
  run [
    editor-event-loop screen:&amp;:screen, console:&amp;:console, <span class="Constant">2</span>:&amp;:editor
    <span class="Constant">4</span>:num<span class="Special"> &lt;- </span>get *<span class="Constant">2</span>:&amp;:editor, <span class="Constant">cursor-row:offset</span>
    <span class="Constant">5</span>:num<span class="Special"> &lt;- </span>get *<span class="Constant">2</span>:&amp;:editor, <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="Constant"> .          .</span>
  ]
  check-trace-count-for-label <span class="Constant">1</span>, <span class="Constant">[print-character]</span>
]

<span class="muRecipe">after</span> <span class="Constant">&lt;handle-special-character&gt;</span> [
  <span class="Delimiter">{</span>
    move-to-end-of-line?:bool<span class="Special"> &lt;- </span>equal c, <span class="Constant">5/ctrl-e</span>
    <span class="muControl">break-unless</span> move-to-end-of-line?
<span class="Constant">    &lt;move-cursor-begin&gt;</span>
    move-to-end-of-line editor
    undo-coalesce-tag:num<span class="Special"> &lt;- </span>copy <span class="Constant">0/never</span>
<span class="Constant">    &lt;move-cursor-end&gt;</span>
    go-render?<span class="Special"> &lt;- </span>copy <span class="Constant">0/false</span>
    <span class="muControl">return</span>
  <span class="Delimiter">}</span>
]

<span class="muRecipe">after</span> <span class="Constant">&lt;handle-special-key&gt;</span> [
  <span class="Delimiter">{</span>
    move-to-end-of-line?:bool<span class="Special"> &lt;- </span>equal k, <span class="Constant">65520/end</span>
    <span class="muControl">break-unless</span> move-to-end-of-line?
<span class="Constant">    &lt;move-cursor-begin&gt;</span>
    move-to-end-of-line editor
    undo-coalesce-tag:num<span class="Special"> &lt;- </span>copy <span class="Constant">0/never</span>
<span class="Constant">    &lt;move-cursor-end&gt;</span>
    go-render?<span class="Special"> &lt;- </span>copy <span class="Constant">0/false</span>
    <span class="muControl">return</span>
  <span class="Delimiter">}</span>
]

<span class="muRecipe">def</span> move-to-end-of-line editor:&amp;:editor<span class="muRecipe"> -&gt; </span>editor:&amp;:editor [
  <span class="Constant">local-scope</span>
  <span class="Constant">load-ingredients</span>
  before-cursor:&amp;:duplex-list:char<span class="Special"> &lt;- </span>get *editor, <span class="Constant">before-cursor:offset</span>
  cursor-column:num<span class="Special"> &lt;- </span>get *editor, <span class="Constant">cursor-column:offset</span>
  <span class="Comment"># while not at start of line, move </span>
  <span class="Delimiter">{</span>
    next:&amp;:duplex-list:char<span class="Special"> &lt;- </span>next before-cursor
    <span class="muControl">break-unless</span> next  <span class="Comment"># end of text</span>
    nextc:char<span class="Special"> &lt;- </span>get *next, <span class="Constant">value:offset</span>
    at-end-of-line?:bool<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
    *editor<span class="Special"> &lt;- </span>put *editor, <span class="Constant">before-cursor:offset</span>, before-cursor
    cursor-column<span class="Special"> &lt;- </span>add cursor-column, <span class="Constant">1</span>
    *editor<span class="Special"> &lt;- </span>put *editor, <span class="Constant">cursor-column:offset</span>, cursor-column
    <span class="muControl">loop</span>
  <span class="Delimiter">}</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>:text<span class="Special"> &lt;- </span>new <span class="Constant">[123</span>
<span class="Constant">456]</span>
  <span class="Constant">2</span>:&amp;:editor<span class="Special"> &lt;- </span>new-editor <span class="Constant">1</span>:text, screen:&amp;:screen, <span class="Constant">0/left</span>, <span class="Constant">10/right</span>
  editor-render screen, <span class="Constant">2</span>:&amp;:editor
<span class="Constant">  $clear-trace</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>
    press ctrl-e
  ]
  run [
    editor-event-loop screen:&amp;:screen, console:&amp;:console, <span class="Constant">2</span>:&amp;:editor
    <span class="Constant">4</span>:num<span class="Special"> &lt;- </span>get *<span class="Constant">2</span>:&amp;:editor, <span class="Constant">cursor-row:offset</span>
    <span class="Constant">5</span>:num<span class="Special"> &lt;- </span>get *<span class="Constant">2</span>:&amp;:editor, <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>
  ]
  check-trace-count-for-label <span class="Constant">0</span>, <span class="Constant">[print-character]</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>:text<span class="Special"> &lt;- </span>new <span class="Constant">[123</span>
<span class="Constant">456]</span>
  <span class="Constant">2</span>:&amp;:editor<span class="Special"> &lt;- </span>new-editor <span class="Constant">1</span>:text, screen:&amp;:screen, <span class="Constant">0/left</span>, <span class="Constant">10/right</span>
  editor-render screen, <span class="Constant">2</span>:&amp;:editor
<span class="Constant">  $clear-trace</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 end
  ]
  run [
    editor-event-loop screen:&amp;:screen, console:&amp;:console, <span class="Constant">2</span>:&amp;:editor
    <span class="Constant">3</span>:num<span class="Special"> &lt;- </span>get *<span class="Constant">2</span>:&amp;:editor, <span class="Constant">cursor-row:offset</span>
    <span class="Constant">4</span>:num<span class="Special"> &lt;- </span>get *<span class="Constant">2</span>:&amp;:editor, <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>
  ]
  check-trace-count-for-label <span class="Constant">0</span>, <span class="Constant">[print-character]</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>:text<span class="Special"> &lt;- </span>new <span class="Constant">[123</span>
<span class="Constant">456]</span>
  <span class="Constant">2</span>:&amp;:editor<span class="Special"> &lt;- </span>new-editor <span class="Constant">1</span>:text, screen:&amp;:screen, <span class="Constant">0/left</span>, <span class="Constant">10/right</span>
  editor-render screen, <span class="Constant">2</span>:&amp;:editor
<span class="Constant">  $clear-trace</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 end
  ]
  run [
    editor-event-loop screen:&amp;:screen, console:&amp;:console, <span class="Constant">2</span>:&amp;:editor
    <span class="Constant">3</span>:num<span class="Special"> &lt;- </span>get *<span class="Constant">2</span>:&amp;:editor, <span class="Constant">cursor-row:offset</span>
    <span class="Constant">4</span>:num<span class="Special"> &lt;- </span>get *<span class="Constant">2</span>:&amp;:editor, <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>
  ]
  check-trace-count-for-label <span class="Constant">0</span>, <span class="Constant">[print-character]</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>:text<span class="Special"> &lt;- </span>new <span class="Constant">[123</span>
<span class="Constant">456]</span>
  <span class="Constant">2</span>:&amp;:editor<span class="Special"> &lt;- </span>new-editor <span class="Constant">1</span>:text, screen:&amp;:screen, <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>
    press ctrl-u
  ]
  run [
    editor-event-loop screen:&amp;:screen, console:&amp;:console, <span class="Constant">2</span>:&amp;:editor
  ]
  <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="Constant"> .          .</span>
  ]
]

<span class="muRecipe">after</span> <span class="Constant">&lt;handle-special-character&gt;</span> [
  <span class="Delimiter">{</span>
    delete-to-start-of-line?:bool<span class="Special"> &lt;- </span>equal c, <span class="Constant">21/ctrl-u</span>
    <span class="muControl">break-unless</span> delete-to-start-of-line?
<span class="Constant">    &lt;delete-to-start-of-line-begin&gt;</span>
    deleted-cells:&amp;:duplex-list:char<span class="Special"> &lt;- </span>delete-to-start-of-line editor
<span class="Constant">    &lt;delete-to-start-of-line-end&gt;</span>
    go-render?<span class="Special"> &lt;- </span>copy <span class="Constant">1/true</span>
    <span class="muControl">return</span>
  <span class="Delimiter">}</span>
]

<span class="muRecipe">def</span> delete-to-start-of-line editor:&amp;:editor<span class="muRecipe"> -&gt; </span>result:&amp;:duplex-list:char, editor:&amp;:editor [
  <span class="Constant">local-scope</span>
  <span class="Constant">load-ingredients</span>
  <span class="Comment"># compute range to delete</span>
  init:&amp;:duplex-list:char<span class="Special"> &lt;- </span>get *editor, <span class="Constant">data:offset</span>
  before-cursor:&amp;:duplex-list:char<span class="Special"> &lt;- </span>get *editor, <span class="Constant">before-cursor:offset</span>
  start:&amp;:duplex-list:char<span class="Special"> &lt;- </span>copy before-cursor
  end:&amp;:duplex-list:char<span class="Special"> &lt;- </span>next before-cursor
  <span class="Delimiter">{</span>
    at-start-of-text?:bool<span class="Special"> &lt;- </span>equal start, init
    <span class="muControl">break-if</span> at-start-of-text?
    curr:char<span class="Special"> &lt;- </span>get *start, <span class="Constant">value:offset</span>
    at-start-of-line?:bool<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 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>
  result:&amp;:duplex-list:char<span class="Special"> &lt;- </span>next start
  remove-between start, end
  <span class="Comment"># adjust cursor</span>
  before-cursor<span class="Special"> &lt;- </span>copy start
  *editor<span class="Special"> &lt;- </span>put *editor, <span class="Constant">before-cursor:offset</span>, before-cursor
  left:num<span class="Special"> &lt;- </span>get *editor, <span class="Constant">left:offset</span>
  *editor<span class="Special"> &lt;- </span>put *editor, <span class="Constant">cursor-column:offset</span>, 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>:text<span class="Special"> &lt;- </span>new <span class="Constant">[123</span>
<span class="Constant">456]</span>
  <span class="Constant">2</span>:&amp;:editor<span class="Special"> &lt;- </span>new-editor <span class="Constant">1</span>:text, screen:&amp;:screen, <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>
    press ctrl-u
  ]
  run [
    editor-event-loop screen:&amp;:screen, console:&amp;:console, <span class="Constant">2</span>:&amp;:editor
  ]
  <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="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>:text<span class="Special"> &lt;- </span>new <span class="Constant">[123</span>
<span class="Constant">456]</span>
  <span class="Constant">2</span>:&amp;:editor<span class="Special"> &lt;- </span>new-editor <span class="Constant">1</span>:text, screen:&amp;:screen, <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>
    press ctrl-u
  ]
  run [
    editor-event-loop screen:&amp;:screen, console:&amp;:console, <span class="Constant">2</span>:&amp;:editor
  ]
  <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="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>:text<span class="Special"> &lt;- </span>new <span class="Constant">[123</span>
<span class="Constant">456]</span>
  <span class="Constant">2</span>:&amp;:editor<span class="Special"> &lt;- </span>new-editor <span class="Constant">1</span>:text, screen:&amp;:screen, <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>
    press ctrl-u
  ]
  run [
    editor-event-loop screen:&amp;:screen, console:&amp;:console, <span class="Constant">2</span>:&amp;:editor
  ]
  <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="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>:text<span class="Special"> &lt;- </span>new <span class="Constant">[123</span>
<span class="Constant">456]</span>
  <span class="Constant">2</span>:&amp;:editor<span class="Special"> &lt;- </span>new-editor <span class="Constant">1</span>:text, screen:&amp;:screen, <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>
    press ctrl-k
  ]
  run [
    editor-event-loop screen:&amp;:screen, console:&amp;:console, <span class="Constant">2</span>:&amp;:editor
  ]
  <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="Constant"> .          .</span>
  ]
]

<span class="muRecipe">after</span> <span class="Constant">&lt;handle-special-character&gt;</span> [
  <span class="Delimiter">{</span>
    delete-to-end-of-line?:bool<span class="Special"> &lt;- </span>equal c, <span class="Constant">11/ctrl-k</span>
    <span class="muControl">break-unless</span> delete-to-end-of-line?
<span class="Constant">    &lt;delete-to-end-of-line-begin&gt;</span>
    deleted-cells:&amp;:duplex-list:char<span class="Special"> &lt;- </span>delete-to-end-of-line editor
<span class="Constant">    &lt;delete-to-end-of-line-end&gt;</span>
    go-render?<span class="Special"> &lt;- </span>copy <span class="Constant">1/true</span>
    <span class="muControl">return</span>
  <span class="Delimiter">}</span>
]

<span class="muRecipe">def</span> delete-to-end-of-line editor:&amp;:editor<span class="muRecipe"> -&gt; </span>result:&amp;:duplex-list:char, editor:&amp;:editor [
  <span class="Constant">local-scope</span>
  <span class="Constant">load-ingredients</span>
  <span class="Comment"># compute range to delete</span>
  start:&amp;:duplex-list:char<span class="Special"> &lt;- </span>get *editor, <span class="Constant">before-cursor:offset</span>
  end:&amp;:duplex-list:char<span class="Special"> &lt;- </span>next start
  <span class="Delimiter">{</span>
    at-end-of-text?:bool<span class="Special"> &lt;- </span>equal end, <span class="Constant">0/null</span>
    <span class="muControl">break-if</span> at-end-of-text?
    curr:char<span class="Special"> &lt;- </span>get *end, <span class="Constant">value:offset</span>
    at-end-of-line?:bool<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 end
    <span class="muControl">loop</span>
  <span class="Delimiter">}</span>
  <span class="Comment"># snip it out</span>
  result<span class="Special"> &lt;- </span>next start
  remove-between start, end
]

<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>:text<span class="Special"> &lt;- </span>new <span class="Constant">[123</span>
<span class="Constant">456]</span>
  <span class="Constant">2</span>:&amp;:editor<span class="Special"> &lt;- </span>new-editor <span class="Constant">1</span>:text, screen:&amp;:screen, <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>
    press ctrl-k
  ]
  run [
    editor-event-loop screen:&amp;:screen, console:&amp;:console, <span class="Constant">2</span>:&amp;:editor
  ]
  <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="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>:text<span class="Special"> &lt;- </span>new <span class="Constant">[123</span>
<span class="Constant">456]</span>
  <span class="Constant">2</span>:&amp;:editor<span class="Special"> &lt;- </span>new-editor <span class="Constant">1</span>:text, screen:&amp;:screen, <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>
    press ctrl-k
  ]
  run [
    editor-event-loop screen:&amp;:screen, console:&amp;:console, <span class="Constant">2</span>:&amp;:editor
  ]
  <span class="Comment"># cursor deletes just last character</span>
  screen-should-contain [
   <span class="Constant"> .          .</span>
   <span class="Constant"> .12        .</span>
   <span class="Constant"> .456       .</span>
<span class="Constant">    .┈┈┈┈┈┈┈┈┈┈.</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>:text<span class="Special"> &lt;- </span>new <span class="Constant">[123</span>
<span class="Constant">456]</span>
  <span class="Constant">2</span>:&amp;:editor<span class="Special"> &lt;- </span>new-editor <span class="Constant">1</span>:text, screen:&amp;:screen, <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>
    press ctrl-k
  ]
  run [
    editor-event-loop screen:&amp;:screen, console:&amp;:console, <span class="Constant">2</span>:&amp;:editor
  ]
  <span class="Comment"># cursor deletes nothing</span>
  screen-should-contain [
   <span class="Constant"> .          .</span>
   <span class="Constant"> .123       .</span>
   <span class="Constant"> .456       .</span>
<span class="Constant">    .┈┈┈┈┈┈┈┈┈┈.</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>:text<span class="Special"> &lt;- </span>new <span class="Constant">[123</span>
<span class="Constant">456]</span>
  <span class="Constant">2</span>:&amp;:editor<span class="Special"> &lt;- </span>new-editor <span class="Constant">1</span>:text, screen:&amp;:screen, <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>
    press ctrl-k
  ]
  run [
    editor-event-loop screen:&amp;:screen, console:&amp;:console, <span class="Constant">2</span>:&amp;:editor
  ]
  <span class="Comment"># cursor deletes just the final character</span>
  screen-should-contain [
   <span class="Constant"> .          .</span>
   <span class="Constant"> .123       .</span>
   <span class="Constant"> .45        .</span>
<span class="Constant">    .┈┈┈┈┈┈┈┈┈┈.</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>:text<span class="Special"> &lt;- </span>new <span class="Constant">[123</span>
<span class="Constant">456]</span>
  <span class="Constant">2</span>:&amp;:editor<span class="Special"> &lt;- </span>new-editor <span class="Constant">1</span>:text, screen:&amp;:screen, <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>
    press ctrl-k
  ]
  run [
    editor-event-loop screen:&amp;:screen, console:&amp;:console, <span class="Constant">2</span>:&amp;:editor
  ]
  <span class="Comment"># cursor deletes nothing</span>
  screen-should-contain [
   <span class="Constant"> .          .</span>
   <span class="Constant"> .123       .</span>
   <span class="Constant"> .456       .</span>
<span class="Constant">    .┈┈┈┈┈┈┈┈┈┈.</span>
   <span class="Constant"> .          .</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>:text<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>:&amp;:editor<span class="Special"> &lt;- </span>new-editor <span class="Constant">1</span>:text, screen:&amp;:screen, <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 down-arrow
  ]
  run [
    editor-event-loop screen:&amp;:screen, console:&amp;:console, <span class="Constant">2</span>:&amp;:editor
  ]
  <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> <span class="Constant">&lt;scroll-down&gt;</span> [
  trace <span class="Constant">10</span>, <span class="Constant">[app]</span>, <span class="Constant">[scroll down]</span>
  top-of-screen:&amp;:duplex-list:char<span class="Special"> &lt;- </span>get *editor, <span class="Constant">top-of-screen:offset</span>
  left:num<span class="Special"> &lt;- </span>get *editor, <span class="Constant">left:offset</span>
  right:num<span class="Special"> &lt;- </span>get *editor, <span class="Constant">right:offset</span>
  max:num<span class="Special"> &lt;- </span>subtract right, left
  old-top:&amp;:duplex-list:char<span class="Special"> &lt;- </span>copy top-of-screen
  top-of-screen<span class="Special"> &lt;- </span>before-start-of-next-line top-of-screen, max
  *editor<span class="Special"> &lt;- </span>put *editor, <span class="Constant">top-of-screen:offset</span>, top-of-screen
  no-movement?:bool<span class="Special"> &lt;- </span>equal old-top, top-of-screen
  go-render?<span class="Special"> &lt;- </span>copy <span class="Constant">0/false</span>
  <span class="muControl">return-if</span> no-movement?
]

<span class="Comment"># takes a pointer into the doubly-linked list, scans ahead at most 'max'</span>
<span class="Comment"># positions until the next newline</span>
<span class="Comment"># beware: never return null pointer.</span>
<span class="muRecipe">def</span> before-start-of-next-line original:&amp;:duplex-list:char, max:num<span class="muRecipe"> -&gt; </span>curr:&amp;:duplex-list:char [
  <span class="Constant">local-scope</span>
  <span class="Constant">load-ingredients</span>
  count:num<span class="Special"> &lt;- </span>copy <span class="Constant">0</span>
  curr:&amp;:duplex-list:char<span class="Special"> &lt;- </span>copy original
  <span class="Comment"># skip the initial newline if it exists</span>
  <span class="Delimiter">{</span>
    c:char<span class="Special"> &lt;- </span>get *curr, <span class="Constant">value:offset</span>
    at-newline?:bool<span class="Special"> &lt;- </span>equal c, <span class="Constant">10/newline</span>
    <span class="muControl">break-unless</span> at-newline?
    curr<span class="Special"> &lt;- </span>next curr
    count<span class="Special"> &lt;- </span>add count, <span class="Constant">1</span>
  <span class="Delimiter">}</span>
  <span class="Delimiter">{</span>
    <span class="muControl">return-unless</span> curr, original
    done?:bool<span class="Special"> &lt;- </span>greater-or-equal count, max
    <span class="muControl">break-if</span> done?
    c:char<span class="Special"> &lt;- </span>get *curr, <span class="Constant">value:offset</span>
    at-newline?:bool<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 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">return-unless</span> curr, original
  <span class="muControl">return</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>:text<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>:&amp;:editor<span class="Special"> &lt;- </span>new-editor <span class="Constant">1</span>:text, screen:&amp;:screen, <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 down-arrow
  ]
  run [
    editor-event-loop screen:&amp;:screen, console:&amp;:console, <span class="Constant">2</span>:&amp;:editor
  ]
  <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>:text<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>:&amp;:editor<span class="Special"> &lt;- </span>new-editor <span class="Constant">1</span>:text, screen:&amp;:screen, <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 down-arrow
  ]
  run [
    editor-event-loop screen:&amp;:screen, console:&amp;:console, <span class="Constant">2</span>:&amp;:editor
  ]
  <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 down-arrow
  ]
  run [
    editor-event-loop screen:&amp;:screen, console:&amp;:console, <span class="Constant">2</span>:&amp;:editor
  ]
  <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>:text<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>:&amp;:editor<span class="Special"> &lt;- </span>new-editor <span class="Constant">1</span>:text, screen:&amp;:screen, <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:&amp;:screen, console:&amp;:console, <span class="Constant">2</span>:&amp;:editor
    <span class="Constant">3</span>:num<span class="Special"> &lt;- </span>get *<span class="Constant">2</span>:&amp;:editor, <span class="Constant">cursor-row:offset</span>
    <span class="Constant">4</span>:num<span class="Special"> &lt;- </span>get *<span class="Constant">2</span>:&amp;:editor, <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>:text<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>:&amp;:editor<span class="Special"> &lt;- </span>new-editor <span class="Constant">1</span>:text, screen:&amp;:screen, <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:&amp;:screen, console:&amp;:console, <span class="Constant">2</span>:&amp;:editor
    <span class="Constant">3</span>:num<span class="Special"> &lt;- </span>get *<span class="Constant">2</span>:&amp;:editor, <span class="Constant">cursor-row:offset</span>
    <span class="Constant">4</span>:num<span class="Special"> &lt;- </span>get *<span class="Constant">2</span>:&amp;:editor, <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>:text<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>:&amp;:editor<span class="Special"> &lt;- </span>new-editor <span class="Constant">1</span>:text, screen:&amp;:screen, <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 right-arrow
  ]
  run [
    editor-event-loop screen:&amp;:screen, console:&amp;:console, <span class="Constant">2</span>:&amp;:editor
    <span class="Constant">3</span>:num<span class="Special"> &lt;- </span>get *<span class="Constant">2</span>:&amp;:editor, <span class="Constant">cursor-row:offset</span>
    <span class="Constant">4</span>:num<span class="Special"> &lt;- </span>get *<span class="Constant">2</span>:&amp;:editor, <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>:text<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>:&amp;:editor<span class="Special"> &lt;- </span>new-editor <span class="Constant">1</span>:text, screen:&amp;:screen, <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 right-arrow
  ]
  run [
    editor-event-loop screen:&amp;:screen, console:&amp;:console, <span class="Constant">2</span>:&amp;:editor
    <span class="Constant">3</span>:num<span class="Special"> &lt;- </span>get *<span class="Constant">2</span>:&amp;:editor, <span class="Constant">cursor-row:offset</span>
    <span class="Constant">4</span>:num<span class="Special"> &lt;- </span>get *<span class="Constant">2</span>:&amp;:editor, <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="muScenario">scenario</span> editor-scrolls-at-end-on-down-arrow [
  assume-screen <span class="Constant">10/width</span>, <span class="Constant">5/height</span>
  <span class="Constant">1</span>:text<span class="Special"> &lt;- </span>new <span class="Constant">[abc</span>
<span class="Constant">de]</span>
  <span class="Constant">2</span>:&amp;:editor<span class="Special"> &lt;- </span>new-editor <span class="Constant">1</span>:text, screen:&amp;:screen, <span class="Constant">0/left</span>, <span class="Constant">10/right</span>
  editor-render screen, <span class="Constant">2</span>:&amp;:editor
<span class="Constant">  $clear-trace</span>
  <span class="Comment"># try to move down past end of text</span>
  assume-console [
    left-click <span class="Constant">2</span>, <span class="Constant">0</span>
    press down-arrow
  ]
  run [
    editor-event-loop screen:&amp;:screen, console:&amp;:console, <span class="Constant">2</span>:&amp;:editor
    <span class="Constant">3</span>:num<span class="Special"> &lt;- </span>get *<span class="Constant">2</span>:&amp;:editor, <span class="Constant">cursor-row:offset</span>
    <span class="Constant">4</span>:num<span class="Special"> &lt;- </span>get *<span class="Constant">2</span>:&amp;:editor, <span class="Constant">cursor-column:offset</span>
  ]
  <span class="Comment"># screen should scroll, moving cursor to end of text</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>
  ]
  assume-console [
    type <span class="Constant">[0]</span>
  ]
  run [
    editor-event-loop screen:&amp;:screen, console:&amp;:console, <span class="Constant">2</span>:&amp;:editor
  ]
  screen-should-contain [
   <span class="Constant"> .          .</span>
   <span class="Constant"> .de0       .</span>
<span class="Constant">    .┈┈┈┈┈┈┈┈┈┈.</span>
   <span class="Constant"> .          .</span>
  ]
  <span class="Comment"># try to move down again</span>
<span class="Constant">  $clear-trace</span>
  assume-console [
    left-click <span class="Constant">2</span>, <span class="Constant">0</span>
    press down-arrow
  ]
  run [
    editor-event-loop screen:&amp;:screen, console:&amp;:console, <span class="Constant">2</span>:&amp;:editor
    <span class="Constant">3</span>:num<span class="Special"> &lt;- </span>get *<span class="Constant">2</span>:&amp;:editor, <span class="Constant">cursor-row:offset</span>
    <span class="Constant">4</span>:num<span class="Special"> &lt;- </span>get *<span class="Constant">2</span>:&amp;:editor, <span class="Constant">cursor-column:offset</span>
  ]
  <span class="Comment"># screen stops scrolling because cursor is already at top</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>
  ]
  check-trace-count-for-label <span class="Constant">0</span>, <span class="Constant">[print-character]</span>
  assume-console [
    type <span class="Constant">[1]</span>
  ]
  run [
    editor-event-loop screen:&amp;:screen, console:&amp;:console, <span class="Constant">2</span>:&amp;:editor
  ]
  screen-should-contain [
   <span class="Constant"> .          .</span>
   <span class="Constant"> .de01      .</span>
<span class="Constant">    .┈┈┈┈┈┈┈┈┈┈.</span>
   <span class="Constant"> .          .</span>
  ]
]

<span class="muScenario">scenario</span> editor-combines-page-and-line-scroll [
  <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 few pages of lines</span>
  <span class="Constant">1</span>:text<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">2</span>:&amp;:editor<span class="Special"> &lt;- </span>new-editor <span class="Constant">1</span>:text, screen:&amp;:screen, <span class="Constant">0/left</span>, <span class="Constant">5/right</span>
  <span class="Comment"># scroll down one page and one line</span>
  assume-console [
    press page-down
    left-click <span class="Constant">3</span>, <span class="Constant">0</span>
    press down-arrow
  ]
  run [
    editor-event-loop screen:&amp;:screen, console:&amp;:console, <span class="Constant">2</span>:&amp;:editor
  ]
  <span class="Comment"># screen scrolls down 3 lines</span>
  screen-should-contain [
   <span class="Constant"> .          .</span>
   <span class="Constant"> .d         .</span>
   <span class="Constant"> .e         .</span>
   <span class="Constant"> .f         .</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>:text<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>:&amp;:editor<span class="Special"> &lt;- </span>new-editor <span class="Constant">1</span>:text, screen:&amp;:screen, <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 page-down
    press up-arrow
  ]
  run [
    editor-event-loop screen:&amp;:screen, console:&amp;:console, <span class="Constant">2</span>:&amp;:editor
  ]
  <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> <span class="Constant">&lt;scroll-up&gt;</span> [
  trace <span class="Constant">10</span>, <span class="Constant">[app]</span>, <span class="Constant">[scroll up]</span>
  top-of-screen:&amp;:duplex-list:char<span class="Special"> &lt;- </span>get *editor, <span class="Constant">top-of-screen:offset</span>
  old-top:&amp;:duplex-list:char<span class="Special"> &lt;- </span>copy top-of-screen
  top-of-screen<span class="Special"> &lt;- </span>before-previous-line top-of-screen, editor
  *editor<span class="Special"> &lt;- </span>put *editor, <span class="Constant">top-of-screen:offset</span>, top-of-screen
  no-movement?:bool<span class="Special"> &lt;- </span>equal old-top, top-of-screen
  go-render?<span class="Special"> &lt;- </span>copy <span class="Constant">0/false</span>
  <span class="muControl">return-if</span> no-movement?
]

<span class="Comment"># takes a pointer into the doubly-linked list, scans back to before start of</span>
<span class="Comment"># previous *wrapped* line</span>
<span class="Comment"># beware: never return null pointer</span>
<span class="muRecipe">def</span> before-previous-line in:&amp;:duplex-list:char, editor:&amp;:editor<span class="muRecipe"> -&gt; </span>out:&amp;:duplex-list:char [
  <span class="Constant">local-scope</span>
  <span class="Constant">load-ingredients</span>
  curr:&amp;:duplex-list:char<span class="Special"> &lt;- </span>copy in
  c:char<span class="Special"> &lt;- </span>get *curr, <span class="Constant">value:offset</span>
  <span class="Comment"># compute max, number of characters to skip</span>
  <span class="Comment">#   1 + len%(width-1)</span>
  <span class="Comment">#   except rotate second term to vary from 1 to width-1 rather than 0 to width-2</span>
  left:num<span class="Special"> &lt;- </span>get *editor, <span class="Constant">left:offset</span>
  right:num<span class="Special"> &lt;- </span>get *editor, <span class="Constant">right:offset</span>
  max-line-length:num<span class="Special"> &lt;- </span>subtract right, left, <span class="Constant">-1/exclusive-right</span>, <span class="Constant">1/wrap-icon</span>
  sentinel:&amp;:duplex-list:char<span class="Special"> &lt;- </span>get *editor, <span class="Constant">data:offset</span>
  len:num<span class="Special"> &lt;- </span>previous-line-length curr, sentinel
  <span class="Delimiter">{</span>
    <span class="muControl">break-if</span> len
    <span class="Comment"># empty line; just skip this newline</span>
    prev:&amp;:duplex-list:char<span class="Special"> &lt;- </span>prev curr
    <span class="muControl">return-unless</span> prev, curr
    <span class="muControl">return</span> prev
  <span class="Delimiter">}</span>
  _, max:num<span class="Special"> &lt;- </span>divide-with-remainder len, max-line-length
  <span class="Comment"># remainder 0 =&gt; scan one width-worth</span>
  <span class="Delimiter">{</span>
    <span class="muControl">break-if</span> max
    max<span class="Special"> &lt;- </span>copy max-line-length
  <span class="Delimiter">}</span>
  max<span class="Special"> &lt;- </span>add max, <span class="Constant">1</span>
  count:num<span class="Special"> &lt;- </span>copy <span class="Constant">0</span>
  <span class="Comment"># skip 'max' characters</span>
  <span class="Delimiter">{</span>
    done?:bool<span class="Special"> &lt;- </span>greater-or-equal count, max
    <span class="muControl">break-if</span> done?
    prev:&amp;:duplex-list:char<span class="Special"> &lt;- </span>prev curr
    <span class="muControl">break-unless</span> prev
    curr<span class="Special"> &lt;- </span>copy prev
    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">return</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>:text<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>:&amp;:editor<span class="Special"> &lt;- </span>new-editor <span class="Constant">1</span>:text, screen:&amp;:screen, <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 page-down
  ]
  run [
    editor-event-loop screen:&amp;:screen, console:&amp;:console, <span class="Constant">2</span>:&amp;:editor
  ]
  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 up-arrow
  ]
  run [
    editor-event-loop screen:&amp;:screen, console:&amp;:console, <span class="Constant">2</span>:&amp;:editor
  ]
  <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>:text<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>:&amp;:editor<span class="Special"> &lt;- </span>new-editor <span class="Constant">1</span>:text, screen:&amp;:screen, <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 page-down
  ]
  run [
    editor-event-loop screen:&amp;:screen, console:&amp;:console, <span class="Constant">2</span>:&amp;:editor
  ]
  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 up-arrow
  ]
  run [
    editor-event-loop screen:&amp;:screen, console:&amp;:console, <span class="Constant">2</span>:&amp;:editor
  ]
  <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 up-arrow
  ]
  run [
    editor-event-loop screen:&amp;:screen, console:&amp;:console, <span class="Constant">2</span>:&amp;:editor
  ]
  <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 up-arrow
  ]
  run [
    editor-event-loop screen:&amp;:screen, console:&amp;:console, <span class="Constant">2</span>:&amp;:editor
  ]
  <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="Comment"># same as editor-scrolls-up-past-wrapped-line-using-arrow-keys but length</span>
<span class="Comment"># slightly off, just to prevent over-training</span>
<span class="muScenario">scenario</span> editor-scrolls-up-past-wrapped-line-using-arrow-keys-3 [
  <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>:text<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>:&amp;:editor<span class="Special"> &lt;- </span>new-editor <span class="Constant">1</span>:text, screen:&amp;:screen, <span class="Constant">0/left</span>, <span class="Constant">6/right</span>
  screen-should-contain [
   <span class="Constant"> .          .</span>
   <span class="Constant"> .abcde↩    .</span>
   <span class="Constant"> .f         .</span>
   <span class="Constant"> .g         .</span>
  ]
  <span class="Comment"># position cursor at top of second page, just below wrapped line</span>
  assume-console [
    press page-down
  ]
  run [
    editor-event-loop screen:&amp;:screen, console:&amp;:console, <span class="Constant">2</span>:&amp;:editor
  ]
  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 up-arrow
  ]
  run [
    editor-event-loop screen:&amp;:screen, console:&amp;:console, <span class="Constant">2</span>:&amp;:editor
  ]
  <span class="Comment"># screen shows partial wrapped line</span>
  screen-should-contain [
   <span class="Constant"> .          .</span>
   <span class="Constant"> .f         .</span>
   <span class="Constant"> .g         .</span>
   <span class="Constant"> .h         .</span>
  ]
]

<span class="Comment"># check empty lines</span>
<span class="muScenario">scenario</span> editor-scrolls-up-past-wrapped-line-using-arrow-keys-4 [
  assume-screen <span class="Constant">10/width</span>, <span class="Constant">4/height</span>
  <span class="Comment"># initialize editor with some lines around an empty line</span>
  <span class="Constant">1</span>:text<span class="Special"> &lt;- </span>new <span class="Constant">[a</span>
<span class="Constant">b</span>

c
d
e]
  <span class="Constant">2</span>:&amp;:editor<span class="Special"> &lt;- </span>new-editor <span class="Constant">1</span>:text, screen:&amp;:screen, <span class="Constant">0/left</span>, <span class="Constant">6/right</span>
  assume-console [
    press page-down
  ]
  run [
    editor-event-loop screen:&amp;:screen, console:&amp;:console, <span class="Constant">2</span>:&amp;:editor
  ]
  screen-should-contain [
   <span class="Constant"> .          .</span>
   <span class="Constant"> .          .</span>
   <span class="Constant"> .c         .</span>
   <span class="Constant"> .d         .</span>
  ]
  assume-console [
    press page-down
  ]
  run [
    editor-event-loop screen:&amp;:screen, console:&amp;:console, <span class="Constant">2</span>:&amp;:editor
  ]
  screen-should-contain [
   <span class="Constant"> .          .</span>
   <span class="Constant"> .d         .</span>
   <span class="Constant"> .e         .</span>
   <span class="Constant"> .┈┈┈┈┈┈    .</span>
  ]
  assume-console [
    press page-up
  ]
  run [
    editor-event-loop screen:&amp;:screen, console:&amp;:console, <span class="Constant">2</span>:&amp;:editor
  ]
  screen-should-contain [
   <span class="Constant"> .          .</span>
   <span class="Constant"> .          .</span>
   <span class="Constant"> .c         .</span>
   <span class="Constant"> .d         .</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>:text<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>:&amp;:editor<span class="Special"> &lt;- </span>new-editor <span class="Constant">1</span>:text, screen:&amp;:screen, <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 page-down
  ]
  run [
    editor-event-loop screen:&amp;:screen, console:&amp;:console, <span class="Constant">2</span>:&amp;:editor
  ]
  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 left-arrow
  ]
  run [
    editor-event-loop screen:&amp;:screen, console:&amp;:console, <span class="Constant">2</span>:&amp;:editor
    <span class="Constant">3</span>:num<span class="Special"> &lt;- </span>get *<span class="Constant">2</span>:&amp;:editor, <span class="Constant">cursor-row:offset</span>
    <span class="Constant">4</span>:num<span class="Special"> &lt;- </span>get *<span class="Constant">2</span>:&amp;:editor, <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="muScenario">scenario</span> editor-can-scroll-up-to-start-of-file [
  <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>:text<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>:&amp;:editor<span class="Special"> &lt;- </span>new-editor <span class="Constant">1</span>:text, screen:&amp;:screen, <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 to start of</span>
  <span class="Comment"># text</span>
  assume-console [
    press page-down
    press up-arrow
    press up-arrow
  ]
  run [
    editor-event-loop screen:&amp;:screen, console:&amp;:console, <span class="Constant">2</span>:&amp;:editor
  ]
  <span class="Comment"># screen slides by one line</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"># try to move up again</span>
  assume-console [
    press up-arrow
  ]
  run [
    editor-event-loop screen:&amp;:screen, console:&amp;:console, <span class="Constant">2</span>:&amp;:editor
  ]
  <span class="Comment"># screen remains unchanged</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"># 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>:text<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>:&amp;:editor<span class="Special"> &lt;- </span>new-editor <span class="Constant">1</span>:text, screen:&amp;:screen, <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 page-down
  ]
  run [
    editor-event-loop screen:&amp;:screen, console:&amp;:console, <span class="Constant">2</span>:&amp;:editor
  ]
  <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> <span class="Constant">&lt;handle-special-character&gt;</span> [
  <span class="Delimiter">{</span>
    page-down?:bool<span class="Special"> &lt;- </span>equal c, <span class="Constant">6/ctrl-f</span>
    <span class="muControl">break-unless</span> page-down?
    old-top:&amp;:duplex-list:char<span class="Special"> &lt;- </span>get *editor, <span class="Constant">top-of-screen:offset</span>
<span class="Constant">    &lt;move-cursor-begin&gt;</span>
    page-down editor
    undo-coalesce-tag:num<span class="Special"> &lt;- </span>copy <span class="Constant">0/never</span>
<span class="Constant">    &lt;move-cursor-end&gt;</span>
    top-of-screen:&amp;:duplex-list:char<span class="Special"> &lt;- </span>get *editor, <span class="Constant">top-of-screen:offset</span>
    no-movement?:bool<span class="Special"> &lt;- </span>equal top-of-screen, old-top
    go-render?<span class="Special"> &lt;- </span>not no-movement?
    <span class="muControl">return</span>
  <span class="Delimiter">}</span>
]

<span class="muRecipe">after</span> <span class="Constant">&lt;handle-special-key&gt;</span> [
  <span class="Delimiter">{</span>
    page-down?:bool<span class="Special"> &lt;- </span>equal k, <span class="Constant">65518/page-down</span>
    <span class="muControl">break-unless</span> page-down?
    old-top:&amp;:duplex-list:char<span class="Special"> &lt;- </span>get *editor, <span class="Constant">top-of-screen:offset</span>
<span class="Constant">    &lt;move-cursor-begin&gt;</span>
    page-down editor
    undo-coalesce-tag:num<span class="Special"> &lt;- </span>copy <span class="Constant">0/never</span>
<span class="Constant">    &lt;move-cursor-end&gt;</span>
    top-of-screen:&amp;:duplex-list:char<span class="Special"> &lt;- </span>get *editor, <span class="Constant">top-of-screen:offset</span>
    no-movement?:bool<span class="Special"> &lt;- </span>equal top-of-screen, old-top
    go-render?<span class="Special"> &lt;- </span>not no-movement?
    <span class="muControl">return</span>
  <span class="Delimiter">}</span>
]

<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">def</span> page-down editor:&amp;:editor<span class="muRecipe"> -&gt; </span>editor:&amp;:editor [
  <span class="Constant">local-scope</span>
  <span class="Constant">load-ingredients</span>
  <span class="Comment"># if editor contents don't overflow screen, do nothing</span>
  bottom-of-screen:&amp;:duplex-list:char<span class="Special"> &lt;- </span>get *editor, <span class="Constant">bottom-of-screen:offset</span>
  <span class="muControl">return-unless</span> bottom-of-screen
  <span class="Comment"># if not, position cursor at final character</span>
  before-cursor:&amp;:duplex-list:char<span class="Special"> &lt;- </span>get *editor, <span class="Constant">before-cursor:offset</span>
  before-cursor:&amp;:duplex-list:char<span class="Special"> &lt;- </span>prev bottom-of-screen
  *editor<span class="Special"> &lt;- </span>put *editor, <span class="Constant">before-cursor:offset</span>, before-cursor
  <span class="Comment"># keep one line in common with previous page</span>
  <span class="Delimiter">{</span>
    last:char<span class="Special"> &lt;- </span>get *before-cursor, <span class="Constant">value:offset</span>
    newline?:bool<span class="Special"> &lt;- </span>equal last, <span class="Constant">10/newline</span>
    <span class="muControl">break-unless</span> newline?:bool
    before-cursor<span class="Special"> &lt;- </span>prev before-cursor
    *editor<span class="Special"> &lt;- </span>put *editor, <span class="Constant">before-cursor:offset</span>, before-cursor
  <span class="Delimiter">}</span>
  <span class="Comment"># move cursor and top-of-screen to start of that line</span>
  move-to-start-of-line editor
  before-cursor<span class="Special"> &lt;- </span>get *editor, <span class="Constant">before-cursor:offset</span>
  *editor<span class="Special"> &lt;- </span>put *editor, <span class="Constant">top-of-screen:offset</span>, before-cursor
]

<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>:text<span class="Special"> &lt;- </span>new <span class="Constant">[a</span>
<span class="Constant">b]</span>
  <span class="Constant">2</span>:&amp;:editor<span class="Special"> &lt;- </span>new-editor <span class="Constant">1</span>:text, screen:&amp;:screen, <span class="Constant">0/left</span>, <span class="Constant">10/right</span>
  editor-render screen, <span class="Constant">2</span>:&amp;:editor
  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 page-down
  ]
  run [
    editor-event-loop screen:&amp;:screen, console:&amp;:console, <span class="Constant">2</span>:&amp;:editor
  ]
  <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>:text<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>:&amp;:editor<span class="Special"> &lt;- </span>new-editor <span class="Constant">1</span>:text, screen:&amp;:screen, <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 page-down
  ]
  run [
    editor-event-loop screen:&amp;:screen, console:&amp;:console, <span class="Constant">2</span>:&amp;:editor
  ]
  <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>:text<span class="Special"> &lt;- </span>new <span class="Constant">[a</span>
<span class="Constant">bcdefgh]</span>
  <span class="Constant">2</span>:&amp;:editor<span class="Special"> &lt;- </span>new-editor <span class="Constant">1</span>:text, screen:&amp;:screen, <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 page-down
  ]
  run [
    editor-event-loop screen:&amp;:screen, console:&amp;:console, <span class="Constant">2</span>:&amp;:editor
  ]
  <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>:text<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>:&amp;:editor<span class="Special"> &lt;- </span>new-editor <span class="Constant">1</span>:text, screen:&amp;:screen, <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 page-down
  ]
  run [
    editor-event-loop screen:&amp;:screen, console:&amp;:console, <span class="Constant">2</span>:&amp;:editor
  ]
  <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 page-up
  ]
  run [
    editor-event-loop screen:&amp;:screen, console:&amp;:console, <span class="Constant">2</span>:&amp;:editor
  ]
  <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> <span class="Constant">&lt;handle-special-character&gt;</span> [
  <span class="Delimiter">{</span>
    page-up?:bool<span class="Special"> &lt;- </span>equal c, <span class="Constant">2/ctrl-b</span>
    <span class="muControl">break-unless</span> page-up?
    old-top:&amp;:duplex-list:char<span class="Special"> &lt;- </span>get *editor, <span class="Constant">top-of-screen:offset</span>
<span class="Constant">    &lt;move-cursor-begin&gt;</span>
    editor<span class="Special"> &lt;- </span>page-up editor, screen-height
    undo-coalesce-tag:num<span class="Special"> &lt;- </span>copy <span class="Constant">0/never</span>
<span class="Constant">    &lt;move-cursor-end&gt;</span>
    top-of-screen:&amp;:duplex-list:char<span class="Special"> &lt;- </span>get *editor, <span class="Constant">top-of-screen:offset</span>
    no-movement?:bool<span class="Special"> &lt;- </span>equal top-of-screen, old-top
    go-render?<span class="Special"> &lt;- </span>not no-movement?
    <span class="muControl">return</span>
  <span class="Delimiter">}</span>
]

<span class="muRecipe">after</span> <span class="Constant">&lt;handle-special-key&gt;</span> [
  <span class="Delimiter">{</span>
    page-up?:bool<span class="Special"> &lt;- </span>equal k, <span class="Constant">65519/page-up</span>
    <span class="muControl">break-unless</span> page-up?
    old-top:&amp;:duplex-list:char<span class="Special"> &lt;- </span>get *editor, <span class="Constant">top-of-screen:offset</span>
<span class="Constant">    &lt;move-cursor-begin&gt;</span>
    editor<span class="Special"> &lt;- </span>page-up editor, screen-height
    undo-coalesce-tag:num<span class="Special"> &lt;- </span>copy <span class="Constant">0/never</span>
<span class="Constant">    &lt;move-cursor-end&gt;</span>
    top-of-screen:&amp;:duplex-list:char<span class="Special"> &lt;- </span>get *editor, <span class="Constant">top-of-screen:offset</span>
    no-movement?:bool<span class="Special"> &lt;- </span>equal top-of-screen, old-top
    <span class="Comment"># don't bother re-rendering if nothing changed. todo: test this</span>
    go-render?<span class="Special"> &lt;- </span>not no-movement?
    <span class="muControl">return</span>
  <span class="Delimiter">}</span>
]

<span class="muRecipe">def</span> page-up editor:&amp;:editor, screen-height:num<span class="muRecipe"> -&gt; </span>editor:&amp;:editor [
  <span class="Constant">local-scope</span>
  <span class="Constant">load-ingredients</span>
  max:num<span class="Special"> &lt;- </span>subtract screen-height, <span class="Constant">1/menu-bar</span>, <span class="Constant">1/overlapping-line</span>
  count:num<span class="Special"> &lt;- </span>copy <span class="Constant">0</span>
  top-of-screen:&amp;:duplex-list:char<span class="Special"> &lt;- </span>get *editor, <span class="Constant">top-of-screen:offset</span>
  <span class="Delimiter">{</span>
    done?:bool<span class="Special"> &lt;- </span>greater-or-equal count, max
    <span class="muControl">break-if</span> done?
    prev:&amp;:duplex-list:char<span class="Special"> &lt;- </span>before-previous-line top-of-screen, editor
    <span class="muControl">break-unless</span> prev
    top-of-screen<span class="Special"> &lt;- </span>copy prev
    *editor<span class="Special"> &lt;- </span>put *editor, <span class="Constant">top-of-screen:offset</span>, top-of-screen
    count<span class="Special"> &lt;- </span>add count, <span class="Constant">1</span>
    <span class="muControl">loop</span>
  <span class="Delimiter">}</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>:text<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>:&amp;:editor<span class="Special"> &lt;- </span>new-editor <span class="Constant">1</span>:text, screen:&amp;:screen, <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 page-down
    press page-down
  ]
  run [
    editor-event-loop screen:&amp;:screen, console:&amp;:console, <span class="Constant">2</span>:&amp;:editor
  ]
  <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 page-up
  ]
  run [
    editor-event-loop screen:&amp;:screen, console:&amp;:console, <span class="Constant">2</span>:&amp;:editor
  ]
  <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 page-up
  ]
  run [
    editor-event-loop screen:&amp;:screen, console:&amp;:console, <span class="Constant">2</span>:&amp;:editor
  ]
  <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="muScenario">scenario</span> editor-can-scroll-up-wrapped-lines [
  <span class="Comment"># screen has 1 line for menu + 5 lines for text</span>
  assume-screen <span class="Constant">10/width</span>, <span class="Constant">6/height</span>
  <span class="Comment"># editor contains a long line in the first page</span>
  <span class="Constant">1</span>:text<span class="Special"> &lt;- </span>new <span class="Constant">[a</span>
<span class="Constant">b</span>
<span class="Constant">cdefgh</span>
<span class="Constant">i</span>
<span class="Constant">j</span>
<span class="Constant">k</span>
<span class="Constant">l</span>
<span class="Constant">m</span>
<span class="Constant">n</span>
<span class="Constant">o]</span>
  <span class="Comment"># editor screen triggers wrap of last line</span>
  <span class="Constant">2</span>:&amp;:editor<span class="Special"> &lt;- </span>new-editor <span class="Constant">1</span>:text, screen:&amp;:screen, <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="Constant"> .fgh       .</span>
   <span class="Constant"> .i         .</span>
  ]
  <span class="Comment"># scroll down a page and a line</span>
  assume-console [
    press page-down
    left-click <span class="Constant">5</span>, <span class="Constant">0</span>
    press down-arrow
  ]
  run [
    editor-event-loop screen:&amp;:screen, console:&amp;:console, <span class="Constant">2</span>:&amp;:editor
  ]
  <span class="Comment"># screen shows entire wrapped line</span>
  screen-should-contain [
   <span class="Constant"> .          .</span>
   <span class="Constant"> .j         .</span>
   <span class="Constant"> .k         .</span>
   <span class="Constant"> .l         .</span>
   <span class="Constant"> .m         .</span>
   <span class="Constant"> .n         .</span>
  ]
  <span class="Comment"># now scroll up one page</span>
  assume-console [
    press page-up
  ]
  run [
    editor-event-loop screen:&amp;:screen, console:&amp;:console, <span class="Constant">2</span>:&amp;:editor
  ]
  <span class="Comment"># screen resets</span>
  screen-should-contain [
   <span class="Constant"> .          .</span>
   <span class="Constant"> .b         .</span>
   <span class="Constant"> .cde↩      .</span>
   <span class="Constant"> .fgh       .</span>
   <span class="Constant"> .i         .</span>
   <span class="Constant"> .j         .</span>
  ]
]

<span class="muScenario">scenario</span> editor-can-scroll-up-wrapped-lines-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>:text<span class="Special"> &lt;- </span>new <span class="Constant">[a</span>
<span class="Constant">bcdefgh]</span>
  <span class="Constant">2</span>:&amp;:editor<span class="Special"> &lt;- </span>new-editor <span class="Constant">1</span>:text, screen:&amp;:screen, <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 page-down
  ]
  run [
    editor-event-loop screen:&amp;:screen, console:&amp;:console, <span class="Constant">2</span>:&amp;:editor
  ]
  <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"># scroll back up</span>
  assume-console [
    press page-up
  ]
  run [
    editor-event-loop screen:&amp;:screen, console:&amp;:console, <span class="Constant">2</span>:&amp;:editor
  ]
  <span class="Comment"># screen resets</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="muScenario">scenario</span> editor-can-scroll-up-past-nonempty-lines [
  assume-screen <span class="Constant">10/width</span>, <span class="Constant">4/height</span>
  <span class="Comment"># text with empty line in second screen</span>
  <span class="Constant">1</span>:text<span class="Special"> &lt;- </span>new <span class="Constant">[axx</span>
<span class="Constant">bxx</span>
<span class="Constant">cxx</span>
<span class="Constant">dxx</span>
<span class="Constant">exx</span>
<span class="Constant">fxx</span>
<span class="Constant">gxx</span>
<span class="Constant">hxx</span>
<span class="Constant">]</span>
  <span class="Constant">2</span>:&amp;:editor<span class="Special"> &lt;- </span>new-editor <span class="Constant">1</span>:text, screen:&amp;:screen, <span class="Constant">0/left</span>, <span class="Constant">4/right</span>
  screen-should-contain [
   <span class="Constant"> .          .</span>
   <span class="Constant"> .axx       .</span>
   <span class="Constant"> .bxx       .</span>
   <span class="Constant"> .cxx       .</span>
  ]
  assume-console [
    press page-down
  ]
  run [
    editor-event-loop screen:&amp;:screen, console:&amp;:console, <span class="Constant">2</span>:&amp;:editor
  ]
  screen-should-contain [
   <span class="Constant"> .          .</span>
   <span class="Constant"> .cxx       .</span>
   <span class="Constant"> .dxx       .</span>
   <span class="Constant"> .exx       .</span>
  ]
  assume-console [
    press page-down
  ]
  run [
    editor-event-loop screen:&amp;:screen, console:&amp;:console, <span class="Constant">2</span>:&amp;:editor
  ]
  screen-should-contain [
   <span class="Constant"> .          .</span>
   <span class="Constant"> .exx       .</span>
   <span class="Constant"> .fxx       .</span>
   <span class="Constant"> .gxx       .</span>
  ]
  <span class="Comment"># scroll back up past empty line</span>
  assume-console [
    press page-up
  ]
  run [
    editor-event-loop screen:&amp;:screen, console:&amp;:console, <span class="Constant">2</span>:&amp;:editor
  ]
  screen-should-contain [
   <span class="Constant"> .          .</span>
   <span class="Constant"> .cxx       .</span>
   <span class="Constant"> .dxx       .</span>
   <span class="Constant"> .exx       .</span>
  ]
]

<span class="muScenario">scenario</span> editor-can-scroll-up-past-empty-lines [
  assume-screen <span class="Constant">10/width</span>, <span class="Constant">4/height</span>
  <span class="Comment"># text with empty line in second screen</span>
  <span class="Constant">1</span>:text<span class="Special"> &lt;- </span>new <span class="Constant">[axy</span>
<span class="Constant">bxy</span>
<span class="Constant">cxy</span>

dxy
exy
fxy
gxy
]
  <span class="Constant">2</span>:&amp;:editor<span class="Special"> &lt;- </span>new-editor <span class="Constant">1</span>:text, screen:&amp;:screen, <span class="Constant">0/left</span>, <span class="Constant">4/right</span>
  screen-should-contain [
   <span class="Constant"> .          .</span>
   <span class="Constant"> .axy       .</span>
   <span class="Constant"> .bxy       .</span>
   <span class="Constant"> .cxy       .</span>
  ]
  assume-console [
    press page-down
  ]
  run [
    editor-event-loop screen:&amp;:screen, console:&amp;:console, <span class="Constant">2</span>:&amp;:editor
  ]
  screen-should-contain [
   <span class="Constant"> .          .</span>
   <span class="Constant"> .cxy       .</span>
   <span class="Constant"> .          .</span>
   <span class="Constant"> .dxy       .</span>
  ]
  assume-console [
    press page-down
  ]
  run [
    editor-event-loop screen:&amp;:screen, console:&amp;:console, <span class="Constant">2</span>:&amp;:editor
  ]
  screen-should-contain [
   <span class="Constant"> .          .</span>
   <span class="Constant"> .dxy       .</span>
   <span class="Constant"> .exy       .</span>
   <span class="Constant"> .fxy       .</span>
  ]
  <span class="Comment"># scroll back up past empty line</span>
  assume-console [
    press page-up
  ]
  run [
    editor-event-loop screen:&amp;:screen, console:&amp;:console, <span class="Constant">2</span>:&amp;:editor
  ]
  screen-should-contain [
   <span class="Constant"> .          .</span>
   <span class="Constant"> .cxy       .</span>
   <span class="Constant"> .          .</span>
   <span class="Constant"> .dxy       .</span>
  ]
]
</pre>
</body>
</html>
<!-- vim: set foldmethod=manual : -->