summary refs log blame commit diff stats
path: root/doc/pydoc/ranger.gui.widgets.taskview.html
blob: 28c63c4e1c59a6736813ee344eebbfc92c73cb94 (plain) (tree)
1
2
3
4
5
6
7
8
9
10
 

                                                                     






                                                                                                                                                                                                                                                                                                                          
                                                                                                                                                                                                                   
















                                                                                                                                                         
                                                                                                                                                                                    




























                                                                                                                                                                                                                                                                                       
                                                                 






                                                                                      

                                                                                 













                                                                                                                                  

                                                                                                                                 















                                                                                                                                                                                                                        

























                                                                                                                                                                                                              
                                                                                                                                                           
 
                                                                                                                                                                                              




                                                                                                                                                                              
                                           






                                                                                                                         
                                                                                                                                                                                                                                               








                                                                                                                                    
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<html><head><title>Python: module ranger.gui.widgets.taskview</title>
</head><body bgcolor="#f0f0f8">

<table width="100%" cellspacing=0 cellpadding=2 border=0 summary="heading">
<tr bgcolor="#7799ee">
<td valign=bottom>&nbsp;<br>
<font color="#ffffff" face="helvetica, arial">&nbsp;<br><big><big><strong><a href="ranger.html"><font color="#ffffff">ranger</font></a>.<a href="ranger.gui.html"><font color="#ffffff">gui</font></a>.<a href="ranger.gui.widgets.html"><font color="#ffffff">widgets</font></a>.taskview</strong></big></big></font></td
><td align=right valign=bottom
><font color="#ffffff" face="helvetica, arial"><a href=".">index</a><br><a href="file:/home/hut/ranger/ranger/gui/widgets/taskview.py">/home/hut/ranger/ranger/gui/widgets/taskview.py</a></font></td></tr></table>
    <p><tt>The&nbsp;<a href="#TaskView">TaskView</a>&nbsp;allows&nbsp;you&nbsp;to&nbsp;modify&nbsp;what&nbsp;the&nbsp;loader&nbsp;is&nbsp;doing.</tt></p>
<p>
<table width="100%" cellspacing=0 cellpadding=2 border=0 summary="section">
<tr bgcolor="#aa55cc">
<td colspan=3 valign=bottom>&nbsp;<br>
<font color="#ffffff" face="helvetica, arial"><big><strong>Modules</strong></big></font></td></tr>
    
<tr><td bgcolor="#aa55cc"><tt>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</tt></td><td>&nbsp;</td>
<td width="100%"><table width="100%" summary="list"><tr><td width="25%" valign=top><a href="curses.html">curses</a><br>
</td><td width="25%" valign=top></td><td width="25%" valign=top></td><td width="25%" valign=top></td></tr></table>
<!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/002-typing.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; }
.muRecipe { color: #ff8700; }
.muData { color: #ffff00; }
.Special { color: #c00000; }
.muScenario { color: #00af00; }
.Delimiter { color: #800080; }
.Comment { color: #9090ff; }
.Constant { color: #00a0a0; }
.SalientComment { color: #00ffff; }
.muControl { color: #c0a020; }
-->
</style>

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

-->
</script>
</head>
<body>
<pre id='vimCodeElement'>
<span class="SalientComment">## handling events from the keyboard, mouse, touch screen, ...</span>

<span class="Comment"># temporary main: interactive editor</span>
<span class="Comment"># hit ctrl-c to exit</span>
<span class="muRecipe">def!</span> main text:text [
  <span class="Constant">local-scope</span>
  <span class="Constant">load-ingredients</span>
  open-console
  editor:&amp;:editor<span class="Special"> &lt;- </span>new-editor text, <span class="Constant">0/screen</span>, <span class="Constant">5/left</span>, <span class="Constant">45/right</span>
  editor-event-loop <span class="Constant">0/screen</span>, <span class="Constant">0/console</span>, editor
  close-console
]

<span class="muRecipe">def</span> editor-event-loop screen:&amp;:screen, console:&amp;:console, editor:&amp;:editor<span class="muRecipe"> -&gt; </span>screen:&amp;:screen, console:&amp;:console, editor:&amp;:editor [
  <span class="Constant">local-scope</span>
  <span class="Constant">load-ingredients</span>
  <span class="Delimiter">{</span>
    <span class="Comment"># looping over each (keyboard or touch) event as it occurs</span>
<span class="Constant">    +next-event</span>
    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
    e:event, console:&amp;:console, found?:bool, quit?:bool<span class="Special"> &lt;- </span>read-event console
    <span class="muControl">loop-unless</span> found?
    <span class="muControl">break-if</span> quit?  <span class="Comment"># only in tests</span>
    trace <span class="Constant">10</span>, <span class="Constant">[app]</span>, <span class="Constant">[next-event]</span>
    <span class="Comment"># 'touch' event</span>
    t:touch-event, is-touch?:bool<span class="Special"> &lt;- </span>maybe-convert e, <span class="Constant">touch:variant</span>
    <span class="Delimiter">{</span>
      <span class="muControl">break-unless</span> is-touch?
      move-cursor-in-editor screen, editor, t
      <span class="muControl">loop</span> <span class="Constant">+next-event:label</span>
    <span class="Delimiter">}</span>
    <span class="Comment"># keyboard events</span>
    <span class="Delimiter">{</span>
      <span class="muControl">break-if</span> is-touch?
      screen, editor, go-render?:bool<span class="Special"> &lt;- </span>handle-keyboard-event screen, editor, e
      <span class="Delimiter">{</span>
        <span class="muControl">break-unless</span> go-render?
        screen<span class="Special"> &lt;- </span>editor-render screen, editor
      <span class="Delimiter">}</span>
    <span class="Delimiter">}</span>
    <span class="muControl">loop</span>
  <span class="Delimiter">}</span>
]

<span class="Comment"># process click, return if it was on current editor</span>
<span class="muRecipe">def</span> move-cursor-in-editor screen:&amp;:screen, editor:&amp;:editor, t:touch-event<span class="muRecipe"> -&gt; </span>in-focus?:bool, editor:&amp;:editor [
  <span class="Constant">local-scope</span>
  <span class="Constant">load-ingredients</span>
  <span class="muControl">return-unless</span> editor, <span class="Constant">0/false</span>
  click-row:num<span class="Special"> &lt;- </span>get t, <span class="Constant">row:offset</span>
  <span class="muControl">return-unless</span> click-row, <span class="Constant">0/false</span>  <span class="Comment"># ignore clicks on 'menu'</span>
  click-column:num<span class="Special"> &lt;- </span>get t, <span class="Constant">column:offset</span>
  left:num<span class="Special"> &lt;- </span>get *editor, <span class="Constant">left:offset</span>
  too-far-left?:bool<span class="Special"> &lt;- </span>lesser-than click-column, left
  <span class="muControl">return-if</span> too-far-left?, <span class="Constant">0/false</span>
  right:num<span class="Special"> &lt;- </span>get *editor, <span class="Constant">right:offset</span>
  too-far-right?:bool<span class="Special"> &lt;- </span>greater-than click-column, right
  <span class="muControl">return-if</span> too-far-right?, <span class="Constant">0/false</span>
  <span class="Comment"># position cursor</span>
<span class="Constant">  &lt;move-cursor-begin&gt;</span>
  editor<span class="Special"> &lt;- </span>snap-cursor screen, editor, click-row, click-column
  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>
  <span class="Comment"># gain focus</span>
  <span class="muControl">return</span> <span class="Constant">1/true</span>
]

<span class="Comment"># Variant of 'render' that only moves the cursor (coordinates and</span>
<span class="Comment"># before-cursor). If it's past the end of a line, it 'slides' it left. If it's</span>
<span class="Comment"># past the last line it positions at end of last line.</span>
<span class="muRecipe">def</span> snap-cursor screen:&amp;:screen, editor:&amp;:editor, target-row:num, target-column:num<span class="muRecipe"> -&gt; </span>editor:&amp;:editor [
  <span class="Constant">local-scope</span>
  <span class="Constant">load-ingredients</span>
  <span class="muControl">return-unless</span> editor
  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>
  screen-height:num<span class="Special"> &lt;- </span>screen-height screen
  <span class="Comment"># count newlines until screen row</span>
  curr:&amp;:duplex-list:char<span class="Special"> &lt;- </span>get *editor, <span class="Constant">top-of-screen:offset</span>
  prev:&amp;:duplex-list:char<span class="Special"> &lt;- </span>copy curr  <span class="Comment"># just in case curr becomes null and we can't compute prev</span>
  curr<span class="Special"> &lt;- </span>next curr
  row:num<span class="Special"> &lt;- </span>copy <span class="Constant">1/top</span>
  column:num<span class="Special"> &lt;- </span>copy left
  *editor<span class="Special"> &lt;- </span>put *editor, <span class="Constant">cursor-row:offset</span>, target-row
  cursor-row:num<span class="Special"> &lt;- </span>copy target-row
  *editor<span class="Special"> &lt;- </span>put *editor, <span class="Constant">cursor-column:offset</span>, target-column
  cursor-column:num<span class="Special"> &lt;- </span>copy target-column
  before-cursor:&amp;:duplex-list:char<span class="Special"> &lt;- </span>get *editor, <span class="Constant">before-cursor:offset</span>
  <span class="Delimiter">{</span>
<span class="Constant">    +next-character</span>
    <span class="muControl">break-unless</span> curr
    off-screen?:bool<span class="Special"> &lt;- </span>greater-or-equal row, screen-height
    <span class="muControl">break-if</span> off-screen?
    <span class="Comment"># update editor.before-cursor</span>
    <span class="Comment"># Doing so at the start of each iteration ensures it stays one step behind</span>
    <span class="Comment"># the current character.</span>
    <span class="Delimiter">{</span>
      at-cursor-row?:bool<span class="Special"> &lt;- </span
gt; at-cursor-row? at-cursor?:bool<span class="Special"> &lt;- </span>equal column, cursor-column <span class="muControl">break-unless</span> at-cursor? 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 <span class="Delimiter">}</span> c:char<span class="Special"> &lt;- </span>get *curr, <span class="Constant">value:offset</span> <span class="Delimiter">{</span> <span class="Comment"># newline? move to left rather than 0</span> newline?:bool<span class="Special"> &lt;- </span>equal c, <span class="Constant">10/newline</span> <span class="muControl">break-unless</span> newline? <span class="Comment"># adjust cursor if necessary</span> <span class="Delimiter">{</span> at-cursor-row?:bool<span class="Special"> &lt;- </span>equal row, cursor-row <span class="muControl">break-unless</span> at-cursor-row? left-of-cursor?:bool<span class="Special"> &lt;- </span>lesser-than column, cursor-column <span class="muControl">break-unless</span> left-of-cursor? cursor-column<span class="Special"> &lt;- </span>copy column *editor<span class="Special"> &lt;- </span>put *editor, <span class="Constant">cursor-column:offset</span>, cursor-column 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 <span class="Delimiter">}</span> <span class="Comment"># skip to next line</span> row<span class="Special"> &lt;- </span>add row, <span class="Constant">1</span> column<span class="Special"> &lt;- </span>copy left curr<span class="Special"> &lt;- </span>next curr prev<span class="Special"> &lt;- </span>next prev <span class="muControl">loop</span> <span class="Constant">+next-character:label</span> <span class="Delimiter">}</span> <span class="Delimiter">{</span> <span class="Comment"># at right? wrap. even if there's only one more letter left; we need</span> <span class="Comment"># room for clicking on the cursor after it.</span> at-right?:bool<span class="Special"> &lt;- </span>equal column, right <span class="muControl">break-unless</span> at-right? column<span class="Special"> &lt;- </span>copy left row<span class="Special"> &lt;- </span>add row, <span class="Constant">1</span> <span class="Comment"># don't increment curr/prev</span> <span class="muControl">loop</span> <span class="Constant">+next-character:label</span> <span class="Delimiter">}</span> curr<span class="Special"> &lt;- </span>next curr prev<span class="Special"> &lt;- </span>next prev column<span class="Special"> &lt;- </span>add column, <span class="Constant">1</span> <span class="muControl">loop</span> <span class="Delimiter">}</span> <span class="Comment"># is cursor to the right of the last line? move to end</span> <span class="Delimiter">{</span> at-cursor-row?:bool<span class="Special"> &lt;- </span>equal row, cursor-row cursor-outside-line?:bool<span class="Special"> &lt;- </span>lesser-or-equal column, cursor-column before-cursor-on-same-line?:bool<span class="Special"> &lt;- </span>and at-cursor-row?, cursor-outside-line? above-cursor-row?:bool<span class="Special"> &lt;- </span>lesser-than row, cursor-row before-cursor?:bool<span class="Special"> &lt;- </span>or before-cursor-on-same-line?, above-cursor-row? <span class="muControl">break-unless</span> before-cursor? cursor-row<span class="Special"> &lt;- </span>copy row *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 column *editor<span class="Special"> &lt;- </span>put *editor, <span class="Constant">cursor-column:offset</span>, cursor-column 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 <span class="Delimiter">}</span> ] <span class="Comment"># Process an event 'e' and try to minimally update the screen.</span> <span class="Comment"># Set 'go-render?' to true to indicate the caller must perform a non-minimal update.</span> <span class="muRecipe">def</span> handle-keyboard-event screen:&amp;:screen, editor:&amp;:editor, e:event<span class="muRecipe"> -&gt; </span>screen:&amp;:screen, editor:&amp;:editor, go-render?:bool [ <span class="Constant">local-scope</span> <span class="Constant">load-ingredients</span> go-render?<span class="Special"> &lt;- </span>copy <span class="Constant">0/false</span> <span class="muControl">return-unless</span> editor screen-width:num<span class="Special"> &lt;- </span>screen-width screen screen-height:num<span class="Special"> &lt;- </span>screen-height screen 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> 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> save-row:num<span class="Special"> &lt;- </span>copy cursor-row save-column:num<span class="Special"> &lt;- </span>copy cursor-column <span class="Comment"># character</span> <span class="Delimiter">{</span> c:char, is-unicode?:bool<span class="Special"> &lt;- </span>maybe-convert e, <span class="Constant">text:variant</span> <span class="muControl">break-unless</span> is-unicode? trace <span class="Constant">10</span>, <span class="Constant">[app]</span>, <span class="Constant">[handle-keyboard-event: special character]</span> <span class="Comment"># exceptions for special characters go here</span> <span class="Constant"> &lt;handle-special-character&gt;</span> <span class="Comment"># ignore any other special characters</span> regular-character?:bool<span class="Special"> &lt;- </span>greater-or-equal c, <span class="Constant">32/space</span> go-render?<span class="Special"> &lt;- </span>copy <span class="Constant">0/false</span> <span class="muControl">return-unless</span> regular-character? <span class="Comment"># otherwise type it in</span> <span class="Constant"> &lt;insert-character-begin&gt;</span> editor, screen, go-render?:bool<span class="Special"> &lt;- </span>insert-at-cursor editor, c, screen <span class="Constant"> &lt;insert-character-end&gt;</span> <span class="muControl">return</span> <span class="Delimiter">}</span> <span class="Comment"># special key to modify the text or move the cursor</span> k:num, is-keycode?:bool<span class="Special"> &lt;- </span>maybe-convert e:event, <span class="Constant">keycode:variant</span> assert is-keycode?, <span class="Constant">[event was of unknown type; neither keyboard nor mouse]</span> <span class="Comment"># handlers for each special key will go here</span> <span class="Constant"> &lt;handle-special-key&gt;</span> go-render?<span class="Special"> &lt;- </span>copy <span class="Constant">1/true</span> <span class="muControl">return</span> ] <span class="muRecipe">def</span> insert-at-cursor editor:&amp;:editor, c:char, screen:&amp;:screen<span class="muRecipe"> -&gt; </span>editor:&amp;:editor, screen:&amp;:screen, 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> insert c, before-cursor before-cursor<span class="Special"> &lt;- </span>next before-cursor *editor<span class="Special"> &lt;- </span>put *editor, <span class="Constant">before-cursor:offset</span>, before-cursor 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> save-row:num<span class="Special"> &lt;- </span>copy cursor-row save-column:num<span class="Special"> &lt;- </span>copy cursor-column screen-width:num<span class="Special"> &lt;- </span>screen-width screen screen-height:num<span class="Special"> &lt;- </span>screen-height screen <span class="Comment"># occasionally we'll need to mess with the cursor</span> <span class="Constant"> &lt;insert-character-special-case&gt;</span> <span class="Comment"># but mostly we'll just move the cursor right</span> cursor-column<span class="Special"> &lt;- </span>add cursor-column, <span class="Constant">1</span> *editor<span class="Special"> &lt;- </span>put *editor, <span class="Constant">cursor-column:offset</span>, cursor-column next:&amp;:duplex-list:char<span class="Special"> &lt;- </span>next before-cursor <span class="Delimiter">{</span> <span class="Comment"># at end of all text? no need to scroll? just print the character and leave</span> at-end?:bool<span class="Special"> &lt;- </span>equal next, <span class="Constant">0/null</span> <span class="muControl">break-unless</span> at-end? bottom:num<span class="Special"> &lt;- </span>subtract screen-height, <span class="Constant">1</span> at-bottom?:bool<span class="Special"> &lt;- </span>equal save-row, bottom at-right?:bool<span class="Special"> &lt;- </span>equal save-column, right overflow?:bool<span class="Special"> &lt;- </span>and at-bottom?, at-right? <span class="muControl">break-if</span> overflow? move-cursor screen, save-row, save-column print screen, c 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"># not at right margin? print the character and rest of line</span> <span class="muControl">break-unless</span> next at-right?:bool<span class="Special"> &lt;- </span>greater-or-equal cursor-column, screen-width <span class="muControl">break-if</span> at-right? curr:&amp;:duplex-list:char<span class="Special"> &lt;- </span>copy before-cursor move-cursor screen, save-row, save-column curr-column:num<span class="Special"> &lt;- </span>copy save-column <span class="Delimiter">{</span> <span class="Comment"># hit right margin? give up and let caller render</span> go-render?<span class="Special"> &lt;- </span>copy <span class="Constant">1/true</span> at-right?:bool<span class="Special"> &lt;- </span>greater-than curr-column, right <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? 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> go-render?<span class="Special"> &lt;- </span>copy <span class="Constant">0/false</span> <span class="muControl">return</span> <span class="Delimiter">}</span> go-render?<span class="Special"> &lt;- </span>copy <span class="Constant">1/true</span> <span class="muControl">return</span> ] <span class="Comment"># helper for tests</span> <span class="muRecipe">def</span> editor-render screen:&amp;:screen, editor:&amp;:editor<span class="muRecipe"> -&gt; </span>screen:&amp;:screen, editor:&amp;:editor [ <span class="Constant">local-scope</span> <span class="Constant">load-ingredients</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> row:num, column:num<span class="Special"> &lt;- </span>render screen, editor clear-line-until screen, right row<span class="Special"> &lt;- </span>add row, <span class="Constant">1</span> draw-horizontal screen, row, left, right, <span class="Constant">9480/horizontal-dotted</span> row<span class="Special"> &lt;- </span>add row, <span class="Constant">1</span> clear-screen-from screen, row, left, left, right ] <span class="muScenario">scenario</span> editor-handles-empty-event-queue [ assume-screen <span class="Constant">10/width</span>, <span class="Constant">5/height</span> <span class="Constant">1</span>:text<span class="Special"> &lt;- </span>new <span class="Constant">[abc]</span> <span class="Constant">2</span>:&amp;:editor<span class="Special"> &lt;- </span>new-editor <span class="Constant">1</span>:text, screen:&amp;:screen, <span class="Constant">0/left</span>, <span class="Constant">10/right</span> editor-render screen, <span class="Constant">2</span>:&amp;:editor assume-console <span class="Constant">[]</span> run [ editor-event-loop screen:&amp;:screen, console:&amp;:console, <span class="Constant">2</span>:&amp;:editor ] screen-should-contain [ <span class="Constant"> . .</span> <span class="Constant"> .abc .</span> <span class="Constant"> .┈┈┈┈┈┈┈┈┈┈.</span> <span class="Constant"> . .</span> ] ] <span class="muScenario">scenario</span> editor-handles-mouse-clicks [ assume-screen <span class="Constant">10/width</span>, <span class="Constant">5/height</span> <span class="Constant">1</span>:text<span class="Special"> &lt;- </span>new <span class="Constant">[abc]</span> <span class="Constant">2</span>:&amp;:editor<span class="Special"> &lt;- </span>new-editor <span class="Constant">1</span>:text, screen:&amp;:screen, <span class="Constant">0/left</span>, <span class="Constant">10/right</span> editor-render screen, <span class="Constant">2</span>:&amp;:editor <span class="Constant"> $clear-trace</span> assume-console [ left-click <span class="Constant">1</span>, <span class="Constant">1</span> <span class="Comment"># on the 'b'</span> ] run [ editor-event-loop screen:&amp;:screen, console:&amp;:console, <span class="Constant">2</span>:&amp;:editor <span class="Constant">3</span>:num<span class="Special"> &lt;- </span>get *<span class="Constant">2</span>:&amp;:editor, <span class="Constant">cursor-row:offset</span> <span class="Constant">4</span>:num<span class="Special"> &lt;- </span>get *<span class="Constant">2</span>:&amp;:editor, <span class="Constant">cursor-column:offset</span> ] screen-should-contain [ <span class="Constant"> . .</span> <span class="Constant"> .abc .</span> <span class="Constant"> .┈┈┈┈┈┈┈┈┈┈.</span> <span class="Constant"> . .</span> ] memory-should-contain [ <span class="Constant">3</span><span class="Special"> &lt;- </span><span class="Constant">1</span> <span class="Comment"># cursor is at row 0..</span> <span class="Constant">4</span><span class="Special"> &lt;- </span><span class="Constant">1</span> <span class="Comment"># ..and column 1</span> ] check-trace-count-for-label <span class="Constant">0</span>, <span class="Constant">[print-character]</span> ] <span class="muScenario">scenario</span> editor-handles-mouse-clicks-outside-text [ assume-screen <span class="Constant">10/width</span>, <span class="Constant">5/height</span> <span class="Constant">1</span>:text<span class="Special"> &lt;- </span>new <span class="Constant">[abc]</span> <span class="Constant">2</span>:&amp;:editor<span class="Special"> &lt;- </span>new-editor <span class="Constant">1</span>:text, screen:&amp;:screen, <span class="Constant">0/left</span>, <span class="Constant">10/right</span> <span class="Constant"> $clear-trace</span> assume-console [ left-click <span class="Constant">1</span>, <span class="Constant">7</span> <span class="Comment"># last line, to the right of text</span> ] run [ editor-event-loop screen:&amp;:screen, console:&amp;:console, <span class="Constant">2</span>:&amp;:editor <span class="Constant">3</span>:num<span class="Special"> &lt;- </span>get *<span class="Constant">2</span>:&amp;:editor, <span class="Constant">cursor-row:offset</span> <span class="Constant">4</span>:num<span class="Special"> &lt;- </span>get *<span class="Constant">2</span>:&amp;:editor, <span class="Constant">cursor-column:offset</span> ] memory-should-contain [ <span class="Constant">3</span><span class="Special"> &lt;- </span><span class="Constant">1</span> <span class="Comment"># cursor row</span> <span class="Constant">4</span><span class="Special"> &lt;- </span><span class="Constant">3</span> <span class="Comment"># cursor column</span> ] check-trace-count-for-label <span class="Constant">0</span>, <span class="Constant">[print-character]</span> ] <span class="muScenario">scenario</span> editor-handles-mouse-clicks-outside-text-2 [ assume-screen <span class="Constant">10/width</span>, <span class="Constant">5/height</span> <span class="Constant">1</span>:text<span class="Special"> &lt;- </span>new <span class="Constant">[abc</span> <span class="Constant">def]</span> <span class="Constant">2</span>:&amp;:editor<span class="Special"> &lt;- </span>new-editor <span class="Constant">1</span>:text, screen:&amp;:screen, <span class="Constant">0/left</span>, <span class="Constant">10/right</span> <span class="Constant"> $clear-trace</span> assume-console [ left-click <span class="Constant">1</span>, <span class="Constant">7</span> <span class="Comment"># interior line, to the right of text</span> ] run [ editor-event-loop screen:&amp;:screen, console:&amp;:console, <span class="Constant">2</span>:&amp;:editor <span class="Constant">3</span>:num<span class="Special"> &lt;- </span>get *<span class="Constant">2</span>:&amp;:editor, <span class="Constant">cursor-row:offset</span> <span class="Constant">4</span>:num<span class="Special"> &lt;- </span>get *<span class="Constant">2</span>:&amp;:editor, <span class="Constant">cursor-column:offset</span> ] memory-should-contain [ <span class="Constant">3</span><span class="Special"> &lt;- </span><span class="Constant">1</span> <span class="Comment"># cursor row</span> <span class="Constant">4</span><span class="Special"> &lt;- </span><span class="Constant">3</span> <span class="Comment"># cursor column</span> ] check-trace-count-for-label <span class="Constant">0</span>, <span class="Constant">[print-character]</span> ] <span class="muScenario">scenario</span> editor-handles-mouse-clicks-outside-text-3 [ assume-screen <span class="Constant">10/width</span>, <span class="Constant">5/height</span> <span class="Constant">1</span>:text<span class="Special"> &lt;- </span>new <span class="Constant">[abc</span> <span class="Constant">def]</span> <span class="Constant">2</span>:&amp;:editor<span class="Special"> &lt;- </span>new-editor <span class="Constant">1</span>:text, screen:&amp;:screen, <span class="Constant">0/left</span>, <span class="Constant">10/right</span> <span class="Constant"> $clear-trace</span> assume-console [ left-click <span class="Constant">3</span>, <span class="Constant">7</span> <span class="Comment"># below text</span> ] run [ editor-event-loop screen:&amp;:screen, console:&amp;:console, <span class="Constant">2</span>:&amp;:editor <span class="Constant">3</span>:num<span class="Special"> &lt;- </span>get *<span class="Constant">2</span>:&amp;:editor, <span class="Constant">cursor-row:offset</span> <span class="Constant">4</span>:num<span class="Special"> &lt;- </span>get *<span class="Constant">2</span>:&amp;:editor, <span class="Constant">cursor-column:offset</span> ] memory-should-contain [ <span class="Constant">3</span><span class="Special"> &lt;- </span><span class="Constant">2</span> <span class="Comment"># cursor row</span> <span class="Constant">4</span><span class="Special"> &lt;- </span><span class="Constant">3</span> <span class="Comment"># cursor column</span> ] check-trace-count-for-label <span class="Constant">0</span>, <span class="Constant">[print-character]</span> ] <span class="muScenario">scenario</span> editor-handles-mouse-clicks-outside-column [ assume-screen <span class="Constant">10/width</span>, <span class="Constant">5/height</span> <span class="Constant">1</span>:text<span class="Special"> &lt;- </span>new <span class="Constant">[abc]</span> <span class="Comment"># editor occupies only left half of screen</span> <span class="Constant">2</span>:&amp;:editor<span class="Special"> &lt;- </span>new-editor <span class="Constant">1</span>:text, screen:&amp;:screen, <span class="Constant">0/left</span>, <span class="Constant">5/right</span> editor-render screen, <span class="Constant">2</span>:&amp;:editor <span class="Constant"> $clear-trace</span> assume-console [ <span class="Comment"># click on right half of screen</span> left-click <span class="Constant">3</span>, <span class="Constant">8</span> ] run [ editor-event-loop screen:&amp;:screen, console:&amp;:console, <span class="Constant">2</span>:&amp;:editor <span class="Constant">3</span>:num<span class="Special"> &lt;- </span>get *<span class="Constant">2</span>:&amp;:editor, <span class="Constant">cursor-row:offset</span> <span class="Constant">4</span>:num<span class="Special"> &lt;- </span>get *<span class="Constant">2</span>:&amp;:editor, <span class="Constant">cursor-column:offset</span> ] screen-should-contain [ <span class="Constant"> . .</span> <span class="Constant"> .abc .</span> <span class="Constant"> .┈┈┈┈┈ .</span> <span class="Constant"> . .</span> ] memory-should-contain [ <span class="Constant">3</span><span class="Special"> &lt;- </span><span class="Constant">1</span> <span class="Comment"># no change to cursor row</span> <span class="Constant">4</span><span class="Special"> &lt;- </span><span class="Constant">0</span> <span class="Comment"># ..or column</span> ] check-trace-count-for-label <span class="Constant">0</span>, <span class="Constant">[print-character]</span> ] <span class="muScenario">scenario</span> editor-handles-mouse-clicks-in-menu-area [ assume-screen <span class="Constant">10/width</span>, <span class="Constant">5/height</span> <span class="Constant">1</span>:text<span class="Special"> &lt;- </span>new <span class="Constant">[abc]</span> <span class="Constant">2</span>:&amp;:editor<span class="Special"> &lt;- </span>new-editor <span class="Constant">1</span>:text, screen:&amp;:screen, <span class="Constant">0/left</span>, <span class="Constant">5/right</span> editor-render screen, <span class="Constant">2</span>:&amp;:editor <span class="Constant"> $clear-trace</span> assume-console [ <span class="Comment"># click on first, 'menu' row</span> left-click <span class="Constant">0</span>, <span class="Constant">3</span> ] run [ editor-event-loop screen:&amp;:screen, console:&amp;:console, <span class="Constant">2</span>:&amp;:editor <span class="Constant">3</span>:num<span class="Special"> &lt;- </span>get *<span class="Constant">2</span>:&amp;:editor, <span class="Constant">cursor-row:offset</span> <span class="Constant">4</span>:num<span class="Special"> &lt;- </span>get *<span class="Constant">2</span>:&amp;:editor, <span class="Constant">cursor-column:offset</span> ] <span class="Comment"># no change to cursor</span> memory-should-contain [ <span class="Constant">3</span><span class="Special"> &lt;- </span><span class="Constant">1</span> <span class="Constant">4</span><span class="Special"> &lt;- </span><span class="Constant">0</span> ] ] <span class="muScenario">scenario</span> editor-inserts-characters-into-empty-editor [ assume-screen <span class="Constant">10/width</span>, <span class="Constant">5/height</span> <span class="Constant">1</span>:text<span class="Special"> &lt;- </span>new <span class="Constant">[]</span> <span class="Constant">2</span>:&amp;:editor<span class="Special"> &lt;- </span>new-editor <span class="Constant">1</span>:text, screen:&amp;:screen, <span class="Constant">0/left</span>, <span class="Constant">5/right</span> editor-render screen, <span class="Constant">2</span>:&amp;:editor <span class="Constant"> $clear-trace</span> assume-console [ type <span class="Constant">[abc]</span> ] run [ editor-event-loop screen:&amp;:screen, console:&amp;:console, <span class="Constant">2</span>:&amp;:editor ] screen-should-contain [ <span class="Constant"> . .</span> <span class="Constant"> .abc .</span> <span class="Constant"> .┈┈┈┈┈ .</span> <span class="Constant"> . .</span> ] check-trace-count-for-label <span class="Constant">3</span>, <span class="Constant">[print-character]</span> ] <span class="muScenario">scenario</span> editor-inserts-characters-at-cursor [ assume-screen <span class="Constant">10/width</span>, <span class="Constant">5/height</span> <span class="Constant">1</span>:text<span class="Special"> &lt;- </span>new <span class="Constant">[abc]</span> <span class="Constant">2</span>:&amp;:editor<span class="Special"> &lt;- </span>new-editor <span class="Constant">1</span>:text, screen:&amp;:screen, <span class="Constant">0/left</span>, <span class="Constant">10/right</span> editor-render screen, <span class="Constant">2</span>:&amp;:editor <span class="Constant"> $clear-trace</span> <span class="Comment"># type two letters at different places</span> assume-console [ type <span class="Constant">[0]</span> left-click <span class="Constant">1</span>, <span class="Constant">2</span> type <span class="Constant">[d]</span> ] run [ editor-event-loop screen:&amp;:screen, console:&amp;:console, <span class="Constant">2</span>:&amp;:editor ] screen-should-contain [ <span class="Constant"> . .</span> <span class="Constant"> .0adbc .</span> <span class="Constant"> .┈┈┈┈┈┈┈┈┈┈.</span> <span class="Constant"> . .</span> ] check-trace-count-for-label <span class="Constant">7</span>, <span class="Constant">[print-character]</span> <span class="Comment"># 4 for first letter, 3 for second</span> ] <span class="muScenario">scenario</span> editor-inserts-characters-at-cursor-2 [ assume-screen <span class="Constant">10/width</span>, <span class="Constant">5/height</span> <span class="Constant">1</span>:text<span class="Special"> &lt;- </span>new <span class="Constant">[abc]</span> <span class="Constant">2</span>:&amp;:editor<span class="Special"> &lt;- </span>new-editor <span class="Constant">1</span>:text, screen:&amp;:screen, <span class="Constant">0/left</span>, <span class="Constant">10/right</span> editor-render screen, <span class="Constant">2</span>:&amp;:editor <span class="Constant"> $clear-trace</span> assume-console [ left-click <span class="Constant">1</span>, <span class="Constant">5</span> <span class="Comment"># right of last line</span> type <span class="Constant">[d]</span> ] run [ editor-event-loop screen:&amp;:screen, console:&amp;:console, <span class="Constant">2</span>:&amp;:editor ] screen-should-contain [ <span class="Constant"> . .</span> <span class="Constant"> .abcd .</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="muScenario">scenario</span> editor-inserts-characters-at-cursor-5 [ assume-screen <span class="Constant">10/width</span>, <span class="Constant">5/height</span> <span class="Constant">1</span>:text<span class="Special"> &lt;- </span>new <span class="Constant">[abc</span> <span class="Constant">d]</span> <span class="Constant">2</span>:&amp;:editor<span class="Special"> &lt;- </span>new-editor <span class="Constant">1</span>:text, screen:&amp;:screen, <span class="Constant">0/left</span>, <span class="Constant">10/right</span> editor-render screen, <span class="Constant">2</span>:&amp;:editor <span class="Constant"> $clear-trace</span> assume-console [ left-click <span class="Constant">1</span>, <span class="Constant">5</span> <span class="Comment"># right of non-last line</span> type <span class="Constant">[e]</span> ] run [ editor-event-loop screen:&amp;:screen, console:&amp;:console, <span class="Constant">2</span>:&amp;:editor ] screen-should-contain [ <span class="Constant"> . .</span> <span class="Constant"> .abce .</span> <span class="Constant"> .d .</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="muScenario">scenario</span> editor-inserts-characters-at-cursor-3 [ assume-screen <span class="Constant">10/width</span>, <span class="Constant">5/height</span> <span class="Constant">1</span>:text<span class="Special"> &lt;- </span>new <span class="Constant">[abc]</span> <span class="Constant">2</span>:&amp;:editor<span class="Special"> &lt;- </span>new-editor <span class="Constant">1</span>:text, screen:&amp;:screen, <span class="Constant">0/left</span>, <span class="Constant">10/right</span> editor-render screen, <span class="Constant">2</span>:&amp;:editor <span class="Constant"> $clear-trace</span> assume-console [ left-click <span class="Constant">3</span>, <span class="Constant">5</span> <span class="Comment"># below all text</span> type <span class="Constant">[d]</span> ] run [ editor-event-loop screen:&amp;:screen, console:&amp;:console, <span class="Constant">2</span>:&amp;:editor ] screen-should-contain [ <span class="Constant"> . .</span> <span class="Constant"> .abcd .</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="muScenario">scenario</span> editor-inserts-characters-at-cursor-4 [ assume-screen <span class="Constant">10/width</span>, <span class="Constant">5/height</span> <span class="Constant">1</span>:text<span class="Special"> &lt;- </span>new <span class="Constant">[abc</span> <span class="Constant">d]</span> <span class="Constant">2</span>:&amp;:editor<span class="Special"> &lt;- </span>new-editor <span class="Constant">1</span>:text, screen:&amp;:screen, <span class="Constant">0/left</span>, <span class="Constant">10/right</span> editor-render screen, <span class="Constant">2</span>:&amp;:editor <span class="Constant"> $clear-trace</span> assume-console [ left-click <span class="Constant">3</span>, <span class="Constant">5</span> <span class="Comment"># below all text</span> type <span class="Constant">[e]</span> ] run [ editor-event-loop screen:&amp;:screen, console:&amp;:console, <span class="Constant">2</span>:&amp;:editor ] screen-should-contain [ <span class="Constant"> . .</span> <span class="Constant"> .abc .</span> <span class="Constant"> .de .</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="muScenario">scenario</span> editor-inserts-characters-at-cursor-6 [ assume-screen <span class="Constant">10/width</span>, <span class="Constant">5/height</span> <span class="Constant">1</span>:text<span class="Special"> &lt;- </span>new <span class="Constant">[abc</span> <span class="Constant">d]</span> <span class="Constant">2</span>:&amp;:editor<span class="Special"> &lt;- </span>new-editor <span class="Constant">1</span>:text, screen:&amp;:screen, <span class="Constant">0/left</span>, <span class="Constant">10/right</span> editor-render screen, <span class="Constant">2</span>:&amp;:editor <span class="Constant"> $clear-trace</span> assume-console [ left-click <span class="Constant">3</span>, <span class="Constant">5</span> <span class="Comment"># below all text</span> type <span class="Constant">[ef]</span> ] run [ editor-event-loop screen:&amp;:screen, console:&amp;:console, <span class="Constant">2</span>:&amp;:editor ] screen-should-contain [ <span class="Constant"> . .</span> <span class="Constant"> .abc .</span> <span class="Constant"> .def .</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="muScenario">scenario</span> editor-moves-cursor-after-inserting-characters [ assume-screen <span class="Constant">10/width</span>, <span class="Constant">5/height</span> <span class="Constant">1</span>:text<span class="Special"> &lt;- </span>new <span class="Constant">[ab]</span> <span class="Constant">2</span>:&amp;:editor<span class="Special"> &lt;- </span>new-editor <span class="Constant">1</span>:text, screen:&amp;:screen, <span class="Constant">0/left</span>, <span class="Constant">5/right</span> editor-render screen, <span class="Constant">2</span>:&amp;:editor assume-console [ type <span class="Constant">[01]</span> ] run [ editor-event-loop screen:&amp;:screen, console:&amp;:console, <span class="Constant">2</span>:&amp;:editor ] screen-should-contain [ <span class="Constant"> . .</span> <span class="Constant"> .01ab .</span> <span class="Constant"> .┈┈┈┈┈ .</span> <span class="Constant"> . .</span> ] ] <span class="Comment"># if the cursor reaches the right margin, wrap the line</span> <span class="muScenario">scenario</span> editor-wraps-line-on-insert [ assume-screen <span class="Constant">5/width</span>, <span class="Constant">5/height</span> <span class="Constant">1</span>:text<span class="Special"> &lt;- </span>new <span class="Constant">[abc]</span> <span class="Constant">2</span>:&amp;:editor<span class="Special"> &lt;- </span>new-editor <span class="Constant">1</span>:text, screen:&amp;:screen, <span class="Constant">0/left</span>, <span class="Constant">5/right</span> editor-render screen, <span class="Constant">2</span>:&amp;:editor <span class="Comment"># type a letter</span> assume-console [ type <span class="Constant">[e]</span> ] run [ editor-event-loop screen:&amp;:screen, console:&amp;:console, <span class="Constant">2</span>:&amp;:editor ] <span class="Comment"># no wrap yet</span> screen-should-contain [ <span class="Constant"> . .</span> <span class="Constant"> .eabc .</span> <span class="Constant"> .┈┈┈┈┈.</span> <span class="Constant"> . .</span> <span class="Constant"> . .</span> ] <span class="Comment"># type a second letter</span> assume-console [ type <span class="Constant">[f]</span> ] run [ editor-event-loop screen:&amp;:screen, console:&amp;:console, <span class="Constant">2</span>:&amp;:editor ] <span class="Comment"># now wrap</span> screen-should-contain [ <span class="Constant"> . .</span> <span class="Constant"> .efab↩.</span> <span class="Constant"> .c .</span> <span class="Constant"> .┈┈┈┈┈.</span> <span class="Constant"> . .</span> ] ] <span class="muScenario">scenario</span> editor-wraps-line-on-insert-2 [ <span class="Comment"># create an editor with some text</span> assume-screen <span class="Constant">10/width</span>, <span class="Constant">5/height</span> <span class="Constant">1</span>:text<span class="Special"> &lt;- </span>new <span class="Constant">[abcdefg</span> <span class="Constant">defg]</span> <span class="Constant">2</span>:&amp;:editor<span class="Special"> &lt;- </span>new-editor <span class="Constant">1</span>:text, screen:&amp;:screen, <span class="Constant">0/left</span>, <span class="Constant">5/right</span> editor-render screen, <span class="Constant">2</span>:&amp;:editor <span class="Comment"># type more text at the start</span> assume-console [ left-click <span class="Constant">3</span>, <span class="Constant">0</span> type <span class="Constant">[abc]</span> ] run [ editor-event-loop screen:&amp;:screen, console:&amp;:console, <span class="Constant">2</span>:&amp;:editor <span class="Constant">3</span>:num<span class="Special"> &lt;- </span>get *<span class="Constant">2</span>:&amp;:editor, <span class="Constant">cursor-row:offset</span> <span class="Constant">4</span>:num<span class="Special"> &lt;- </span>get *<span class="Constant">2</span>:&amp;:editor, <span class="Constant">cursor-column:offset</span> ] <span class="Comment"># cursor is not wrapped</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">3</span> ] <span class="Comment"># but line is wrapped</span> screen-should-contain [ <span class="Constant"> . .</span> <span class="Constant"> .abcd↩ .</span> <span class="Constant"> .efg .</span> <span class="Constant"> .abcd↩ .</span> <span class="Constant"> .efg .</span> ] ] <span class="muRecipe">after</span> <span class="Constant">&lt;insert-character-special-case&gt;</span> [ <span class="Comment"># if the line wraps at the cursor, move cursor to start of next row</span> <span class="Delimiter">{</span> <span class="Comment"># if either:</span> <span class="Comment"># a) we're at the end of the line and at the column of the wrap indicator, or</span> <span class="Comment"># b) we're not at end of line and just before the column of the wrap indicator</span> wrap-column:num<span class="Special"> &lt;- </span>copy right before-wrap-column:num<span class="Special"> &lt;- </span>subtract wrap-column, <span class="Constant">1</span> at-wrap?:bool<span class="Special"> &lt;- </span>greater-or-equal cursor-column, wrap-column just-before-wrap?:bool<span class="Special"> &lt;- </span>greater-or-equal cursor-column, before-wrap-column next:&amp;:duplex-list:char<span class="Special"> &lt;- </span>next before-cursor <span class="Comment"># at end of line? next == 0 || next.value == 10/newline</span> at-end-of-line?:bool<span class="Special"> &lt;- </span>equal next, <span class="Constant">0</span> <span class="Delimiter">{</span> <span class="muControl">break-if</span> at-end-of-line? next-character:char<span class="Special"> &lt;- </span>get *next, <span class="Constant">value:offset</span> at-end-of-line?<span class="Special"> &lt;- </span>equal next-character, <span class="Constant">10/newline</span> <span class="Delimiter">}</span> <span class="Comment"># break unless ((eol? and at-wrap?) or (~eol? and just-before-wrap?))</span> move-cursor-to-next-line?:bool<span class="Special"> &lt;- </span>copy <span class="Constant">0/false</span> <span class="Delimiter">{</span> <span class="muControl">break-if</span> at-end-of-line? move-cursor-to-next-line?<span class="Special"> &lt;- </span>copy just-before-wrap? <span class="Comment"># if we're moving the cursor because it's in the middle of a wrapping</span> <span class="Comment"># line, adjust it to left-most column</span> potential-new-cursor-column:num<span class="Special"> &lt;- </span>copy left <span class="Delimiter">}</span> <span class="Delimiter">{</span> <span class="muControl">break-unless</span> at-end-of-line? move-cursor-to-next-line?<span class="Special"> &lt;- </span>copy at-wrap? <span class="Comment"># if we're moving the cursor because it's at the end of a wrapping line,</span> <span class="Comment"># adjust it to one past the left-most column to make room for the</span> <span class="Comment"># newly-inserted wrap-indicator</span> potential-new-cursor-column:num<span class="Special"> &lt;- </span>add left, <span class="Constant">1/make-room-for-wrap-indicator</span> <span class="Delimiter">}</span> <span class="muControl">break-unless</span> move-cursor-to-next-line? cursor-column<span class="Special"> &lt;- </span>copy potential-new-cursor-column *editor<span class="Special"> &lt;- </span>put *editor, <span class="Constant">cursor-column:offset</span>, cursor-column 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 <span class="Comment"># if we're out of the screen, scroll down</span> <span class="Delimiter">{</span> below-screen?:bool<span class="Special"> &lt;- </span>greater-or-equal cursor-row, screen-height <span class="muControl">break-unless</span> below-screen? <span class="Constant"> &lt;scroll-down&gt;</span> <span class="Delimiter">}</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-wraps-cursor-after-inserting-characters-in-middle-of-line [ assume-screen <span class="Constant">10/width</span>, <span class="Constant">5/height</span> <span class="Constant">1</span>:text<span class="Special"> &lt;- </span>new <span class="Constant">[abcde]</span> <span class="Constant">2</span>:&amp;:editor<span class="Special"> &lt;- </span>new-editor <span class="Constant">1</span>:text, screen:&amp;:screen, <span class="Constant">0/left</span>, <span class="Constant">5/right</span> assume-console [ left-click <span class="Constant">1</span>, <span class="Constant">3</span> <span class="Comment"># right before the wrap icon</span> type <span class="Constant">[f]</span> ] run [ editor-event-loop screen:&amp;:screen, console:&amp;:console, <span class="Constant">2</span>:&amp;:editor <span class="Constant">3</span>:num<span class="Special"> &lt;- </span>get *<span class="Constant">2</span>:&amp;:editor, <span class="Constant">cursor-row:offset</span> <span class="Constant">4</span>:num<span class="Special"> &lt;- </span>get *<span class="Constant">2</span>:&amp;:editor, <span class="Constant">cursor-column:offset</span> ] screen-should-contain [ <span class="Constant"> . .</span> <span class="Constant"> .abcf↩ .</span> <span class="Constant"> .de .</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="Comment"># cursor row</span> <span class="Constant">4</span><span class="Special"> &lt;- </span><span class="Constant">0</span> <span class="Comment"># cursor column</span> ] ] <span class="muScenario">scenario</span> editor-wraps-cursor-after-inserting-characters-at-end-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"># create an editor containing two lines</span> contents:text<span class="Special"> &lt;- </span>new <span class="Constant">[abc</span> <span class="Constant">xyz]</span> <span class="Constant">1</span>:&amp;:editor/<span class="Special">raw &lt;- </span>new-editor contents, screen, <span class="Constant">0/left</span>, <span class="Constant">5/right</span> screen-should-contain [ <span class="Constant"> . .</span> <span class="Constant"> .abc .</span> <span class="Constant"> .xyz .</span> <span class="Constant"> . .</span> ] assume-console [ left-click <span class="Constant">1</span>, <span class="Constant">4</span> <span class="Comment"># at end of first line</span> type <span class="Constant">[de]</span> <span class="Comment"># trigger wrap</span> ] run [ editor-event-loop screen:&amp;:screen, console:&amp;:console, <span class="Constant">1</span>:&amp;:editor/<span class="Special">raw</span> ] screen-should-contain [ <span class="Constant"> . .</span> <span class="Constant"> .abcd↩ .</span> <span class="Constant"> .e .</span> <span class="Constant"> .xyz .</span> <span class="Constant"> .┈┈┈┈┈ .</span> ] ] <span class="muScenario">scenario</span> editor-wraps-cursor-to-left-margin [ assume-screen <span class="Constant">10/width</span>, <span class="Constant">5/height</span> <span class="Constant">1</span>:text<span class="Special"> &lt;- </span>new <span class="Constant">[abcde]</span> <span class="Constant">2</span>:&amp;:editor<span class="Special"> &lt;- </span>new-editor <span class="Constant">1</span>:text, screen:&amp;:screen, <span class="Constant">2/left</span>, <span class="Constant">7/right</span> assume-console [ left-click <span class="Constant">1</span>, <span class="Constant">5</span> <span class="Comment"># line is full; no wrap icon yet</span> type <span class="Constant">[01]</span> ] run [ editor-event-loop screen:&amp;:screen, console:&amp;:console, <span class="Constant">2</span>:&amp;:editor <span class="Constant">3</span>:num<span class="Special"> &lt;- </span>get *<span class="Constant">2</span>:&amp;:editor, <span class="Constant">cursor-row:offset</span> <span class="Constant">4</span>:num<span class="Special"> &lt;- </span>get *<span class="Constant">2</span>:&amp;:editor, <span class="Constant">cursor-column:offset</span> ] screen-should-contain [ <span class="Constant"> . .</span> <span class="Constant"> . abc0↩ .</span> <span class="Constant"> . 1de .</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="Comment"># cursor row</span> <span class="Constant">4</span><span class="Special"> &lt;- </span><span class="Constant">3</span> <span class="Comment"># cursor column</span> ] ] <span class="Comment"># if newline, move cursor to start of next line, and maybe align indent with previous line</span> <span class="muData">container</span> editor [ indent?:bool ] <span class="muRecipe">after</span> <span class="Constant">&lt;editor-initialization&gt;</span> [ *result<span class="Special"> &lt;- </span>put *result, <span class="Constant">indent?:offset</span>, <span class="Constant">1/true</span> ] <span class="muScenario">scenario</span> editor-moves-cursor-down-after-inserting-newline [ assume-screen <span class="Constant">10/width</span>, <span class="Constant">5/height</span> <span class="Constant">1</span>:text<span class="Special"> &lt;- </span>new <span class="Constant">[abc]</span> <span class="Constant">2</span>:&amp;:editor<span class="Special"> &lt;- </span>new-editor <span class="Constant">1</span>:text, screen:&amp;:screen, <span class="Constant">0/left</span>, <span class="Constant">10/right</span> assume-console [ type <span class="Constant">[0</span> <span class="Constant">1]</span> ] run [ editor-event-loop screen:&amp;:screen, console:&amp;:console, <span class="Constant">2</span>:&amp;:editor ] screen-should-contain [ <span class="Constant"> . .</span> <span class="Constant"> .0 .</span> <span class="Constant"> .1abc .</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> newline?:bool<span class="Special"> &lt;- </span>equal c, <span class="Constant">10/newline</span> <span class="muControl">break-unless</span> newline? <span class="Constant"> &lt;insert-enter-begin&gt;</span> editor<span class="Special"> &lt;- </span>insert-new-line-and-indent editor, screen <span class="Constant"> &lt;insert-enter-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> insert-new-line-and-indent editor:&amp;:editor, screen:&amp;:screen<span class="muRecipe"> -&gt; </span>editor:&amp;:editor, screen:&amp;:screen, 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> screen-height:num<span class="Special"> &lt;- </span>screen-height screen <span class="Comment"># insert newline</span> insert <span class="Constant">10/newline</span>, before-cursor before-cursor<span class="Special"> &lt;- </span>next before-cursor *editor<span class="Special"> &lt;- </span>put *editor, <span class="Constant">before-cursor:offset</span>, before-cursor 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 <span class="Comment"># maybe scroll</span> <span class="Delimiter">{</span> below-screen?:bool<span class="Special"> &lt;- </span>greater-or-equal cursor-row, screen-height <span class="Comment"># must be equal, never greater</span> <span class="muControl">break-unless</span> below-screen? <span class="Constant"> &lt;scroll-down&gt;</span> go-render?<span class="Special"> &lt;- </span>copy <span class="Constant">1/true</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 <span class="Delimiter">}</span> <span class="Comment"># indent if necessary</span> indent?:bool<span class="Special"> &lt;- </span>get *editor, <span class="Constant">indent?:offset</span> <span class="muControl">return-unless</span> indent? d:&amp;:duplex-list:char<span class="Special"> &lt;- </span>get *editor, <span class="Constant">data:offset</span> end-of-previous-line:&amp;:duplex-list:char<span class="Special"> &lt;- </span>prev before-cursor indent:num<span class="Special"> &lt;- </span>line-indent end-of-previous-line, d i:num<span class="Special"> &lt;- </span>copy <span class="Constant">0</span> <span class="Delimiter">{</span> indent-done?:bool<span class="Special"> &lt;- </span>greater-or-equal i, indent <span class="muControl">break-if</span> indent-done? editor, screen, go-render?:bool<span class="Special"> &lt;- </span>insert-at-cursor editor, <span class="Constant">32/space</span>, screen i<span class="Special"> &lt;- </span>add i, <span class="Constant">1</span> <span class="muControl">loop</span> <span class="Delimiter">}</span> ] <span class="Comment"># takes a pointer 'curr' into the doubly-linked list and its sentinel, counts</span> <span class="Comment"># the number of spaces at the start of the line containing 'curr'.</span> <span class="muRecipe">def</span> line-indent 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? <span class="Comment"># if c is a space, increment result</span> is-space?:bool<span class="Special"> &lt;- </span>equal c, <span class="Constant">32/space</span> <span class="Delimiter">{</span> <span class="muControl">break-unless</span> is-space? result<span class="Special"> &lt;- </span>add result, <span class="Constant">1</span> <span class="Delimiter">}</span> <span class="Comment"># if c is not a space, reset result</span> <span class="Delimiter">{</span> <span class="muControl">break-if</span> is-space? result<span class="Special"> &lt;- </span>copy <span class="Constant">0</span> <span class="Delimiter">}</span> <span class="muControl">loop</span> <span class="Delimiter">}</span> ] <span class="muScenario">scenario</span> editor-moves-cursor-down-after-inserting-newline-2 [ assume-screen <span class="Constant">10/width</span>, <span class="Constant">5/height</span> <span class="Constant">1</span>:text<span class="Special"> &lt;- </span>new <span class="Constant">[abc]</span> <span class="Constant">2</span>:&amp;:editor<span class="Special"> &lt;- </span>new-editor <span class="Constant">1</span>:text, screen:&amp;:screen, <span class="Constant">1/left</span>, <span class="Constant">10/right</span> assume-console [ type <span class="Constant">[0</span> <span class="Constant">1]</span> ] run [ editor-event-loop screen:&amp;:screen, console:&amp;:console, <span class="Constant">2</span>:&amp;:editor ] screen-should-contain [ <span class="Constant"> . .</span> <span class="Constant"> . 0 .</span> <span class="Constant"> . 1abc .</span> <span class="Constant"> . ┈┈┈┈┈┈┈┈┈.</span> <span class="Constant"> . .</span> ] ] <span class="muScenario">scenario</span> editor-clears-previous-line-completely-after-inserting-newline [ assume-screen <span class="Constant">10/width</span>, <span class="Constant">5/height</span> <span class="Constant">1</span>:text<span class="Special"> &lt;- </span>new <span class="Constant">[abcde]</span> <span class="Constant">2</span>:&amp;:editor<span class="Special"> &lt;- </span>new-editor <span class="Constant">1</span>:text, screen:&amp;:screen, <span class="Constant">0/left</span>, <span class="Constant">5/right</span> assume-console [ press enter ] screen-should-contain [ <span class="Constant"> . .</span> <span class="Constant"> .abcd↩ .</span> <span class="Constant"> .e .</span> <span class="Constant"> . .</span> <span class="Constant"> . .</span> ] run [ editor-event-loop screen:&amp;:screen, console:&amp;:console, <span class="Constant">2</span>:&amp;:editor ] <span class="Comment"># line should be fully cleared</span> screen-should-contain [ <span class="Constant"> . .</span> <span class="Constant"> . .</span> <span class="Constant"> .abcd↩ .</span> <span class="Constant"> .e .</span> <span class="Constant"> .┈┈┈┈┈ .</span> ] ] <span class="muScenario">scenario</span> editor-inserts-indent-after-newline [ assume-screen <span class="Constant">10/width</span>, <span class="Constant">10/height</span> <span class="Constant">1</span>:text<span class="Special"> &lt;- </span>new <span class="Constant">[ab</span> <span class="Constant"> cd</span> <span class="Constant">ef]</span> <span class="Constant">2</span>:&amp;:editor<span class="Special"> &lt;- </span>new-editor <span class="Constant">1</span>:text, screen:&amp;:screen, <span class="Constant">0/left</span>, <span class="Constant">10/right</span> <span class="Comment"># position cursor after 'cd' and hit 'newline'</span> assume-console [ left-click <span class="Constant">2</span>, <span class="Constant">8</span> type [ ] ] run [ editor-event-loop screen:&amp;:screen, console:&amp;:console, <span class="Constant">2</span>:&amp;:editor <span class="Constant">3</span>:num<span class="Special"> &lt;- </span>get *<span class="Constant">2</span>:&amp;:editor, <span class="Constant">cursor-row:offset</span> <span class="Constant">4</span>:num<span class="Special"> &lt;- </span>get *<span class="Constant">2</span>:&amp;:editor, <span class="Constant">cursor-column:offset</span> ] <span class="Comment"># cursor should be below start of previous line</span> memory-should-contain [ <span class="Constant">3</span><span class="Special"> &lt;- </span><span class="Constant">3</span> <span class="Comment"># cursor row</span> <span class="Constant">4</span><span class="Special"> &lt;- </span><span class="Constant">2</span> <span class="Comment"># cursor column (indented)</span> ] ] <span class="muScenario">scenario</span> editor-skips-indent-around-paste [ assume-screen <span class="Constant">10/width</span>, <span class="Constant">10/height</span> <span class="Constant">1</span>:text<span class="Special"> &lt;- </span>new <span class="Constant">[ab</span> <span class="Constant"> cd</span> <span class="Constant">ef]</span> <span class="Constant">2</span>:&amp;:editor<span class="Special"> &lt;- </span>new-editor <span class="Constant">1</span>:text, screen:&amp;:screen, <span class="Constant">0/left</span>, <span class="Constant">10/right</span> <span class="Comment"># position cursor after 'cd' and hit 'newline' surrounded by paste markers</span> assume-console [ left-click <span class="Constant">2</span>, <span class="Constant">8</span> press <span class="Constant">65507</span> <span class="Comment"># start paste</span> press enter press <span class="Constant">65506</span> <span class="Comment"># end paste</span> ] run [ editor-event-loop screen:&amp;:screen, console:&amp;:console, <span class="Constant">2</span>:&amp;:editor <span class="Constant">3</span>:num<span class="Special"> &lt;- </span>get *<span class="Constant">2</span>:&amp;:editor, <span class="Constant">cursor-row:offset</span> <span class="Constant">4</span>:num<span class="Special"> &lt;- </span>get *<span class="Constant">2</span>:&amp;:editor, <span class="Constant">cursor-column:offset</span> ] <span class="Comment"># cursor should be below start of previous line</span> memory-should-contain [ <span class="Constant">3</span><span class="Special"> &lt;- </span><span class="Constant">3</span> <span class="Comment"># cursor row</span> <span class="Constant">4</span><span class="Special"> &lt;- </span><span class="Constant">0</span> <span class="Comment"># cursor column (not indented)</span> ] ] <span class="muRecipe">after</span> <span class="Constant">&lt;handle-special-key&gt;</span> [ <span class="Delimiter">{</span> paste-start?:bool<span class="Special"> &lt;- </span>equal k, <span class="Constant">65507/paste-start</span> <span class="muControl">break-unless</span> paste-start? *editor<span class="Special"> &lt;- </span>put *editor, <span class="Constant">indent?:offset</span>, <span class="Constant">0/false</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">after</span> <span class="Constant">&lt;handle-special-key&gt;</span> [ <span class="Delimiter">{</span> paste-end?:bool<span class="Special"> &lt;- </span>equal k, <span class="Constant">65506/paste-end</span> <span class="muControl">break-unless</span> paste-end? *editor<span class="Special"> &lt;- </span>put *editor, <span class="Constant">indent?:offset</span>, <span class="Constant">1/true</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="SalientComment">## helpers</span> <span class="muRecipe">def</span> draw-horizontal screen:&amp;:screen, row:num, x:num, right:num<span class="muRecipe"> -&gt; </span>screen:&amp;:screen [ <span class="Constant">local-scope</span> <span class="Constant">load-ingredients</span> style:char, style-found?:bool<span class="Special"> &lt;- </span><span class="Constant">next-ingredient</span> <span class="Delimiter">{</span> <span class="muControl">break-if</span> style-found? style<span class="Special"> &lt;- </span>copy <span class="Constant">9472/horizontal</span> <span class="Delimiter">}</span> color:num, color-found?:bool<span class="Special"> &lt;- </span><span class="Constant">next-ingredient</span> <span class="Delimiter">{</span> <span class="Comment"># default color to white</span> <span class="muControl">break-if</span> color-found? color<span class="Special"> &lt;- </span>copy <span class="Constant">245/grey</span> <span class="Delimiter">}</span> bg-color:num, bg-color-found?:bool<span class="Special"> &lt;- </span><span class="Constant">next-ingredient</span> <span class="Delimiter">{</span> <span class="muControl">break-if</span> bg-color-found? bg-color<span class="Special"> &lt;- </span>copy <span class="Constant">0/black</span> <span class="Delimiter">}</span> screen<span class="Special"> &lt;- </span>move-cursor screen, row, x <span class="Delimiter">{</span> continue?:bool<span class="Special"> &lt;- </span>lesser-or-equal x, right <span class="Comment"># right is inclusive, to match editor semantics</span> <span class="muControl">break-unless</span> continue? print screen, style, color, bg-color x<span class="Special"> &lt;- </span>add x, <span class="Constant">1</span> <span class="muControl">loop</span> <span class="Delimiter">}</span> ] </pre> </body> </html> <!-- vim: set foldmethod=manual : -->