<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
<title>Mu - edit.mu</title>
<meta name="Generator" content="Vim/7.4">
<meta name="plugin-version" content="vim7.4_v1">
<meta name="syntax" content="none">
<meta name="settings" content="use_css,pre_wrap,no_foldcolumn,expand_tabs,prevent_copy=">
<meta name="colorscheme" content="minimal">
<style type="text/css">
<!--
pre { white-space: pre-wrap; font-family: monospace; color: #eeeeee; background-color: #080808; }
body { font-family: monospace; color: #eeeeee; background-color: #080808; }
* { font-size: 1.05em; }
.muScenario { color: #00af00; }
.SalientComment { color: #00ffff; }
.Delimiter { color: #a04060; }
.CommentedCode { color: #6c6c6c; }
.Comment { color: #9090ff; }
.Constant { color: #00a0a0; }
.Special { color: #ff6060; }
.muControl { color: #c0a020; }
.muRecipe { color: #ff8700; }
-->
</style>
<script type='text/javascript'>
<!--
-->
</script>
</head>
<body>
<pre id='vimCodeElement'>
<span class="Comment"># Environment for learning programming using mu.</span>
<span class="muRecipe">recipe</span> main [
<span class="Constant">local-scope</span>
open-console
initial-recipe:address:array:character<span class="Special"> <- </span>restore <span class="Constant">[recipes.mu]</span>
initial-sandbox:address:array:character<span class="Special"> <- </span>new <span class="Constant">[]</span>
env:address:programming-environment-data<span class="Special"> <- </span>new-programming-environment <span class="Constant">0:literal/screen</span>, initial-recipe:address:array:character, initial-sandbox:address:array:character
env:address:programming-environment-data<span class="Special"> <- </span>restore-sandboxes env:address:programming-environment-data
render-all <span class="Constant">0:literal/screen</span>, env:address:programming-environment-data
show-screen <span class="Constant">0:literal/screen</span>
event-loop <span class="Constant">0:literal/screen</span>, <span class="Constant">0:literal/console</span>, env:address:programming-environment-data
<span class="Comment"># never gets here</span>
]
container programming-environment-data [
recipes:address:editor-data
recipe-warnings:address:array:character
current-sandbox:address:editor-data
sandbox:address:sandbox-data
sandbox-in-focus?:boolean <span class="Comment"># false => focus in recipes; true => focus in current-sandbox</span>
]
<span class="muRecipe">recipe</span> new-programming-environment [
<span class="Constant">local-scope</span>
screen:address<span class="Special"> <- </span><span class="Constant">next-ingredient</span>
initial-recipe-contents:address:array:character<span class="Special"> <- </span><span class="Constant">next-ingredient</span>
initial-sandbox-contents:address:array:character<span class="Special"> <- </span><span class="Constant">next-ingredient</span>
width:number<span class="Special"> <- </span>screen-width screen:address
height:number<span class="Special"> <- </span>screen-height screen:address
<span class="Comment"># top menu</span>
result:address:programming-environment-data<span class="Special"> <- </span>new programming-environment-data:type
draw-horizontal screen:address, <span class="Constant">0:literal</span>, <span class="Constant">0:literal/left</span>, width:number, <span class="Constant">32:literal/space</span>, <span class="Constant">0:literal/black</span>, <span class="Constant">238:literal/grey</span>
button-start:number<span class="Special"> <- </span>subtract width:number, <span class="Constant">20:literal</span>
button-on-screen?:boolean<span class="Special"> <- </span>greater-or-equal button-start:number, <span class="Constant">0:literal</span>
assert button-on-screen?:boolean, <span class="Constant">[screen too narrow for menu]</span>
move-cursor screen:address, <span class="Constant">0:literal/row</span>, button-start:number/column
run-button:address:array:character<span class="Special"> <- </span>new <span class="Constant">[ run (F10) ]</span>
print-string screen:address, run-button:address:array:character, <span class="Constant">255:literal/white</span>, <span class="Constant">161:literal/reddish</span>
<span class="Comment"># dotted line down the middle</span>
divider:number, _<span class="Special"> <- </span>divide-with-remainder width:number, <span class="Constant">2:literal</span>
draw-vertical screen:address, divider:number, <span class="Constant">1:literal/top</span>, height:number, <span class="Constant">9482:literal/vertical-dotted</span>
<span class="Comment"># recipe editor on the left</span>
recipes:address:address:editor-data<span class="Special"> <- </span>get-address result:address:programming-environment-data/deref, recipes:offset
recipes:address:address:editor-data/deref<span class="Special"> <- </span>new-editor initial-recipe-contents:address:array:character, screen:address, <span class="Constant">0:literal/left</span>, divider:number/right
<span class="Comment"># sandbox editor on the right</span>
new-left:number<span class="Special"> <- </span>add divider:number, <span class="Constant">1:literal</span>
new-right:number<span class="Special"> <- </span>add new-left:number, <span class="Constant">5:literal</span>
current-sandbox:address:address:editor-data<span class="Special"> <- </span>get-address result:address:programming-environment-data/deref, current-sandbox:offset
current-sandbox:address:address:editor-data/deref<span class="Special"> <- </span>new-editor initial-sandbox-contents:address:array:character, screen:address, new-left:number, width:number
screen:address<span class="Special"> <- </span>render-all screen:address, result:address:programming-environment-data
<span class="muControl">reply</span> result:address:programming-environment-data
]
<span class="muScenario">scenario</span> editor-initially-prints-string-to-screen [
assume-screen <span class="Constant">10:literal/width</span>, <span class="Constant">5:literal/height</span>
run [
1:address:array:character<span class="Special"> <- </span>new <span class="Constant">[abc]</span>
new-editor 1:address:array:character, screen:address, <span class="Constant">0:literal/left</span>, <span class="Constant">10:literal/right</span>
]
screen-should-contain [
<span class="Constant"> . .</span>
<span class="Constant"> .abc .</span>
<span class="Constant"> . .</span>
]
]
<span class="SalientComment">## In which we introduce the editor data structure, and show how it displays</span>
<span class="SalientComment">## text to the screen.</span>
container editor-data [
<span class="Comment"># editable text: doubly linked list of characters (head contains a special sentinel)</span>
data:address:duplex-list
<span class="Comment"># location before cursor inside data</span>
before-cursor:address:duplex-list
<span class="Comment"># raw bounds of display area on screen</span>
<span class="Comment"># always displays from row 1 and at most until bottom of screen</span>
left:number
right:number
<span class="Comment"># raw screen coordinates of cursor</span>
cursor-row:number
cursor-column:number
]
<span class="Comment"># editor:address, screen:address <- new-editor s:address:array:character, screen:address, left:number, right:number</span>
<span class="Comment"># creates a new editor widget and renders its initial appearance to screen.</span>
<span class="Comment"># top/left/right constrain the screen area available to the new editor.</span>
<span class="Comment"># right is exclusive.</span>
<span class="muRecipe">recipe</span> new-editor [
<span class="Constant">local-scope</span>
s:address:array:character<span class="Special"> <- </span><span class="Constant">next-ingredient</span>
screen:address<span class="Special"> <- </span><span class="Constant">next-ingredient</span>
<span class="Comment"># no clipping of bounds</span>
left:number<span class="Special"> <- </span><span class="Constant">next-ingredient</span>
right:number<span class="Special"> <- </span><span class="Constant">next-ingredient</span>
right:number<span class="Special"> <- </span>subtract right:number, <span class="Constant">1:literal</span>
result:address:editor-data<span class="Special"> <- </span>new editor-data:type
<span class="Comment"># initialize screen-related fields</span>
x:address:number<span class="Special"> <- </span>get-address result:address:editor-data/deref, left:offset
x:address:number/deref<span class="Special"> <- </span>copy left:number
x:address:number<span class="Special"> <- </span>get-address result:address:editor-data/deref, right:offset
x:address:number/deref<span class="Special"> <- </span>copy right:number
<span class="Comment"># initialize cursor</span>
x:address:number<span class="Special"> <- </span>get-address result:address:editor-data/deref, cursor-row:offset
x:address:number/deref<span class="Special"> <- </span>copy <span class="Constant">1:literal/top</span>
x:address:number<span class="Special"> <- </span>get-address result:address:editor-data/deref, cursor-column:offset
x:address:number/deref<span class="Special"> <- </span>copy left:number
init:address:address:duplex-list<span class="Special"> <- </span>get-address result:address:editor-data/deref, data:offset
init:address:address:duplex-list/deref<span class="Special"> <- </span>push-duplex <span class="Constant">167:literal/§</span>, <span class="Constant">0:literal/tail</span>
y:address:address:duplex-list<span class="Special"> <- </span>get-address result:address:editor-data/deref, before-cursor:offset
y:address:address:duplex-list/deref<span class="Special"> <- </span>copy init:address:address:duplex-list/deref
<span class="Comment"># early exit if s is empty</span>
<span class="muControl">reply-unless</span> s:address:array:character, result:address:editor-data
len:number<span class="Special"> <- </span>length s:address:array:character/deref
<span class="muControl">reply-unless</span> len:number, result:address:editor-data
idx:number<span class="Special"> <- </span>copy <span class="Constant">0:literal</span>
<span class="Comment"># now we can start appending the rest, character by character</span>
curr:address:duplex-list<span class="Special"> <- </span>copy init:address:address:duplex-list/deref
<span class="Delimiter">{</span>
done?:boolean<span class="Special"> <- </span>greater-or-equal idx:number, len:number
<span class="muControl">break-if</span> done?:boolean
c:character<span class="Special"> <- </span>index s:address:array:character/deref, idx:number
insert-duplex c:character, curr:address:duplex-list
<span class="Comment"># next iter</span>
curr:address:duplex-list<span class="Special"> <- </span>next-duplex curr:address:duplex-list
idx:number<span class="Special"> <- </span>add idx:number, <span class="Constant">1:literal</span>
<span class="muControl">loop</span>
<span class="Delimiter">}</span>
<span class="Comment"># initialize cursor to top of screen</span>
y:address:address:duplex-list<span class="Special"> <- </span>get-address result:address:editor-data/deref, before-cursor:offset
y:address:address:duplex-list/deref<span class="Special"> <- </span>copy init:address:address:duplex-list/deref
<span class="Comment"># initial render to screen, just for some old tests</span>
_, screen:address<span class="Special"> <- </span>render screen:address, result:address:editor-data
<span class="muControl">reply</span> result:address:editor-data
]
<span class="muScenario">scenario</span> editor-initializes-without-data [
assume-screen <span class="Constant">5:literal/width</span>, <span class="Constant">3:literal/height</span>
run [
1:address:editor-data<span class="Special"> <- </span>new-editor <span class="Constant">0:literal/data</span>, screen:address, <span class="Constant">2:literal/left</span>, <span class="Constant">5:literal/right</span>
2:editor-data<span class="Special"> <- </span>copy 1:address:editor-data/deref
]
memory-should-contain [
<span class="Comment"># 2 (data) <- just the § sentinel</span>
<span class="Comment"># 3 (before cursor) <- the § sentinel</span>
4<span class="Special"> <- </span>2 <span class="Comment"># left</span>
5<span class="Special"> <- </span>4 <span class="Comment"># right (inclusive)</span>
6<span class="Special"> <- </span>1 <span class="Comment"># cursor row</span>
7<span class="Special"> <- </span>2 <span class="Comment"># cursor column</span>
]
screen-should-contain [
<span class="Constant"> . .</span>
<span class="Constant"> . .</span>
<span class="Constant"> . .</span>
]
]
<span class="Comment"># bottom:number, screen:address <- render screen:address, editor:address:editor-data</span>
<span class="muRecipe">recipe</span> render [
<span class="Constant">local-scope</span>
screen:address<span class="Special"> <- </span><span class="Constant">next-ingredient</span>
editor:address:editor-data<span class="Special"> <- </span><span class="Constant">next-ingredient</span>
<span class="muControl">reply-unless</span> editor:address:editor-data, <span class="Constant">1:literal/top</span>, screen:address/same-as-ingredient:0
left:number<span class="Special"> <- </span>get editor:address:editor-data/deref, left:offset
screen-height:number<span class="Special"> <- </span>screen-height screen:address
right:number<span class="Special"> <- </span>get editor:address:editor-data/deref, right:offset
hide-screen screen:address
<span class="Comment"># highlight mu code with color</span>
color:number<span class="Special"> <- </span>copy <span class="Constant">7:literal/white</span>
highlighting-state:number<span class="Special"> <- </span>copy <span class="Constant">0:literal/normal</span>
<span class="Comment"># traversing editor</span>
curr:address:duplex-list<span class="Special"> <- </span>get editor:address:editor-data/deref, data:offset
prev:address:duplex-list<span class="Special"> <- </span>copy curr:address:duplex-list
curr:address:duplex-list<span class="Special"> <- </span>next-duplex curr:address:duplex-list
<span class="Comment"># traversing screen</span>
row:number<span class="Special"> <- </span>copy <span class="Constant">1:literal/top</span>
column:number<span class="Special"> <- </span>copy left:number
cursor-row:address:number<span class="Special"> <- </span>get-address editor:address:editor-data/deref, cursor-row:offset
cursor-column:address:number<span class="Special"> <- </span>get-address editor:address:editor-data/deref, cursor-column:offset
before-cursor:address:address:duplex-list<span class="Special"> <- </span>get-address editor:address:editor-data/deref, before-cursor:offset
move-cursor screen:address, row:number, column:number
<span class="Delimiter">{</span>
<span class="Constant"> +next-character</span>
<span class="muControl">break-unless</span> curr:address:duplex-list
off-screen?:boolean<span class="Special"> <- </span>greater-or-equal row:number, screen-height:number
<span class="muControl">break-if</span> off-screen?:boolean
<span class="Comment"># update editor-data.before-cursor</span>
<span class="Comment"># Doing so at the start of each iteration ensures it stays one step behind</span>
<span class="Comment"># the current character.</span>
<span class="Delimiter">{</span>
at-cursor-row?:boolean<span class="Special"> <- </span>equal row:number, cursor-row:address:number/deref
<span class="muControl">break-unless</span> at-cursor-row?:boolean
at-cursor?:boolean<span class="Special"> <- </span>equal column:number, cursor-column:address:number/deref
<span class="muControl">break-unless</span> at-cursor?:boolean
before-cursor:address:address:duplex-list/deref<span class="Special"> <- </span>prev-duplex curr:address:duplex-list
<span class="Delimiter">}</span>
c:character<span class="Special"> <- </span>get curr:address:duplex-list/deref, value:offset
color:number, highlighting-state:number<span class="Special"> <- </span>get-color color:number, highlighting-state:number, c:character
<span class="Delimiter">{</span>
<span class="Comment"># newline? move to left rather than 0</span>
newline?:boolean<span class="Special"> <- </span>equal c:character, <span class="Constant">10:literal/newline</span>
<span class="muControl">break-unless</span> newline?:boolean
<span class="Comment"># adjust cursor if necessary</span>
<span class="Delimiter">{</span>
at-cursor-row?:boolean<span class="Special"> <- </span>equal row:number, cursor-row:address:number/deref
<span class="muControl">break-unless</span> at-cursor-row?:boolean
left-of-cursor?:boolean<span class="Special"> <- </span>lesser-than column:number, cursor-column:address:number/deref
<span class="muControl">break-unless</span> left-of-cursor?:boolean
cursor-column:address:number/deref<span class="Special"> <- </span>copy column:number
before-cursor:address:address:duplex-list/deref<span class="Special"> <- </span>prev-duplex curr:address:duplex-list
<span class="Delimiter">}</span>
<span class="Comment"># clear rest of line in this window</span>
clear-line-delimited screen:address, column:number, right:number
<span class="Comment"># skip to next line</span>
row:number<span class="Special"> <- </span>add row:number, <span class="Constant">1:literal</span>
column:number<span class="Special"> <- </span>copy left:number
move-cursor screen:address, row:number, column:number
curr:address:duplex-list<span class="Special"> <- </span>next-duplex curr:address:duplex-list
prev:address:duplex-list<span class="Special"> <- </span>next-duplex prev:address:duplex-list
<span class="muControl">loop</span> <span class="Constant">+next-character:label</span>
<span class="Delimiter">}</span>
<span class="Delimiter">{</span>
<span class="Comment"># at right? wrap. even if there's only one more letter left; we need</span>
<span class="Comment"># room for clicking on the cursor after it.</span>
at-right?:boolean<span class="Special"> <- </span>equal column:number, right:number
<span class="muControl">break-unless</span> at-right?:boolean
<span class="Comment"># print wrap icon</span>
print-character screen:address, <span class="Constant">8617:literal/loop-back-to-left</span>, <span class="Constant">245:literal/grey</span>
column:number<span class="Special"> <- </span>copy left:number
row:number<span class="Special"> <- </span>add row:number, <span class="Constant">1:literal</span>
move-cursor screen:address, row:number, column:number
<span class="Comment"># don't increment curr</span>
<span class="muControl">loop</span> <span class="Constant">+next-character:label</span>
<span class="Delimiter">}</span>
print-character screen:address, c:character, color:number
curr:address:duplex-list<span class="Special"> <- </span>next-duplex curr:address:duplex-list
prev:address:duplex-list<span class="Special"> <- </span>next-duplex prev:address:duplex-list
column:number<span class="Special"> <- </span>add column:number, <span class="Constant">1:literal</span>
<span class="muControl">loop</span>
<span class="Delimiter">}</span>
<span class="Comment"># is cursor to the right of the last line? move to end</span>
<span class="Delimiter">{</span>
at-cursor-row?:boolean<span class="Special"> <- </span>equal row:number, cursor-row:address:number/deref
cursor-outside-line?:boolean<span class="Special"> <- </span>lesser-or-equal column:number, cursor-column:address:number/deref
before-cursor-on-same-line?:boolean<span class="Special"> <- </span>and at-cursor-row?:boolean, cursor-outside-line?:boolean
above-cursor-row?:boolean<span class="Special"> <- </span>lesser-than row:number, cursor-row:address:number/deref
before-cursor?:boolean<span class="Special"> <- </span>or before-cursor-on-same-line?:boolean, above-cursor-row?:boolean
<span class="muControl">break-unless</span> before-cursor?:boolean
cursor-row:address:number/deref<span class="Special"> <- </span>copy row:number
cursor-column:address:number/deref<span class="Special"> <- </span>copy column:number
<span class="Comment"># line not wrapped but cursor outside bounds? wrap cursor</span>
<span class="Delimiter">{</span>
too-far-right?:boolean<span class="Special"> <- </span>greater-than cursor-column:address:number/deref, right:number
<span class="muControl">break-unless</span> too-far-right?:boolean
cursor-column:address:number/deref<span class="Special"> <- </span>copy left:number
cursor-row:address:number/deref<span class="Special"> <- </span>add cursor-row:address:number/deref, <span class="Constant">1:literal</span>
above-screen-bottom?:boolean<span class="Special"> <- </span>lesser-than cursor-row:address:number/deref, screen-height:number
assert above-screen-bottom?:boolean, <span class="Constant">[unimplemented: wrapping cursor past bottom of screen]</span>
<span class="Delimiter">}</span>
before-cursor:address:address:duplex-list/deref<span class="Special"> <- </span>copy prev:address:duplex-list
<span class="Delimiter">}</span>
<span class="Comment"># clear rest of current line</span>
clear-line-delimited screen:address, column:number, right:number
<span class="muControl">reply</span> row:number, screen:address/same-as-ingredient:0
]
<span class="Comment"># row:number, screen:address <- render-string screen:address, s:address:array:character, left:number, right:number, color:number, row:number</span>
<span class="Comment"># move cursor at start of next line</span>
<span class="Comment"># print a string 's' to 'editor' in 'color' starting at 'row'</span>
<span class="Comment"># clear rest of last line, but don't move cursor to next line</span>
<span class="muRecipe">recipe</span> render-string [
<span class="Constant">local-scope</span>
screen:address<span class="Special"> <- </span><span class="Constant">next-ingredient</span>
s:address:array:character<span class="Special"> <- </span><span class="Constant">next-ingredient</span>
left:number<span class="Special"> <- </span><span class="Constant">next-ingredient</span>
right:number<span class="Special"> <- </span><span class="Constant">next-ingredient</span>
color:number<span class="Special"> <- </span><span class="Constant">next-ingredient</span>
row:number<span class="Special"> <- </span><span class="Constant">next-ingredient</span>
row:number<span class="Special"> <- </span>add row:number, <span class="Constant">1:literal</span>
<span class="muControl">reply-unless</span> s:address:array:character, row:number/same-as-ingredient:5, screen:address/same-as-ingredient:0
column:number<span class="Special"> <- </span>copy left:number
move-cursor screen:address, row:number, column:number
screen-height:number<span class="Special"> <- </span>screen-height screen:address
i:number<span class="Special"> <- </span>copy <span class="Constant">0:literal</span>
len:number<span class="Special"> <- </span>length s:address:array:character/deref
<span class="Delimiter">{</span>
<span class="Constant"> +next-character</span>
done?:boolean<span class="Special"> <- </span>greater-or-equal i:number, len:number
<span class="muControl">break-if</span> done?:boolean
done?:boolean<span class="Special"> <- </span>greater-or-equal row:number, screen-height:number
<span class="muControl">break-if</span> done?:boolean
c:character<span class="Special"> <- </span>index s:address:array:character/deref, i:number
<span class="Delimiter">{</span>
<span class="Comment"># at right? wrap.</span>
at-right?:boolean<span class="Special"> <- </span>equal column:number, right:number
<span class="muControl">break-unless</span> at-right?:boolean
<span class="Comment"># print wrap icon</span>
print-character screen:address, <span class="Constant">8617:literal/loop-back-to-left</span>, <span class="Constant">245:literal/grey</span>
column:number<span class="Special"> <- </span>copy left:number
row:number<span class="Special"> <- </span>add row:number, <span class="Constant">1:literal</span>
move-cursor screen:address, row:number, column:number
<span class="muControl">loop</span> <span class="Constant">+next-character:label</span> <span class="Comment"># retry i</span>
<span class="Delimiter">}</span>
i:number<span class="Special"> <- </span>add i:number, <span class="Constant">1:literal</span>
<span class="Delimiter">{</span>
<span class="Comment"># newline? move to left rather than 0</span>
newline?:boolean<span class="Special"> <- </span>equal c:character, <span class="Constant">10:literal/newline</span>
<span class="muControl">break-unless</span> newline?:boolean
<span class="Comment"># clear rest of line in this window</span>
<span class="Delimiter">{</span>
done?:boolean<span class="Special"> <- </span>greater-than column:number, right:number
<span class="muControl">break-if</span> done?:boolean
print-character screen:address, <span class="Constant">32:literal/space</span>
column:number<span class="Special"> <- </span>add column:number, <span class="Constant">1:literal</span>
<span class="muControl">loop</span>
<span class="Delimiter">}</span>
row:number<span class="Special"> <- </span>add row:number, <span class="Constant">1:literal</span>
column:number<span class="Special"> <- </span>copy left:number
move-cursor screen:address, row:number, column:number
<span class="muControl">loop</span> <span class="Constant">+next-character:label</span>
<span class="Delimiter">}</span>
print-character screen:address, c:character, color:number
column:number<span class="Special"> <- </span>add column:number, <span class="Constant">1:literal</span>
<span class="muControl">loop</span>
<span class="Delimiter">}</span>
<span class="Delimiter">{</span>
<span class="Comment"># clear rest of current line</span>
line-done?:boolean<span class="Special"> <- </span>greater-than column:number, right:number
<span class="muControl">break-if</span> line-done?:boolean
print-character screen:address, <span class="Constant">32:literal/space</span>
column:number<span class="Special"> <- </span>add column:number, <span class="Constant">1:literal</span>
<span class="muControl">loop</span>
<span class="Delimiter">}</span>
<span class="muControl">reply</span> row:number/same-as-ingredient:5, screen:address/same-as-ingredient:0
]
<span class="Comment"># row:number, screen:address <- render-screen screen:address, sandbox-screen:address, left:number, right:number, row:number</span>
<span class="Comment"># print the fake sandbox screen to 'screen' with appropriate delimiters</span>
<span class="Comment"># leave cursor at start of next line</span>
<span class="muRecipe">recipe</span> render-screen [
<span class="Constant">local-scope</span>
screen:address<span class="Special"> <- </span><span class="Constant">next-ingredient</span>
s:address:screen<span class="Special"> <- </span><span class="Constant">next-ingredient</span>
left:number<span class="Special"> <- </span><span class="Constant">next-ingredient</span>
right:number<span class="Special"> <- </span><span class="Constant">next-ingredient</span>
row:number<span class="Special"> <- </span><span class="Constant">next-ingredient</span>
row:number<span class="Special"> <- </span>add row:number, <span class="Constant">1:literal</span>
<span class="muControl">reply-unless</span> s:address:screen, row:number/same-as-ingredient:4, screen:address/same-as-ingredient:0
<span class="Comment"># print 'screen:'</span>
header:address:array:character<span class="Special"> <- </span>new <span class="Constant">[screen:]</span>
row:number<span class="Special"> <- </span>subtract row:number, <span class="Constant">1:literal</span> <span class="Comment"># compensate for render-string below</span>
row:number<span class="Special"> <- </span>render-string screen:address, header:address:array:character, left:number, right:number, <span class="Constant">245:literal/grey</span>, row:number
<span class="Comment"># newline</span>
row:number<span class="Special"> <- </span>add row:number, <span class="Constant">1:literal</span>
move-cursor screen:address, row:number, left:number
<span class="Comment"># start printing s</span>
column:number<span class="Special"> <- </span>copy left:number
s-width:number<span class="Special"> <- </span>screen-width s:address:screen
s-height:number<span class="Special"> <- </span>screen-height s:address:screen
buf:address:array:screen-cell<span class="Special"> <- </span>get s:address:screen/deref, data:offset
stop-printing:number<span class="Special"> <- </span>add left:number, s-width:number, <span class="Constant">3:literal</span>
max-column:number<span class="Special"> <- </span>min stop-printing:number, right:number
i:number<span class="Special"> <- </span>copy <span class="Constant">0:literal</span>
len:number<span class="Special"> <- </span>length buf:address:array:screen-cell/deref
screen-height:number<span class="Special"> <- </span>screen-height screen:address
<span class="Delimiter">{</span>
done?:boolean<span class="Special"> <- </span>greater-or-equal i:number, len:number
<span class="muControl">break-if</span> done?:boolean
done?:boolean<span class="Special"> <- </span>greater-or-equal row:number, screen-height:number
<span class="muControl">break-if</span> done?:boolean
column:number<span class="Special"> <- </span>copy left:number
move-cursor screen:address, row:number, column:number
<span class="Comment"># initial leader for each row: two spaces and a '.'</span>
print-character screen:address, <span class="Constant">32:literal/space</span>, <span class="Constant">245:literal/grey</span>
print-character screen:address, <span class="Constant">32:literal/space</span>, <span class="Constant">245:literal/grey</span>
print-character screen:address, <span class="Constant">46:literal/full-stop</span>, <span class="Constant">245:literal/grey</span>
column:number<span class="Special"> <- </span>add left:number, <span class="Constant">3:literal</span>
<span class="Delimiter">{</span>
<span class="Comment"># print row</span>
row-done?:boolean<span class="Special"> <- </span>greater-or-equal column:number, max-column:number
<span class="muControl">break-if</span> row-done?:boolean
curr:screen-cell<span class="Special"> <- </span>index buf:address:array:screen-cell/deref, i:number
c:character<span class="Special"> <- </span>get curr:screen-cell, contents:offset
print-character screen:address, c:character, <span class="Constant">245:literal/grey</span>
column:number<span class="Special"> <- </span>add column:number, <span class="Constant">1:literal</span>
i:number<span class="Special"> <- </span>add i:number, <span class="Constant">1:literal</span>
<span class="muControl">loop</span>
<span class="Delimiter">}</span>
<span class="Comment"># print final '.'</span>
print-character screen:address, <span class="Constant">46:literal/full-stop</span>, <span class="Constant">245:literal/grey</span>
column:number<span class="Special"> <- </span>add column:number, <span class="Constant">1:literal</span>
<span class="Delimiter">{</span>
<span class="Comment"># clear rest of current line</span>
line-done?:boolean<span class="Special"> <- </span>greater-than column:number, right:number
<span class="muControl">break-if</span> line-done?:boolean
print-character screen:address, <span class="Constant">32:literal/space</span>
column:number<span class="Special"> <- </span>add column:number, <span class="Constant">1:literal</span>
<span class="muControl">loop</span>
<span class="Delimiter">}</span>
row:number<span class="Special"> <- </span>add row:number, <span class="Constant">1:literal</span>
<span class="muControl">loop</span>
<span class="Delimiter">}</span>
<span class="muControl">reply</span> row:number/same-as-ingredient:4, screen:address/same-as-ingredient:0
]
<span class="muRecipe">recipe</span> clear-line-delimited [
<span class="Constant">local-scope</span>
screen:address<span class="Special"> <- </span><span class="Constant">next-ingredient</span>
left:number<span class="Special"> <- </span><span class="Constant">next-ingredient</span>
right:number<span class="Special"> <- </span><span class="Constant">next-ingredient</span>
column:number<span class="Special"> <- </span>copy left:number
<span class="Delimiter">{</span>
done?:boolean<span class="Special"> <- </span>greater-than column:number, right:number
<span class="muControl">break-if</span> done?:boolean
print-character screen:address, <span class="Constant">32:literal/space</span>
column:number<span class="Special"> <- </span>add column:number, <span class="Constant">1:literal</span>
<span class="muControl">loop</span>
<span class="Delimiter">}</span>
]
<span class="muScenario">scenario</span> editor-initially-prints-multiple-lines [
assume-screen <span class="Constant">5:literal/width</span>, <span class="Constant">5:literal/height</span>
run [
s:address:array:character<span class="Special"> <- </span>new <span class="Constant">[abc</span>
<span class="Constant">def]</span>
new-editor s:address:array:character, screen:address, <span class="Constant">0:literal/left</span>, <span class="Constant">5:literal/right</span>
]
screen-should-contain [
<span class="Constant"> . .</span>
<span class="Constant"> .abc .</span>
<span class="Constant"> .def .</span>
<span class="Constant"> . .</span>
]
]
<span class="muScenario">scenario</span> editor-initially-handles-offsets [
assume-screen <span class="Constant">5:literal/width</span>, <span class="Constant">5:literal/height</span>
run [
s:address:array:character<span class="Special"> <- </span>new <span class="Constant">[abc]</span>
new-editor s:address:array:character, screen:address, <span class="Constant">1:literal/left</span>, <span class="Constant">5:literal/right</span>
]
screen-should-contain [
<span class="Constant"> . .</span>
<span class="Constant"> . abc .</span>
<span class="Constant"> . .</span>
]
]
<span class="muScenario">scenario</span> editor-initially-prints-multiple-lines-at-offset [
assume-screen <span class="Constant">5:literal/width</span>, <span class="Constant">5:literal/height</span>
run [
s:address:array:character<span class="Special"> <- </span>new <span class="Constant">[abc</span>
<span class="Constant">def]</span>
new-editor s:address:array:character, screen:address, <span class="Constant">1:literal/left</span>, <span class="Constant">5:literal/right</span>
]
screen-should-contain [
<span class="Constant"> . .</span>
<span class="Constant"> . abc .</span>
<span class="Constant"> . def .</span>
<span class="Constant"> . .</span>
]
]
<span class="muScenario">scenario</span> editor-initially-wraps-long-lines [
assume-screen <span class="Constant">5:literal/width</span>, <span class="Constant">5:literal/height</span>
run [
s:address:array:character<span class="Special"> <- </span>new <span class="Constant">[abc def]</span>
new-editor s:address:array:character, screen:address, <span class="Constant">0:literal/left</span>, <span class="Constant">5:literal/right</span>
]
screen-should-contain [
<span class="Constant"> . .</span>
<span class="Constant"> .abc ↩.</span>
<span class="Constant"> .def .</span>
<span class="Constant"> . .</span>
]
screen-should-contain-in-color <span class="Constant">245:literal/grey</span> [
<span class="Constant"> . .</span>
<span class="Constant"> . ↩.</span>
<span class="Constant"> . .</span>
<span class="Constant"> . .</span>
]
]
<span class="muScenario">scenario</span> editor-initially-wraps-barely-long-lines [
assume-screen <span class="Constant">5:literal/width</span>, <span class="Constant">5:literal/height</span>
run [
s:address:array:character<span class="Special"> <- </span>new <span class="Constant">[abcde]</span>
new-editor s:address:array:character, screen:address, <span class="Constant">0:literal/left</span>, <span class="Constant">5:literal/right</span>
]
<span class="Comment"># still wrap, even though the line would fit. We need room to click on the</span>
<span class="Comment"># end of the line</span>
screen-should-contain [
<span class="Constant"> . .</span>
<span class="Constant"> .abcd↩.</span>
<span class="Constant"> .e .</span>
<span class="Constant"> . .</span>
]
screen-should-contain-in-color <span class="Constant">245:literal/grey</span> [
<span class="Constant"> . .</span>
<span class="Constant"> . ↩.</span>
<span class="Constant"> . .</span>
<span class="Constant"> . .</span>
]
]
<span class="muScenario">scenario</span> editor-initializes-empty-text [
assume-screen <span class="Constant">5:literal/width</span>, <span class="Constant">5:literal/height</span>
run [
1:address:array:character<span class="Special"> <- </span>new <span class="Constant">[]</span>
2:address:editor-data<span class="Special"> <- </span>new-editor 1:address:array:character, screen:address, <span class="Constant">0:literal/left</span>, <span class="Constant">5:literal/right</span>
3:number<span class="Special"> <- </span>get 2:address:editor-data/deref, cursor-row:offset
4:number<span class="Special"> <- </span>get 2:address:editor-data/deref, cursor-column:offset
]
screen-should-contain [
<span class="Constant"> . .</span>
<span class="Constant"> . .</span>
<span class="Constant"> . .</span>
]
memory-should-contain [
3<span class="Special"> <- </span>1 <span class="Comment"># cursor row</span>
4<span class="Special"> <- </span>0 <span class="Comment"># cursor column</span>
]
]
<span class="SalientComment">## highlighting mu code</span>
<span class="muScenario">scenario</span> render-colors-comments [
assume-screen <span class="Constant">5:literal/width</span>, <span class="Constant">5:literal/height</span>
run [
s:address:array:character<span class="Special"> <- </span>new <span class="Constant">[abc</span>
<span class="Constant"># de</span>
<span class="Constant">f]</span>
new-editor s:address:array:character, screen:address, <span class="Constant">0:literal/left</span>, <span class="Constant">5:literal/right</span>
]
screen-should-contain [
<span class="Constant"> . .</span>
<span class="Constant"> .abc .</span>
<span class="Constant"> .# de .</span>
<span class="Constant"> .f .</span>
<span class="Constant"> . .</span>
]
screen-should-contain-in-color <span class="Constant">12:literal/lightblue</span>, [
<span class="Constant"> . .</span>
<span class="Constant"> . .</span>
<span class="Constant"> .# de .</span>
<span class="Constant"> . .</span>
<span class="Constant"> . .</span>
]
screen-should-contain-in-color <span class="Constant">7:literal/white</span>, [
<span class="Constant"> . .</span>
<span class="Constant"> .abc .</span>
<span class="Constant"> . .</span>
<span class="Constant"> .f .</span>
<span class="Constant"> . .</span>
]
]
<span class="Comment"># color:number, highlighting-state:number <- get-color color:number, highlighting-state:number, c:character</span>
<span class="muRecipe">recipe</span> get-color [
<span class="Constant">local-scope</span>
color:number<span class="Special"> <- </span><span class="Constant">next-ingredient</span>
highlighting-state:number<span class="Special"> <- </span><span class="Constant">next-ingredient</span>
c:character<span class="Special"> <- </span><span class="Constant">next-ingredient</span>
color-is-white?:boolean<span class="Special"> <- </span>equal color:number, <span class="Constant">7:literal/white</span>
<span class="CommentedCode">#? $print [character: ], c:character, 10:literal/newline #? 1</span>
<span class="Comment"># if color is white and next character is '#', switch color to blue</span>
<span class="Delimiter">{</span>
<span class="muControl">break-unless</span> color-is-white?:boolean
starting-comment?:boolean<span class="Special"> <- </span>equal c:character, <span class="Constant">35:literal/#</span>
<span class="muControl">break-unless</span> starting-comment?:boolean
<span class="CommentedCode">#? $print [switch color back to blue], 10:literal/newline #? 1</span>
color:number<span class="Special"> <- </span>copy <span class="Constant">12:literal/lightblue</span>
<span class="muControl">jump</span> <span class="Constant">+exit:label</span>
<span class="Delimiter">}</span>
<span class="Comment"># if color is blue and next character is newline, switch color to white</span>
<span class="Delimiter">{</span>
color-is-blue?:boolean<span class="Special"> <- </span>equal color:number, <span class="Constant">12:literal/lightblue</span>
<span class="muControl">break-unless</span> color-is-blue?:boolean
ending-comment?:boolean<span class="Special"> <- </span>equal c:character, <span class="Constant">10:literal/newline</span>
<span class="muControl">break-unless</span> ending-comment?:boolean
<span class="CommentedCode">#? $print [switch color back to white], 10:literal/newline #? 1</span>
color:number<span class="Special"> <- </span>copy <span class="Constant">7:literal/white</span>
<span class="muControl">jump</span> <span class="Constant">+exit:label</span>
<span class="Delimiter">}</span>
<span class="Comment"># if color is white (no comments) and next character is '<', switch color to red</span>
<span class="Delimiter">{</span>
<span class="muControl">break-unless</span> color-is-white?:boolean
starting-assignment?:boolean<span class="Special"> <- </span>equal c:character, <span class="Constant">60:literal/<</span>
<span class="muControl">break-unless</span> starting-assignment?:boolean
color:number<span class="Special"> <- </span>copy <span class="Constant">1:literal/red</span>
<span class="muControl">jump</span> <span class="Constant">+exit:label</span>
<span class="Delimiter">}</span>
<span class="Comment"># if color is red and next character is space, switch color to white</span>
<span class="Delimiter">{</span>
color-is-red?:boolean<span class="Special"> <- </span>equal color:number, <span class="Constant">1:literal/red</span>
<span class="muControl">break-unless</span> color-is-red?:boolean
ending-assignment?:boolean<span class="Special"> <- </span>equal c:character, <span class="Constant">32:literal/space</span>
<span class="muControl">break-unless</span> ending-assignment?:boolean
color:number<span class="Special"> <- </span>copy <span class="Constant">7:literal/white</span>
<span class="muControl">jump</span> <span class="Constant">+exit:label</span>
<span class="Delimiter">}</span>
<span class="Comment"># otherwise no change</span>
<span class="Constant"> +exit</span>
<span class="muControl">reply</span> color:number, highlighting-state:number
]
<span class="muScenario">scenario</span> render-colors-assignment [
assume-screen <span class="Constant">8:literal/width</span>, <span class="Constant">5:literal/height</span>
run [
s:address:array:character<span class="Special"> <- </span>new <span class="Constant">[abc</span>
<span class="Constant">d <- e</span>
<span class="Constant">f]</span>
new-editor s:address:array:character, screen:address, <span class="Constant">0:literal/left</span>, <span class="Constant">8:literal/right</span>
]
screen-should-contain [
<span class="Constant"> . .</span>
<span class="Constant"> .abc .</span>
<span class="Constant"> .d <- e .</span>
<span class="Constant"> .f .</span>
<span class="Constant"> . .</span>
]
screen-should-contain-in-color <span class="Constant">1:literal/red</span>, [
<span class="Constant"> . .</span>
<span class="Constant"> . .</span>
<span class="Constant"> . <- .</span>
<span class="Constant"> . .</span>
<span class="Constant"> . .</span>
]
]
<span class="SalientComment">## handling events from the keyboard, mouse, touch screen, ...</span>
<span class="muRecipe">recipe</span> event-loop [
<span class="Constant">local-scope</span>
screen:address<span class="Special"> <- </span><span class="Constant">next-ingredient</span>
console:address<span class="Special"> <- </span><span class="Constant">next-ingredient</span>
env:address:programming-environment-data<span class="Special"> <- </span><span class="Constant">next-ingredient</span>
recipes:address:editor-data<span class="Special"> <- </span>get env:address:programming-environment-data/deref, recipes:offset
current-sandbox:address:editor-data<span class="Special"> <- </span>get env:address:programming-environment-data/deref, current-sandbox:offset
sandbox-in-focus?:address:boolean<span class="Special"> <- </span>get-address env:address:programming-environment-data/deref, sandbox-in-focus?:offset
<span class="Delimiter">{</span>
<span class="Comment"># looping over each (keyboard or touch) event as it occurs</span>
<span class="Constant"> +next-event</span>
e:event, console:address, found?:boolean, quit?:boolean<span class="Special"> <- </span>read-event console:address
<span class="muControl">loop-unless</span> found?:boolean
<span class="muControl">break-if</span> quit?:boolean <span class="Comment"># only in tests</span>
trace <span class="Constant">[app]</span>, <span class="Constant">[next-event]</span>
<span class="Comment"># check for global events that will trigger regardless of which editor has focus</span>
<span class="Delimiter">{</span>
k:address:number<span class="Special"> <- </span>maybe-convert e:event, keycode:variant
<span class="muControl">break-unless</span> k:address:number
<span class="Comment"># F10? load all code and run all sandboxes.</span>
<span class="Delimiter">{</span>
do-run?:boolean<span class="Special"> <- </span>equal k:address:number/deref, <span class="Constant">65526:literal/F10</span>
<span class="muControl">break-unless</span> do-run?:boolean
run-sandboxes env:address:programming-environment-data
<span class="Comment"># F10 might update warnings and results on both sides</span>
screen:address<span class="Special"> <- </span>render-all screen:address, env:address:programming-environment-data
update-cursor screen:address, recipes:address:editor-data, current-sandbox:address:editor-data, sandbox-in-focus?:address:boolean/deref
show-screen screen:address
<span class="muControl">loop</span> <span class="Constant">+next-event:label</span>
<span class="Delimiter">}</span>
<span class="Delimiter">}</span>
<span class="Comment"># 'touch' event</span>
<span class="Delimiter">{</span>
t:address:touch-event<span class="Special"> <- </span>maybe-convert e:event, touch:variant
<span class="muControl">break-unless</span> t:address:touch-event
<span class="Comment"># on a sandbox delete icon? process delete</span>
<span class="Delimiter">{</span>
was-delete?:boolean<span class="Special"> <- </span>delete-sandbox t:address:touch-event/deref, env:address:programming-environment-data
<span class="muControl">break-unless</span> was-delete?:boolean
screen:address<span class="Special"> <- </span>render-sandbox-side screen:address, env:address:programming-environment-data, <span class="Constant">1:literal/clear</span>
update-cursor screen:address, recipes:address:editor-data, current-sandbox:address:editor-data, sandbox-in-focus?:address:boolean/deref
<span class="muControl">loop</span> <span class="Constant">+next-event:label</span>
<span class="Delimiter">}</span>
<span class="Comment"># if not, send to both editors</span>
_<span class="Special"> <- </span>move-cursor-in-editor screen:address, recipes:address:editor-data, t:address:touch-event/deref
sandbox-in-focus?:address:boolean/deref<span class="Special"> <- </span>move-cursor-in-editor screen:address, current-sandbox:address:editor-data, t:address:touch-event/deref
<span class="muControl">jump</span> <span class="Constant">+continue:label</span>
<span class="Delimiter">}</span>
<span class="Comment"># if it's not global, send to appropriate editor</span>
<span class="Delimiter">{</span>
<span class="Delimiter">{</span>
<span class="muControl">break-if</span> sandbox-in-focus?:address:boolean/deref
handle-event screen:address, console:address, recipes:address:editor-data, e:event
<span class="Delimiter">}</span>
<span class="Delimiter">{</span>
<span class="muControl">break-unless</span> sandbox-in-focus?:address:boolean/deref
handle-event screen:address, console:address, current-sandbox:address:editor-data, e:event
<span class="Delimiter">}</span>
<span class="Delimiter">}</span>
<span class="Constant"> +continue</span>
<span class="Comment"># if no more events currently left to process, render.</span>
<span class="Comment"># we rely on 'render' to update 'before-cursor' on pointer events, but</span>
<span class="Comment"># they won't usually come fast enough to trigger this.</span>
<span class="Comment"># todo: test this</span>
<span class="Delimiter">{</span>
more-events?:boolean<span class="Special"> <- </span>has-more-events? console:address
<span class="muControl">break-if</span> more-events?:boolean
render-minimal screen:address, env:address:programming-environment-data
<span class="Delimiter">}</span>
<span class="muControl">loop</span>
<span class="Delimiter">}</span>
]
<span class="Comment"># helper for testing a single editor</span>
<span class="muRecipe">recipe</span> editor-event-loop [
<span class="Constant">local-scope</span>
screen:address<span class="Special"> <- </span><span class="Constant">next-ingredient</span>
console:address<span class="Special"> <- </span><span class="Constant">next-ingredient</span>
editor:address:editor-data<span class="Special"> <- </span><span class="Constant">next-ingredient</span>
<span class="Delimiter">{</span>
<span class="Comment"># looping over each (keyboard or touch) event as it occurs</span>
<span class="Constant"> +next-event</span>
e:event, console:address, found?:boolean, quit?:boolean<span class="Special"> <- </span>read-event console:address
<span class="muControl">loop-unless</span> found?:boolean
<span class="muControl">break-if</span> quit?:boolean <span class="Comment"># only in tests</span>
trace <span class="Constant">[app]</span>, <span class="Constant">[next-event]</span>
<span class="Comment"># 'touch' event - send to both editors</span>
<span class="Delimiter">{</span>
t:address:touch-event<span class="Special"> <- </span>maybe-convert e:event, touch:variant
<span class="muControl">break-unless</span> t:address:touch-event
move-cursor-in-editor screen:address, editor:address:editor-data, t:address:touch-event/deref
<span class="muControl">jump</span> <span class="Constant">+continue:label</span>
<span class="Delimiter">}</span>
<span class="Comment"># other events - send to appropriate editor</span>
handle-event screen:address, console:address, editor:address:editor-data, e:event
<span class="Constant"> +continue</span>
row:number, screen:address<span class="Special"> <- </span>render screen:address, editor:address:editor-data
<span class="Comment"># clear next line, in case we just processed a backspace</span>
left:number<span class="Special"> <- </span>get editor:address:editor-data/deref, left:offset
right:number<span class="Special"> <- </span>get editor:address:editor-data/deref, right:offset
row:number<span class="Special"> <- </span>add row:number, <span class="Constant">1:literal</span>
move-cursor screen:address, row:number, left:number
clear-line-delimited screen:address, left:number, right:number
<span class="muControl">loop</span>
<span class="Delimiter">}</span>
]
<span class="muRecipe">recipe</span> handle-event [
<span class="Constant">local-scope</span>
screen:address<span class="Special"> <- </span><span class="Constant">next-ingredient</span>
console:address<span class="Special"> <- </span><span class="Constant">next-ingredient</span>
editor:address:editor-data<span class="Special"> <- </span><span class="Constant">next-ingredient</span>
e:event<span class="Special"> <- </span><span class="Constant">next-ingredient</span>
<span class="muControl">reply-unless</span> editor:address:editor-data
<span class="Comment"># character</span>
<span class="Delimiter">{</span>
c:address:character<span class="Special"> <- </span>maybe-convert e:event, text:variant
<span class="muControl">break-unless</span> c:address:character
<span class="Comment"># check for special characters</span>
<span class="Comment"># unless it's a backspace</span>
<span class="Delimiter">{</span>
backspace?:boolean<span class="Special"> <- </span>equal c:address:character/deref, <span class="Constant">8:literal/backspace</span>
<span class="muControl">break-unless</span> backspace?:boolean
delete-before-cursor editor:address:editor-data
<span class="muControl">reply</span>
<span class="Delimiter">}</span>
<span class="Comment"># ctrl-a</span>
<span class="Delimiter">{</span>
ctrl-a?:boolean<span class="Special"> <- </span>equal c:address:character/deref, <span class="Constant">1:literal/ctrl-a</span>
<span class="muControl">break-unless</span> ctrl-a?:boolean
move-to-start-of-line editor:address:editor-data
<span class="muControl">reply</span>
<span class="Delimiter">}</span>
<span class="Comment"># ctrl-e</span>
<span class="Delimiter">{</span>
ctrl-e?:boolean<span class="Special"> <- </span>equal c:address:character/deref, <span class="Constant">5:literal/ctrl-e</span>
<span class="muControl">break-unless</span> ctrl-e?:boolean
move-to-end-of-line editor:address:editor-data
<span class="muControl">reply</span>
<span class="Delimiter">}</span>
<span class="Comment"># ctrl-u</span>
<span class="Delimiter">{</span>
ctrl-u?:boolean<span class="Special"> <- </span>equal c:address:character/deref, <span class="Constant">21:literal/ctrl-u</span>
<span class="muControl">break-unless</span> ctrl-u?:boolean
delete-to-start-of-line editor:address:editor-data
<span class="muControl">reply</span>
<span class="Delimiter">}</span>
<span class="Comment"># ctrl-k</span>
<span class="Delimiter">{</span>
ctrl-k?:boolean<span class="Special"> <- </span>equal c:address:character/deref, <span class="Constant">11:literal/ctrl-k</span>
<span class="muControl">break-unless</span> ctrl-k?:boolean
delete-to-end-of-line editor:address:editor-data
<span class="muControl">reply</span>
<span class="Delimiter">}</span>
<span class="Comment"># otherwise type it in</span>
insert-at-cursor editor:address:editor-data, c:address:character/deref, screen:address
<span class="muControl">reply</span>
<span class="Delimiter">}</span>
<span class="Comment"># otherwise it's a special key</span>
k:address:number<span class="Special"> <- </span>maybe-convert e:event, keycode:variant
assert k:address:number, <span class="Constant">[event was of unknown type; neither keyboard nor mouse]</span>
d:address:duplex-list<span class="Special"> <- </span>get editor:address:editor-data/deref, data:offset
before-cursor:address:address:duplex-list<span class="Special"> <- </span>get-address editor:address:editor-data/deref, before-cursor:offset
cursor-row:address:number<span class="Special"> <- </span>get-address editor:address:editor-data/deref, cursor-row:offset
cursor-column:address:number<span class="Special"> <- </span>get-address editor:address:editor-data/deref, cursor-column:offset
screen-height:number<span class="Special"> <- </span>screen-height screen:address
left:number<span class="Special"> <- </span>get editor:address:editor-data/deref, left:offset
right:number<span class="Special"> <- </span>get editor:address:editor-data/deref, right:offset
<span class="Comment"># arrows; update cursor-row and cursor-column, leave before-cursor to 'render'.</span>
<span class="Comment"># right arrow</span>
<span class="Delimiter">{</span>
move-to-next-character?:boolean<span class="Special"> <- </span>equal k:address:number/deref, <span class="Constant">65514:literal/right-arrow</span>
<span class="muControl">break-unless</span> move-to-next-character?:boolean
<span class="Comment"># if not at end of text</span>
old-cursor:address:duplex-list<span class="Special"> <- </span>next-duplex before-cursor:address:address:duplex-list/deref
<span class="muControl">break-unless</span> old-cursor:address:duplex-list
<span class="Comment"># scan to next character</span>
before-cursor:address:address:duplex-list/deref<span class="Special"> <- </span>copy old-cursor:address:duplex-list
<span class="Comment"># if crossed a newline, move cursor to start of next row</span>
<span class="Delimiter">{</span>
old-cursor-character:character<span class="Special"> <- </span>get before-cursor:address:address:duplex-list/deref/deref, value:offset
was-at-newline?:boolean<span class="Special"> <- </span>equal old-cursor-character:character, <span class="Constant">10:literal/newline</span>
<span class="muControl">break-unless</span> was-at-newline?:boolean
cursor-row:address:number/deref<span class="Special"> <- </span>add cursor-row:address:number/deref, <span class="Constant">1:literal</span>
cursor-column:address:number/deref<span class="Special"> <- </span>copy left:number
<span class="Comment"># todo: what happens when cursor is too far down?</span>
screen-height:number<span class="Special"> <- </span>screen-height screen:address
above-screen-bottom?:boolean<span class="Special"> <- </span>lesser-than cursor-row:address:number/deref, screen-height:number
assert above-screen-bottom?:boolean, <span class="Constant">[unimplemented: moving past bottom of screen]</span>
<span class="muControl">reply</span>
<span class="Delimiter">}</span>
<span class="Comment"># if the line wraps, move cursor to start of next row</span>
<span class="Delimiter">{</span>
<span class="Comment"># if we're at the column just before the wrap indicator</span>
wrap-column:number<span class="Special"> <- </span>subtract right:number, <span class="Constant">1:literal</span>
at-wrap?:boolean<span class="Special"> <- </span>equal cursor-column:address:number/deref, wrap-column:number
<span class="muControl">break-unless</span> at-wrap?:boolean
<span class="Comment"># and if next character isn't newline</span>
new-cursor:address:duplex-list<span class="Special"> <- </span>next-duplex old-cursor:address:duplex-list
<span class="muControl">break-unless</span> new-cursor:address:duplex-list
next-character:character<span class="Special"> <- </span>get new-cursor:address:duplex-list/deref, value:offset
newline?:boolean<span class="Special"> <- </span>equal next-character:character, <span class="Constant">10:literal/newline</span>
<span class="muControl">break-if</span> newline?:boolean
cursor-row:address:number/deref<span class="Special"> <- </span>add cursor-row:address:number/deref, <span class="Constant">1:literal</span>
cursor-column:address:number/deref<span class="Special"> <- </span>copy left:number
<span class="Comment"># todo: what happens when cursor is too far down?</span>
above-screen-bottom?:boolean<span class="Special"> <- </span>lesser-than cursor-row:address:number/deref, screen-height:number
assert above-screen-bottom?:boolean, <span class="Constant">[unimplemented: moving past bottom of screen]</span>
<span class="muControl">reply</span>
<span class="Delimiter">}</span>
<span class="Comment"># otherwise move cursor one character right</span>
cursor-column:address:number/deref<span class="Special"> <- </span>add cursor-column:address:number/deref, <span class="Constant">1:literal</span>
<span class="Delimiter">}</span>
<span class="Comment"># left arrow</span>
<span class="Delimiter">{</span>
move-to-previous-character?:boolean<span class="Special"> <- </span>equal k:address:number/deref, <span class="Constant">65515:literal/left-arrow</span>
<span class="muControl">break-unless</span> move-to-previous-character?:boolean
<span class="CommentedCode">#? trace [app], [left arrow] #? 1</span>
<span class="Comment"># if not at start of text (before-cursor at § sentinel)</span>
prev:address:duplex-list<span class="Special"> <- </span>prev-duplex before-cursor:address:address:duplex-list/deref
<span class="muControl">break-unless</span> prev:address:duplex-list
<span class="Comment"># if cursor not at left margin, move one character left</span>
<span class="Delimiter">{</span>
at-left-margin?:boolean<span class="Special"> <- </span>equal cursor-column:address:number/deref, <span class="Constant">0:literal</span>
<span class="muControl">break-if</span> at-left-margin?:boolean
<span class="CommentedCode">#? trace [app], [decrementing] #? 1</span>
cursor-column:address:number/deref<span class="Special"> <- </span>subtract cursor-column:address:number/deref, <span class="Constant">1:literal</span>
<span class="muControl">reply</span>
<span class="Delimiter">}</span>
<span class="Comment"># if at left margin, there's guaranteed to be a previous line, since we're</span>
<span class="Comment"># not at start of text</span>
<span class="Delimiter">{</span>
<span class="Comment"># if before-cursor is at newline, figure out how long the previous line is</span>
prevc:character<span class="Special"> <- </span>get before-cursor:address:address:duplex-list/deref/deref, value:offset
previous-character-is-newline?:boolean<span class="Special"> <- </span>equal prevc:character, <span class="Constant">10:literal/newline</span>
<span class="muControl">break-unless</span> previous-character-is-newline?:boolean
<span class="CommentedCode">#? trace [app], [previous line] #? 1</span>
<span class="Comment"># compute length of previous line</span>
end-of-line:number<span class="Special"> <- </span>previous-line-length before-cursor:address:address:duplex-list/deref, d:address:duplex-list
cursor-row:address:number/deref<span class="Special"> <- </span>subtract cursor-row:address:number/deref, <span class="Constant">1:literal</span>
cursor-column:address:number/deref<span class="Special"> <- </span>copy end-of-line:number
<span class="muControl">reply</span>
<span class="Delimiter">}</span>
<span class="Comment"># if before-cursor is not at newline, we're just at a wrapped line</span>
assert cursor-row:address:number/deref, <span class="Constant">[unimplemented: moving cursor above top of screen]</span>
cursor-row:address:number/deref<span class="Special"> <- </span>subtract cursor-row:address:number/deref, <span class="Constant">1:literal</span>
cursor-column:address:number/deref<span class="Special"> <- </span>subtract right:number, <span class="Constant">1:literal</span> <span class="Comment"># leave room for wrap icon</span>
<span class="Delimiter">}</span>
<span class="Comment"># down arrow</span>
<span class="Delimiter">{</span>
move-to-next-line?:boolean<span class="Special"> <- </span>equal k:address:number/deref, <span class="Constant">65516:literal/down-arrow</span>
<span class="muControl">break-unless</span> move-to-next-line?:boolean
<span class="Comment"># todo: support scrolling</span>
already-at-bottom?:boolean<span class="Special"> <- </span>greater-or-equal cursor-row:address:number/deref, screen-height:number
<span class="muControl">break-if</span> already-at-bottom?:boolean
<span class="CommentedCode">#? $print [moving down</span>
<span class="CommentedCode">#? ] #? 1</span>
cursor-row:address:number/deref<span class="Special"> <- </span>add cursor-row:address:number/deref, <span class="Constant">1:literal</span>
<span class="Comment"># that's it; render will adjust cursor-column as necessary</span>
<span class="Delimiter">}</span>
<span class="Comment"># up arrow</span>
<span class="Delimiter">{</span>
move-to-previous-line?:boolean<span class="Special"> <- </span>equal k:address:number/deref, <span class="Constant">65517:literal/up-arrow</span>
<span class="muControl">break-unless</span> move-to-previous-line?:boolean
<span class="Comment"># todo: support scrolling</span>
already-at-top?:boolean<span class="Special"> <- </span>lesser-or-equal cursor-row:address:number/deref, <span class="Constant">1:literal/top</span>
<span class="muControl">break-if</span> already-at-top?:boolean
<span class="CommentedCode">#? $print [moving up</span>
<span class="CommentedCode">#? ] #? 1</span>
cursor-row:address:number/deref<span class="Special"> <- </span>subtract cursor-row:address:number/deref, <span class="Constant">1:literal</span>
<span class="Comment"># that's it; render will adjust cursor-column as necessary</span>
<span class="Delimiter">}</span>
<span class="Comment"># home</span>
<span class="Delimiter">{</span>
home?:boolean<span class="Special"> <- </span>equal k:address:number/deref, <span class="Constant">65521:literal/home</span>
<span class="muControl">break-unless</span> home?:boolean
move-to-start-of-line editor:address:editor-data
<span class="muControl">reply</span>
<span class="Delimiter">}</span>
<span class="Comment"># end</span>
<span class="Delimiter">{</span>
end?:boolean<span class="Special"> <- </span>equal k:address:number/deref, <span class="Constant">65520:literal/end</span>
<span class="muControl">break-unless</span> end?:boolean
move-to-end-of-line editor:address:editor-data
<span class="muControl">reply</span>
<span class="Delimiter">}</span>
]
<span class="Comment"># process click, return if it was on current editor</span>
<span class="Comment"># todo: ignores menu bar (for now just displays shortcuts)</span>
<span class="muRecipe">recipe</span> move-cursor-in-editor [
<span class="Constant">local-scope</span>
screen:address<span class="Special"> <- </span><span class="Constant">next-ingredient</span>
editor:address:editor-data<span class="Special"> <- </span><span class="Constant">next-ingredient</span>
t:touch-event<span class="Special"> <- </span><span class="Constant">next-ingredient</span>
<span class="muControl">reply-unless</span> editor:address:editor-data, <span class="Constant">0:literal/false</span>
click-column:number<span class="Special"> <- </span>get t:touch-event, column:offset
left:number<span class="Special"> <- </span>get editor:address:editor-data/deref, left:offset
too-far-left?:boolean<span class="Special"> <- </span>lesser-than click-column:number, left:number
<span class="muControl">reply-if</span> too-far-left?:boolean, <span class="Constant">0:literal/false</span>
right:number<span class="Special"> <- </span>get editor:address:editor-data/deref, right:offset
too-far-right?:boolean<span class="Special"> <- </span>greater-than click-column:number, right:number
<span class="muControl">reply-if</span> too-far-right?:boolean, <span class="Constant">0:literal/false</span>
<span class="Comment"># update cursor</span>
cursor-row:address:number<span class="Special"> <- </span>get-address editor:address:editor-data/deref, cursor-row:offset
cursor-row:address:number/deref<span class="Special"> <- </span>get t:touch-event, row:offset
cursor-column:address:number<span class="Special"> <- </span>get-address editor:address:editor-data/deref, cursor-column:offset
cursor-column:address:number/deref<span class="Special"> <- </span>get t:touch-event, column:offset
<span class="Comment"># gain focus</span>
<span class="muControl">reply</span> <span class="Constant">1:literal/true</span>
]
<span class="muRecipe">recipe</span> insert-at-cursor [
<span class="Constant">local-scope</span>
editor:address:editor-data<span class="Special"> <- </span><span class="Constant">next-ingredient</span>
c:character<span class="Special"> <- </span><span class="Constant">next-ingredient</span>
screen:address<span class="Special"> <- </span><span class="Constant">next-ingredient</span>
<span class="CommentedCode">#? $print [insert ], c:character, 10:literal/newline</span>
before-cursor:address:address:duplex-list<span class="Special"> <- </span>get-address editor:address:editor-data/deref, before-cursor:offset
d:address:duplex-list<span class="Special"> <- </span>get editor:address:editor-data/deref, data:offset
insert-duplex c:character, before-cursor:address:address:duplex-list/deref
before-cursor:address:address:duplex-list/deref<span class="Special"> <- </span>next-duplex before-cursor:address:address:duplex-list/deref
cursor-row:address:number<span class="Special"> <- </span>get-address editor:address:editor-data/deref, cursor-row:offset
cursor-column:address:number<span class="Special"> <- </span>get-address editor:address:editor-data/deref, cursor-column:offset
left:number<span class="Special"> <- </span>get editor:address:editor-data/deref, left:offset
right:number<span class="Special"> <- </span>get editor:address:editor-data/deref, right:offset
<span class="Comment"># update cursor: if newline, move cursor to start of next line</span>
<span class="Comment"># todo: bottom of screen</span>
<span class="Delimiter">{</span>
newline?:boolean<span class="Special"> <- </span>equal c:character, <span class="Constant">10:literal/newline</span>
<span class="muControl">break-unless</span> newline?:boolean
cursor-row:address:number/deref<span class="Special"> <- </span>add cursor-row:address:number/deref, <span class="Constant">1:literal</span>
cursor-column:address:number/deref<span class="Special"> <- </span>copy left:number
<span class="muControl">reply</span>
<span class="Delimiter">}</span>
<span class="Comment"># if the line wraps at the cursor, move cursor to start of next row</span>
<span class="Delimiter">{</span>
<span class="Comment"># if we're at the column just before the wrap indicator</span>
wrap-column:number<span class="Special"> <- </span>subtract right:number, <span class="Constant">1:literal</span>
<span class="CommentedCode">#? $print [wrap? ], cursor-column:address:number/deref, [ vs ], wrap-column:number, 10:literal/newline</span>
at-wrap?:boolean<span class="Special"> <- </span>greater-or-equal cursor-column:address:number/deref, wrap-column:number
<span class="muControl">break-unless</span> at-wrap?:boolean
<span class="CommentedCode">#? $print [wrap!</span>
<span class="CommentedCode">#? ] #? 1</span>
cursor-column:address:number/deref<span class="Special"> <- </span>subtract cursor-column:address:number/deref, wrap-column:number
cursor-row:address:number/deref<span class="Special"> <- </span>add cursor-row:address:number/deref, <span class="Constant">1:literal</span>
<span class="Comment"># todo: what happens when cursor is too far down?</span>
screen-height:number<span class="Special"> <- </span>screen-height screen:address
above-screen-bottom?:boolean<span class="Special"> <- </span>lesser-than cursor-row:address:number/deref, screen-height:number
assert above-screen-bottom?:boolean, <span class="Constant">[unimplemented: typing past bottom of screen]</span>
<span class="CommentedCode">#? $print [return</span>
<span class="CommentedCode">#? ] #? 1</span>
<span class="muControl">reply</span>
<span class="Delimiter">}</span>
<span class="Comment"># otherwise move cursor right</span>
cursor-column:address:number/deref<span class="Special"> <- </span>add cursor-column:address:number/deref, <span class="Constant">1:literal</span>
]
<span class="muRecipe">recipe</span> delete-before-cursor [
<span class="Constant">local-scope</span>
editor:address:editor-data<span class="Special"> <- </span><span class="Constant">next-ingredient</span>
before-cursor:address:address:duplex-list<span class="Special"> <- </span>get-address editor:address:editor-data/deref, before-cursor:offset
d:address:duplex-list<span class="Special"> <- </span>get editor:address:editor-data/deref, data:offset
<span class="Comment"># unless already at start</span>
at-start?:boolean<span class="Special"> <- </span>equal before-cursor:address:address:duplex-list/deref, d:address:duplex-list
<span class="muControl">reply-if</span> at-start?:boolean
<span class="Comment"># delete character</span>
prev:address:duplex-list<span class="Special"> <- </span>prev-duplex before-cursor:address:address:duplex-list/deref
remove-duplex before-cursor:address:address:duplex-list/deref
<span class="Comment"># update cursor</span>
before-cursor:address:address:duplex-list/deref<span class="Special"> <- </span>copy prev:address:duplex-list
cursor-column:address:number<span class="Special"> <- </span>get-address editor:address:editor-data/deref, cursor-column:offset
cursor-column:address:number/deref<span class="Special"> <- </span>subtract cursor-column:address:number/deref, <span class="Constant">1:literal</span>
<span class="CommentedCode">#? $print [delete-before-cursor: ], cursor-column:address:number/deref, 10:literal/newline</span>
]
<span class="Comment"># takes a pointer 'curr' into the doubly-linked list and its sentinel, counts</span>
<span class="Comment"># the length of the previous line before the 'curr' pointer.</span>
<span class="muRecipe">recipe</span> previous-line-length [
<span class="Constant">local-scope</span>
curr:address:duplex-list<span class="Special"> <- </span><span class="Constant">next-ingredient</span>
start:address:duplex-list<span class="Special"> <- </span><span class="Constant">next-ingredient</span>
result:number<span class="Special"> <- </span>copy <span class="Constant">0:literal</span>
<span class="muControl">reply-unless</span> curr:address:duplex-list, result:number
at-start?:boolean<span class="Special"> <- </span>equal curr:address:duplex-list, start:address:duplex-list
<span class="muControl">reply-if</span> at-start?:boolean, result:number
<span class="Delimiter">{</span>
curr:address:duplex-list<span class="Special"> <- </span>prev-duplex curr:address:duplex-list
<span class="muControl">break-unless</span> curr:address:duplex-list
at-start?:boolean<span class="Special"> <- </span>equal curr:address:duplex-list, start:address:duplex-list
<span class="muControl">break-if</span> at-start?:boolean
c:character<span class="Special"> <- </span>get curr:address:duplex-list/deref, value:offset
at-newline?:boolean<span class="Special"> <- </span>equal c:character <span class="Constant">10:literal/newline</span>
<span class="muControl">break-if</span> at-newline?:boolean
result:number<span class="Special"> <- </span>add result:number, <span class="Constant">1:literal</span>
<span class="muControl">loop</span>
<span class="Delimiter">}</span>
<span class="muControl">reply</span> result:number
]
<span class="muRecipe">recipe</span> move-to-start-of-line [
<span class="Constant">local-scope</span>
editor:address:editor-data<span class="Special"> <- </span><span class="Constant">next-ingredient</span>
<span class="Comment"># update cursor column</span>
left:number<span class="Special"> <- </span>get editor:address:editor-data/deref, left:offset
cursor-column:address:number<span class="Special"> <- </span>get-address editor:address:editor-data/deref, cursor-column:offset
cursor-column:address:number/deref<span class="Special"> <- </span>copy left:number
<span class="Comment"># update before-cursor</span>
before-cursor:address:address:duplex-list<span class="Special"> <- </span>get-address editor:address:editor-data/deref, before-cursor:offset
init:address:duplex-list<span class="Special"> <- </span>get editor:address:editor-data/deref, data:offset
<span class="Comment"># while not at start of line, move </span>
<span class="Delimiter">{</span>
at-start-of-text?:boolean<span class="Special"> <- </span>equal before-cursor:address:address:duplex-list/deref, init:address:duplex-list
<span class="muControl">break-if</span> at-start-of-text?:boolean
prev:character<span class="Special"> <- </span>get before-cursor:address:address:duplex-list/deref/deref, value:offset
at-start-of-line?:boolean<span class="Special"> <- </span>equal prev:character, <span class="Constant">10:literal/newline</span>
<span class="muControl">break-if</span> at-start-of-line?:boolean
before-cursor:address:address:duplex-list/deref<span class="Special"> <- </span>prev-duplex before-cursor:address:address:duplex-list/deref
assert before-cursor:address:address:duplex-list/deref, <span class="Constant">[move-to-start-of-line tried to move before start of text]</span>
<span class="muControl">loop</span>
<span class="Delimiter">}</span>
]
<span class="muRecipe">recipe</span> move-to-end-of-line [
<span class="Constant">local-scope</span>
editor:address:editor-data<span class="Special"> <- </span><span class="Constant">next-ingredient</span>
before-cursor:address:address:duplex-list<span class="Special"> <- </span>get-address editor:address:editor-data/deref, before-cursor:offset
cursor-column:address:number<span class="Special"> <- </span>get-address editor:address:editor-data/deref, cursor-column:offset
<span class="Comment"># while not at start of line, move </span>
<span class="Delimiter">{</span>
next:address:duplex-list<span class="Special"> <- </span>next-duplex before-cursor:address:address:duplex-list/deref
<span class="muControl">break-unless</span> next:address:duplex-list <span class="Comment"># end of text</span>
nextc:character<span class="Special"> <- </span>get next:address:duplex-list/deref, value:offset
at-end-of-line?:boolean<span class="Special"> <- </span>equal nextc:character, <span class="Constant">10:literal/newline</span>
<span class="muControl">break-if</span> at-end-of-line?:boolean
before-cursor:address:address:duplex-list/deref<span class="Special"> <- </span>copy next:address:duplex-list
cursor-column:address:number/deref<span class="Special"> <- </span>add cursor-column:address:number/deref, <span class="Constant">1:literal</span>
<span class="muControl">loop</span>
<span class="Delimiter">}</span>
<span class="Comment"># move one past end of line</span>
cursor-column:address:number/deref<span class="Special"> <- </span>add cursor-column:address:number/deref, <span class="Constant">1:literal</span>
]
<span class="muRecipe">recipe</span> delete-to-start-of-line [
<span class="Constant">local-scope</span>
editor:address:editor-data<span class="Special"> <- </span><span class="Constant">next-ingredient</span>
<span class="Comment"># compute range to delete</span>
init:address:duplex-list<span class="Special"> <- </span>get editor:address:editor-data/deref, data:offset
before-cursor:address:address:duplex-list<span class="Special"> <- </span>get-address editor:address:editor-data/deref, before-cursor:offset
start:address:duplex-list<span class="Special"> <- </span>copy before-cursor:address:address:duplex-list/deref
end:address:duplex-list<span class="Special"> <- </span>next-duplex before-cursor:address:address:duplex-list/deref
<span class="Delimiter">{</span>
at-start-of-text?:boolean<span class="Special"> <- </span>equal start:address:duplex-list, init:address:duplex-list
<span class="muControl">break-if</span> at-start-of-text?:boolean
curr:character<span class="Special"> <- </span>get start:address:duplex-list/deref, value:offset
at-start-of-line?:boolean<span class="Special"> <- </span>equal curr:character, <span class="Constant">10:literal/newline</span>
<span class="muControl">break-if</span> at-start-of-line?:boolean
start:address:duplex-list<span class="Special"> <- </span>prev-duplex start:address:duplex-list
assert start:address:duplex-list, <span class="Constant">[delete-to-start-of-line tried to move before start of text]</span>
<span class="muControl">loop</span>
<span class="Delimiter">}</span>
<span class="Comment"># snip it out</span>
start-next:address:address:duplex-list<span class="Special"> <- </span>get-address start:address:duplex-list/deref, next:offset
start-next:address:address:duplex-list/deref<span class="Special"> <- </span>copy end:address:duplex-list
end-prev:address:address:duplex-list<span class="Special"> <- </span>get-address end:address:duplex-list/deref, prev:offset
end-prev:address:address:duplex-list/deref<span class="Special"> <- </span>copy start:address:duplex-list
<span class="Comment"># adjust cursor</span>
before-cursor:address:address:duplex-list/deref<span class="Special"> <- </span>prev-duplex end:address:duplex-list
left:number<span class="Special"> <- </span>get editor:address:editor-data/deref, left:offset
cursor-column:address:number<span class="Special"> <- </span>get-address editor:address:editor-data/deref, cursor-column:offset
cursor-column:address:number/deref<span class="Special"> <- </span>copy left:number
]
<span class="muRecipe">recipe</span> delete-to-end-of-line [
<span class="Constant">local-scope</span>
editor:address:editor-data<span class="Special"> <- </span><span class="Constant">next-ingredient</span>
<span class="Comment"># compute range to delete</span>
start:address:duplex-list<span class="Special"> <- </span>get editor:address:editor-data/deref, before-cursor:offset
end:address:duplex-list<span class="Special"> <- </span>next-duplex start:address:duplex-list
<span class="Delimiter">{</span>
at-end-of-text?:boolean<span class="Special"> <- </span>equal end:address:duplex-list, <span class="Constant">0:literal/null</span>
<span class="muControl">break-if</span> at-end-of-text?:boolean
curr:character<span class="Special"> <- </span>get end:address:duplex-list/deref, value:offset
at-end-of-line?:boolean<span class="Special"> <- </span>equal curr:character, <span class="Constant">10:literal/newline</span>
<span class="muControl">break-if</span> at-end-of-line?:boolean
end:address:duplex-list<span class="Special"> <- </span>next-duplex end:address:duplex-list
<span class="muControl">loop</span>
<span class="Delimiter">}</span>
<span class="Comment"># snip it out</span>
start-next:address:address:duplex-list<span class="Special"> <- </span>get-address start:address:duplex-list/deref, next:offset
start-next:address:address:duplex-list/deref<span class="Special"> <- </span>copy end:address:duplex-list
<span class="Delimiter">{</span>
<span class="muControl">break-unless</span> end:address:duplex-list
end-prev:address:address:duplex-list<span class="Special"> <- </span>get-address end:address:duplex-list/deref, prev:offset
end-prev:address:address:duplex-list/deref<span class="Special"> <- </span>copy start:address:duplex-list
<span class="Delimiter">}</span>
]
<span class="muRecipe">recipe</span> render-all [
<span class="Constant">local-scope</span>
screen:address<span class="Special"> <- </span><span class="Constant">next-ingredient</span>
env:address:programming-environment-data<span class="Special"> <- </span><span class="Constant">next-ingredient</span>
screen:address<span class="Special"> <- </span>render-recipes screen:address, env:address:programming-environment-data, <span class="Constant">1:literal/clear-below</span>
screen:address<span class="Special"> <- </span>render-sandbox-side screen:address, env:address:programming-environment-data, <span class="Constant">1:literal/clear-below</span>
recipes:address:editor-data<span class="Special"> <- </span>get env:address:programming-environment-data/deref, recipes:offset
current-sandbox:address:editor-data<span class="Special"> <- </span>get env:address:programming-environment-data/deref, current-sandbox:offset
sandbox-in-focus?:boolean<span class="Special"> <- </span>get env:address:programming-environment-data/deref, sandbox-in-focus?:offset
update-cursor screen:address, recipes:address:editor-data, current-sandbox:address:editor-data, sandbox-in-focus?:boolean
show-screen screen:address
<span class="muControl">reply</span> screen:address/same-as-ingredient:0
]
<span class="muRecipe">recipe</span> render-minimal [
<span class="Constant">local-scope</span>
screen:address<span class="Special"> <- </span><span class="Constant">next-ingredient</span>
env:address:programming-environment-data<span class="Special"> <- </span><span class="Constant">next-ingredient</span>
recipes:address:editor-data<span class="Special"> <- </span>get env:address:programming-environment-data/deref, recipes:offset
current-sandbox:address:editor-data<span class="Special"> <- </span>get env:address:programming-environment-data/deref, current-sandbox:offset
sandbox-in-focus?:boolean<span class="Special"> <- </span>get env:address:programming-environment-data/deref, sandbox-in-focus?:offset
<span class="Delimiter">{</span>
<span class="muControl">break-if</span> sandbox-in-focus?:boolean
screen:address<span class="Special"> <- </span>render-recipes screen:address, env:address:programming-environment-data
cursor-row:number<span class="Special"> <- </span>get recipes:address:editor-data/deref, cursor-row:offset
cursor-column:number<span class="Special"> <- </span>get recipes:address:editor-data/deref, cursor-column:offset
<span class="Delimiter">}</span>
<span class="Delimiter">{</span>
<span class="muControl">break-unless</span> sandbox-in-focus?:boolean
screen:address<span class="Special"> <- </span>render-sandbox-side screen:address, env:address:programming-environment-data
cursor-row:number<span class="Special"> <- </span>get current-sandbox:address:editor-data/deref, cursor-row:offset
cursor-column:number<span class="Special"> <- </span>get current-sandbox:address:editor-data/deref, cursor-column:offset
<span class="Delimiter">}</span>
move-cursor screen:address, cursor-row:number, cursor-column:number
show-screen screen:address
<span class="muControl">reply</span> screen:address/same-as-ingredient:0
]
<span class="muRecipe">recipe</span> render-recipes [
<span class="Constant">local-scope</span>
screen:address<span class="Special"> <- </span><span class="Constant">next-ingredient</span>
env:address:programming-environment-data<span class="Special"> <- </span><span class="Constant">next-ingredient</span>
clear:boolean<span class="Special"> <- </span><span class="Constant">next-ingredient</span>
recipes:address:editor-data<span class="Special"> <- </span>get env:address:programming-environment-data/deref, recipes:offset
<span class="Comment"># render recipes</span>
left:number<span class="Special"> <- </span>get recipes:address:editor-data/deref, left:offset
right:number<span class="Special"> <- </span>get recipes:address:editor-data/deref, right:offset
row:number, screen:address<span class="Special"> <- </span>render screen:address, recipes:address:editor-data
recipe-warnings:address:array:character<span class="Special"> <- </span>get env:address:programming-environment-data/deref, recipe-warnings:offset
<span class="Delimiter">{</span>
<span class="Comment"># print any warnings</span>
<span class="muControl">break-unless</span> recipe-warnings:address:array:character
row:number, screen:address<span class="Special"> <- </span>render-string screen:address, recipe-warnings:address:array:character, left:number, right:number, <span class="Constant">1:literal/red</span>, row:number
<span class="Delimiter">}</span>
<span class="Delimiter">{</span>
<span class="Comment"># no warnings? move to next line</span>
<span class="muControl">break-if</span> recipe-warnings:address:array:character
row:number<span class="Special"> <- </span>add row:number, <span class="Constant">1:literal</span>
<span class="Delimiter">}</span>
<span class="Comment"># draw dotted line after recipes</span>
draw-horizontal screen:address, row:number, left:number, right:number, <span class="Constant">9480:literal/horizontal-dotted</span>
<span class="Comment"># clear next line, in case we just processed a backspace</span>
row:number<span class="Special"> <- </span>add row:number, <span class="Constant">1:literal</span>
move-cursor screen:address, row:number, left:number
clear-line-delimited screen:address, left:number, right:number
<span class="Comment"># clear rest of screen in this column, if requested</span>
<span class="muControl">reply-unless</span> clear:boolean, screen:address/same-as-ingredient:0
screen-height:number<span class="Special"> <- </span>screen-height screen:address
<span class="Delimiter">{</span>
at-bottom-of-screen?:boolean<span class="Special"> <- </span>greater-or-equal row:number, screen-height:number
<span class="muControl">break-if</span> at-bottom-of-screen?:boolean
move-cursor screen:address, row:number, left:number
clear-line-delimited screen:address, left:number, right:number
row:number<span class="Special"> <- </span>add row:number, <span class="Constant">1:literal</span>
<span class="muControl">loop</span>
<span class="Delimiter">}</span>
<span class="muControl">reply</span> screen:address/same-as-ingredient:0
]
<span class="muRecipe">recipe</span> update-cursor [
<span class="Constant">local-scope</span>
screen:address<span class="Special"> <- </span><span class="Constant">next-ingredient</span>
recipes:address:editor-data<span class="Special"> <- </span><span class="Constant">next-ingredient</span>
current-sandbox:address:editor-data<span class="Special"> <- </span><span class="Constant">next-ingredient</span>
sandbox-in-focus?:boolean<span class="Special"> <- </span><span class="Constant">next-ingredient</span>
<span class="Delimiter">{</span>
<span class="muControl">break-if</span> sandbox-in-focus?:boolean
<span class="CommentedCode">#? $print [recipes in focus</span>
<span class="CommentedCode">#? ] #? 1</span>
cursor-row:number<span class="Special"> <- </span>get recipes:address:editor-data/deref, cursor-row:offset
cursor-column:number<span class="Special"> <- </span>get recipes:address:editor-data/deref, cursor-column:offset
<span class="Delimiter">}</span>
<span class="Delimiter">{</span>
<span class="muControl">break-unless</span> sandbox-in-focus?:boolean
<span class="CommentedCode">#? $print [sandboxes in focus</span>
<span class="CommentedCode">#? ] #? 1</span>
cursor-row:number<span class="Special"> <- </span>get current-sandbox:address:editor-data/deref, cursor-row:offset
cursor-column:number<span class="Special"> <- </span>get current-sandbox:address:editor-data/deref, cursor-column:offset
<span class="Delimiter">}</span>
move-cursor screen:address, cursor-row:number, cursor-column:number
]
<span class="muScenario">scenario</span> editor-handles-empty-event-queue [
assume-screen <span class="Constant">10:literal/width</span>, <span class="Constant">5:literal/height</span>
1:address:array:character<span class="Special"> <- </span>new <span class="Constant">[abc]</span>
2:address:editor-data<span class="Special"> <- </span>new-editor 1:address:array:character, screen:address, <span class="Constant">0:literal/left</span>, <span class="Constant">10:literal/right</span>
assume-console <span class="Constant">[]</span>
run [
editor-event-loop screen:address, console:address, 2:address:editor-data
]
screen-should-contain [
<span class="Constant"> . .</span>
<span class="Constant"> .abc .</span>
<span class="Constant"> . .</span>
]
]
<span class="muScenario">scenario</span> editor-handles-mouse-clicks [
assume-screen <span class="Constant">10:literal/width</span>, <span class="Constant">5:literal/height</span>
1:address:array:character<span class="Special"> <- </span>new <span class="Constant">[abc]</span>
2:address:editor-data<span class="Special"> <- </span>new-editor 1:address:array:character, screen:address, <span class="Constant">0:literal/left</span>, <span class="Constant">10:literal/right</span>
assume-console [
left-click 1, 1 <span class="Comment"># on the 'b'</span>
]
run [
editor-event-loop screen:address, console:address, 2:address:editor-data
3:number<span class="Special"> <- </span>get 2:address:editor-data/deref, cursor-row:offset
4:number<span class="Special"> <- </span>get 2:address:editor-data/deref, cursor-column:offset
]
screen-should-contain [
<span class="Constant"> . .</span>
<span class="Constant"> .abc .</span>
<span class="Constant"> . .</span>
]
memory-should-contain [
3<span class="Special"> <- </span>1 <span class="Comment"># cursor is at row 0..</span>
4<span class="Special"> <- </span>1 <span class="Comment"># ..and column 1</span>
]
]
<span class="muScenario">scenario</span> editor-handles-mouse-clicks-outside-text [
assume-screen <span class="Constant">10:literal/width</span>, <span class="Constant">5:literal/height</span>
1:address:array:character<span class="Special"> <- </span>new <span class="Constant">[abc]</span>
2:address:editor-data<span class="Special"> <- </span>new-editor 1:address:array:character, screen:address, <span class="Constant">0:literal/left</span>, <span class="Constant">10:literal/right</span>
assume-console [
left-click 1, 7 <span class="Comment"># last line, to the right of text</span>
]
run [
editor-event-loop screen:address, console:address, 2:address:editor-data
3:number<span class="Special"> <- </span>get 2:address:editor-data/deref, cursor-row:offset
4:number<span class="Special"> <- </span>get 2:address:editor-data/deref, cursor-column:offset
]
memory-should-contain [
3<span class="Special"> <- </span>1 <span class="Comment"># cursor row</span>
4<span class="Special"> <- </span>3 <span class="Comment"># cursor column</span>
]
]
<span class="muScenario">scenario</span> editor-handles-mouse-clicks-outside-text-2 [
assume-screen <span class="Constant">10:literal/width</span>, <span class="Constant">5:literal/height</span>
1:address:array:character<span class="Special"> <- </span>new <span class="Constant">[abc</span>
<span class="Constant">def]</span>
2:address:editor-data<span class="Special"> <- </span>new-editor 1:address:array:character, screen:address, <span class="Constant">0:literal/left</span>, <span class="Constant">10:literal/right</span>
assume-console [
left-click 1, 7 <span class="Comment"># interior line, to the right of text</span>
]
run [
editor-event-loop screen:address, console:address, 2:address:editor-data
3:number<span class="Special"> <- </span>get 2:address:editor-data/deref, cursor-row:offset
4:number<span class="Special"> <- </span>get 2:address:editor-data/deref, cursor-column:offset
]
memory-should-contain [
3<span class="Special"> <- </span>1 <span class="Comment"># cursor row</span>
4<span class="Special"> <- </span>3 <span class="Comment"># cursor column</span>
]
]
<span class="muScenario">scenario</span> editor-handles-mouse-clicks-outside-text-3 [
assume-screen <span class="Constant">10:literal/width</span>, <span class="Constant">5:literal/height</span>
1:address:array:character<span class="Special"> <- </span>new <span class="Constant">[abc</span>
<span class="Constant">def]</span>
2:address:editor-data<span class="Special"> <- </span>new-editor 1:address:array:character, screen:address, <span class="Constant">0:literal/left</span>, <span class="Constant">10:literal/right</span>
assume-console [
left-click 3, 7 <span class="Comment"># below text</span>
]
run [
editor-event-loop screen:address, console:address, 2:address:editor-data
3:number<span class="Special"> <- </span>get 2:address:editor-data/deref, cursor-row:offset
4:number<span class="Special"> <- </span>get 2:address:editor-data/deref, cursor-column:offset
]
memory-should-contain [
3<span class="Special"> <- </span>2 <span class="Comment"># cursor row</span>
4<span class="Special"> <- </span>3 <span class="Comment"># cursor column</span>
]
]
<span class="muScenario">scenario</span> editor-handles-mouse-clicks-outside-column [
assume-screen <span class="Constant">10:literal/width</span>, <span class="Constant">5:literal/height</span>
1:address:array:character<span class="Special"> <- </span>new <span class="Constant">[abc]</span>
<span class="Comment"># editor occupies only left half of screen</span>
2:address:editor-data<span class="Special"> <- </span>new-editor 1:address:array:character, screen:address, <span class="Constant">0:literal/left</span>, <span class="Constant">5:literal/right</span>
assume-console [
<span class="Comment"># click on right half of screen</span>
left-click 3, 8
]
run [
editor-event-loop screen:address, console:address, 2:address:editor-data
3:number<span class="Special"> <- </span>get 2:address:editor-data/deref, cursor-row:offset
4:number<span class="Special"> <- </span>get 2:address:editor-data/deref, cursor-column:offset
]
screen-should-contain [
<span class="Constant"> . .</span>
<span class="Constant"> .abc .</span>
<span class="Constant"> . .</span>
]
memory-should-contain [
3<span class="Special"> <- </span>1 <span class="Comment"># no change to cursor row</span>
4<span class="Special"> <- </span>0 <span class="Comment"># ..or column</span>
]
]
<span class="muScenario">scenario</span> editor-inserts-characters-into-empty-editor [
assume-screen <span class="Constant">10:literal/width</span>, <span class="Constant">5:literal/height</span>
1:address:array:character<span class="Special"> <- </span>new <span class="Constant">[]</span>
2:address:editor-data<span class="Special"> <- </span>new-editor 1:address:array:character, screen:address, <span class="Constant">0:literal/left</span>, <span class="Constant">5:literal/right</span>
assume-console [
type <span class="Constant">[abc]</span>
]
run [
editor-event-loop screen:address, console:address, 2:address:editor-data
]
screen-should-contain [
<span class="Constant"> . .</span>
<span class="Constant"> .abc .</span>
<span class="Constant"> . .</span>
]
]
<span class="muScenario">scenario</span> editor-inserts-characters-at-cursor [
assume-screen <span class="Constant">10:literal/width</span>, <span class="Constant">5:literal/height</span>
1:address:array:character<span class="Special"> <- </span>new <span class="Constant">[abc]</span>
2:address:editor-data<span class="Special"> <- </span>new-editor 1:address:array:character, screen:address, <span class="Constant">0:literal/left</span>, <span class="Constant">10:literal/right</span>
assume-console [
type <span class="Constant">[0]</span>
left-click 1, 2
type <span class="Constant">[d]</span>
]
run [
editor-event-loop screen:address, console:address, 2:address:editor-data
]
screen-should-contain [
<span class="Constant"> . .</span>
<span class="Constant"> .0adbc .</span>
<span class="Constant"> . .</span>
]
]
<span class="muScenario">scenario</span> editor-inserts-characters-at-cursor-2 [
assume-screen <span class="Constant">10:literal/width</span>, <span class="Constant">5:literal/height</span>
1:address:array:character<span class="Special"> <- </span>new <span class="Constant">[abc]</span>
2:address:editor-data<span class="Special"> <- </span>new-editor 1:address:array:character, screen:address, <span class="Constant">0:literal/left</span>, <span class="Constant">10:literal/right</span>
assume-console [
left-click 1, 5 <span class="Comment"># right of last line</span>
type <span class="Constant">[d]</span> <span class="Comment"># should append</span>
]
run [
editor-event-loop screen:address, console:address, 2:address:editor-data
]
screen-should-contain [
<span class="Constant"> . .</span>
<span class="Constant"> .abcd .</span>
<span class="Constant"> . .</span>
]
]
<span class="muScenario">scenario</span> editor-inserts-characters-at-cursor-3 [
assume-screen <span class="Constant">10:literal/width</span>, <span class="Constant">5:literal/height</span>
1:address:array:character<span class="Special"> <- </span>new <span class="Constant">[abc]</span>
2:address:editor-data<span class="Special"> <- </span>new-editor 1:address:array:character, screen:address, <span class="Constant">0:literal/left</span>, <span class="Constant">10:literal/right</span>
assume-console [
left-click 3, 5 <span class="Comment"># below all text</span>
type <span class="Constant">[d]</span> <span class="Comment"># should append</span>
]
run [
editor-event-loop screen:address, console:address, 2:address:editor-data
]
screen-should-contain [
<span class="Constant"> . .</span>
<span class="Constant"> .abcd .</span>
<span class="Constant"> . .</span>
]
]
<span class="muScenario">scenario</span> editor-inserts-characters-at-cursor-4 [
assume-screen <span class="Constant">10:literal/width</span>, <span class="Constant">5:literal/height</span>
1:address:array:character<span class="Special"> <- </span>new <span class="Constant">[abc</span>
<span class="Constant">d]</span>
2:address:editor-data<span class="Special"> <- </span>new-editor 1:address:array:character, screen:address, <span class="Constant">0:literal/left</span>, <span class="Constant">10:literal/right</span>
assume-console [
left-click 3, 5 <span class="Comment"># below all text</span>
type <span class="Constant">[e]</span> <span class="Comment"># should append</span>
]
run [
editor-event-loop screen:address, console:address, 2:address:editor-data
]
screen-should-contain [
<span class="Constant"> . .</span>
<span class="Constant"> .abc .</span>
<span class="Constant"> .de .</span>
<span class="Constant"> . .</span>
]
]
<span class="muScenario">scenario</span> editor-inserts-characters-at-cursor-5 [
assume-screen <span class="Constant">10:literal/width</span>, <span class="Constant">5:literal/height</span>
1:address:array:character<span class="Special"> <- </span>new <span class="Constant">[abc</span>
<span class="Constant">d]</span>
2:address:editor-data<span class="Special"> <- </span>new-editor 1:address:array:character, screen:address, <span class="Constant">0:literal/left</span>, <span class="Constant">10:literal/right</span>
assume-console [
left-click 3, 5 <span class="Comment"># below all text</span>
type <span class="Constant">[ef]</span> <span class="Comment"># should append multiple characters in order</span>
]
run [
editor-event-loop screen:address, console:address, 2:address:editor-data
]
screen-should-contain [
<span class="Constant"> . .</span>
<span class="Constant"> .abc .</span>
<span class="Constant"> .def .</span>
<span class="Constant"> . .</span>
]
]
<span class="muScenario">scenario</span> editor-wraps-line-on-insert [
assume-screen <span class="Constant">5:literal/width</span>, <span class="Constant">5:literal/height</span>
1:address:array:character<span class="Special"> <- </span>new <span class="Constant">[abc]</span>
2:address:editor-data<span class="Special"> <- </span>new-editor 1:address:array:character, screen:address, <span class="Constant">0:literal/left</span>, <span class="Constant">5:literal/right</span>
<span class="Comment"># type a letter</span>
assume-console [
type <span class="Constant">[e]</span>
]
run [
editor-event-loop screen:address, console:address, 2:address:editor-data
]
<span class="Comment"># no wrap yet</span>
screen-should-contain [
<span class="Constant"> . .</span>
<span class="Constant"> .eabc .</span>
<span class="Constant"> . .</span>
<span class="Constant"> . .</span>
]
<span class="Comment"># type a second letter</span>
assume-console [
type <span class="Constant">[f]</span>
]
run [
editor-event-loop screen:address, console:address, 2:address:editor-data
]
<span class="Comment"># now wrap</span>
screen-should-contain [
<span class="Constant"> . .</span>
<span class="Constant"> .efab↩.</span>
<span class="Constant"> .c .</span>
<span class="Constant"> . .</span>
]
]
<span class="muScenario">scenario</span> editor-moves-cursor-after-inserting-characters [
assume-screen <span class="Constant">10:literal/width</span>, <span class="Constant">5:literal/height</span>
1:address:array:character<span class="Special"> <- </span>new <span class="Constant">[ab]</span>
2:address:editor-data<span class="Special"> <- </span>new-editor 1:address:array:character, screen:address, <span class="Constant">0:literal/left</span>, <span class="Constant">5:literal/right</span>
assume-console [
type <span class="Constant">[01]</span>
]
run [
editor-event-loop screen:address, console:address, 2:address:editor-data
]
screen-should-contain [
<span class="Constant"> . .</span>
<span class="Constant"> .01ab .</span>
<span class="Constant"> . .</span>
]
]
<span class="muScenario">scenario</span> editor-wraps-cursor-after-inserting-characters [
assume-screen <span class="Constant">10:literal/width</span>, <span class="Constant">5:literal/height</span>
1:address:array:character<span class="Special"> <- </span>new <span class="Constant">[abcde]</span>
2:address:editor-data<span class="Special"> <- </span>new-editor 1:address:array:character, screen:address, <span class="Constant">0:literal/left</span>, <span class="Constant">5:literal/right</span>
assume-console [
left-click 1, 4 <span class="Comment"># line is full; no wrap icon yet</span>
type <span class="Constant">[f]</span>
]
run [
editor-event-loop screen:address, console:address, 2:address:editor-data
3:number<span class="Special"> <- </span>get 2:address:editor-data/deref, cursor-row:offset
4:number<span class="Special"> <- </span>get 2:address:editor-data/deref, cursor-column:offset
]
screen-should-contain [
<span class="Constant"> . .</span>
<span class="Constant"> .abcd↩ .</span>
<span class="Constant"> .fe .</span>
<span class="Constant"> . .</span>
]
memory-should-contain [
3<span class="Special"> <- </span>2 <span class="Comment"># cursor row</span>
4<span class="Special"> <- </span>1 <span class="Comment"># cursor column</span>
]
]
<span class="muScenario">scenario</span> editor-wraps-cursor-after-inserting-characters-2 [
assume-screen <span class="Constant">10:literal/width</span>, <span class="Constant">5:literal/height</span>
1:address:array:character<span class="Special"> <- </span>new <span class="Constant">[abcde]</span>
2:address:editor-data<span class="Special"> <- </span>new-editor 1:address:array:character, screen:address, <span class="Constant">0:literal/left</span>, <span class="Constant">5:literal/right</span>
assume-console [
left-click 1, 3 <span class="Comment"># right before the wrap icon</span>
type <span class="Constant">[f]</span>
]
run [
editor-event-loop screen:address, console:address, 2:address:editor-data
3:number<span class="Special"> <- </span>get 2:address:editor-data/deref, cursor-row:offset
4:number<span class="Special"> <- </span>get 2:address:editor-data/deref, cursor-column:offset
]
screen-should-contain [
<span class="Constant"> . .</span>
<span class="Constant"> .abcf↩ .</span>
<span class="Constant"> .de .</span>
<span class="Constant"> . .</span>
]
memory-should-contain [
3<span class="Special"> <- </span>2 <span class="Comment"># cursor row</span>
4<span class="Special"> <- </span>0 <span class="Comment"># cursor column</span>
]
]
<span class="muScenario">scenario</span> editor-moves-cursor-down-after-inserting-newline [
assume-screen <span class="Constant">10:literal/width</span>, <span class="Constant">5:literal/height</span>
1:address:array:character<span class="Special"> <- </span>new <span class="Constant">[abc]</span>
2:address:editor-data<span class="Special"> <- </span>new-editor 1:address:array:character, screen:address, <span class="Constant">0:literal/left</span>, <span class="Constant">10:literal/right</span>
assume-console [
type <span class="Constant">[0</span>
<span class="Constant">1]</span>
]
run [
editor-event-loop screen:address, console:address, 2:address:editor-data
]
screen-should-contain [
<span class="Constant"> . .</span>
<span class="Constant"> .0 .</span>
<span class="Constant"> .1abc .</span>
<span class="Constant"> . .</span>
]
]
<span class="muScenario">scenario</span> editor-moves-cursor-down-after-inserting-newline-2 [
assume-screen <span class="Constant">10:literal/width</span>, <span class="Constant">5:literal/height</span>
1:address:array:character<span class="Special"> <- </span>new <span class="Constant">[abc]</span>
2:address:editor-data<span class="Special"> <- </span>new-editor 1:address:array:character, screen:address, <span class="Constant">1:literal/left</span>, <span class="Constant">10:literal/right</span>
assume-console [
type <span class="Constant">[0</span>
<span class="Constant">1]</span>
]
run [
editor-event-loop screen:address, console:address, 2:address:editor-data
]
screen-should-contain [
<span class="Constant"> . .</span>
<span class="Constant"> . 0 .</span>
<span class="Constant"> . 1abc .</span>
<span class="Constant"> . .</span>
]
]
<span class="muScenario">scenario</span> editor-clears-previous-line-completely-after-inserting-newline [
assume-screen <span class="Constant">10:literal/width</span>, <span class="Constant">5:literal/height</span>
1:address:array:character<span class="Special"> <- </span>new <span class="Constant">[abcde]</span>
2:address:editor-data<span class="Special"> <- </span>new-editor 1:address:array:character, screen:address, <span class="Constant">0:literal/left</span>, <span class="Constant">5:literal/right</span>
<span class="Comment"># press just a 'newline'</span>
assume-console [
type [
]
]
screen-should-contain [
<span class="Constant"> . .</span>
<span class="Constant"> .abcd↩ .</span>
<span class="Constant"> .e .</span>
<span class="Constant"> . .</span>
<span class="Constant"> . .</span>
]
run [
editor-event-loop screen:address, console:address, 2:address:editor-data
]
<span class="Comment"># line should be fully cleared</span>
screen-should-contain [
<span class="Constant"> . .</span>
<span class="Constant"> . .</span>
<span class="Constant"> .abcd↩ .</span>
<span class="Constant"> .e .</span>
<span class="Constant"> . .</span>
]
]
<span class="muScenario">scenario</span> editor-handles-backspace-key [
assume-screen <span class="Constant">10:literal/width</span>, <span class="Constant">5:literal/height</span>
1:address:array:character<span class="Special"> <- </span>new <span class="Constant">[abc]</span>
2:address:editor-data<span class="Special"> <- </span>new-editor 1:address:array:character, screen:address, <span class="Constant">0:literal/left</span>, <span class="Constant">10:literal/right</span>
assume-console [
left-click 1, 1
type <span class="Constant">[«]</span>
]
3:event/backspace<span class="Special"> <- </span>merge <span class="Constant">0:literal/text</span>, <span class="Constant">8:literal/backspace</span>, <span class="Constant">0:literal/dummy</span>, <span class="Constant">0:literal/dummy</span>
replace-in-console <span class="Constant">171:literal/«</span>, 3:event/backspace
run [
editor-event-loop screen:address, console:address, 2:address:editor-data
4:number<span class="Special"> <- </span>get 2:address:editor-data/deref, cursor-row:offset
5:number<span class="Special"> <- </span>get 2:address:editor-data/deref, cursor-column:offset
]
screen-should-contain [
<span class="Constant"> . .</span>
<span class="Constant"> .bc .</span>
<span class="Constant"> . .</span>
]
memory-should-contain [
4<span class="Special"> <- </span>1
5<span class="Special"> <- </span>0
]
]
<span class="muScenario">scenario</span> editor-clears-last-line-on-backspace [
assume-screen <span class="Constant">10:literal/width</span>, <span class="Constant">5:literal/height</span>
<span class="Comment"># just one character in final line</span>
1:address:array:character<span class="Special"> <- </span>new <span class="Constant">[ab</span>
<span class="Constant">cd]</span>
2:address:editor-data<span class="Special"> <- </span>new-editor 1:address:array:character, screen:address, <span class="Constant">0:literal/left</span>, <span class="Constant">5:literal/right</span>
assume-console [
left-click 2, 0 <span class="Comment"># cursor at only character in final line</span>
type <span class="Constant">[«]</span>
]
3:event/backspace<span class="Special"> <- </span>merge <span class="Constant">0:literal/text</span>, <span class="Constant">8:literal/backspace</span>, <span class="Constant">0:literal/dummy</span>, <span class="Constant">0:literal/dummy</span>
replace-in-console <span class="Constant">171:literal/«</span>, 3:event/backspace
run [
editor-event-loop screen:address, console:address, 2:address:editor-data
]
screen-should-contain [
<span class="Constant"> . .</span>
<span class="Constant"> .abcd .</span>
<span class="Constant"> . .</span>
]
]
<span class="muScenario">scenario</span> editor-moves-cursor-right-with-key [
assume-screen <span class="Constant">10:literal/width</span>, <span class="Constant">5:literal/height</span>
1:address:array:character<span class="Special"> <- </span>new <span class="Constant">[abc]</span>
2:address:editor-data<span class="Special"> <- </span>new-editor 1:address:array:character, screen:address, <span class="Constant">0:literal/left</span>, <span class="Constant">10:literal/right</span>
assume-console [
press 65514 <span class="Comment"># right arrow</span>
type <span class="Constant">[0]</span>
]
run [
editor-event-loop screen:address, console:address, 2:address:editor-data
]
screen-should-contain [
<span class="Constant"> . .</span>
<span class="Constant"> .a0bc .</span>
<span class="Constant"> . .</span>
]
]
<span class="muScenario">scenario</span> editor-moves-cursor-to-next-line-with-right-arrow [
assume-screen <span class="Constant">10:literal/width</span>, <span class="Constant">5:literal/height</span>
1:address:array:character<span class="Special"> <- </span>new <span class="Constant">[abc</span>
<span class="Constant">d]</span>
2:address:editor-data<span class="Special"> <- </span>new-editor 1:address:array:character, screen:address, <span class="Constant">0:literal/left</span>, <span class="Constant">10:literal/right</span>
assume-console [
press 65514 <span class="Comment"># right arrow</span>
press 65514 <span class="Comment"># right arrow</span>
press 65514 <span class="Comment"># right arrow</span>
press 65514 <span class="Comment"># right arrow - next line</span>
type <span class="Constant">[0]</span>
]
run [
editor-event-loop screen:address, console:address, 2:address:editor-data
]
screen-should-contain [
<span class="Constant"> . .</span>
<span class="Constant"> .abc .</span>
<span class="Constant"> .0d .</span>
<span class="Constant"> . .</span>
]
]
<span class="muScenario">scenario</span> editor-moves-cursor-to-next-line-with-right-arrow-2 [
assume-screen <span class="Constant">10:literal/width</span>, <span class="Constant">5:literal/height</span>
1:address:array:character<span class="Special"> <- </span>new <span class="Constant">[abc</span>
<span class="Constant">d]</span>
2:address:editor-data<span class="Special"> <- </span>new-editor 1:address:array:character, screen:address, <span class="Constant">1:literal/left</span>, <span class="Constant">10:literal/right</span>
assume-console [
press 65514 <span class="Comment"># right arrow</span>
press 65514 <span class="Comment"># right arrow</span>
press 65514 <span class="Comment"># right arrow</span>
press 65514 <span class="Comment"># right arrow - next line</span>
type <span class="Constant">[0]</span>
]
run [
editor-event-loop screen:address, console:address, 2:address:editor-data
]
screen-should-contain [
<span class="Constant"> . .</span>
<span class="Constant"> . abc .</span>
<span class="Constant"> . 0d .</span>
<span class="Constant"> . .</span>
]
]
<span class="muScenario">scenario</span> editor-moves-cursor-to-next-wrapped-line-with-right-arrow [
assume-screen <span class="Constant">10:literal/width</span>, <span class="Constant">5:literal/height</span>
1:address:array:character<span class="Special"> <- </span>new <span class="Constant">[abcdef]</span>
2:address:editor-data<span class="Special"> <- </span>new-editor 1:address:array:character, screen:address, <span class="Constant">0:literal/left</span>, <span class="Constant">5:literal/right</span>
assume-console [
left-click 1, 3
press 65514 <span class="Comment"># right arrow</span>
]
run [
editor-event-loop screen:address, console:address, 2:address:editor-data
3:number<span class="Special"> <- </span>get 2:address:editor-data/deref, cursor-row:offset
4:number<span class="Special"> <- </span>get 2:address:editor-data/deref, cursor-column:offset
]
screen-should-contain [
<span class="Constant"> . .</span>
<span class="Constant"> .abcd↩ .</span>
<span class="Constant"> .ef .</span>
<span class="Constant"> . .</span>
]
memory-should-contain [
3<span class="Special"> <- </span>2
4<span class="Special"> <- </span>0
]
]
<span class="muScenario">scenario</span> editor-moves-cursor-to-next-wrapped-line-with-right-arrow-2 [
assume-screen <span class="Constant">10:literal/width</span>, <span class="Constant">5:literal/height</span>
<span class="Comment"># line just barely wrapping</span>
1:address:array:character<span class="Special"> <- </span>new <span class="Constant">[abcde]</span>
2:address:editor-data<span class="Special"> <- </span>new-editor 1:address:array:character, screen:address, <span class="Constant">0:literal/left</span>, <span class="Constant">5:literal/right</span>
<span class="Comment"># position cursor at last character before wrap and hit right-arrow</span>
assume-console [
left-click 1, 3
press 65514 <span class="Comment"># right arrow</span>
]
run [
editor-event-loop screen:address, console:address, 2:address:editor-data
3:number<span class="Special"> <- </span>get 2:address:editor-data/deref, cursor-row:offset
4:number<span class="Special"> <- </span>get 2:address:editor-data/deref, cursor-column:offset
]
memory-should-contain [
3<span class="Special"> <- </span>2
4<span class="Special"> <- </span>0
]
<span class="Comment"># now hit right arrow again</span>
assume-console [
press 65514
]
run [
editor-event-loop screen:address, console:address, 2:address:editor-data
3:number<span class="Special"> <- </span>get 2:address:editor-data/deref, cursor-row:offset
4:number<span class="Special"> <- </span>get 2:address:editor-data/deref, cursor-column:offset
]
memory-should-contain [
3<span class="Special"> <- </span>2
4<span class="Special"> <- </span>1
]
]
<span class="muScenario">scenario</span> editor-moves-cursor-to-next-wrapped-line-with-right-arrow-3 [
assume-screen <span class="Constant">10:literal/width</span>, <span class="Constant">5:literal/height</span>
1:address:array:character<span class="Special"> <- </span>new <span class="Constant">[abcdef]</span>
2:address:editor-data<span class="Special"> <- </span>new-editor 1:address:array:character, screen:address, <span class="Constant">1:literal/left</span>, <span class="Constant">6:literal/right</span>
assume-console [
left-click 1, 4
press 65514 <span class="Comment"># right arrow</span>
]
run [
editor-event-loop screen:address, console:address, 2:address:editor-data
3:number<span class="Special"> <- </span>get 2:address:editor-data/deref, cursor-row:offset
4:number<span class="Special"> <- </span>get 2:address:editor-data/deref, cursor-column:offset
]
screen-should-contain [
<span class="Constant"> . .</span>
<span class="Constant"> . abcd↩ .</span>
<span class="Constant"> . ef .</span>
<span class="Constant"> . .</span>
]
memory-should-contain [
3<span class="Special"> <- </span>2
4<span class="Special"> <- </span>1
]
]
<span class="muScenario">scenario</span> editor-moves-cursor-to-next-line-with-right-arrow-at-end-of-line [
assume-screen <span class="Constant">10:literal/width</span>, <span class="Constant">5:literal/height</span>
1:address:array:character<span class="Special"> <- </span>new <span class="Constant">[abc</span>
<span class="Constant">d]</span>
2:address:editor-data<span class="Special"> <- </span>new-editor 1:address:array:character, screen:address, <span class="Constant">0:literal/left</span>, <span class="Constant">10:literal/right</span>
assume-console [
left-click 1, 3
press 65514 <span class="Comment"># right arrow - next line</span>
type <span class="Constant">[0]</span>
]
run [
editor-event-loop screen:address, console:address, 2:address:editor-data
]
screen-should-contain [
<span class="Constant"> . .</span>
<span class="Constant"> .abc .</span>
<span class="Constant"> .0d .</span>
<span class="Constant"> . .</span>
]
]
<span class="muScenario">scenario</span> editor-moves-cursor-left-with-key [
assume-screen <span class="Constant">10:literal/width</span>, <span class="Constant">5:literal/height</span>
1:address:array:character<span class="Special"> <- </span>new <span class="Constant">[abc]</span>
2:address:editor-data<span class="Special"> <- </span>new-editor 1:address:array:character, screen:address, <span class="Constant">0:literal/left</span>, <span class="Constant">10:literal/right</span>
assume-console [
left-click 1, 2
press 65515 <span class="Comment"># left arrow</span>
type <span class="Constant">[0]</span>
]
run [
editor-event-loop screen:address, console:address, 2:address:editor-data
]
screen-should-contain [
<span class="Constant"> . .</span>
<span class="Constant"> .a0bc .</span>
<span class="Constant"> . .</span>
]
]
<span class="muScenario">scenario</span> editor-moves-cursor-to-previous-line-with-left-arrow-at-start-of-line [
assume-screen <span class="Constant">10:literal/width</span>, <span class="Constant">5:literal/height</span>
<span class="Comment"># initialize editor with two lines</span>
1:address:array:character<span class="Special"> <- </span>new <span class="Constant">[abc</span>
<span class="Constant">d]</span>
2:address:editor-data<span class="Special"> <- </span>new-editor 1:address:array:character, screen:address, <span class="Constant">0:literal/left</span>, <span class="Constant">10:literal/right</span>
<span class="Comment"># position cursor at start of second line (so there's no previous newline)</span>
assume-console [
left-click 2, 0
press 65515 <span class="Comment"># left arrow</span>
]
run [
editor-event-loop screen:address, console:address, 2:address:editor-data
3:number<span class="Special"> <- </span>get 2:address:editor-data/deref, cursor-row:offset
4:number<span class="Special"> <- </span>get 2:address:editor-data/deref, cursor-column:offset
]
memory-should-contain [
3<span class="Special"> <- </span>1
4<span class="Special"> <- </span>3
]
]
<span class="muScenario">scenario</span> editor-moves-cursor-to-previous-line-with-left-arrow-at-start-of-line-2 [
assume-screen <span class="Constant">10:literal/width</span>, <span class="Constant">5:literal/height</span>
<span class="Comment"># initialize editor with three lines</span>
1:address:array:character<span class="Special"> <- </span>new <span class="Constant">[abc</span>
<span class="Constant">def</span>
<span class="Constant">g]</span>
2:address:editor-data<span class="Special"> <- </span>new-editor 1:address:array:character, screen:address, <span class="Constant">0:literal/left</span>, <span class="Constant">10:literal/right</span>
<span class="Comment"># position cursor further down (so there's a newline before the character at</span>
<span class="Comment"># the cursor)</span>
assume-console [
left-click 3, 0
press 65515 <span class="Comment"># left arrow</span>
type <span class="Constant">[0]</span>
]
run [
editor-event-loop screen:address, console:address, 2:address:editor-data
]
screen-should-contain [
<span class="Constant"> . .</span>
<span class="Constant"> .abc .</span>
<span class="Constant"> .def0 .</span>
<span class="Constant"> .g .</span>
<span class="Constant"> . .</span>
]
]
<span class="muScenario">scenario</span> editor-moves-cursor-to-previous-line-with-left-arrow-at-start-of-line-3 [
assume-screen <span class="Constant">10:literal/width</span>, <span class="Constant">5:literal/height</span>
1:address:array:character<span class="Special"> <- </span>new <span class="Constant">[abc</span>
<span class="Constant">def</span>
<span class="Constant">g]</span>
2:address:editor-data<span class="Special"> <- </span>new-editor 1:address:array:character, screen:address, <span class="Constant">0:literal/left</span>, <span class="Constant">10:literal/right</span>
<span class="Comment"># position cursor at start of text</span>
assume-console [
left-click 1, 0
press 65515 <span class="Comment"># left arrow should have no effect</span>
type <span class="Constant">[0]</span>
]
run [
editor-event-loop screen:address, console:address, 2:address:editor-data
]
screen-should-contain [
<span class="Constant"> . .</span>
<span class="Constant"> .0abc .</span>
<span class="Constant"> .def .</span>
<span class="Constant"> .g .</span>
<span class="Constant"> . .</span>
]
]
<span class="muScenario">scenario</span> editor-moves-cursor-to-previous-line-with-left-arrow-at-start-of-line-4 [
assume-screen <span class="Constant">10:literal/width</span>, <span class="Constant">5:literal/height</span>
<span class="Comment"># initialize editor with text containing an empty line</span>
1:address:array:character<span class="Special"> <- </span>new <span class="Constant">[abc</span>
d]
2:address:editor-data<span class="Special"> <- </span>new-editor 1:address:array:character, screen:address, <span class="Constant">0:literal/left</span>, <span class="Constant">10:literal/right</span>
<span class="Comment"># position cursor right after empty line</span>
assume-console [
left-click 3, 0
press 65515 <span class="Comment"># left arrow</span>
type <span class="Constant">[0]</span>
]
run [
editor-event-loop screen:address, console:address, 2:address:editor-data
]
screen-should-contain [
<span class="Constant"> . .</span>
<span class="Constant"> .abc .</span>
<span class="Constant"> .0 .</span>
<span class="Constant"> .d .</span>
<span class="Constant"> . .</span>
]
]
<span class="muScenario">scenario</span> editor-moves-across-screen-lines-across-wrap-with-left-arrow [
assume-screen <span class="Constant">10:literal/width</span>, <span class="Constant">5:literal/height</span>
<span class="Comment"># initialize editor with text containing an empty line</span>
1:address:array:character<span class="Special"> <- </span>new <span class="Constant">[abcdef]</span>
2:address:editor-data<span class="Special"> <- </span>new-editor 1:address:array:character, screen:address, <span class="Constant">0:literal/left</span>, <span class="Constant">5:literal/right</span>
screen-should-contain [
<span class="Constant"> . .</span>
<span class="Constant"> .abcd↩ .</span>
<span class="Constant"> .ef .</span>
<span class="Constant"> . .</span>
]
<span class="Comment"># position cursor right after empty line</span>
assume-console [
left-click 2, 0
press 65515 <span class="Comment"># left arrow</span>
]
run [
editor-event-loop screen:address, console:address, 2:address:editor-data
3:number<span class="Special"> <- </span>get 2:address:editor-data/deref, cursor-row:offset
4:number<span class="Special"> <- </span>get 2:address:editor-data/deref, cursor-column:offset
]
memory-should-contain [
3<span class="Special"> <- </span>1 <span class="Comment"># previous row</span>
4<span class="Special"> <- </span>3 <span class="Comment"># end of wrapped line</span>
]
]
<span class="muScenario">scenario</span> editor-moves-to-previous-line-with-up-arrow [
assume-screen <span class="Constant">10:literal/width</span>, <span class="Constant">5:literal/height</span>
1:address:array:character<span class="Special"> <- </span>new <span class="Constant">[abc</span>
<span class="Constant">def]</span>
2:address:editor-data<span class="Special"> <- </span>new-editor 1:address:array:character, screen:address, <span class="Constant">0:literal/left</span>, <span class="Constant">10:literal/right</span>
assume-console [
left-click 2, 1
press 65517 <span class="Comment"># up arrow</span>
]
run [
editor-event-loop screen:address, console:address, 2:address:editor-data
3:number<span class="Special"> <- </span>get 2:address:editor-data/deref, cursor-row:offset
4:number<span class="Special"> <- </span>get 2:address:editor-data/deref, cursor-column:offset
]
memory-should-contain [
3<span class="Special"> <- </span>1
4<span class="Special"> <- </span>1
]
]
<span class="muScenario">scenario</span> editor-moves-to-next-line-with-down-arrow [
assume-screen <span class="Constant">10:literal/width</span>, <span class="Constant">5:literal/height</span>
1:address:array:character<span class="Special"> <- </span>new <span class="Constant">[abc</span>
<span class="Constant">def]</span>
2:address:editor-data<span class="Special"> <- </span>new-editor 1:address:array:character, screen:address, <span class="Constant">0:literal/left</span>, <span class="Constant">10:literal/right</span>
<span class="Comment"># cursor starts out at (1, 0)</span>
assume-console [
press 65516 <span class="Comment"># down arrow</span>
]
run [
editor-event-loop screen:address, console:address, 2:address:editor-data
3:number<span class="Special"> <- </span>get 2:address:editor-data/deref, cursor-row:offset
4:number<span class="Special"> <- </span>get 2:address:editor-data/deref, cursor-column:offset
]
<span class="Comment"># ..and ends at (2, 0)</span>
memory-should-contain [
3<span class="Special"> <- </span>2
4<span class="Special"> <- </span>0
]
]
<span class="muScenario">scenario</span> editor-adjusts-column-at-previous-line [
assume-screen <span class="Constant">10:literal/width</span>, <span class="Constant">5:literal/height</span>
1:address:array:character<span class="Special"> <- </span>new <span class="Constant">[ab</span>
<span class="Constant">def]</span>
2:address:editor-data<span class="Special"> <- </span>new-editor 1:address:array:character, screen:address, <span class="Constant">0:literal/left</span>, <span class="Constant">10:literal/right</span>
assume-console [
left-click 2, 3
press 65517 <span class="Comment"># up arrow</span>
]
run [
editor-event-loop screen:address, console:address, 2:address:editor-data
3:number<span class="Special"> <- </span>get 2:address:editor-data/deref, cursor-row:offset
4:number<span class="Special"> <- </span>get 2:address:editor-data/deref, cursor-column:offset
]
memory-should-contain [
3<span class="Special"> <- </span>1
4<span class="Special"> <- </span>2
]
]
<span class="muScenario">scenario</span> editor-adjusts-column-at-next-line [
assume-screen <span class="Constant">10:literal/width</span>, <span class="Constant">5:literal/height</span>
1:address:array:character<span class="Special"> <- </span>new <span class="Constant">[abc</span>
<span class="Constant">de]</span>
2:address:editor-data<span class="Special"> <- </span>new-editor 1:address:array:character, screen:address, <span class="Constant">0:literal/left</span>, <span class="Constant">10:literal/right</span>
assume-console [
left-click 1, 3
press 65516 <span class="Comment"># down arrow</span>
]
run [
editor-event-loop screen:address, console:address, 2:address:editor-data
3:number<span class="Special"> <- </span>get 2:address:editor-data/deref, cursor-row:offset
4:number<span class="Special"> <- </span>get 2:address:editor-data/deref, cursor-column:offset
]
memory-should-contain [
3<span class="Special"> <- </span>2
4<span class="Special"> <- </span>2
]
]
<span class="muScenario">scenario</span> editor-moves-to-start-of-line-with-ctrl-a [
assume-screen <span class="Constant">10:literal/width</span>, <span class="Constant">5:literal/height</span>
1:address:array:character<span class="Special"> <- </span>new <span class="Constant">[123</span>
<span class="Constant">456]</span>
2:address:editor-data<span class="Special"> <- </span>new-editor 1:address:array:character, screen:address, <span class="Constant">0:literal/left</span>, <span class="Constant">10:literal/right</span>
<span class="Comment"># start on second line, press ctrl-a</span>
assume-console [
left-click 2, 3
type <span class="Constant">[a]</span> <span class="Comment"># ctrl-a</span>
]
3:event/ctrl-a<span class="Special"> <- </span>merge <span class="Constant">0:literal/text</span>, <span class="Constant">1:literal/ctrl-a</span>, <span class="Constant">0:literal/dummy</span>, <span class="Constant">0:literal/dummy</span>
replace-in-console <span class="Constant">97:literal/a</span>, 3:event/ctrl-a
run [
editor-event-loop screen:address, console:address, 2:address:editor-data
4:number<span class="Special"> <- </span>get 2:address:editor-data/deref, cursor-row:offset
5:number<span class="Special"> <- </span>get 2:address:editor-data/deref, cursor-column:offset
]
<span class="Comment"># cursor moves to start of line</span>
memory-should-contain [
4<span class="Special"> <- </span>2
5<span class="Special"> <- </span>0
]
]
<span class="muScenario">scenario</span> editor-moves-to-start-of-line-with-ctrl-a-2 [
assume-screen <span class="Constant">10:literal/width</span>, <span class="Constant">5:literal/height</span>
1:address:array:character<span class="Special"> <- </span>new <span class="Constant">[123</span>
<span class="Constant">456]</span>
2:address:editor-data<span class="Special"> <- </span>new-editor 1:address:array:character, screen:address, <span class="Constant">0:literal/left</span>, <span class="Constant">10:literal/right</span>
<span class="Comment"># start on first line (no newline before), press ctrl-a</span>
assume-console [
left-click 1, 3
type <span class="Constant">[a]</span> <span class="Comment"># ctrl-a</span>
]
3:event/ctrl-a<span class="Special"> <- </span>merge <span class="Constant">0:literal/text</span>, <span class="Constant">1:literal/ctrl-a</span>, <span class="Constant">0:literal/dummy</span>, <span class="Constant">0:literal/dummy</span>
replace-in-console <span class="Constant">97:literal/a</span>, 3:event/ctrl-a
run [
editor-event-loop screen:address, console:address, 2:address:editor-data
4:number<span class="Special"> <- </span>get 2:address:editor-data/deref, cursor-row:offset
5:number<span class="Special"> <- </span>get 2:address:editor-data/deref, cursor-column:offset
]
<span class="Comment"># cursor moves to start of line</span>
memory-should-contain [
4<span class="Special"> <- </span>1
5<span class="Special"> <- </span>0
]
]
<span class="muScenario">scenario</span> editor-moves-to-start-of-line-with-home [
assume-screen <span class="Constant">10:literal/width</span>, <span class="Constant">5:literal/height</span>
1:address:array:character<span class="Special"> <- </span>new <span class="Constant">[123</span>
<span class="Constant">456]</span>
2:address:editor-data<span class="Special"> <- </span>new-editor 1:address:array:character, screen:address, <span class="Constant">0:literal/left</span>, <span class="Constant">10:literal/right</span>
<span class="Comment"># start on second line, press 'home'</span>
assume-console [
left-click 2, 3
press 65521 <span class="Comment"># 'home'</span>
]
run [
editor-event-loop screen:address, console:address, 2:address:editor-data
3:number<span class="Special"> <- </span>get 2:address:editor-data/deref, cursor-row:offset
4:number<span class="Special"> <- </span>get 2:address:editor-data/deref, cursor-column:offset
]
<span class="Comment"># cursor moves to start of line</span>
memory-should-contain [
3<span class="Special"> <- </span>2
4<span class="Special"> <- </span>0
]
]
<span class="muScenario">scenario</span> editor-moves-to-start-of-line-with-home-2 [
assume-screen <span class="Constant">10:literal/width</span>, <span class="Constant">5:literal/height</span>
1:address:array:character<span class="Special"> <- </span>new <span class="Constant">[123</span>
<span class="Constant">456]</span>
2:address:editor-data<span class="Special"> <- </span>new-editor 1:address:array:character, screen:address, <span class="Constant">0:literal/left</span>, <span class="Constant">10:literal/right</span>
<span class="Comment"># start on first line (no newline before), press 'home'</span>
assume-console [
left-click 1, 3
press 65521 <span class="Comment"># 'home'</span>
]
run [
editor-event-loop screen:address, console:address, 2:address:editor-data
3:number<span class="Special"> <- </span>get 2:address:editor-data/deref, cursor-row:offset
4:number<span class="Special"> <- </span>get 2:address:editor-data/deref, cursor-column:offset
]
<span class="Comment"># cursor moves to start of line</span>
memory-should-contain [
3<span class="Special"> <- </span>1
4<span class="Special"> <- </span>0
]
]
<span class="muScenario">scenario</span> editor-moves-to-start-of-line-with-ctrl-e [
assume-screen <span class="Constant">10:literal/width</span>, <span class="Constant">5:literal/height</span>
1:address:array:character<span class="Special"> <- </span>new <span class="Constant">[123</span>
<span class="Constant">456]</span>
2:address:editor-data<span class="Special"> <- </span>new-editor 1:address:array:character, screen:address, <span class="Constant">0:literal/left</span>, <span class="Constant">10:literal/right</span>
<span class="Comment"># start on first line, press ctrl-e</span>
assume-console [
left-click 1, 1
type <span class="Constant">[e]</span> <span class="Comment"># ctrl-e</span>
]
3:event/ctrl-e<span class="Special"> <- </span>merge <span class="Constant">0:literal/text</span>, <span class="Constant">5:literal/ctrl-e</span>, <span class="Constant">0:literal/dummy</span>, <span class="Constant">0:literal/dummy</span>
replace-in-console <span class="Constant">101:literal/e</span>, 3:event/ctrl-e
run [
editor-event-loop screen:address, console:address, 2:address:editor-data
4:number<span class="Special"> <- </span>get 2:address:editor-data/deref, cursor-row:offset
5:number<span class="Special"> <- </span>get 2:address:editor-data/deref, cursor-column:offset
]
<span class="Comment"># cursor moves to end of line</span>
memory-should-contain [
4<span class="Special"> <- </span>1
5<span class="Special"> <- </span>3
]
<span class="Comment"># editor inserts future characters at cursor</span>
assume-console [
type <span class="Constant">[z]</span>
]
run [
editor-event-loop screen:address, console:address, 2:address:editor-data
4:number<span class="Special"> <- </span>get 2:address:editor-data/deref, cursor-row:offset
5:number<span class="Special"> <- </span>get 2:address:editor-data/deref, cursor-column:offset
]
memory-should-contain [
4<span class="Special"> <- </span>1
5<span class="Special"> <- </span>4
]
screen-should-contain [
<span class="Constant"> . .</span>
<span class="Constant"> .123z .</span>
<span class="Constant"> .456 .</span>
<span class="Constant"> . .</span>
]
]
<span class="muScenario">scenario</span> editor-moves-to-end-of-line-with-ctrl-e-2 [
assume-screen <span class="Constant">10:literal/width</span>, <span class="Constant">5:literal/height</span>
1:address:array:character<span class="Special"> <- </span>new <span class="Constant">[123</span>
<span class="Constant">456]</span>
2:address:editor-data<span class="Special"> <- </span>new-editor 1:address:array:character, screen:address, <span class="Constant">0:literal/left</span>, <span class="Constant">10:literal/right</span>
<span class="Comment"># start on second line (no newline after), press ctrl-e</span>
assume-console [
left-click 2, 1
type <span class="Constant">[e]</span> <span class="Comment"># ctrl-e</span>
]
3:event/ctrl-e<span class="Special"> <- </span>merge <span class="Constant">0:literal/text</span>, <span class="Constant">5:literal/ctrl-e</span>, <span class="Constant">0:literal/dummy</span>, <span class="Constant">0:literal/dummy</span>
replace-in-console <span class="Constant">101:literal/e</span>, 3:event/ctrl-e
run [
editor-event-loop screen:address, console:address, 2:address:editor-data
4:number<span class="Special"> <- </span>get 2:address:editor-data/deref, cursor-row:offset
5:number<span class="Special"> <- </span>get 2:address:editor-data/deref, cursor-column:offset
]
<span class="Comment"># cursor moves to end of line</span>
memory-should-contain [
4<span class="Special"> <- </span>2
5<span class="Special"> <- </span>3
]
]
<span class="muScenario">scenario</span> editor-moves-to-end-of-line-with-end [
assume-screen <span class="Constant">10:literal/width</span>, <span class="Constant">5:literal/height</span>
1:address:array:character<span class="Special"> <- </span>new <span class="Constant">[123</span>
<span class="Constant">456]</span>
2:address:editor-data<span class="Special"> <- </span>new-editor 1:address:array:character, screen:address, <span class="Constant">0:literal/left</span>, <span class="Constant">10:literal/right</span>
<span class="Comment"># start on first line, press 'end'</span>
assume-console [
left-click 1, 1
press 65520 <span class="Comment"># 'end'</span>
]
run [
editor-event-loop screen:address, console:address, 2:address:editor-data
3:number<span class="Special"> <- </span>get 2:address:editor-data/deref, cursor-row:offset
4:number<span class="Special"> <- </span>get 2:address:editor-data/deref, cursor-column:offset
]
<span class="Comment"># cursor moves to end of line</span>
memory-should-contain [
3<span class="Special"> <- </span>1
4<span class="Special"> <- </span>3
]
]
<span class="muScenario">scenario</span> editor-moves-to-end-of-line-with-end-2 [
assume-screen <span class="Constant">10:literal/width</span>, <span class="Constant">5:literal/height</span>
1:address:array:character<span class="Special"> <- </span>new <span class="Constant">[123</span>
<span class="Constant">456]</span>
2:address:editor-data<span class="Special"> <- </span>new-editor 1:address:array:character, screen:address, <span class="Constant">0:literal/left</span>, <span class="Constant">10:literal/right</span>
<span class="Comment"># start on second line (no newline after), press 'end'</span>
assume-console [
left-click 2, 1
press 65520 <span class="Comment"># 'end'</span>
]
run [
editor-event-loop screen:address, console:address, 2:address:editor-data
3:number<span class="Special"> <- </span>get 2:address:editor-data/deref, cursor-row:offset
4:number<span class="Special"> <- </span>get 2:address:editor-data/deref, cursor-column:offset
]
<span class="Comment"># cursor moves to end of line</span>
memory-should-contain [
3<span class="Special"> <- </span>2
4<span class="Special"> <- </span>3
]
]
<span class="muScenario">scenario</span> editor-deletes-to-start-of-line-with-ctrl-u [
assume-screen <span class="Constant">10:literal/width</span>, <span class="Constant">5:literal/height</span>
1:address:array:character<span class="Special"> <- </span>new <span class="Constant">[123</span>
<span class="Constant">456]</span>
2:address:editor-data<span class="Special"> <- </span>new-editor 1:address:array:character, screen:address, <span class="Constant">0:literal/left</span>, <span class="Constant">10:literal/right</span>
<span class="Comment"># start on second line, press ctrl-u</span>
assume-console [
left-click 2, 2
type <span class="Constant">[u]</span> <span class="Comment"># ctrl-u</span>
]
3:event/ctrl-a<span class="Special"> <- </span>merge <span class="Constant">0:literal/text</span>, <span class="Constant">21:literal/ctrl-u</span>, <span class="Constant">0:literal/dummy</span>, <span class="Constant">0:literal/dummy</span>
replace-in-console <span class="Constant">117:literal/u</span>, 3:event/ctrl-u
run [
editor-event-loop screen:address, console:address, 2:address:editor-data
]
<span class="Comment"># cursor deletes to start of line</span>
screen-should-contain [
<span class="Constant"> . .</span>
<span class="Constant"> .123 .</span>
<span class="Constant"> .6 .</span>
<span class="Constant"> . .</span>
]
]
<span class="muScenario">scenario</span> editor-deletes-to-start-of-line-with-ctrl-u-2 [
assume-screen <span class="Constant">10:literal/width</span>, <span class="Constant">5:literal/height</span>
1:address:array:character<span class="Special"> <- </span>new <span class="Constant">[123</span>
<span class="Constant">456]</span>
2:address:editor-data<span class="Special"> <- </span>new-editor 1:address:array:character, screen:address, <span class="Constant">0:literal/left</span>, <span class="Constant">10:literal/right</span>
<span class="Comment"># start on first line (no newline before), press ctrl-u</span>
assume-console [
left-click 1, 2
type <span class="Constant">[u]</span> <span class="Comment"># ctrl-u</span>
]
3:event/ctrl-u<span class="Special"> <- </span>merge <span class="Constant">0:literal/text</span>, <span class="Constant">21:literal/ctrl-a</span>, <span class="Constant">0:literal/dummy</span>, <span class="Constant">0:literal/dummy</span>
replace-in-console <span class="Constant">117:literal/a</span>, 3:event/ctrl-u
run [
editor-event-loop screen:address, console:address, 2:address:editor-data
]
<span class="Comment"># cursor deletes to start of line</span>
screen-should-contain [
<span class="Constant"> . .</span>
<span class="Constant"> .3 .</span>
<span class="Constant"> .456 .</span>
<span class="Constant"> . .</span>
]
]
<span class="muScenario">scenario</span> editor-deletes-to-start-of-line-with-ctrl-u-3 [
assume-screen <span class="Constant">10:literal/width</span>, <span class="Constant">5:literal/height</span>
1:address:array:character<span class="Special"> <- </span>new <span class="Constant">[123</span>
<span class="Constant">456]</span>
2:address:editor-data<span class="Special"> <- </span>new-editor 1:address:array:character, screen:address, <span class="Constant">0:literal/left</span>, <span class="Constant">10:literal/right</span>
<span class="Comment"># start past end of line, press ctrl-u</span>
assume-console [
left-click 1, 3
type <span class="Constant">[u]</span> <span class="Comment"># ctrl-u</span>
]
3:event/ctrl-u<span class="Special"> <- </span>merge <span class="Constant">0:literal/text</span>, <span class="Constant">21:literal/ctrl-a</span>, <span class="Constant">0:literal/dummy</span>, <span class="Constant">0:literal/dummy</span>
replace-in-console <span class="Constant">117:literal/a</span>, 3:event/ctrl-u
run [
editor-event-loop screen:address, console:address, 2:address:editor-data
]
<span class="Comment"># cursor deletes to start of line</span>
screen-should-contain [
<span class="Constant"> . .</span>
<span class="Constant"> . .</span>
<span class="Constant"> .456 .</span>
<span class="Constant"> . .</span>
]
]
<span class="muScenario">scenario</span> editor-deletes-to-end-of-line-with-ctrl-k [
assume-screen <span class="Constant">10:literal/width</span>, <span class="Constant">5:literal/height</span>
1:address:array:character<span class="Special"> <- </span>new <span class="Constant">[123</span>
<span class="Constant">456]</span>
2:address:editor-data<span class="Special"> <- </span>new-editor 1:address:array:character, screen:address, <span class="Constant">0:literal/left</span>, <span class="Constant">10:literal/right</span>
<span class="Comment"># start on first line, press ctrl-k</span>
assume-console [
left-click 1, 1
type <span class="Constant">[k]</span> <span class="Comment"># ctrl-k</span>
]
3:event/ctrl-k<span class="Special"> <- </span>merge <span class="Constant">0:literal/text</span>, <span class="Constant">11:literal/ctrl-k</span>, <span class="Constant">0:literal/dummy</span>, <span class="Constant">0:literal/dummy</span>
replace-in-console <span class="Constant">107:literal/k</span>, 3:event/ctrl-k
run [
editor-event-loop screen:address, console:address, 2:address:editor-data
]
<span class="Comment"># cursor deletes to end of line</span>
screen-should-contain [
<span class="Constant"> . .</span>
<span class="Constant"> .1 .</span>
<span class="Constant"> .456 .</span>
<span class="Constant"> . .</span>
]
]
<span class="muScenario">scenario</span> editor-deletes-to-end-of-line-with-ctrl-k-2 [
assume-screen <span class="Constant">10:literal/width</span>, <span class="Constant">5:literal/height</span>
1:address:array:character<span class="Special"> <- </span>new <span class="Constant">[123</span>
<span class="Constant">456]</span>
2:address:editor-data<span class="Special"> <- </span>new-editor 1:address:array:character, screen:address, <span class="Constant">0:literal/left</span>, <span class="Constant">10:literal/right</span>
<span class="Comment"># start on second line (no newline after), press ctrl-k</span>
assume-console [
left-click 2, 1
type <span class="Constant">[k]</span> <span class="Comment"># ctrl-k</span>
]
3:event/ctrl-k<span class="Special"> <- </span>merge <span class="Constant">0:literal/text</span>, <span class="Constant">11:literal/ctrl-k</span>, <span class="Constant">0:literal/dummy</span>, <span class="Constant">0:literal/dummy</span>
replace-in-console <span class="Constant">107:literal/k</span>, 3:event/ctrl-k
run [
editor-event-loop screen:address, console:address, 2:address:editor-data
]
<span class="Comment"># cursor deletes to end of line</span>
screen-should-contain [
<span class="Constant"> . .</span>
<span class="Constant"> .123 .</span>
<span class="Constant"> .4 .</span>
<span class="Constant"> . .</span>
]
]
<span class="muScenario">scenario</span> editor-deletes-to-end-of-line-with-ctrl-k-3 [
assume-screen <span class="Constant">10:literal/width</span>, <span class="Constant">5:literal/height</span>
1:address:array:character<span class="Special"> <- </span>new <span class="Constant">[123</span>
<span class="Constant">456]</span>
2:address:editor-data<span class="Special"> <- </span>new-editor 1:address:array:character, screen:address, <span class="Constant">0:literal/left</span>, <span class="Constant">10:literal/right</span>
<span class="Comment"># start at end of line</span>
assume-console [
left-click 1, 2
type <span class="Constant">[k]</span> <span class="Comment"># ctrl-k</span>
]
3:event/ctrl-k<span class="Special"> <- </span>merge <span class="Constant">0:literal/text</span>, <span class="Constant">11:literal/ctrl-k</span>, <span class="Constant">0:literal/dummy</span>, <span class="Constant">0:literal/dummy</span>
replace-in-console <span class="Constant">107:literal/k</span>, 3:event/ctrl-k
run [
editor-event-loop screen:address, console:address, 2:address:editor-data
]
<span class="Comment"># cursor deletes to end of line</span>
screen-should-contain [
<span class="Constant"> . .</span>
<span class="Constant"> .12 .</span>
<span class="Constant"> .456 .</span>
<span class="Constant"> . .</span>
]
]
<span class="muScenario">scenario</span> editor-deletes-to-end-of-line-with-ctrl-k-4 [
assume-screen <span class="Constant">10:literal/width</span>, <span class="Constant">5:literal/height</span>
1:address:array:character<span class="Special"> <- </span>new <span class="Constant">[123</span>
<span class="Constant">456]</span>
2:address:editor-data<span class="Special"> <- </span>new-editor 1:address:array:character, screen:address, <span class="Constant">0:literal/left</span>, <span class="Constant">10:literal/right</span>
<span class="Comment"># start past end of line</span>
assume-console [
left-click 1, 3
type <span class="Constant">[k]</span> <span class="Comment"># ctrl-k</span>
]
3:event/ctrl-k<span class="Special"> <- </span>merge <span class="Constant">0:literal/text</span>, <span class="Constant">11:literal/ctrl-k</span>, <span class="Constant">0:literal/dummy</span>, <span class="Constant">0:literal/dummy</span>
replace-in-console <span class="Constant">107:literal/k</span>, 3:event/ctrl-k
run [
editor-event-loop screen:address, console:address, 2:address:editor-data
]
<span class="Comment"># cursor deletes to end of line</span>
screen-should-contain [
<span class="Constant"> . .</span>
<span class="Constant"> .123 .</span>
<span class="Constant"> .456 .</span>
<span class="Constant"> . .</span>
]
]
<span class="muScenario">scenario</span> editor-deletes-to-end-of-line-with-ctrl-k-5 [
assume-screen <span class="Constant">10:literal/width</span>, <span class="Constant">5:literal/height</span>
1:address:array:character<span class="Special"> <- </span>new <span class="Constant">[123</span>
<span class="Constant">456]</span>
2:address:editor-data<span class="Special"> <- </span>new-editor 1:address:array:character, screen:address, <span class="Constant">0:literal/left</span>, <span class="Constant">10:literal/right</span>
<span class="Comment"># start at end of text</span>
assume-console [
left-click 2, 2
type <span class="Constant">[k]</span> <span class="Comment"># ctrl-k</span>
]
3:event/ctrl-k<span class="Special"> <- </span>merge <span class="Constant">0:literal/text</span>, <span class="Constant">11:literal/ctrl-k</span>, <span class="Constant">0:literal/dummy</span>, <span class="Constant">0:literal/dummy</span>
replace-in-console <span class="Constant">107:literal/k</span>, 3:event/ctrl-k
run [
editor-event-loop screen:address, console:address, 2:address:editor-data
]
<span class="Comment"># cursor deletes to end of line</span>
screen-should-contain [
<span class="Constant"> . .</span>
<span class="Constant"> .123 .</span>
<span class="Constant"> .45 .</span>
<span class="Constant"> . .</span>
]
]
<span class="muScenario">scenario</span> editor-deletes-to-end-of-line-with-ctrl-k-6 [
assume-screen <span class="Constant">10:literal/width</span>, <span class="Constant">5:literal/height</span>
1:address:array:character<span class="Special"> <- </span>new <span class="Constant">[123</span>
<span class="Constant">456]</span>
2:address:editor-data<span class="Special"> <- </span>new-editor 1:address:array:character, screen:address, <span class="Constant">0:literal/left</span>, <span class="Constant">10:literal/right</span>
<span class="Comment"># start past end of text</span>
assume-console [
left-click 2, 3
type <span class="Constant">[k]</span> <span class="Comment"># ctrl-k</span>
]
3:event/ctrl-k<span class="Special"> <- </span>merge <span class="Constant">0:literal/text</span>, <span class="Constant">11:literal/ctrl-k</span>, <span class="Constant">0:literal/dummy</span>, <span class="Constant">0:literal/dummy</span>
replace-in-console <span class="Constant">107:literal/k</span>, 3:event/ctrl-k
run [
editor-event-loop screen:address, console:address, 2:address:editor-data
]
<span class="Comment"># cursor deletes to end of line</span>
screen-should-contain [
<span class="Constant"> . .</span>
<span class="Constant"> .123 .</span>
<span class="Constant"> .456 .</span>
<span class="Constant"> . .</span>
]
]
<span class="muScenario">scenario</span> point-at-multiple-editors [
<span class="Constant"> $close-trace</span>
assume-screen <span class="Constant">30:literal/width</span>, <span class="Constant">5:literal/height</span>
<span class="Comment"># initialize both halves of screen</span>
1:address:array:character<span class="Special"> <- </span>new <span class="Constant">[abc]</span>
2:address:array:character<span class="Special"> <- </span>new <span class="Constant">[def]</span>
3:address:programming-environment-data<span class="Special"> <- </span>new-programming-environment screen:address, 1:address:array:character, 2:address:array:character
<span class="Comment"># focus on both sides</span>
assume-console [
left-click 1, 1
left-click 1, 17
]
<span class="Comment"># check cursor column in each</span>
run [
event-loop screen:address, console:address, 3:address:programming-environment-data
4:address:editor-data<span class="Special"> <- </span>get 3:address:programming-environment-data/deref, recipes:offset
5:number<span class="Special"> <- </span>get 4:address:editor-data/deref, cursor-column:offset
6:address:editor-data<span class="Special"> <- </span>get 3:address:programming-environment-data/deref, current-sandbox:offset
7:number<span class="Special"> <- </span>get 6:address:editor-data/deref, cursor-column:offset
]
memory-should-contain [
5<span class="Special"> <- </span>1
7<span class="Special"> <- </span>17
]
]
<span class="muScenario">scenario</span> edit-multiple-editors [
<span class="Constant"> $close-trace</span>
assume-screen <span class="Constant">30:literal/width</span>, <span class="Constant">5:literal/height</span>
<span class="Comment"># initialize both halves of screen</span>
1:address:array:character<span class="Special"> <- </span>new <span class="Constant">[abc]</span>
2:address:array:character<span class="Special"> <- </span>new <span class="Constant">[def]</span>
3:address:programming-environment-data<span class="Special"> <- </span>new-programming-environment screen:address, 1:address:array:character, 2:address:array:character
<span class="Comment"># type one letter in each of them</span>
assume-console [
left-click 1, 1
type <span class="Constant">[0]</span>
left-click 1, 17
type <span class="Constant">[1]</span>
]
run [
event-loop screen:address, console:address, 3:address:programming-environment-data
4:address:editor-data<span class="Special"> <- </span>get 3:address:programming-environment-data/deref, recipes:offset
5:number<span class="Special"> <- </span>get 4:address:editor-data/deref, cursor-column:offset
6:address:editor-data<span class="Special"> <- </span>get 3:address:programming-environment-data/deref, current-sandbox:offset
7:number<span class="Special"> <- </span>get 6:address:editor-data/deref, cursor-column:offset
]
screen-should-contain [
<span class="Constant"> . run (F10) . # this line has a different background, but we don't test that yet</span>
<span class="Constant"> .a0bc ┊d1ef .</span>
<span class="Constant"> .┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┊━━━━━━━━━━━━━━.</span>
<span class="Constant"> . ┊ .</span>
]
memory-should-contain [
5<span class="Special"> <- </span>2 <span class="Comment"># cursor column of recipe editor</span>
7<span class="Special"> <- </span>18 <span class="Comment"># cursor column of sandbox editor</span>
]
<span class="Comment"># show the cursor at the right window</span>
run [
screen:address<span class="Special"> <- </span>print-character screen:address, <span class="Constant">9251:literal/␣</span>
]
screen-should-contain [
<span class="Constant"> . run (F10) .</span>
<span class="Constant"> .a0bc ┊d1␣f .</span>
<span class="Constant"> .┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┊━━━━━━━━━━━━━━.</span>
<span class="Constant"> . ┊ .</span>
]
]
<span class="muScenario">scenario</span> multiple-editors-cover-only-their-own-areas [
<span class="Constant"> $close-trace</span>
assume-screen <span class="Constant">60:literal/width</span>, <span class="Constant">10:literal/height</span>
run [
1:address:array:character<span class="Special"> <- </span>new <span class="Constant">[abc]</span>
2:address:array:character<span class="Special"> <- </span>new <span class="Constant">[def]</span>
3:address:programming-environment-data<span class="Special"> <- </span>new-programming-environment screen:address, 1:address:array:character, 2:address:array:character
]
<span class="Comment"># divider isn't messed up</span>
screen-should-contain [
<span class="Constant"> . run (F10) .</span>
<span class="Constant"> .abc ┊def .</span>
<span class="Constant"> .┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┊━━━━━━━━━━━━━━━━━━━━━━━━━━━━━.</span>
<span class="Constant"> . ┊ .</span>
<span class="Constant"> . ┊ .</span>
]
]
<span class="muScenario">scenario</span> editor-in-focus-keeps-cursor [
<span class="Constant"> $close-trace</span>
assume-screen <span class="Constant">30:literal/width</span>, <span class="Constant">5:literal/height</span>
1:address:array:character<span class="Special"> <- </span>new <span class="Constant">[abc]</span>
2:address:array:character<span class="Special"> <- </span>new <span class="Constant">[def]</span>
<span class="Comment"># initialize programming environment and highlight cursor</span>
assume-console <span class="Constant">[]</span>
run [
3:address:programming-environment-data<span class="Special"> <- </span>new-programming-environment screen:address, 1:address:array:character, 2:address:array:character
event-loop screen:address, console:address, 3:address:programming-environment-data
screen:address<span class="Special"> <- </span>print-character screen:address, <span class="Constant">9251:literal/␣</span>
]
<span class="Comment"># is cursor at the right place?</span>
screen-should-contain [
<span class="Constant"> . run (F10) .</span>
<span class="Constant"> .␣bc ┊def .</span>
<span class="Constant"> .┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┊━━━━━━━━━━━━━━.</span>
<span class="Constant"> . ┊ .</span>
]
<span class="Comment"># now try typing a letter</span>
assume-console [
type <span class="Constant">[z]</span>
]
run [
3:address:programming-environment-data<span class="Special"> <- </span>new-programming-environment screen:address, 1:address:array:character, 2:address:array:character
event-loop screen:address, console:address, 3:address:programming-environment-data
screen:address<span class="Special"> <- </span>print-character screen:address, <span class="Constant">9251:literal/␣</span>
]
<span class="Comment"># cursor should still be right</span>
screen-should-contain [
<span class="Constant"> . run (F10) .</span>
<span class="Constant"> .z␣bc ┊def .</span>
<span class="Constant"> .┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┊━━━━━━━━━━━━━━.</span>
<span class="Constant"> . ┊ .</span>
]
]
<span class="SalientComment">## Running code from the editors</span>
container sandbox-data [
data:address:array:character
response:address:array:character
warnings:address:array:character
starting-row-on-screen:number <span class="Comment"># to track clicks on delete</span>
screen:address:screen <span class="Comment"># prints in the sandbox go here</span>
next-sandbox:address:sandbox-data
]
<span class="muScenario">scenario</span> run-and-show-results [
$close-trace <span class="Comment"># trace too long for github</span>
assume-screen <span class="Constant">100:literal/width</span>, <span class="Constant">15:literal/height</span>
<span class="Comment"># recipe editor is empty</span>
1:address:array:character<span class="Special"> <- </span>new <span class="Constant">[]</span>
<span class="Comment"># sandbox editor contains an instruction without storing outputs</span>
2:address:array:character<span class="Special"> <- </span>new <span class="Constant">[divide-with-remainder 11:literal, 3:literal]</span>
3:address:programming-environment-data<span class="Special"> <- </span>new-programming-environment screen:address, 1:address:array:character, 2:address:array:character
<span class="Comment"># run the code in the editors</span>
assume-console [
press 65526 <span class="Comment"># F10</span>
]
run [
event-loop screen:address, console:address, 3:address:programming-environment-data
]
<span class="Comment"># check that screen prints the results</span>
screen-should-contain [
<span class="Constant"> . run (F10) .</span>
<span class="Constant"> . ┊ .</span>
<span class="Constant"> .┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┊━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━.</span>
<span class="Constant"> . ┊ x.</span>
<span class="Constant"> . ┊divide-with-remainder 11:literal, 3:literal .</span>
<span class="Constant"> . ┊3 .</span>
<span class="Constant"> . ┊2 .</span>
<span class="Constant"> . ┊━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━.</span>
<span class="Constant"> . ┊ .</span>
]
screen-should-contain-in-color <span class="Constant">7:literal/white</span>, [
<span class="Constant"> . .</span>
<span class="Constant"> . .</span>
<span class="Constant"> . .</span>
<span class="Constant"> . .</span>
<span class="Constant"> . divide-with-remainder 11:literal, 3:literal .</span>
<span class="Constant"> . .</span>
<span class="Constant"> . .</span>
<span class="Constant"> . .</span>
<span class="Constant"> . .</span>
]
screen-should-contain-in-color <span class="Constant">245:literal/grey</span>, [
<span class="Constant"> . .</span>
<span class="Constant"> . ┊ .</span>
<span class="Constant"> .┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┊━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━.</span>
<span class="Constant"> . ┊ x.</span>
<span class="Constant"> . ┊ .</span>
<span class="Constant"> . ┊3 .</span>
<span class="Constant"> . ┊2 .</span>
<span class="Constant"> . ┊━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━.</span>
<span class="Constant"> . ┊ .</span>
]
<span class="Comment"># run another command</span>
assume-console [
left-click 1, 80
type <span class="Constant">[add 2:literal, 2:literal]</span>
press 65526 <span class="Comment"># F10</span>
]
run [
event-loop screen:address, console:address, 3:address:programming-environment-data
]
<span class="Comment"># check that screen prints the results</span>
screen-should-contain [
<span class="Constant"> . run (F10) .</span>
<span class="Constant"> . ┊ .</span>
<span class="Constant"> .┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┊━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━.</span>
<span class="Constant"> . ┊ x.</span>
<span class="Constant"> . ┊add 2:literal, 2:literal .</span>
<span class="Constant"> . ┊4 .</span>
<span class="Constant"> . ┊━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━.</span>
<span class="Constant"> . ┊ x.</span>
<span class="Constant"> . ┊divide-with-remainder 11:literal, 3:literal .</span>
<span class="Constant"> . ┊3 .</span>
<span class="Constant"> . ┊2 .</span>
<span class="Constant"> . ┊━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━.</span>
<span class="Constant"> . ┊ .</span>
]
]
<span class="muRecipe">recipe</span> run-sandboxes [
<span class="Constant">local-scope</span>
env:address:programming-environment-data<span class="Special"> <- </span><span class="Constant">next-ingredient</span>
recipes:address:editor-data<span class="Special"> <- </span>get env:address:programming-environment-data/deref, recipes:offset
current-sandbox:address:editor-data<span class="Special"> <- </span>get env:address:programming-environment-data/deref, current-sandbox:offset
<span class="Comment"># copy code from recipe editor, persist, load into mu, save any warnings</span>
in:address:array:character<span class="Special"> <- </span>editor-contents recipes:address:editor-data
save <span class="Constant">[recipes.mu]</span>, in:address:array:character
recipe-warnings:address:address:array:character<span class="Special"> <- </span>get-address env:address:programming-environment-data/deref, recipe-warnings:offset
recipe-warnings:address:address:array:character/deref<span class="Special"> <- </span>reload in:address:array:character
<span class="Comment"># if recipe editor has errors, stop</span>
<span class="muControl">reply-if</span> recipe-warnings:address:address:array:character/deref
<span class="Comment"># check contents of right editor (sandbox)</span>
<span class="Delimiter">{</span>
sandbox-contents:address:array:character<span class="Special"> <- </span>editor-contents current-sandbox:address:editor-data
<span class="muControl">break-unless</span> sandbox-contents:address:array:character
<span class="Comment"># if contents exist, first save them</span>
<span class="Comment"># run them and turn them into a new sandbox-data</span>
new-sandbox:address:sandbox-data<span class="Special"> <- </span>new sandbox-data:type
data:address:address:array:character<span class="Special"> <- </span>get-address new-sandbox:address:sandbox-data/deref, data:offset
data:address:address:array:character/deref<span class="Special"> <- </span>copy sandbox-contents:address:array:character
<span class="Comment"># push to head of sandbox list</span>
dest:address:address:sandbox-data<span class="Special"> <- </span>get-address env:address:programming-environment-data/deref, sandbox:offset
next:address:address:sandbox-data<span class="Special"> <- </span>get-address new-sandbox:address:sandbox-data/deref, next-sandbox:offset
next:address:address:sandbox-data/deref<span class="Special"> <- </span>copy dest:address:address:sandbox-data/deref
dest:address:address:sandbox-data/deref<span class="Special"> <- </span>copy new-sandbox:address:sandbox-data
<span class="Comment"># clear sandbox editor</span>
init:address:address:duplex-list<span class="Special"> <- </span>get-address current-sandbox:address:editor-data/deref, data:offset
init:address:address:duplex-list/deref<span class="Special"> <- </span>push-duplex <span class="Constant">167:literal/§</span>, <span class="Constant">0:literal/tail</span>
<span class="Delimiter">}</span>
<span class="Comment"># save all sandboxes before running, just in case we die when running</span>
curr:address:sandbox-data<span class="Special"> <- </span>get env:address:programming-environment-data/deref, sandbox:offset
filename:number<span class="Special"> <- </span>copy <span class="Constant">0:literal</span>
<span class="Delimiter">{</span>
<span class="muControl">break-unless</span> curr:address:sandbox-data
data:address:address:array:character<span class="Special"> <- </span>get-address curr:address:sandbox-data/deref, data:offset
save filename:number, data:address:address:array:character/deref
filename:number<span class="Special"> <- </span>add filename:number, <span class="Constant">1:literal</span>
curr:address:sandbox-data<span class="Special"> <- </span>get curr:address:sandbox-data/deref, next-sandbox:offset
<span class="muControl">loop</span>
<span class="Delimiter">}</span>
<span class="Comment"># run all sandboxes</span>
curr:address:sandbox-data<span class="Special"> <- </span>get env:address:programming-environment-data/deref, sandbox:offset
<span class="Delimiter">{</span>
<span class="muControl">break-unless</span> curr:address:sandbox-data
data:address:address:array:character<span class="Special"> <- </span>get-address curr:address:sandbox-data/deref, data:offset
response:address:address:array:character<span class="Special"> <- </span>get-address curr:address:sandbox-data/deref, response:offset
warnings:address:address:array:character<span class="Special"> <- </span>get-address curr:address:sandbox-data/deref, warnings:offset
fake-screen:address:address:screen<span class="Special"> <- </span>get-address curr:address:sandbox-data/deref, screen:offset
response:address:address:array:character/deref, warnings:address:address:array:character/deref, fake-screen:address:address:screen/deref<span class="Special"> <- </span>run-interactive data:address:address:array:character/deref
<span class="CommentedCode">#? $print warnings:address:address:array:character/deref, [ ], warnings:address:address:array:character/deref/deref, 10:literal/newline</span>
curr:address:sandbox-data<span class="Special"> <- </span>get curr:address:sandbox-data/deref, next-sandbox:offset
<span class="muControl">loop</span>
<span class="Delimiter">}</span>
]
<span class="muRecipe">recipe</span> render-sandbox-side [
<span class="Constant">local-scope</span>
screen:address<span class="Special"> <- </span><span class="Constant">next-ingredient</span>
env:address:programming-environment-data<span class="Special"> <- </span><span class="Constant">next-ingredient</span>
clear:boolean<span class="Special"> <- </span><span class="Constant">next-ingredient</span>
current-sandbox:address:editor-data<span class="Special"> <- </span>get env:address:programming-environment-data/deref, current-sandbox:offset
left:number<span class="Special"> <- </span>get current-sandbox:address:editor-data/deref, left:offset
right:number<span class="Special"> <- </span>get current-sandbox:address:editor-data/deref, right:offset
row:number, screen:address<span class="Special"> <- </span>render screen:address, current-sandbox:address:editor-data
row:number<span class="Special"> <- </span>add row:number, <span class="Constant">1:literal</span>
draw-horizontal screen:address, row:number, left:number, right:number, <span class="Constant">9473:literal/horizontal-double</span>
sandbox:address:sandbox-data<span class="Special"> <- </span>get env:address:programming-environment-data/deref, sandbox:offset
row:number, screen:address<span class="Special"> <- </span>render-sandboxes screen:address, sandbox:address:sandbox-data, left:number, right:number, row:number
<span class="Comment"># clear next line, in case we just processed a backspace</span>
row:number<span class="Special"> <- </span>add row:number, <span class="Constant">1:literal</span>
move-cursor screen:address, row:number, left:number
clear-line-delimited screen:address, left:number, right:number
<span class="muControl">reply-unless</span> clear:boolean, screen:address/same-as-ingredient:0
screen-height:number<span class="Special"> <- </span>screen-height screen:address
<span class="Delimiter">{</span>
at-bottom-of-screen?:boolean<span class="Special"> <- </span>greater-or-equal row:number, screen-height:number
<span class="muControl">break-if</span> at-bottom-of-screen?:boolean
move-cursor screen:address, row:number, left:number
clear-line-delimited screen:address, left:number, right:number
row:number<span class="Special"> <- </span>add row:number, <span class="Constant">1:literal</span>
<span class="muControl">loop</span>
<span class="Delimiter">}</span>
<span class="muControl">reply</span> screen:address/same-as-ingredient:0
]
<span class="muRecipe">recipe</span> render-sandboxes [
<span class="Constant">local-scope</span>
screen:address<span class="Special"> <- </span><span class="Constant">next-ingredient</span>
sandbox:address:sandbox-data<span class="Special"> <- </span><span class="Constant">next-ingredient</span>
left:number<span class="Special"> <- </span><span class="Constant">next-ingredient</span>
right:number<span class="Special"> <- </span><span class="Constant">next-ingredient</span>
row:number<span class="Special"> <- </span><span class="Constant">next-ingredient</span>
<span class="muControl">reply-unless</span> sandbox:address:sandbox-data, row:number/same-as-ingredient:4, screen:address/same-as-ingredient:0
screen-height:number<span class="Special"> <- </span>screen-height screen:address
at-bottom?:boolean<span class="Special"> <- </span>greater-or-equal row:number screen-height:number
<span class="muControl">reply-if</span> at-bottom?:boolean, row:number/same-as-ingredient:4, screen:address/same-as-ingredient:0
<span class="CommentedCode">#? $print [rendering sandbox ], sandbox:address:sandbox-data, 10:literal/newline</span>
<span class="Comment"># render sandbox menu</span>
row:number<span class="Special"> <- </span>add row:number, <span class="Constant">1:literal</span>
move-cursor screen:address, row:number, left:number
clear-line-delimited screen:address, left:number, right:number
print-character screen:address, <span class="Constant">120:literal/x</span>, <span class="Constant">245:literal/grey</span>
<span class="Comment"># save menu row so we can detect clicks to it later</span>
starting-row:address:number<span class="Special"> <- </span>get-address sandbox:address:sandbox-data/deref, starting-row-on-screen:offset
starting-row:address:number/deref<span class="Special"> <- </span>copy row:number
<span class="Comment"># render sandbox contents</span>
sandbox-data:address:array:character<span class="Special"> <- </span>get sandbox:address:sandbox-data/deref, data:offset
row:number, screen:address<span class="Special"> <- </span>render-string screen:address, sandbox-data:address:array:character, left:number, right:number, <span class="Constant">7:literal/white</span>, row:number
<span class="Comment"># render sandbox warnings, screen or response, in that order</span>
sandbox-response:address:array:character<span class="Special"> <- </span>get sandbox:address:sandbox-data/deref, response:offset
sandbox-warnings:address:array:character<span class="Special"> <- </span>get sandbox:address:sandbox-data/deref, warnings:offset
sandbox-screen:address<span class="Special"> <- </span>get sandbox:address:sandbox-data/deref, screen:offset
<span class="Delimiter">{</span>
<span class="muControl">break-unless</span> sandbox-warnings:address:array:character
row:number, screen:address<span class="Special"> <- </span>render-string screen:address, sandbox-warnings:address:array:character, left:number, right:number, <span class="Constant">1:literal/red</span>, row:number
<span class="Delimiter">}</span>
<span class="Delimiter">{</span>
<span class="muControl">break-if</span> sandbox-warnings:address:array:character
empty-screen?:boolean<span class="Special"> <- </span>fake-screen-is-clear? sandbox-screen:address
<span class="muControl">break-if</span> empty-screen?:boolean
row:number, screen:address<span class="Special"> <- </span>render-screen screen:address, sandbox-screen:address, left:number, right:number, row:number
<span class="Delimiter">}</span>
<span class="Delimiter">{</span>
<span class="muControl">break-if</span> sandbox-warnings:address:array:character
<span class="muControl">break-unless</span> empty-screen?:boolean
row:number, screen:address<span class="Special"> <- </span>render-string screen:address, sandbox-response:address:array:character, left:number, right:number, <span class="Constant">245:literal/grey</span>, row:number
<span class="Delimiter">}</span>
at-bottom?:boolean<span class="Special"> <- </span>greater-or-equal row:number screen-height:number
<span class="muControl">reply-if</span> at-bottom?:boolean, row:number/same-as-ingredient:4, screen:address/same-as-ingredient:0
<span class="Comment"># draw solid line after sandbox</span>
draw-horizontal screen:address, row:number, left:number, right:number, <span class="Constant">9473:literal/horizontal-double</span>
<span class="Comment"># draw next sandbox</span>
next-sandbox:address:sandbox-data<span class="Special"> <- </span>get sandbox:address:sandbox-data/deref, next-sandbox:offset
row:number, screen:address<span class="Special"> <- </span>render-sandboxes screen:address, next-sandbox:address:sandbox-data, left:number, right:number, row:number
<span class="muControl">reply</span> row:number/same-as-ingredient:4, screen:address/same-as-ingredient:0
]
<span class="Comment"># assumes programming environment has no sandboxes; restores them from previous session</span>
<span class="muRecipe">recipe</span> restore-sandboxes [
<span class="Constant">local-scope</span>
env:address:programming-environment-data<span class="Special"> <- </span><span class="Constant">next-ingredient</span>
<span class="Comment"># read all scenarios, pushing them to end of a list of scenarios</span>
filename:number<span class="Special"> <- </span>copy <span class="Constant">0:literal</span>
curr:address:address:sandbox-data<span class="Special"> <- </span>get-address env:address:programming-environment-data/deref, sandbox:offset
<span class="Delimiter">{</span>
contents:address:array:character<span class="Special"> <- </span>restore filename:number
<span class="muControl">break-unless</span> contents:address:array:character <span class="Comment"># stop at first error; assuming file didn't exist</span>
<span class="CommentedCode">#? $print contents:address:array:character, 10:literal/newline</span>
<span class="Comment"># create new sandbox for file</span>
curr:address:address:sandbox-data/deref<span class="Special"> <- </span>new sandbox-data:type
data:address:address:array:character<span class="Special"> <- </span>get-address curr:address:address:sandbox-data/deref/deref, data:offset
data:address:address:array:character/deref<span class="Special"> <- </span>copy contents:address:array:character
<span class="Comment"># increment loop variables</span>
filename:number<span class="Special"> <- </span>add filename:number, <span class="Constant">1:literal</span>
curr:address:address:sandbox-data<span class="Special"> <- </span>get-address curr:address:address:sandbox-data/deref/deref, next-sandbox:offset
<span class="muControl">loop</span>
<span class="Delimiter">}</span>
<span class="muControl">reply</span> env:address:programming-environment-data/same-as-ingredient:0
]
<span class="Comment"># was-deleted?:boolean <- delete-sandbox t:touch-event, env:address:programming-environment-data</span>
<span class="muRecipe">recipe</span> delete-sandbox [
<span class="Constant">local-scope</span>
t:touch-event<span class="Special"> <- </span><span class="Constant">next-ingredient</span>
env:address:programming-environment-data<span class="Special"> <- </span><span class="Constant">next-ingredient</span>
click-column:number<span class="Special"> <- </span>get t:touch-event, column:offset
current-sandbox:address:editor-data<span class="Special"> <- </span>get env:address:programming-environment-data/deref, current-sandbox:offset
right:number<span class="Special"> <- </span>get current-sandbox:address:editor-data/deref, right:offset
<span class="CommentedCode">#? $print [comparing column ], click-column:number, [ vs ], right:number, 10:literal/newline</span>
at-right?:boolean<span class="Special"> <- </span>equal click-column:number, right:number
<span class="muControl">reply-unless</span> at-right?:boolean, <span class="Constant">0:literal/false</span>
<span class="CommentedCode">#? $print [trying to delete</span>
<span class="CommentedCode">#? ] #? 1</span>
click-row:number<span class="Special"> <- </span>get t:touch-event, row:offset
prev:address:address:sandbox-data<span class="Special"> <- </span>get-address env:address:programming-environment-data/deref, sandbox:offset
<span class="CommentedCode">#? $print [prev: ], prev:address:address:sandbox-data, [ -> ], prev:address:address:sandbox-data/deref, 10:literal/newline</span>
curr:address:sandbox-data<span class="Special"> <- </span>get env:address:programming-environment-data/deref, sandbox:offset
<span class="Delimiter">{</span>
<span class="CommentedCode">#? $print [next sandbox</span>
<span class="CommentedCode">#? ] #? 1</span>
<span class="muControl">break-unless</span> curr:address:sandbox-data
<span class="Comment"># more sandboxes to check</span>
<span class="Delimiter">{</span>
<span class="CommentedCode">#? $print [checking</span>
<span class="CommentedCode">#? ] #? 1</span>
target-row:number<span class="Special"> <- </span>get curr:address:sandbox-data/deref, starting-row-on-screen:offset
<span class="CommentedCode">#? $print [comparing row ], target-row:number, [ vs ], click-row:number, 10:literal/newline</span>
delete-curr?:boolean<span class="Special"> <- </span>equal target-row:number, click-row:number
<span class="muControl">break-unless</span> delete-curr?:boolean
<span class="CommentedCode">#? $print [found!</span>
<span class="CommentedCode">#? ] #? 1</span>
<span class="Comment"># delete this sandbox, rerender and stop</span>
prev:address:address:sandbox-data/deref<span class="Special"> <- </span>get curr:address:sandbox-data/deref, next-sandbox:offset
<span class="CommentedCode">#? $print [setting prev: ], prev:address:address:sandbox-data, [ -> ], prev:address:address:sandbox-data/deref, 10:literal/newline</span>
<span class="muControl">reply</span> <span class="Constant">1:literal/true</span>
<span class="Delimiter">}</span>
prev:address:address:sandbox-data<span class="Special"> <- </span>get-address curr:address:sandbox-data/deref, next-sandbox:offset
<span class="CommentedCode">#? $print [prev: ], prev:address:address:sandbox-data, [ -> ], prev:address:address:sandbox-data/deref, 10:literal/newline</span>
curr:address:sandbox-data<span class="Special"> <- </span>get curr:address:sandbox-data/deref, next-sandbox:offset
<span class="muControl">loop</span>
<span class="Delimiter">}</span>
<span class="muControl">reply</span> <span class="Constant">0:literal/false</span>
]
<span class="muScenario">scenario</span> run-updates-results [
$close-trace <span class="Comment"># trace too long for github</span>
assume-screen <span class="Constant">100:literal/width</span>, <span class="Constant">12:literal/height</span>
<span class="Comment"># define a recipe (no indent for the 'add' line below so column numbers are more obvious)</span>
1:address:array:character<span class="Special"> <- </span>new <span class="Constant">[ </span>
<span class="Constant">recipe foo [</span>
<span class="Constant">z:number <- add 2:literal, 2:literal</span>
<span class="Constant">]</span>]
<span class="Comment"># sandbox editor contains an instruction without storing outputs</span>
2:address:array:character<span class="Special"> <- </span>new <span class="Constant">[foo]</span>
3:address:programming-environment-data<span class="Special"> <- </span>new-programming-environment screen:address, 1:address:array:character, 2:address:array:character
<span class="Comment"># run the code in the editors</span>
assume-console [
press 65526 <span class="Comment"># F10</span>
]
run [
event-loop screen:address, console:address, 3:address:programming-environment-data
]
<span class="Comment"># check that screen prints the results</span>
screen-should-contain [
<span class="Constant"> . run (F10) .</span>
<span class="Constant"> . ┊ .</span>
<span class="Constant"> .recipe foo [ ┊━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━.</span>
<span class="Constant"> .z:number <- add 2:literal, 2:literal ┊ x.</span>
<span class="Constant"> .] ┊foo .</span>
<span class="Constant"> .┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┊4 .</span>
<span class="Constant"> . ┊━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━.</span>
<span class="Constant"> . ┊ .</span>
]
<span class="Comment"># make a change (incrementing one of the args to 'add'), then rerun</span>
assume-console [
left-click 3, 28 <span class="Comment"># one past the value of the second arg</span>
type <span class="Constant">[«3]</span> <span class="Comment"># replace</span>
press 65526 <span class="Comment"># F10</span>
]
4:event/backspace<span class="Special"> <- </span>merge <span class="Constant">0:literal/text</span>, <span class="Constant">8:literal/backspace</span>, <span class="Constant">0:literal/dummy</span>, <span class="Constant">0:literal/dummy</span>
replace-in-console <span class="Constant">171:literal/«</span>, 4:event/backspace
run [
event-loop screen:address, console:address, 3:address:programming-environment-data
]
<span class="Comment"># check that screen updates the result on the right</span>
screen-should-contain [
<span class="Constant"> . run (F10) .</span>
<span class="Constant"> . ┊ .</span>
<span class="Constant"> .recipe foo [ ┊━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━.</span>
<span class="Constant"> .z:number <- add 2:literal, 3:literal ┊ x.</span>
<span class="Constant"> .] ┊foo .</span>
<span class="Constant"> .┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┊5 .</span>
<span class="Constant"> . ┊━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━.</span>
<span class="Constant"> . ┊ .</span>
]
]
<span class="muScenario">scenario</span> run-instruction-and-print-warnings [
$close-trace <span class="Comment"># trace too long for github</span>
assume-screen <span class="Constant">100:literal/width</span>, <span class="Constant">10:literal/height</span>
<span class="Comment"># left editor is empty</span>
1:address:array:character<span class="Special"> <- </span>new <span class="Constant">[]</span>
<span class="Comment"># right editor contains an illegal instruction</span>
2:address:array:character<span class="Special"> <- </span>new <span class="Constant">[get 1234:number, foo:offset]</span>
3:address:programming-environment-data<span class="Special"> <- </span>new-programming-environment screen:address, 1:address:array:character, 2:address:array:character
<span class="Comment"># run the code in the editors</span>
assume-console [
press 65526 <span class="Comment"># F10</span>
]
run [
event-loop screen:address, console:address, 3:address:programming-environment-data
]
<span class="Comment"># check that screen prints error message in red</span>
screen-should-contain [
<span class="Constant"> . run (F10) .</span>
<span class="Constant"> . ┊ .</span>
<span class="Constant"> .┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┊━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━.</span>
<span class="Constant"> . ┊ x.</span>
<span class="Constant"> . ┊get 1234:number, foo:offset .</span>
<span class="Constant"> . ┊unknown element foo in container number .</span>
<span class="Constant"> . ┊━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━.</span>
<span class="Constant"> . ┊ .</span>
]
screen-should-contain-in-color <span class="Constant">7:literal/white</span>, [
<span class="Constant"> . .</span>
<span class="Constant"> . .</span>
<span class="Constant"> . .</span>
<span class="Constant"> . .</span>
<span class="Constant"> . get 1234:number, foo:offset .</span>
<span class="Constant"> . .</span>
<span class="Constant"> . .</span>
<span class="Constant"> . .</span>
]
screen-should-contain-in-color <span class="Constant">1:literal/red</span>, [
<span class="Constant"> . .</span>
<span class="Constant"> . .</span>
<span class="Constant"> . .</span>
<span class="Constant"> . .</span>
<span class="Constant"> . .</span>
<span class="Constant"> . unknown element foo in container number .</span>
<span class="Constant"> . .</span>
]
screen-should-contain-in-color <span class="Constant">245:literal/grey</span>, [
<span class="Constant"> . .</span>
<span class="Constant"> . ┊ .</span>
<span class="Constant"> .┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┊━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━.</span>
<span class="Constant"> . ┊ x.</span>
<span class="Constant"> . ┊ .</span>
<span class="Constant"> . ┊ .</span>
<span class="Constant"> . ┊━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━.</span>
<span class="Constant"> . ┊ .</span>
]
]
<span class="muScenario">scenario</span> run-instruction-and-print-warnings-only-once [
$close-trace <span class="Comment"># trace too long for github</span>
assume-screen <span class="Constant">100:literal/width</span>, <span class="Constant">10:literal/height</span>
<span class="Comment"># left editor is empty</span>
1:address:array:character<span class="Special"> <- </span>new <span class="Constant">[]</span>
<span class="Comment"># right editor contains an illegal instruction</span>
2:address:array:character<span class="Special"> <- </span>new <span class="Constant">[get 1234:number, foo:offset]</span>
3:address:programming-environment-data<span class="Special"> <- </span>new-programming-environment screen:address, 1:address:array:character, 2:address:array:character
<span class="Comment"># run the code in the editors multiple times</span>
assume-console [
press 65526 <span class="Comment"># F10</span>
press 65526 <span class="Comment"># F10</span>
]
run [
event-loop screen:address, console:address, 3:address:programming-environment-data
]
<span class="Comment"># check that screen prints error message just once</span>
screen-should-contain [
<span class="Constant"> . run (F10) .</span>
<span class="Constant"> . ┊ .</span>
<span class="Constant"> .┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┊━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━.</span>
<span class="Constant"> . ┊ x.</span>
<span class="Constant"> . ┊get 1234:number, foo:offset .</span>
<span class="Constant"> . ┊unknown element foo in container number .</span>
<span class="Constant"> . ┊━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━.</span>
<span class="Constant"> . ┊ .</span>
]
]
<span class="muScenario">scenario</span> deleting-sandboxes [
$close-trace <span class="Comment"># trace too long for github</span>
assume-screen <span class="Constant">100:literal/width</span>, <span class="Constant">15:literal/height</span>
1:address:array:character<span class="Special"> <- </span>new <span class="Constant">[]</span>
2:address:array:character<span class="Special"> <- </span>new <span class="Constant">[]</span>
3:address:programming-environment-data<span class="Special"> <- </span>new-programming-environment screen:address, 1:address:array:character, 2:address:array:character
<span class="Comment"># run a few commands</span>
assume-console [
left-click 1, 80
type <span class="Constant">[divide-with-remainder 11:literal, 3:literal]</span>
press 65526 <span class="Comment"># F10</span>
type <span class="Constant">[add 2:literal, 2:literal]</span>
press 65526 <span class="Comment"># F10</span>
]
run [
event-loop screen:address, console:address, 3:address:programming-environment-data
]
screen-should-contain [
<span class="Constant"> . run (F10) .</span>
<span class="Constant"> . ┊ .</span>
<span class="Constant"> .┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┊━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━.</span>
<span class="Constant"> . ┊ x.</span>
<span class="Constant"> . ┊add 2:literal, 2:literal .</span>
<span class="Constant"> . ┊4 .</span>
<span class="Constant"> . ┊━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━.</span>
<span class="Constant"> . ┊ x.</span>
<span class="Constant"> . ┊divide-with-remainder 11:literal, 3:literal .</span>
<span class="Constant"> . ┊3 .</span>
<span class="Constant"> . ┊2 .</span>
<span class="Constant"> . ┊━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━.</span>
<span class="Constant"> . ┊ .</span>
]
<span class="Comment"># delete second sandbox</span>
assume-console [
left-click 7, 99
]
run [
event-loop screen:address, console:address, 3:address:programming-environment-data
]
screen-should-contain [
<span class="Constant"> . run (F10) .</span>
<span class="Constant"> . ┊ .</span>
<span class="Constant"> .┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┊━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━.</span>
<span class="Constant"> . ┊ x.</span>
<span class="Constant"> . ┊add 2:literal, 2:literal .</span>
<span class="Constant"> . ┊4 .</span>
<span class="Constant"> . ┊━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━.</span>
<span class="Constant"> . ┊ .</span>
<span class="Constant"> . ┊ .</span>
]
<span class="Comment"># delete first sandbox</span>
assume-console [
left-click 3, 99
]
run [
event-loop screen:address, console:address, 3:address:programming-environment-data
]
screen-should-contain [
<span class="Constant"> . run (F10) .</span>
<span class="Constant"> . ┊ .</span>
<span class="Constant"> .┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┊━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━.</span>
<span class="Constant"> . ┊ .</span>
<span class="Constant"> . ┊ .</span>
]
]
<span class="muScenario">scenario</span> run-instruction-manages-screen-per-sandbox [
$close-trace <span class="Comment"># trace too long for github #? 1</span>
assume-screen <span class="Constant">100:literal/width</span>, <span class="Constant">20:literal/height</span>
<span class="Comment"># left editor is empty</span>
1:address:array:character<span class="Special"> <- </span>new <span class="Constant">[]</span>
<span class="Comment"># right editor contains an illegal instruction</span>
2:address:array:character<span class="Special"> <- </span>new <span class="Constant">[print-integer screen:address, 4]</span>
3:address:programming-environment-data<span class="Special"> <- </span>new-programming-environment screen:address, 1:address:array:character, 2:address:array:character
<span class="Comment"># run the code in the editor</span>
assume-console [
press 65526 <span class="Comment"># F10</span>
]
run [
event-loop screen:address, console:address, 3:address:programming-environment-data
]
<span class="Comment"># check that it prints a little 5x5 toy screen</span>
<span class="Comment"># hack: screen address is brittle</span>
screen-should-contain [
<span class="Constant"> . run (F10) .</span>
<span class="Constant"> . ┊ .</span>
<span class="Constant"> .┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┊━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━.</span>
<span class="Constant"> . ┊ x.</span>
<span class="Constant"> . ┊print-integer screen:address, 4 .</span>
<span class="Constant"> . ┊screen: .</span>
<span class="Constant"> . ┊ .4 . .</span>
<span class="Constant"> . ┊ . . .</span>
<span class="Constant"> . ┊ . . .</span>
<span class="Constant"> . ┊ . . .</span>
<span class="Constant"> . ┊ . . .</span>
<span class="Constant"> . ┊━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━.</span>
<span class="Constant"> . ┊ .</span>
]
]
<span class="muRecipe">recipe</span> editor-contents [
<span class="Constant">local-scope</span>
editor:address:editor-data<span class="Special"> <- </span><span class="Constant">next-ingredient</span>
buf:address:buffer<span class="Special"> <- </span>new-buffer <span class="Constant">80:literal</span>
curr:address:duplex-list<span class="Special"> <- </span>get editor:address:editor-data/deref, data:offset
<span class="Comment"># skip § sentinel</span>
assert curr:address:duplex-list, <span class="Constant">[editor without data is illegal; must have at least a sentinel]</span>
curr:address:duplex-list<span class="Special"> <- </span>next-duplex curr:address:duplex-list
<span class="muControl">reply-unless</span> curr:address:duplex-list, <span class="Constant">0:literal</span>
<span class="Delimiter">{</span>
<span class="muControl">break-unless</span> curr:address:duplex-list
c:character<span class="Special"> <- </span>get curr:address:duplex-list/deref, value:offset
buffer-append buf:address:buffer, c:character
curr:address:duplex-list<span class="Special"> <- </span>next-duplex curr:address:duplex-list
<span class="muControl">loop</span>
<span class="Delimiter">}</span>
result:address:array:character<span class="Special"> <- </span>buffer-to-array buf:address:buffer
<span class="muControl">reply</span> result:address:array:character
]
<span class="muScenario">scenario</span> editor-provides-edited-contents [
assume-screen <span class="Constant">10:literal/width</span>, <span class="Constant">5:literal/height</span>
1:address:array:character<span class="Special"> <- </span>new <span class="Constant">[abc]</span>
2:address:editor-data<span class="Special"> <- </span>new-editor 1:address:array:character, screen:address, <span class="Constant">0:literal/left</span>, <span class="Constant">10:literal/right</span>
assume-console [
left-click 1, 2
type <span class="Constant">[def]</span>
]
run [
editor-event-loop screen:address, console:address, 2:address:editor-data
3:address:array:character<span class="Special"> <- </span>editor-contents 2:address:editor-data
4:array:character<span class="Special"> <- </span>copy 3:address:array:character/deref
]
memory-should-contain [
4:string<span class="Special"> <- </span><span class="Constant">[abdefc]</span>
]
]
<span class="SalientComment">## handling malformed programs</span>
<span class="muScenario">scenario</span> run-shows-warnings-in-get [
<span class="Constant"> $close-trace</span>
assume-screen <span class="Constant">100:literal/width</span>, <span class="Constant">15:literal/height</span>
assume-console [
press 65526 <span class="Comment"># F10</span>
]
run [
x:address:array:character<span class="Special"> <- </span>new <span class="Constant">[ </span>
<span class="Constant">recipe foo [</span>
<span class="Constant"> get 123:number, foo:offset</span>
<span class="Constant">]</span>]
y:address:array:character<span class="Special"> <- </span>new <span class="Constant">[foo]</span>
env:address:programming-environment-data<span class="Special"> <- </span>new-programming-environment screen:address, x:address:array:character, y:address:array:character
event-loop screen:address, console:address, env:address:programming-environment-data
]
screen-should-contain [
<span class="Constant"> . run (F10) .</span>
<span class="Constant"> . ┊foo .</span>
<span class="Constant"> .recipe foo [ ┊━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━.</span>
<span class="Constant"> . get 123:number, foo:offset ┊ .</span>
<span class="Constant"> .] ┊ .</span>
<span class="Constant"> .unknown element foo in container number ┊ .</span>
<span class="Constant"> .┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┊ .</span>
<span class="Constant"> . ┊ .</span>
]
screen-should-contain-in-color <span class="Constant">1:literal/red</span>, [
<span class="Constant"> . .</span>
<span class="Constant"> . .</span>
<span class="Constant"> . .</span>
<span class="Constant"> . .</span>
<span class="Constant"> . .</span>
<span class="Constant"> .unknown element foo in container number .</span>
<span class="Constant"> . .</span>
]
]
<span class="muScenario">scenario</span> run-shows-missing-type-warnings [
<span class="Constant"> $close-trace</span>
assume-screen <span class="Constant">100:literal/width</span>, <span class="Constant">15:literal/height</span>
assume-console [
press 65526 <span class="Comment"># F10</span>
]
run [
x:address:array:character<span class="Special"> <- </span>new <span class="Constant">[ </span>
<span class="Constant">recipe foo [</span>
<span class="Constant"> x:number <- copy 0</span>
<span class="Constant"> copy x</span>
<span class="Constant">]</span>]
y:address:array:character<span class="Special"> <- </span>new <span class="Constant">[foo]</span>
env:address:programming-environment-data<span class="Special"> <- </span>new-programming-environment screen:address, x:address:array:character, y:address:array:character
event-loop screen:address, console:address, env:address:programming-environment-data
]
screen-should-contain [
<span class="Constant"> . run (F10) .</span>
<span class="Constant"> . ┊foo .</span>
<span class="Constant"> .recipe foo [ ┊━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━.</span>
<span class="Constant"> . x:number <- copy 0 ┊ .</span>
<span class="Constant"> . copy x ┊ .</span>
<span class="Constant"> .] ┊ .</span>
<span class="Constant"> .missing type in 'copy x' ┊ .</span>
<span class="Constant"> .┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┊ .</span>
<span class="Constant"> . ┊ .</span>
]
]
<span class="muScenario">scenario</span> run-shows-get-on-non-container-warnings [
<span class="Constant"> $close-trace</span>
assume-screen <span class="Constant">100:literal/width</span>, <span class="Constant">15:literal/height</span>
assume-console [
press 65526 <span class="Comment"># F10</span>
]
run [
x:address:array:character<span class="Special"> <- </span>new <span class="Constant">[ </span>
<span class="Constant">recipe foo [</span>
<span class="Constant"> x:address:point <- new point:type</span>
<span class="Constant"> get x:address:point, 1:offset</span>
<span class="Constant">]</span>]
y:address:array:character<span class="Special"> <- </span>new <span class="Constant">[foo]</span>
env:address:programming-environment-data<span class="Special"> <- </span>new-programming-environment screen:address, x:address:array:character, y:address:array:character
event-loop screen:address, console:address, env:address:programming-environment-data
]
screen-should-contain [
<span class="Constant"> . run (F10) .</span>
<span class="Constant"> . ┊ .</span>
<span class="Constant"> .recipe foo [ ┊━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━.</span>
<span class="Constant"> . x:address:point <- new point:type ┊ x.</span>
<span class="Constant"> . get x:address:point, 1:offset ┊foo .</span>
<span class="Constant"> .] ┊foo: 'get' on a non-container x:address:point .</span>
<span class="Constant"> .┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┊━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━.</span>
<span class="Constant"> . ┊ .</span>
]
]
<span class="muScenario">scenario</span> run-shows-non-literal-get-argument-warnings [
<span class="Constant"> $close-trace</span>
assume-screen <span class="Constant">100:literal/width</span>, <span class="Constant">15:literal/height</span>
assume-console [
press 65526 <span class="Comment"># F10</span>
]
run [
x:address:array:character<span class="Special"> <- </span>new <span class="Constant">[ </span>
<span class="Constant">recipe foo [</span>
<span class="Constant"> x:number <- copy 0</span>
<span class="Constant"> y:address:point <- new point:type</span>
<span class="Constant"> get y:address:point/deref, x:number</span>
<span class="Constant">]</span>]
y:address:array:character<span class="Special"> <- </span>new <span class="Constant">[foo]</span>
env:address:programming-environment-data<span class="Special"> <- </span>new-programming-environment screen:address, x:address:array:character, y:address:array:character
event-loop screen:address, console:address, env:address:programming-environment-data
]
screen-should-contain [
<span class="Constant"> . run (F10) .</span>
<span class="Constant"> . ┊foo .</span>
<span class="Constant"> .recipe foo [ ┊━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━.</span>
<span class="Constant"> . x:number <- copy 0 ┊ .</span>
<span class="Constant"> . y:address:point <- new point:type ┊ .</span>
<span class="Constant"> . get y:address:point/deref, x:number ┊ .</span>
<span class="Constant"> .] ┊ .</span>
<span class="Constant"> .foo: expected ingredient 1 of 'get' to have type ↩┊ .</span>
<span class="Constant"> .'offset'; got x:number ┊ .</span>
<span class="Constant"> .┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┊ .</span>
<span class="Constant"> . ┊ .</span>
]
]
<span class="SalientComment">## helpers for drawing editor borders</span>
<span class="muRecipe">recipe</span> draw-box [
<span class="Constant">local-scope</span>
screen:address<span class="Special"> <- </span><span class="Constant">next-ingredient</span>
top:number<span class="Special"> <- </span><span class="Constant">next-ingredient</span>
left:number<span class="Special"> <- </span><span class="Constant">next-ingredient</span>
bottom:number<span class="Special"> <- </span><span class="Constant">next-ingredient</span>
right:number<span class="Special"> <- </span><span class="Constant">next-ingredient</span>
color:number, color-found?:boolean<span class="Special"> <- </span><span class="Constant">next-ingredient</span>
<span class="Delimiter">{</span>
<span class="Comment"># default color to white</span>
<span class="muControl">break-if</span> color-found?:boolean
color:number<span class="Special"> <- </span>copy <span class="Constant">245:literal/grey</span>
<span class="Delimiter">}</span>
<span class="Comment"># top border</span>
draw-horizontal screen:address, top:number, left:number, right:number, color:number
draw-horizontal screen:address, bottom:number, left:number, right:number, color:number
draw-vertical screen:address, left:number, top:number, bottom:number, color:number
draw-vertical screen:address, right:number, top:number, bottom:number, color:number
draw-top-left screen:address, top:number, left:number, color:number
draw-top-right screen:address, top:number, right:number, color:number
draw-bottom-left screen:address, bottom:number, left:number, color:number
draw-bottom-right screen:address, bottom:number, right:number, color:number
<span class="Comment"># position cursor inside box</span>
move-cursor screen:address, top:number, left:number
cursor-down screen:address
cursor-right screen:address
]
<span class="muRecipe">recipe</span> draw-horizontal [
<span class="Constant">local-scope</span>
screen:address<span class="Special"> <- </span><span class="Constant">next-ingredient</span>
row:number<span class="Special"> <- </span><span class="Constant">next-ingredient</span>
x:number<span class="Special"> <- </span><span class="Constant">next-ingredient</span>
right:number<span class="Special"> <- </span><span class="Constant">next-ingredient</span>
style:character, style-found?:boolean<span class="Special"> <- </span><span class="Constant">next-ingredient</span>
<span class="Delimiter">{</span>
<span class="muControl">break-if</span> style-found?:boolean
style:character<span class="Special"> <- </span>copy <span class="Constant">9472:literal/horizontal</span>
<span class="Delimiter">}</span>
color:number, color-found?:boolean<span class="Special"> <- </span><span class="Constant">next-ingredient</span>
<span class="Delimiter">{</span>
<span class="Comment"># default color to white</span>
<span class="muControl">break-if</span> color-found?:boolean
color:number<span class="Special"> <- </span>copy <span class="Constant">245:literal/grey</span>
<span class="Delimiter">}</span>
bg-color:number, bg-color-found?:boolean<span class="Special"> <- </span><span class="Constant">next-ingredient</span>
<span class="Delimiter">{</span>
<span class="muControl">break-if</span> bg-color-found?:boolean
bg-color:number<span class="Special"> <- </span>copy <span class="Constant">0:literal/black</span>
<span class="Delimiter">}</span>
move-cursor screen:address, row:number, x:number
<span class="Delimiter">{</span>
continue?:boolean<span class="Special"> <- </span>lesser-or-equal x:number, right:number <span class="Comment"># right is inclusive, to match editor-data semantics</span>
<span class="muControl">break-unless</span> continue?:boolean
print-character screen:address, style:character, color:number, bg-color:number
x:number<span class="Special"> <- </span>add x:number, <span class="Constant">1:literal</span>
<span class="muControl">loop</span>
<span class="Delimiter">}</span>
]
<span class="muRecipe">recipe</span> draw-vertical [
<span class="Constant">local-scope</span>
screen:address<span class="Special"> <- </span><span class="Constant">next-ingredient</span>
col:number<span class="Special"> <- </span><span class="Constant">next-ingredient</span>
x:number<span class="Special"> <- </span><span class="Constant">next-ingredient</span>
bottom:number<span class="Special"> <- </span><span class="Constant">next-ingredient</span>
style:character, style-found?:boolean<span class="Special"> <- </span><span class="Constant">next-ingredient</span>
<span class="Delimiter">{</span>
<span class="muControl">break-if</span> style-found?:boolean
style:character<span class="Special"> <- </span>copy <span class="Constant">9474:literal/vertical</span>
<span class="Delimiter">}</span>
color:number, color-found?:boolean<span class="Special"> <- </span><span class="Constant">next-ingredient</span>
<span class="Delimiter">{</span>
<span class="Comment"># default color to white</span>
<span class="muControl">break-if</span> color-found?:boolean
color:number<span class="Special"> <- </span>copy <span class="Constant">245:literal/grey</span>
<span class="Delimiter">}</span>
<span class="Delimiter">{</span>
continue?:boolean<span class="Special"> <- </span>lesser-than x:number, bottom:number
<span class="muControl">break-unless</span> continue?:boolean
move-cursor screen:address, x:number, col:number
print-character screen:address, style:character, color:number
x:number<span class="Special"> <- </span>add x:number, <span class="Constant">1:literal</span>
<span class="muControl">loop</span>
<span class="Delimiter">}</span>
]
<span class="muRecipe">recipe</span> draw-top-left [
<span class="Constant">local-scope</span>
screen:address<span class="Special"> <- </span><span class="Constant">next-ingredient</span>
top:number<span class="Special"> <- </span><span class="Constant">next-ingredient</span>
left:number<span class="Special"> <- </span><span class="Constant">next-ingredient</span>
color:number, color-found?:boolean<span class="Special"> <- </span><span class="Constant">next-ingredient</span>
<span class="Delimiter">{</span>
<span class="Comment"># default color to white</span>
<span class="muControl">break-if</span> color-found?:boolean
color:number<span class="Special"> <- </span>copy <span class="Constant">245:literal/grey</span>
<span class="Delimiter">}</span>
move-cursor screen:address, top:number, left:number
print-character screen:address, <span class="Constant">9484:literal/down-right</span>, color:number
]
<span class="muRecipe">recipe</span> draw-top-right [
<span class="Constant">local-scope</span>
screen:address<span class="Special"> <- </span><span class="Constant">next-ingredient</span>
top:number<span class="Special"> <- </span><span class="Constant">next-ingredient</span>
right:number<span class="Special"> <- </span><span class="Constant">next-ingredient</span>
color:number, color-found?:boolean<span class="Special"> <- </span><span class="Constant">next-ingredient</span>
<span class="Delimiter">{</span>
<span class="Comment"># default color to white</span>
<span class="muControl">break-if</span> color-found?:boolean
color:number<span class="Special"> <- </span>copy <span class="Constant">245:literal/grey</span>
<span class="Delimiter">}</span>
move-cursor screen:address, top:number, right:number
print-character screen:address, <span class="Constant">9488:literal/down-left</span>, color:number
]
<span class="muRecipe">recipe</span> draw-bottom-left [
<span class="Constant">local-scope</span>
screen:address<span class="Special"> <- </span><span class="Constant">next-ingredient</span>
bottom:number<span class="Special"> <- </span><span class="Constant">next-ingredient</span>
left:number<span class="Special"> <- </span><span class="Constant">next-ingredient</span>
color:number, color-found?:boolean<span class="Special"> <- </span><span class="Constant">next-ingredient</span>
<span class="Delimiter">{</span>
<span class="Comment"># default color to white</span>
<span class="muControl">break-if</span> color-found?:boolean
color:number<span class="Special"> <- </span>copy <span class="Constant">245:literal/grey</span>
<span class="Delimiter">}</span>
move-cursor screen:address, bottom:number, left:number
print-character screen:address, <span class="Constant">9492:literal/up-right</span>, color:number
]
<span class="muRecipe">recipe</span> draw-bottom-right [
<span class="Constant">local-scope</span>
screen:address<span class="Special"> <- </span><span class="Constant">next-ingredient</span>
bottom:number<span class="Special"> <- </span><span class="Constant">next-ingredient</span>
right:number<span class="Special"> <- </span><span class="Constant">next-ingredient</span>
color:number, color-found?:boolean<span class="Special"> <- </span><span class="Constant">next-ingredient</span>
<span class="Delimiter">{</span>
<span class="Comment"># default color to white</span>
<span class="muControl">break-if</span> color-found?:boolean
color:number<span class="Special"> <- </span>copy <span class="Constant">245:literal/grey</span>
<span class="Delimiter">}</span>
move-cursor screen:address, bottom:number, right:number
print-character screen:address, <span class="Constant">9496:literal/up-left</span>, color:number
]
<span class="muRecipe">recipe</span> print-string-with-gradient-background [
<span class="Constant">local-scope</span>
x:address:screen<span class="Special"> <- </span><span class="Constant">next-ingredient</span>
s:address:array:character<span class="Special"> <- </span><span class="Constant">next-ingredient</span>
color:number<span class="Special"> <- </span><span class="Constant">next-ingredient</span>
bg-color1:number<span class="Special"> <- </span><span class="Constant">next-ingredient</span>
bg-color2:number<span class="Special"> <- </span><span class="Constant">next-ingredient</span>
len:number<span class="Special"> <- </span>length s:address:array:character/deref
color-range:number<span class="Special"> <- </span>subtract bg-color2:number, bg-color1:number
color-quantum:number<span class="Special"> <- </span>divide color-range:number, len:number
<span class="CommentedCode">#? close-console #? 2</span>
<span class="CommentedCode">#? $print len:number, [, ], color-range:number, [, ], color-quantum:number, 10:literal/newline</span>
<span class="CommentedCode">#? #? $exit #? 3</span>
bg-color:number<span class="Special"> <- </span>copy bg-color1:number
i:number<span class="Special"> <- </span>copy <span class="Constant">0:literal</span>
<span class="Delimiter">{</span>
done?:boolean<span class="Special"> <- </span>greater-or-equal i:number, len:number
<span class="muControl">break-if</span> done?:boolean
c:character<span class="Special"> <- </span>index s:address:array:character/deref, i:number
print-character x:address:screen, c:character, color:number, bg-color:number
i:number<span class="Special"> <- </span>add i:number, <span class="Constant">1:literal</span>
bg-color:number<span class="Special"> <- </span>add bg-color:number, color-quantum:number
<span class="CommentedCode">#? $print [=> ], bg-color:number, 10:literal/newline</span>
<span class="muControl">loop</span>
<span class="Delimiter">}</span>
<span class="CommentedCode">#? $exit #? 1</span>
<span class="muControl">reply</span> x:address:screen/same-as-ingredient:0
]
</pre>
</body>
</html>
<!-- vim: set foldmethod=manual : -->