about summary refs log blame commit diff stats
path: root/html/edit/003-shortcuts.mu.html
blob: cc2432811b4991cbdaf780397d0ab8f619d6f00f (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; }
.Delimiter { color: #800080; }
.muControl { color: #c0a020; }
.Special { color: #c00000; }
.Comment { color: #9090ff; }
.Constant { color: #00a0a0; }
.SalientComment { color: #00ffff; }
.muRecipe { color: #ff8700; }
.muScenario { color: #00af00; }
-->
</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 [
  <span class="Constant">local-scope</span>
  assume-screen <span class="Constant">10/width</span>, <span class="Constant">5/height</span>
  <span class="Comment"># just one character in final line</span>
  s:text <span class="Special">&lt;-</span> new <span class="Constant">[ab</span>
<span class="Constant">cd]</span>
  e:&amp;:editor <span class="Special">&lt;-</span> new-editor s, screen, <span class="Constant">0/left</span>, <span class="Constant">5/right</span>
  assume-console [
    press tab
  ]
  run [
    editor-event-loop screen, console, e
  ]
  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 [
  <span class="Constant">local-scope</span>
  assume-screen <span class="Constant">10/width</span>, <span class="Constant">5/height</span>
  e:&amp;:editor <span class="Special">&lt;-</span> new-editor <span class="Constant">[abc]</span>, screen, <span class="Constant">0/left</span>, <span class="Constant">10/right</span>
  editor-render screen, e
<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, console, e
    4:num/<span class="Special">raw</span> <span class="Special">&lt;-</span> get *e, <span class="Constant">cursor-row:offset</span>
    5:num/<span class="Special">raw</span> <span class="Special">&lt;-</span> get *e, <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 [
  <span class="Constant">local-scope</span>
  assume-screen <span class="Constant">10/width</span>, <span class="Constant">5/height</span>
  <span class="Comment"># just one character in final line</span>
  s:text <span class="Special">&lt;-</span> new <span class="Constant">[ab</span>
<span class="Constant">cd]</span>
  e:&amp;:editor <span class="Special">&lt;-</span> new-editor s, 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, console, e
    4:num/<span class="Special">raw</span> <span class="Special">&lt;-</span> get *e, <span class="Constant">cursor-row:offset</span>
    5:num/<span class="Special">raw</span> <span class="Special">&lt;-</span> get *e, <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 [
  <span class="Constant">local-scope</span>
  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>
  s:text <span class="Special">&lt;-</span> new <span class="Constant">[abc def</span>
<span class="Constant">ghi jkl]</span>
  e:&amp;:editor <span class="Special">&lt;-</span> new-editor s, screen, <span class="Constant">0/left</span>, <span class="Constant">10/right</span>
  editor-render screen, e
<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, console, e
  ]
  <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 [
  <span class="Constant">local-scope</span>
  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>
  e:&amp;:editor <span class="Special">&lt;-</span> new-editor <span class="Constant">[abc def ghij]</span>, screen, <span class="Constant">0/left</span>, <span class="Constant">8/right</span>
  editor-render screen, e
  <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, console, e
  ]
  <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 [
  <span class="Constant">local-scope</span>
  assume-screen <span class="Constant">10/width</span>, <span class="Constant">5/height</span>
  e:&amp;:editor <span class="Special">&lt;-</span> new-editor <span class="Constant">[abc]</span>, screen, <span class="Constant">0/left</span>, <span class="Constant">10/right</span>
  editor-render screen, e
<span class="Constant">  $clear-trace</span>
  assume-console [
    press delete
  ]
  run [
    editor-event-loop screen, console, e
  ]
  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, console, e
  ]
  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 [
  <span class="Constant">local-scope</span>
  assume-screen <span class="Constant">10/width</span>, <span class="Constant">5/height</span>
  e:&amp;:editor <span class="Special">&lt;-</span> new-editor <span class="Constant">[abc]</span>, screen, <span class="Constant">0/left</span>, <span class="Constant">10/right</span>
  editor-render screen, e
<span class="Constant">  $clear-trace</span>
  assume-console [
    press right-arrow
    type <span class="Constant">[0]</span>
  ]
  run [
    editor-event-loop screen, console, e
  ]
  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:0, <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 [
  <span class="Constant">local-scope</span>
  assume-screen <span class="Constant">10/width</span>, <span class="Constant">5/height</span>
  s:text <span class="Special">&lt;-</span> new <span class="Constant">[abc</span>
<span class="Constant">d]</span>
  e:&amp;:editor <span class="Special">&lt;-</span> new-editor s, screen, <span class="Constant">0/left</span>, <span class="Constant">10/right</span>
  editor-render screen, e
<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, console, e
  ]
  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, console, e
  ]
  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 [
  <span class="Constant">local-scope</span>
  assume-screen <span class="Constant">10/width</span>, <span class="Constant">5/height</span>
  s:text <span class="Special">&lt;-</span> new <span class="Constant">[abc</span>
<span class="Constant">d]</span>
  e:&amp;:editor <span class="Special">&lt;-</span> new-editor s, screen, <span class="Constant">1/left</span>, <span class="Constant">10/right</span>
  editor-render screen, e
  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, console, e
  ]
  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 [
  <span class="Constant">local-scope</span>
  assume-screen <span class="Constant">10/width</span>, <span class="Constant">5/height</span>
  e:&amp;:editor <span class="Special">&lt;-</span> new-editor <span class="Constant">[abcdef]</span>, screen, <span class="Constant">0/left</span>, <span class="Constant">5/right</span>
  editor-render screen, e
<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, console, e
    3:num/<span class="Special">raw</span> <span class="Special">&lt;-</span> get *e, <span class="Constant">cursor-row:offset</span>
    4:num/<span class="Special">raw</span> <span class="Special">&lt;-</span> get *e, <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 [
  <span class="Constant">local-scope</span>
  assume-screen <span class="Constant">10/width</span>, <span class="Constant">5/height</span>
  <span class="Comment"># line just barely wrapping</span>
  e:&amp;:editor <span class="Special">&lt;-</span> new-editor <span class="Constant">[abcde]</span>, screen, <span class="Constant">0/left</span>, <span class="Constant">5/right</span>
  editor-render screen, e
<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, console, e
    3:num/<span class="Special">raw</span> <span class="Special">&lt;-</span> get *e, <span class="Constant">cursor-row:offset</span>
    4:num/<span class="Special">raw</span> <span class="Special">&lt;-</span> get *e, <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, console, e
    3:num/<span class="Special">raw</span> <span class="Special">&lt;-</span> get *e, <span class="Constant">cursor-row:offset</span>
    4:num/<span class="Special">raw</span> <span class="Special">&lt;-</span> get *e, <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 [
  <span class="Constant">local-scope</span>
  assume-screen <span class="Constant">10/width</span>, <span class="Constant">5/height</span>
  e:&amp;:editor <span class="Special">&lt;-</span> new-editor <span class="Constant">[abcdef]</span>, screen, <span class="Constant">1/left</span>, <span class="Constant">6/right</span>
  editor-render screen, e
<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, console, e
    3:num/<span class="Special">raw</span> <span class="Special">&lt;-</span> get *e, <span class="Constant">cursor-row:offset</span>
    4:num/<span class="Special">raw</span> <span class="Special">&lt;-</span> get *e, <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 [
  <span class="Constant">local-scope</span>
  assume-screen <span class="Constant">10/width</span>, <span class="Constant">5/height</span>
  s:text <span class="Special">&lt;-</span> new <span class="Constant">[abc</span>
<span class="Constant">d]</span>
  e:&amp;:editor <span class="Special">&lt;-</span> new-editor s, screen, <span class="Constant">0/left</span>, <span class="Constant">10/right</span>
  editor-render screen, e
<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, console, e
  ]
  <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 [
  <span class="Constant">local-scope</span>
  assume-screen <span class="Constant">10/width</span>, <span class="Constant">5/height</span>
  e:&amp;:editor <span class="Special">&lt;-</span> new-editor <span class="Constant">[abc]</span>, screen, <span class="Constant">0/left</span>, <span class="Constant">10/right</span>
  editor-render screen, e
<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, console, e
  ]
  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 [
  <span class="Constant">local-scope</span>
  assume-screen <span class="Constant">10/width</span>, <span class="Constant">5/height</span>
  <span class="Comment"># initialize editor with two lines</span>
  s:text <span class="Special">&lt;-</span> new <span class="Constant">[abc</span>
<span class="Constant">d]</span>
  e:&amp;:editor <span class="Special">&lt;-</span> new-editor s, screen, <span class="Constant">0/left</span>, <span class="Constant">10/right</span>
  editor-render screen, e
<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, console, e
    3:num/<span class="Special">raw</span> <span class="Special">&lt;-</span> get *e, <span class="Constant">cursor-row:offset</span>
    4:num/<span class="Special">raw</span> <span class="Special">&lt;-</span> get *e, <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 [
  <span class="Constant">local-scope</span>
  assume-screen <span class="Constant">10/width</span>, <span class="Constant">5/height</span>
  <span class="Comment"># initialize editor with three lines</span>
  s:text <span class="Special">&lt;-</span> new <span class="Constant">[abc</span>
<span class="Constant">def</span>
<span class="Constant">g]</span>
  e:&amp;:editor <span class="Special">&lt;-</span> new-editor s:text, screen, <span class="Constant">0/left</span>, <span class="Constant">10/right</span>
  editor-render screen, e
<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, console, e
  ]
  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 [
  <span class="Constant">local-scope</span>
  assume-screen <span class="Constant">10/width</span>, <span class="Constant">5/height</span>
  s:text <span class="Special">&lt;-</span> new <span class="Constant">[abc</span>
<span class="Constant">def</span>
<span class="Constant">g]</span>
  e:&amp;:editor <span class="Special">&lt;-</span> new-editor s, screen, <span class="Constant">0/left</span>, <span class="Constant">10/right</span>
  editor-render screen, e
<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, console, e
  ]
  <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 [
  <span class="Constant">local-scope</span>
  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>
  s:text <span class="Special">&lt;-</span> new <span class="Constant">[abc</span>

d]
  e:&amp;:editor <span class="Special">&lt;-</span> new-editor s, screen, <span class="Constant">0/left</span>, <span class="Constant">10/right</span>
  editor-render screen, e:&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, console, e
  ]
  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 [
  <span class="Constant">local-scope</span>
  assume-screen <span class="Constant">10/width</span>, <span class="Constant">5/height</span>
  <span class="Comment"># initialize editor with a wrapping line</span>
  e:&amp;:editor <span class="Special">&lt;-</span> new-editor <span class="Constant">[abcdef]</span>, screen, <span class="Constant">0/left</span>, <span class="Constant">5/right</span>
  editor-render screen, e
<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, console, e
    3:num/<span class="Special">raw</span> <span class="Special">&lt;-</span> get *e, <span class="Constant">cursor-row:offset</span>
    4:num/<span class="Special">raw</span> <span class="Special">&lt;-</span> get *e, <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 [
  <span class="Constant">local-scope</span>
  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>
  s:text <span class="Special">&lt;-</span> new <span class="Constant">[abcdef</span>
<span class="Constant">g]</span>
  e:&amp;:editor <span class="Special">&lt;-</span> new-editor s, screen, <span class="Constant">0/left</span>, <span class="Constant">5/right</span>
  editor-render screen, e
<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, console, e
    3:num/<span class="Special">raw</span> <span class="Special">&lt;-</span> get *e, <span class="Constant">cursor-row:offset</span>
    4:num/<span class="Special">raw</span> <span class="Special">&lt;-</span> get *e, <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 [
  <span class="Constant">local-scope</span>
  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>
  s:text <span class="Special">&lt;-</span> new <span class="Constant">[abcd</span>
<span class="Constant">e]</span>
  e:&amp;:editor <span class="Special">&lt;-</span> new-editor s, screen, <span class="Constant">0/left</span>, <span class="Constant">5/right</span>
  editor-render screen, e
<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, console, e
    3:num/<span class="Special">raw</span> <span class="Special">&lt;-</span> get *e, <span class="Constant">cursor-row:offset</span>
    4:num/<span class="Special">raw</span> <span class="Special">&lt;-</span> get *e, <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 [
  <span class="Constant">local-scope</span>
  assume-screen <span class="Constant">10/width</span>, <span class="Constant">5/height</span>
  s:text <span class="Special">&lt;-</span> new <span class="Constant">[abc</span>
<span class="Constant">def]</span>
  e:&amp;:editor <span class="Special">&lt;-</span> new-editor s, screen, <span class="Constant">0/left</span>, <span class="Constant">10/right</span>
  editor-render screen, e
<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, console, e
    3:num/<span class="Special">raw</span> <span class="Special">&lt;-</span> get *e, <span class="Constant">cursor-row:offset</span>
    4:num/<span class="Special">raw</span> <span class="Special">&lt;-</span> get *e, <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, console, e
  ]
  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 [
  <span class="Constant">local-scope</span>
  assume-screen <span class="Constant">10/width</span>, <span class="Constant">5/height</span>
  s:text <span class="Special">&lt;-</span> new <span class="Constant">[ab</span>
<span class="Constant">def]</span>
  e:&amp;:editor <span class="Special">&lt;-</span> new-editor s, screen, <span class="Constant">0/left</span>, <span class="Constant">10/right</span>
  editor-render screen, e
<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, console, e
    3:num/<span class="Special">raw</span> <span class="Special">&lt;-</span> get *e, <span class="Constant">cursor-row:offset</span>
    4:num/<span class="Special">raw</span> <span class="Special">&lt;-</span> get *e, <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, console, e
  ]
  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 [
  <span class="Constant">local-scope</span>
  assume-screen <span class="Constant">10/width</span>, <span class="Constant">5/height</span>
  s:text <span class="Special">&lt;-</span> new [
<span class="muRecipe">def</span>]
  e:&amp;:editor <span class="Special">&lt;-</span> new-editor s, screen, <span class="Constant">0/left</span>, <span class="Constant">10/right</span>
  editor-render screen, e
<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, console, e
    3:num/<span class="Special">raw</span> <span class="Special">&lt;-</span> get *e, <span class="Constant">cursor-row:offset</span>
    4:num/<span class="Special">raw</span> <span class="Special">&lt;-</span> get *e, <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, console, e
  ]
  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 [
  <span class="Constant">local-scope</span>
  assume-screen <span class="Constant">10/width</span>, <span class="Constant">5/height</span>
  <span class="Comment"># start out with three lines</span>
  s:text <span class="Special">&lt;-</span> new <span class="Constant">[abc</span>
<span class="Constant">def</span>
<span class="Constant">ghi]</span>
  e:&amp;:editor <span class="Special">&lt;-</span> new-editor s, screen, <span class="Constant">0/left</span>, <span class="Constant">10/right</span>
  editor-render screen, e
<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, console, e
    3:num/<span class="Special">raw</span> <span class="Special">&lt;-</span> get *e, <span class="Constant">cursor-row:offset</span>
    4:num/<span class="Special">raw</span> <span class="Special">&lt;-</span> get *e, <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, console, e
  ]
  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 [
  <span class="Constant">local-scope</span>
  assume-screen <span class="Constant">10/width</span>, <span class="Constant">5/height</span>
  s:text <span class="Special">&lt;-</span> new <span class="Constant">[abc</span>
<span class="Constant">def]</span>
  e:&amp;:editor <span class="Special">&lt;-</span> new-editor s, screen, <span class="Constant">0/left</span>, <span class="Constant">10/right</span>
  editor-render screen, e
<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, console, e
    3:num/<span class="Special">raw</span> <span class="Special">&lt;-</span> get *e, <span class="Constant">cursor-row:offset</span>
    4:num/<span class="Special">raw</span> <span class="Special">&lt;-</span> get *e, <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, console, e
  ]
  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</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 [
  <span class="Constant">local-scope</span>
  assume-screen <span class="Constant">10/width</span>, <span class="Constant">5/height</span>
  s:text <span class="Special">&lt;-</span> new <span class="Constant">[abc</span>
<span class="Constant">de]</span>
  e:&amp;:editor <span class="Special">&lt;-</span> new-editor s, screen, <span class="Constant">0/left</span>, <span class="Constant">10/right</span>
  editor-render screen, e
<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, console, e
    3:num/<span class="Special">raw</span> <span class="Special">&lt;-</span> get *e, <span class="Constant">cursor-row:offset</span>
    4:num/<span class="Special">raw</span> <span class="Special">&lt;-</span> get *e, <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, console, e
  ]
  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 [
  <span class="Constant">local-scope</span>
  assume-screen <span class="Constant">10/width</span>, <span class="Constant">5/height</span>
  s:text <span class="Special">&lt;-</span> new <span class="Constant">[123</span>
<span class="Constant">456]</span>
  e:&amp;:editor <span class="Special">&lt;-</span> new-editor s, screen, <span class="Constant">0/left</span>, <span class="Constant">10/right</span>
  editor-render screen, e
<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, console, e
    4:num/<span class="Special">raw</span> <span class="Special">&lt;-</span> get *e, <span class="Constant">cursor-row:offset</span>
    5:num/<span class="Special">raw</span> <span class="Special">&lt;-</span> get *e, <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 [
  <span class="Constant">local-scope</span>
  assume-screen <span class="Constant">10/width</span>, <span class="Constant">5/height</span>
  s:text <span class="Special">&lt;-</span> new <span class="Constant">[123</span>
<span class="Constant">456]</span>
  e:&amp;:editor <span class="Special">&lt;-</span> new-editor s, screen, <span class="Constant">0/left</span>, <span class="Constant">10/right</span>
  editor-render screen, e
<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, console, e
    4:num/<span class="Special">raw</span> <span class="Special">&lt;-</span> get *e, <span class="Constant">cursor-row:offset</span>
    5:num/<span class="Special">raw</span> <span class="Special">&lt;-</span> get *e, <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 [
  <span class="Constant">local-scope</span>
  assume-screen <span class="Constant">10/width</span>, <span class="Constant">5/height</span>
  s:text <span class="Special">&lt;-</span> new <span class="Constant">[123</span>
<span class="Constant">456]</span>
  e:&amp;:editor <span class="Special">&lt;-</span> new-editor s, 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, console, e
    3:num/<span class="Special">raw</span> <span class="Special">&lt;-</span> get *e, <span class="Constant">cursor-row:offset</span>
    4:num/<span class="Special">raw</span> <span class="Special">&lt;-</span> get *e, <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 [
  <span class="Constant">local-scope</span>
  assume-screen <span class="Constant">10/width</span>, <span class="Constant">5/height</span>
  s:text <span class="Special">&lt;-</span> new <span class="Constant">[123</span>
<span class="Constant">456]</span>
  e:&amp;:editor <span class="Special">&lt;-</span> new-editor s, screen, <span class="Constant">0/left</span>, <span class="Constant">10/right</span>
  editor-render screen, e
<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, console, e
    3:num/<span class="Special">raw</span> <span class="Special">&lt;-</span> get *e, <span class="Constant">cursor-row:offset</span>
    4:num/<span class="Special">raw</span> <span class="Special">&lt;-</span> get *e, <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 [
  <span class="Constant">local-scope</span>
  assume-screen <span class="Constant">10/width</span>, <span class="Constant">5/height</span>
  s:text <span class="Special">&lt;-</span> new <span class="Constant">[123</span>
<span class="Constant">456]</span>
  e:&amp;:editor <span class="Special">&lt;-</span> new-editor s, screen, <span class="Constant">0/left</span>, <span class="Constant">10/right</span>
  editor-render screen, e
<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, console, e
    4:num/<span class="Special">raw</span> <span class="Special">&lt;-</span> get *e, <span class="Constant">cursor-row:offset</span>
    5:num/<span class="Special">raw</span> <span class="Special">&lt;-</span> get *e, <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, console, e
    4:num/<span class="Special">raw</span> <span class="Special">&lt;-</span> get *e, <span class="Constant">cursor-row:offset</span>
    5:num/<span class="Special">raw</span> <span class="Special">&lt;-</span> get *e, <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 [
  <span class="Constant">local-scope</span>
  assume-screen <span class="Constant">10/width</span>, <span class="Constant">5/height</span>
  s:text <span class="Special">&lt;-</span> new <span class="Constant">[123</span>
<span class="Constant">456]</span>
  e:&amp;:editor <span class="Special">&lt;-</span> new-editor s, screen, <span class="Constant">0/left</span>, <span class="Constant">10/right</span>
  editor-render screen, e
<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, console, e
    4:num/<span class="Special">raw</span> <span class="Special">&lt;-</span> get *e, <span class="Constant">cursor-row:offset</span>
    5:num/<span class="Special">raw</span> <span class="Special">&lt;-</span> get *e, <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 [
  <span class="Constant">local-scope</span>
  assume-screen <span class="Constant">10/width</span>, <span class="Constant">5/height</span>
  s:text <span class="Special">&lt;-</span> new <span class="Constant">[123</span>
<span class="Constant">456]</span>
  e:&amp;:editor <span class="Special">&lt;-</span> new-editor s, screen, <span class="Constant">0/left</span>, <span class="Constant">10/right</span>
  editor-render screen, e
<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, console, e
    3:num/<span class="Special">raw</span> <span class="Special">&lt;-</span> get *e, <span class="Constant">cursor-row:offset</span>
    4:num/<span class="Special">raw</span> <span class="Special">&lt;-</span> get *e, <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 [
  <span class="Constant">local-scope</span>
  assume-screen <span class="Constant">10/width</span>, <span class="Constant">5/height</span>
  s:text <span class="Special">&lt;-</span> new <span class="Constant">[123</span>
<span class="Constant">456]</span>
  e:&amp;:editor <span class="Special">&lt;-</span> new-editor s, screen, <span class="Constant">0/left</span>, <span class="Constant">10/right</span>
  editor-render screen, e
<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, console, e
    3:num/<span class="Special">raw</span> <span class="Special">&lt;-</span> get *e, <span class="Constant">cursor-row:offset</span>
    4:num/<span class="Special">raw</span> <span class="Special">&lt;-</span> get *e, <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 [
  <span class="Constant">local-scope</span>
  assume-screen <span class="Constant">10/width</span>, <span class="Constant">5/height</span>
  s:text <span class="Special">&lt;-</span> new <span class="Constant">[123</span>
<span class="Constant">456]</span>
  e:&amp;:editor <span class="Special">&lt;-</span> new-editor s, 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, console, e
  ]
  <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 [
  <span class="Constant">local-scope</span>
  assume-screen <span class="Constant">10/width</span>, <span class="Constant">5/height</span>
  s:text <span class="Special">&lt;-</span> new <span class="Constant">[123</span>
<span class="Constant">456]</span>
  e:&amp;:editor <span class="Special">&lt;-</span> new-editor s, 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, console, e
  ]
  <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 [
  <span class="Constant">local-scope</span>
  assume-screen <span class="Constant">10/width</span>, <span class="Constant">5/height</span>
  s:text <span class="Special">&lt;-</span> new <span class="Constant">[123</span>
<span class="Constant">456]</span>
  e:&amp;:editor <span class="Special">&lt;-</span> new-editor s, 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, console, e
  ]
  <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 [
  <span class="Constant">local-scope</span>
  assume-screen <span class="Constant">10/width</span>, <span class="Constant">5/height</span>
  s:text <span class="Special">&lt;-</span> new <span class="Constant">[123</span>
<span class="Constant">456]</span>
  e:&amp;:editor <span class="Special">&lt;-</span> new-editor s, 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, console, e
  ]
  <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 [
  <span class="Constant">local-scope</span>
  assume-screen <span class="Constant">10/width</span>, <span class="Constant">5/height</span>
  s:text <span class="Special">&lt;-</span> new <span class="Constant">[123</span>
<span class="Constant">456]</span>
  e:&amp;:editor <span class="Special">&lt;-</span> new-editor s, 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, console, e
  ]
  <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 [
  <span class="Constant">local-scope</span>
  assume-screen <span class="Constant">10/width</span>, <span class="Constant">5/height</span>
  s:text <span class="Special">&lt;-</span> new <span class="Constant">[123</span>
<span class="Constant">456]</span>
  e:&amp;:editor <span class="Special">&lt;-</span> new-editor s, 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, console, e
  ]
  <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 [
  <span class="Constant">local-scope</span>
  assume-screen <span class="Constant">10/width</span>, <span class="Constant">5/height</span>
  s:text <span class="Special">&lt;-</span> new <span class="Constant">[123</span>
<span class="Constant">456]</span>
  e:&amp;:editor <span class="Special">&lt;-</span> new-editor s, 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, console, e
  ]
  <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 [
  <span class="Constant">local-scope</span>
  assume-screen <span class="Constant">10/width</span>, <span class="Constant">5/height</span>
  s:text <span class="Special">&lt;-</span> new <span class="Constant">[123</span>
<span class="Constant">456]</span>
  e:&amp;:editor <span class="Special">&lt;-</span> new-editor s, 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, console, e
  ]
  <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 [
  <span class="Constant">local-scope</span>
  assume-screen <span class="Constant">10/width</span>, <span class="Constant">5/height</span>
  s:text <span class="Special">&lt;-</span> new <span class="Constant">[123</span>
<span class="Constant">456]</span>
  e:&amp;:editor <span class="Special">&lt;-</span> new-editor s, 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, console, e
  ]
  <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 [
  <span class="Constant">local-scope</span>
  assume-screen <span class="Constant">10/width</span>, <span class="Constant">5/height</span>
  s:text <span class="Special">&lt;-</span> new <span class="Constant">[123</span>
<span class="Constant">456]</span>
  e:&amp;:editor <span class="Special">&lt;-</span> new-editor s, 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, console, e
  ]
  <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="Constant">local-scope</span>
  <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>
  s: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>
  e:&amp;:editor <span class="Special">&lt;-</span> new-editor s, 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, console, e
  ]
  <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="Constant">local-scope</span>
  <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>
  s: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>
  e:&amp;:editor <span class="Special">&lt;-</span> new-editor s, 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, console, e
  ]
  <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="Constant">local-scope</span>
  <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>
  s: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>
  e:&amp;:editor <span class="Special">&lt;-</span> new-editor s, 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, console, e
  ]
  <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, console, e
  ]
  <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="Constant">local-scope</span>
  <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>
  s:text <span class="Special">&lt;-</span> new <span class="Constant">[a</span>
<span class="Constant">b</span>
<span class="Constant">cdef]</span>
  e:&amp;:editor <span class="Special">&lt;-</span> new-editor s, 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, console, e
    3:num/<span class="Special">raw</span> <span class="Special">&lt;-</span> get *e, <span class="Constant">cursor-row:offset</span>
    4:num/<span class="Special">raw</span> <span class="Special">&lt;-</span> get *e, <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 [
  <span class="Constant">local-scope</span>
  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>
  s:text <span class="Special">&lt;-</span> new <span class="Constant">[a</span>
<span class="Constant">b</span>
<span class="Constant">c]</span>
  e:&amp;:editor <span class="Special">&lt;-</span> new-editor s, 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, console, e
    3:num/<span class="Special">raw</span> <span class="Special">&lt;-</span> get *e, <span class="Constant">cursor-row:offset</span>
    4:num/<span class="Special">raw</span> <span class="Special">&lt;-</span> get *e, <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="Constant">local-scope</span>
  <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>
  s:text <span class="Special">&lt;-</span> new <span class="Constant">[a</span>
<span class="Constant">b</span>
<span class="Constant">cdefgh]</span>
  e:&amp;:editor <span class="Special">&lt;-</span> new-editor s, 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, console, e
    3:num/<span class="Special">raw</span> <span class="Special">&lt;-</span> get *e, <span class="Constant">cursor-row:offset</span>
    4:num/<span class="Special">raw</span> <span class="Special">&lt;-</span> get *e, <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="Constant">local-scope</span>
  <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>
  s: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>
  e:&amp;:editor <span class="Special">&lt;-</span> new-editor s, 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, console, e
    3:num/<span class="Special">raw</span> <span class="Special">&lt;-</span> get *e, <span class="Constant">cursor-row:offset</span>
    4:num/<span class="Special">raw</span> <span class="Special">&lt;-</span> get *e, <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 [
  <span class="Constant">local-scope</span>
  assume-screen <span class="Constant">10/width</span>, <span class="Constant">5/height</span>
  s:text <span class="Special">&lt;-</span> new <span class="Constant">[abc</span>
<span class="Constant">de]</span>
  e:&amp;:editor <span class="Special">&lt;-</span> new-editor s, screen, <span class="Constant">0/left</span>, <span class="Constant">10/right</span>
  editor-render screen, e
<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, console, e
    3:num/<span class="Special">raw</span> <span class="Special">&lt;-</span> get *e, <span class="Constant">cursor-row:offset</span>
    4:num/<span class="Special">raw</span> <span class="Special">&lt;-</span> get *e, <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, console, e
  ]
  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, console, e
    3:num/<span class="Special">raw</span> <span class="Special">&lt;-</span> get *e, <span class="Constant">cursor-row:offset</span>
    4:num/<span class="Special">raw</span> <span class="Special">&lt;-</span> get *e, <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, console, e
  ]
  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="Constant">local-scope</span>
  <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>
  s: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>
  e:&amp;:editor <span class="Special">&lt;-</span> new-editor s, 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, console, e
  ]
  <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="Constant">local-scope</span>
  <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>
  s: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>
  e:&amp;:editor <span class="Special">&lt;-</span> new-editor s, 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, console, e
  ]
  <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="Constant">local-scope</span>
  <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>
  s: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>
  e:&amp;:editor <span class="Special">&lt;-</span> new-editor s, 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, console, e
  ]
  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, console, e
  ]
  <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="Constant">local-scope</span>
  <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>
  s: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>
  e:&amp;:editor <span class="Special">&lt;-</span> new-editor s, 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, console, e
  ]
  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, console, e
  ]
  <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, console, e
  ]
  <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, console, e
  ]
  <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="Constant">local-scope</span>
  <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>
  s: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>
  e:&amp;:editor <span class="Special">&lt;-</span> new-editor s, 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, console, e
  ]
  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, console, e
  ]
  <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 [
  <span class="Constant">local-scope</span>
  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>
  s:text <span class="Special">&lt;-</span> new <span class="Constant">[a</span>
<span class="Constant">b</span>

c
d
e]
  e:&amp;:editor <span class="Special">&lt;-</span> new-editor s, screen, <span class="Constant">0/left</span>, <span class="Constant">6/right</span>
  assume-console [
    press page-down
  ]
  run [
    editor-event-loop screen, console, e
  ]
  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, console, e
  ]
  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, console, e
  ]
  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="Constant">local-scope</span>
  <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>
  s: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>
  e:&amp;:editor <span class="Special">&lt;-</span> new-editor s, 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, console, e
  ]
  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, console, e
    3:num/<span class="Special">raw</span> <span class="Special">&lt;-</span> get *e, <span class="Constant">cursor-row:offset</span>
    4:num/<span class="Special">raw</span> <span class="Special">&lt;-</span> get *e, <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="Constant">local-scope</span>
  <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>
  s: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>
  e:&amp;:editor <span class="Special">&lt;-</span> new-editor s, 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, console, e
  ]
  <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, console, e
  ]
  <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 [
  <span class="Constant">local-scope</span>
  assume-screen <span class="Constant">10/width</span>, <span class="Constant">4/height</span>
  s: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>
  e:&amp;:editor <span class="Special">&lt;-</span> new-editor s, 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, console, e
  ]
  <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 [
  <span class="Constant">local-scope</span>
  assume-screen <span class="Constant">10/width</span>, <span class="Constant">4/height</span>
  s:text <span class="Special">&lt;-</span> new <span class="Constant">[a</span>
<span class="Constant">b]</span>
  e:&amp;:editor <span class="Special">&lt;-</span> new-editor s, screen, <span class="Constant">0/left</span>, <span class="Constant">10/right</span>
  editor-render screen, e
  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, console, e
  ]
  <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="Constant">local-scope</span>
  <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>
  s: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>
  e:&amp;:editor <span class="Special">&lt;-</span> new-editor s, 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, console, e
  ]
  <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="Constant">local-scope</span>
  <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>
  s:text <span class="Special">&lt;-</span> new <span class="Constant">[a</span>
<span class="Constant">bcdefgh]</span>
  e:&amp;:editor <span class="Special">&lt;-</span> new-editor s, 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, console, e
  ]
  <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 [
  <span class="Constant">local-scope</span>
  assume-screen <span class="Constant">10/width</span>, <span class="Constant">4/height</span>
  s: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>
  e:&amp;:editor <span class="Special">&lt;-</span> new-editor s, 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, console, e
  ]
  <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, console, e
  ]
  <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="Constant">local-scope</span>
  <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>
  s: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>
  e:&amp;:editor <span class="Special">&lt;-</span> new-editor s, 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, console, e
  ]
  <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, console, e
  ]
  <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, console, e
  ]
  <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="Constant">local-scope</span>
  <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>
  s: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>
  e:&amp;:editor <span class="Special">&lt;-</span> new-editor s, 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, console, e
  ]
  <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, console, e
  ]
  <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="Constant">local-scope</span>
  <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>
  s:text <span class="Special">&lt;-</span> new <span class="Constant">[a</span>
<span class="Constant">bcdefgh]</span>
  e:&amp;:editor <span class="Special">&lt;-</span> new-editor s, 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, console, e
  ]
  <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, console, e
  ]
  <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 [
  <span class="Constant">local-scope</span>
  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>
  s: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>
  e:&amp;:editor <span class="Special">&lt;-</span> new-editor s, 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, console, e
  ]
  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, console, e
  ]
  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, console, e
  ]
  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 [
  <span class="Constant">local-scope</span>
  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>
  s: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
]
  e:&amp;:editor <span class="Special">&lt;-</span> new-editor s, 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, console, e
  ]
  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, console, e
  ]
  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, console, e
  ]
  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 : -->