diff options
Diffstat (limited to 'html')
35 files changed, 12270 insertions, 9309 deletions
diff --git a/html/051scenario_test.mu.html b/html/051scenario_test.mu.html index f7807a4d..d38539dd 100644 --- a/html/051scenario_test.mu.html +++ b/html/051scenario_test.mu.html @@ -13,9 +13,10 @@ 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; } .Comment { color: #9090ff; } +.Constant { color: #00a0a0; } .Special { color: #ff6060; } -.Identifier { color: #804000; } --> </style> @@ -29,69 +30,69 @@ body { font-family: monospace; color: #eeeeee; background-color: #080808; } <pre id='vimCodeElement'> <span class="Comment"># tests for 'scenario' in previous layer</span> -scenario first_scenario_in_mu [ +<span class="muScenario">scenario</span> first_scenario_in_mu [ run [ - 1:number<span class="Special"> <- </span>add 2, 2 + <span class="Constant">1</span>:number<span class="Special"> <- </span>add <span class="Constant">2</span>, <span class="Constant">2</span> ] memory-should-contain [ - 1<span class="Special"> <- </span>4 + <span class="Constant">1</span><span class="Special"> <- </span><span class="Constant">4</span> ] ] -scenario scenario_with_comment_in_mu [ +<span class="muScenario">scenario</span> scenario_with_comment_in_mu [ run [ <span class="Comment"># comment</span> - 1:number<span class="Special"> <- </span>add 2, 2 + <span class="Constant">1</span>:number<span class="Special"> <- </span>add <span class="Constant">2</span>, <span class="Constant">2</span> ] memory-should-contain [ - 1<span class="Special"> <- </span>4 + <span class="Constant">1</span><span class="Special"> <- </span><span class="Constant">4</span> ] ] -scenario scenario_with_multiple_comments_in_mu [ +<span class="muScenario">scenario</span> scenario_with_multiple_comments_in_mu [ run [ <span class="Comment"># comment1</span> <span class="Comment"># comment2</span> - 1:number<span class="Special"> <- </span>add 2, 2 + <span class="Constant">1</span>:number<span class="Special"> <- </span>add <span class="Constant">2</span>, <span class="Constant">2</span> ] memory-should-contain [ - 1<span class="Special"> <- </span>4 + <span class="Constant">1</span><span class="Special"> <- </span><span class="Constant">4</span> ] ] -scenario check_string_in_memory [ +<span class="muScenario">scenario</span> check_string_in_memory [ run [ - 1:number<span class="Special"> <- </span><span class="Identifier">copy</span> 3 - 2:character<span class="Special"> <- </span><span class="Identifier">copy</span> 97 <span class="Comment"># 'a'</span> - 3:character<span class="Special"> <- </span><span class="Identifier">copy</span> 98 <span class="Comment"># 'b'</span> - 4:character<span class="Special"> <- </span><span class="Identifier">copy</span> 99 <span class="Comment"># 'c'</span> + <span class="Constant">1</span>:number<span class="Special"> <- </span>copy <span class="Constant">3</span> + <span class="Constant">2</span>:character<span class="Special"> <- </span>copy <span class="Constant">97</span> <span class="Comment"># 'a'</span> + <span class="Constant">3</span>:character<span class="Special"> <- </span>copy <span class="Constant">98</span> <span class="Comment"># 'b'</span> + <span class="Constant">4</span>:character<span class="Special"> <- </span>copy <span class="Constant">99</span> <span class="Comment"># 'c'</span> ] memory-should-contain [ - 1:string<span class="Special"> <- </span>[abc] + <span class="Constant">1</span>:string<span class="Special"> <- </span><span class="Constant">[abc]</span> ] ] -scenario check_trace [ +<span class="muScenario">scenario</span> check_trace [ run [ - 1:number<span class="Special"> <- </span>add 2, 2 + <span class="Constant">1</span>:number<span class="Special"> <- </span>add <span class="Constant">2</span>, <span class="Constant">2</span> ] trace-should-contain [ - mem: storing 4 <span class="Identifier">in</span> location 1 + mem: storing <span class="Constant">4</span> in location <span class="Constant">1</span> ] ] -scenario check_trace_negative [ +<span class="muScenario">scenario</span> check_trace_negative [ run [ - 1:number<span class="Special"> <- </span>add 2, 2 + <span class="Constant">1</span>:number<span class="Special"> <- </span>add <span class="Constant">2</span>, <span class="Constant">2</span> ] trace-should-not-contain [ - mem: storing 5 <span class="Identifier">in</span> location 1 + mem: storing <span class="Constant">5</span> in location <span class="Constant">1</span> ] ] -scenario check_trace_instruction [ +<span class="muScenario">scenario</span> check_trace_instruction [ run [ - trace 1, [foo], [aaa] + trace <span class="Constant">1</span>, <span class="Constant">[foo]</span>, <span class="Constant">[aaa]</span> ] trace-should-contain [ foo: aaa diff --git a/html/060string.mu.html b/html/060string.mu.html index ff86a100..a5cf9f7a 100644 --- a/html/060string.mu.html +++ b/html/060string.mu.html @@ -13,10 +13,14 @@ 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; } -.Special { color: #ff6060; } +.muRecipe { color: #ff8700; } +.muData { color: #ffff00; } +.muScenario { color: #00af00; } .Comment { color: #9090ff; } -.Underlined { color: #c000c0; text-decoration: underline; } -.Identifier { color: #804000; } +.Constant { color: #00a0a0; } +.Special { color: #ff6060; } +.Delimiter { color: #a04060; } +.muControl { color: #c0a020; } --> </style> @@ -30,70 +34,70 @@ body { font-family: monospace; color: #eeeeee; background-color: #080808; } <pre id='vimCodeElement'> <span class="Comment"># Some useful helpers for dealing with strings.</span> -recipe string-equal [ - <span class="Underlined">local</span>-scope - a:address:<span class="Identifier">array</span>:character<span class="Special"> <- </span>next-ingredient - a-len:number<span class="Special"> <- </span><span class="Identifier">length</span> *a - b:address:<span class="Identifier">array</span>:character<span class="Special"> <- </span>next-ingredient - b-len:number<span class="Special"> <- </span><span class="Identifier">length</span> *b +<span class="muRecipe">recipe</span> string-equal [ + <span class="Constant">local-scope</span> + a:address:array:character<span class="Special"> <- </span><span class="Constant">next-ingredient</span> + a-len:number<span class="Special"> <- </span>length *a + b:address:array:character<span class="Special"> <- </span><span class="Constant">next-ingredient</span> + b-len:number<span class="Special"> <- </span>length *b <span class="Comment"># compare lengths</span> - { - trace 99, [string-equal], [comparing lengths] - <span class="Identifier">length</span>-equal?:boolean<span class="Special"> <- </span>equal a-len, b-len - break-if <span class="Identifier">length</span>-equal? - reply 0 - } + <span class="Delimiter">{</span> + trace <span class="Constant">99</span>, <span class="Constant">[string-equal]</span>, <span class="Constant">[comparing lengths]</span> + length-equal?:boolean<span class="Special"> <- </span>equal a-len, b-len + <span class="muControl">break-if</span> length-equal? + <span class="muControl">reply</span> <span class="Constant">0</span> + <span class="Delimiter">}</span> <span class="Comment"># compare each corresponding character</span> - trace 99, [string-equal], [comparing characters] - i:number<span class="Special"> <- </span><span class="Identifier">copy</span> 0 - { + trace <span class="Constant">99</span>, <span class="Constant">[string-equal]</span>, <span class="Constant">[comparing characters]</span> + i:number<span class="Special"> <- </span>copy <span class="Constant">0</span> + <span class="Delimiter">{</span> done?:boolean<span class="Special"> <- </span>greater-or-equal i, a-len - break-if done? + <span class="muControl">break-if</span> done? a2:character<span class="Special"> <- </span>index *a, i b2:character<span class="Special"> <- </span>index *b, i - { - chars-<span class="Identifier">match</span>?:boolean<span class="Special"> <- </span>equal a2, b2 - break-if chars-<span class="Identifier">match</span>? - reply 0 - } - i<span class="Special"> <- </span>add i, 1 - loop - } - reply 1 -] - -scenario string-equal-reflexive [ + <span class="Delimiter">{</span> + chars-match?:boolean<span class="Special"> <- </span>equal a2, b2 + <span class="muControl">break-if</span> chars-match? + <span class="muControl">reply</span> <span class="Constant">0</span> + <span class="Delimiter">}</span> + i<span class="Special"> <- </span>add i, <span class="Constant">1</span> + <span class="muControl">loop</span> + <span class="Delimiter">}</span> + <span class="muControl">reply</span> <span class="Constant">1</span> +] + +<span class="muScenario">scenario</span> string-equal-reflexive [ run [ - default-space:address:<span class="Identifier">array</span>:location<span class="Special"> <- </span><span class="Identifier">new</span> location:<span class="Identifier">type</span>, 30 - x:address:<span class="Identifier">array</span>:character<span class="Special"> <- </span><span class="Identifier">new</span> [abc] - 3:boolean/<span class="Special">raw <- </span>string-equal x, x + <span class="Constant">default-space</span>:address:array:location<span class="Special"> <- </span>new <span class="Constant">location:type</span>, <span class="Constant">30</span> + x:address:array:character<span class="Special"> <- </span>new <span class="Constant">[abc]</span> + <span class="Constant">3</span>:boolean/<span class="Special">raw <- </span>string-equal x, x ] memory-should-contain [ - 3<span class="Special"> <- </span>1 <span class="Comment"># x == x for all x</span> + <span class="Constant">3</span><span class="Special"> <- </span><span class="Constant">1</span> <span class="Comment"># x == x for all x</span> ] ] -scenario string-equal-identical [ +<span class="muScenario">scenario</span> string-equal-identical [ run [ - default-space:address:<span class="Identifier">array</span>:location<span class="Special"> <- </span><span class="Identifier">new</span> location:<span class="Identifier">type</span>, 30 - x:address:<span class="Identifier">array</span>:character<span class="Special"> <- </span><span class="Identifier">new</span> [abc] - y:address:<span class="Identifier">array</span>:character<span class="Special"> <- </span><span class="Identifier">new</span> [abc] - 3:boolean/<span class="Special">raw <- </span>string-equal x, y + <span class="Constant">default-space</span>:address:array:location<span class="Special"> <- </span>new <span class="Constant">location:type</span>, <span class="Constant">30</span> + x:address:array:character<span class="Special"> <- </span>new <span class="Constant">[abc]</span> + y:address:array:character<span class="Special"> <- </span>new <span class="Constant">[abc]</span> + <span class="Constant">3</span>:boolean/<span class="Special">raw <- </span>string-equal x, y ] memory-should-contain [ - 3<span class="Special"> <- </span>1 <span class="Comment"># abc == abc</span> + <span class="Constant">3</span><span class="Special"> <- </span><span class="Constant">1</span> <span class="Comment"># abc == abc</span> ] ] -scenario string-equal-distinct-lengths [ +<span class="muScenario">scenario</span> string-equal-distinct-lengths [ run [ - default-space:address:<span class="Identifier">array</span>:location<span class="Special"> <- </span><span class="Identifier">new</span> location:<span class="Identifier">type</span>, 30 - x:address:<span class="Identifier">array</span>:character<span class="Special"> <- </span><span class="Identifier">new</span> [abc] - y:address:<span class="Identifier">array</span>:character<span class="Special"> <- </span><span class="Identifier">new</span> [abcd] - 3:boolean/<span class="Special">raw <- </span>string-equal x, y + <span class="Constant">default-space</span>:address:array:location<span class="Special"> <- </span>new <span class="Constant">location:type</span>, <span class="Constant">30</span> + x:address:array:character<span class="Special"> <- </span>new <span class="Constant">[abc]</span> + y:address:array:character<span class="Special"> <- </span>new <span class="Constant">[abcd]</span> + <span class="Constant">3</span>:boolean/<span class="Special">raw <- </span>string-equal x, y ] memory-should-contain [ - 3<span class="Special"> <- </span>0 <span class="Comment"># abc != abcd</span> + <span class="Constant">3</span><span class="Special"> <- </span><span class="Constant">0</span> <span class="Comment"># abc != abcd</span> ] trace-should-contain [ string-equal: comparing lengths @@ -103,1250 +107,1250 @@ scenario string-equal-distinct-lengths [ ] ] -scenario string-equal-with-empty [ +<span class="muScenario">scenario</span> string-equal-with-empty [ run [ - default-space:address:<span class="Identifier">array</span>:location<span class="Special"> <- </span><span class="Identifier">new</span> location:<span class="Identifier">type</span>, 30 - x:address:<span class="Identifier">array</span>:character<span class="Special"> <- </span><span class="Identifier">new</span> [] - y:address:<span class="Identifier">array</span>:character<span class="Special"> <- </span><span class="Identifier">new</span> [abcd] - 3:boolean/<span class="Special">raw <- </span>string-equal x, y + <span class="Constant">default-space</span>:address:array:location<span class="Special"> <- </span>new <span class="Constant">location:type</span>, <span class="Constant">30</span> + x:address:array:character<span class="Special"> <- </span>new <span class="Constant">[]</span> + y:address:array:character<span class="Special"> <- </span>new <span class="Constant">[abcd]</span> + <span class="Constant">3</span>:boolean/<span class="Special">raw <- </span>string-equal x, y ] memory-should-contain [ - 3<span class="Special"> <- </span>0 <span class="Comment"># "" != abcd</span> + <span class="Constant">3</span><span class="Special"> <- </span><span class="Constant">0</span> <span class="Comment"># "" != abcd</span> ] ] -scenario string-equal-common-lengths-but-distinct [ +<span class="muScenario">scenario</span> string-equal-common-lengths-but-distinct [ run [ - default-space:address:<span class="Identifier">array</span>:location<span class="Special"> <- </span><span class="Identifier">new</span> location:<span class="Identifier">type</span>, 30 - x:address:<span class="Identifier">array</span>:character<span class="Special"> <- </span><span class="Identifier">new</span> [abc] - y:address:<span class="Identifier">array</span>:character<span class="Special"> <- </span><span class="Identifier">new</span> [abd] - 3:boolean/<span class="Special">raw <- </span>string-equal x, y + <span class="Constant">default-space</span>:address:array:location<span class="Special"> <- </span>new <span class="Constant">location:type</span>, <span class="Constant">30</span> + x:address:array:character<span class="Special"> <- </span>new <span class="Constant">[abc]</span> + y:address:array:character<span class="Special"> <- </span>new <span class="Constant">[abd]</span> + <span class="Constant">3</span>:boolean/<span class="Special">raw <- </span>string-equal x, y ] memory-should-contain [ - 3<span class="Special"> <- </span>0 <span class="Comment"># abc != abd</span> + <span class="Constant">3</span><span class="Special"> <- </span><span class="Constant">0</span> <span class="Comment"># abc != abd</span> ] ] <span class="Comment"># A new type to help incrementally construct strings.</span> -container buffer [ - <span class="Identifier">length</span>:number - data:address:<span class="Identifier">array</span>:character -] - -recipe <span class="Identifier">new</span>-buffer [ - <span class="Underlined">local</span>-scope - result:address:buffer<span class="Special"> <- </span><span class="Identifier">new</span> buffer:<span class="Identifier">type</span> - len:address:number<span class="Special"> <- </span>get-address *result, <span class="Identifier">length</span>:offset - *len:address:number<span class="Special"> <- </span><span class="Identifier">copy</span> 0 - s:address:address:<span class="Identifier">array</span>:character<span class="Special"> <- </span>get-address *result, data:offset - capacity:number, found?:boolean<span class="Special"> <- </span>next-ingredient - <span class="Identifier">assert</span> found?, [<span class="Identifier">new</span>-buffer must get a capacity argument] - *s<span class="Special"> <- </span><span class="Identifier">new</span> character:<span class="Identifier">type</span>, capacity - reply result -] - -recipe grow-buffer [ - <span class="Underlined">local</span>-scope - <span class="Identifier">in</span>:address:buffer<span class="Special"> <- </span>next-ingredient +<span class="muData">container</span> buffer [ + length:number + data:address:array:character +] + +<span class="muRecipe">recipe</span> new-buffer [ + <span class="Constant">local-scope</span> + result:address:buffer<span class="Special"> <- </span>new <span class="Constant">buffer:type</span> + len:address:number<span class="Special"> <- </span>get-address *result, <span class="Constant">length:offset</span> + *len:address:number<span class="Special"> <- </span>copy <span class="Constant">0</span> + s:address:address:array:character<span class="Special"> <- </span>get-address *result, <span class="Constant">data:offset</span> + capacity:number, found?:boolean<span class="Special"> <- </span><span class="Constant">next-ingredient</span> + assert found?, <span class="Constant">[new-buffer must get a capacity argument]</span> + *s<span class="Special"> <- </span>new <span class="Constant">character:type</span>, capacity + <span class="muControl">reply</span> result +] + +<span class="muRecipe">recipe</span> grow-buffer [ + <span class="Constant">local-scope</span> + in:address:buffer<span class="Special"> <- </span><span class="Constant">next-ingredient</span> <span class="Comment"># double buffer size</span> - x:address:address:<span class="Identifier">array</span>:character<span class="Special"> <- </span>get-address *<span class="Identifier">in</span>, data:offset - oldlen:number<span class="Special"> <- </span><span class="Identifier">length</span> **x - newlen:number<span class="Special"> <- </span>multiply oldlen, 2 - olddata:address:<span class="Identifier">array</span>:character<span class="Special"> <- </span><span class="Identifier">copy</span> *x - *x<span class="Special"> <- </span><span class="Identifier">new</span> character:<span class="Identifier">type</span>, newlen + x:address:address:array:character<span class="Special"> <- </span>get-address *in, <span class="Constant">data:offset</span> + oldlen:number<span class="Special"> <- </span>length **x + newlen:number<span class="Special"> <- </span>multiply oldlen, <span class="Constant">2</span> + olddata:address:array:character<span class="Special"> <- </span>copy *x + *x<span class="Special"> <- </span>new <span class="Constant">character:type</span>, newlen <span class="Comment"># copy old contents</span> - i:number<span class="Special"> <- </span><span class="Identifier">copy</span> 0 - { + i:number<span class="Special"> <- </span>copy <span class="Constant">0</span> + <span class="Delimiter">{</span> done?:boolean<span class="Special"> <- </span>greater-or-equal i, oldlen - break-if done? + <span class="muControl">break-if</span> done? src:character<span class="Special"> <- </span>index *olddata, i dest:address:character<span class="Special"> <- </span>index-address **x, i - *dest<span class="Special"> <- </span><span class="Identifier">copy</span> src - i<span class="Special"> <- </span>add i, 1 - loop - } - reply <span class="Identifier">in</span> -] - -recipe buffer-full? [ - <span class="Underlined">local</span>-scope - <span class="Identifier">in</span>:address:buffer<span class="Special"> <- </span>next-ingredient - len:number<span class="Special"> <- </span>get *<span class="Identifier">in</span>, <span class="Identifier">length</span>:offset - s:address:<span class="Identifier">array</span>:character<span class="Special"> <- </span>get *<span class="Identifier">in</span>, data:offset - capacity:number<span class="Special"> <- </span><span class="Identifier">length</span> *s + *dest<span class="Special"> <- </span>copy src + i<span class="Special"> <- </span>add i, <span class="Constant">1</span> + <span class="muControl">loop</span> + <span class="Delimiter">}</span> + <span class="muControl">reply</span> in +] + +<span class="muRecipe">recipe</span> buffer-full? [ + <span class="Constant">local-scope</span> + in:address:buffer<span class="Special"> <- </span><span class="Constant">next-ingredient</span> + len:number<span class="Special"> <- </span>get *in, <span class="Constant">length:offset</span> + s:address:array:character<span class="Special"> <- </span>get *in, <span class="Constant">data:offset</span> + capacity:number<span class="Special"> <- </span>length *s result:boolean<span class="Special"> <- </span>greater-or-equal len, capacity - reply result + <span class="muControl">reply</span> result ] <span class="Comment"># in <- buffer-append in:address:buffer, c:character</span> -recipe buffer-<span class="Identifier">append</span> [ - <span class="Underlined">local</span>-scope - <span class="Identifier">in</span>:address:buffer<span class="Special"> <- </span>next-ingredient - c:character<span class="Special"> <- </span>next-ingredient - len:address:number<span class="Special"> <- </span>get-address *<span class="Identifier">in</span>, <span class="Identifier">length</span>:offset - { +<span class="muRecipe">recipe</span> buffer-append [ + <span class="Constant">local-scope</span> + in:address:buffer<span class="Special"> <- </span><span class="Constant">next-ingredient</span> + c:character<span class="Special"> <- </span><span class="Constant">next-ingredient</span> + len:address:number<span class="Special"> <- </span>get-address *in, <span class="Constant">length:offset</span> + <span class="Delimiter">{</span> <span class="Comment"># backspace? just drop last character if it exists and return</span> - backspace?:boolean<span class="Special"> <- </span>equal c, 8/backspace - break-unless backspace? - empty?:boolean<span class="Special"> <- </span>lesser-or-equal *len, 0 - reply-if empty?, <span class="Identifier">in</span>/same-as-ingredient:0 - *len<span class="Special"> <- </span>subtract *len, 1 - reply <span class="Identifier">in</span>/same-as-ingredient:0 - } - { + backspace?:boolean<span class="Special"> <- </span>equal c, <span class="Constant">8/backspace</span> + <span class="muControl">break-unless</span> backspace? + empty?:boolean<span class="Special"> <- </span>lesser-or-equal *len, <span class="Constant">0</span> + <span class="muControl">reply-if</span> empty?, in/same-as-ingredient:<span class="Constant">0</span> + *len<span class="Special"> <- </span>subtract *len, <span class="Constant">1</span> + <span class="muControl">reply</span> in/same-as-ingredient:<span class="Constant">0</span> + <span class="Delimiter">}</span> + <span class="Delimiter">{</span> <span class="Comment"># grow buffer if necessary</span> - full?:boolean<span class="Special"> <- </span>buffer-full? <span class="Identifier">in</span> - break-unless full? - <span class="Identifier">in</span><span class="Special"> <- </span>grow-buffer <span class="Identifier">in</span> - } - s:address:<span class="Identifier">array</span>:character<span class="Special"> <- </span>get *<span class="Identifier">in</span>, data:offset + full?:boolean<span class="Special"> <- </span>buffer-full? in + <span class="muControl">break-unless</span> full? + in<span class="Special"> <- </span>grow-buffer in + <span class="Delimiter">}</span> + s:address:array:character<span class="Special"> <- </span>get *in, <span class="Constant">data:offset</span> dest:address:character<span class="Special"> <- </span>index-address *s, *len - *dest<span class="Special"> <- </span><span class="Identifier">copy</span> c - *len<span class="Special"> <- </span>add *len, 1 - reply <span class="Identifier">in</span>/same-as-ingredient:0 + *dest<span class="Special"> <- </span>copy c + *len<span class="Special"> <- </span>add *len, <span class="Constant">1</span> + <span class="muControl">reply</span> in/same-as-ingredient:<span class="Constant">0</span> ] -scenario buffer-<span class="Identifier">append</span>-works [ +<span class="muScenario">scenario</span> buffer-append-works [ run [ - <span class="Underlined">local</span>-scope - x:address:buffer<span class="Special"> <- </span><span class="Identifier">new</span>-buffer 3 - s1:address:<span class="Identifier">array</span>:character<span class="Special"> <- </span>get *x:address:buffer, data:offset - x:address:buffer<span class="Special"> <- </span>buffer-<span class="Identifier">append</span> x:address:buffer, 97 <span class="Comment"># 'a'</span> - x:address:buffer<span class="Special"> <- </span>buffer-<span class="Identifier">append</span> x:address:buffer, 98 <span class="Comment"># 'b'</span> - x:address:buffer<span class="Special"> <- </span>buffer-<span class="Identifier">append</span> x:address:buffer, 99 <span class="Comment"># 'c'</span> - s2:address:<span class="Identifier">array</span>:character<span class="Special"> <- </span>get *x:address:buffer, data:offset - 1:boolean/<span class="Special">raw <- </span>equal s1:address:<span class="Identifier">array</span>:character, s2:address:<span class="Identifier">array</span>:character - 2:<span class="Identifier">array</span>:character/<span class="Special">raw <- </span><span class="Identifier">copy</span> *s2:address:<span class="Identifier">array</span>:character - +buffer-filled - x:address:buffer<span class="Special"> <- </span>buffer-<span class="Identifier">append</span> x:address:buffer, 100 <span class="Comment"># 'd'</span> - s3:address:<span class="Identifier">array</span>:character<span class="Special"> <- </span>get *x:address:buffer, data:offset - 10:boolean/<span class="Special">raw <- </span>equal s1:address:<span class="Identifier">array</span>:character, s3:address:<span class="Identifier">array</span>:character - 11:number/<span class="Special">raw <- </span>get *x:address:buffer, <span class="Identifier">length</span>:offset - 12:<span class="Identifier">array</span>:character/<span class="Special">raw <- </span><span class="Identifier">copy</span> *s3:address:<span class="Identifier">array</span>:character + <span class="Constant">local-scope</span> + x:address:buffer<span class="Special"> <- </span>new-buffer <span class="Constant">3</span> + s1:address:array:character<span class="Special"> <- </span>get *x:address:buffer, <span class="Constant">data:offset</span> + x:address:buffer<span class="Special"> <- </span>buffer-append x:address:buffer, <span class="Constant">97</span> <span class="Comment"># 'a'</span> + x:address:buffer<span class="Special"> <- </span>buffer-append x:address:buffer, <span class="Constant">98</span> <span class="Comment"># 'b'</span> + x:address:buffer<span class="Special"> <- </span>buffer-append x:address:buffer, <span class="Constant">99</span> <span class="Comment"># 'c'</span> + s2:address:array:character<span class="Special"> <- </span>get *x:address:buffer, <span class="Constant">data:offset</span> + <span class="Constant">1</span>:boolean/<span class="Special">raw <- </span>equal s1:address:array:character, s2:address:array:character + <span class="Constant">2</span>:array:character/<span class="Special">raw <- </span>copy *s2:address:array:character +<span class="Constant"> +buffer-filled</span> + x:address:buffer<span class="Special"> <- </span>buffer-append x:address:buffer, <span class="Constant">100</span> <span class="Comment"># 'd'</span> + s3:address:array:character<span class="Special"> <- </span>get *x:address:buffer, <span class="Constant">data:offset</span> + <span class="Constant">10</span>:boolean/<span class="Special">raw <- </span>equal s1:address:array:character, s3:address:array:character + <span class="Constant">11</span>:number/<span class="Special">raw <- </span>get *x:address:buffer, <span class="Constant">length:offset</span> + <span class="Constant">12</span>:array:character/<span class="Special">raw <- </span>copy *s3:address:array:character ] memory-should-contain [ <span class="Comment"># before +buffer-filled</span> - 1<span class="Special"> <- </span>1 <span class="Comment"># no change in data pointer</span> - 2<span class="Special"> <- </span>3 <span class="Comment"># size of data</span> - 3<span class="Special"> <- </span>97 <span class="Comment"># data</span> - 4<span class="Special"> <- </span>98 - 5<span class="Special"> <- </span>99 + <span class="Constant">1</span><span class="Special"> <- </span><span class="Constant">1</span> <span class="Comment"># no change in data pointer</span> + <span class="Constant">2</span><span class="Special"> <- </span><span class="Constant">3</span> <span class="Comment"># size of data</span> + <span class="Constant">3</span><span class="Special"> <- </span><span class="Constant">97</span> <span class="Comment"># data</span> + <span class="Constant">4</span><span class="Special"> <- </span><span class="Constant">98</span> + <span class="Constant">5</span><span class="Special"> <- </span><span class="Constant">99</span> <span class="Comment"># in the end</span> - 10<span class="Special"> <- </span>0 <span class="Comment"># data pointer has grown</span> - 11<span class="Special"> <- </span>4 <span class="Comment"># final length</span> - 12<span class="Special"> <- </span>6 <span class="Comment"># but data's capacity has doubled</span> - 13<span class="Special"> <- </span>97 <span class="Comment"># data</span> - 14<span class="Special"> <- </span>98 - 15<span class="Special"> <- </span>99 - 16<span class="Special"> <- </span>100 - 17<span class="Special"> <- </span>0 - 18<span class="Special"> <- </span>0 + <span class="Constant">10</span><span class="Special"> <- </span><span class="Constant">0</span> <span class="Comment"># data pointer has grown</span> + <span class="Constant">11</span><span class="Special"> <- </span><span class="Constant">4</span> <span class="Comment"># final length</span> + <span class="Constant">12</span><span class="Special"> <- </span><span class="Constant">6</span> <span class="Comment"># but data's capacity has doubled</span> + <span class="Constant">13</span><span class="Special"> <- </span><span class="Constant">97</span> <span class="Comment"># data</span> + <span class="Constant">14</span><span class="Special"> <- </span><span class="Constant">98</span> + <span class="Constant">15</span><span class="Special"> <- </span><span class="Constant">99</span> + <span class="Constant">16</span><span class="Special"> <- </span><span class="Constant">100</span> + <span class="Constant">17</span><span class="Special"> <- </span><span class="Constant">0</span> + <span class="Constant">18</span><span class="Special"> <- </span><span class="Constant">0</span> ] ] -scenario buffer-<span class="Identifier">append</span>-handles-backspace [ +<span class="muScenario">scenario</span> buffer-append-handles-backspace [ run [ - <span class="Underlined">local</span>-scope - x:address:buffer<span class="Special"> <- </span><span class="Identifier">new</span>-buffer 3 - x<span class="Special"> <- </span>buffer-<span class="Identifier">append</span> x, 97 <span class="Comment"># 'a'</span> - x<span class="Special"> <- </span>buffer-<span class="Identifier">append</span> x, 98 <span class="Comment"># 'b'</span> - x<span class="Special"> <- </span>buffer-<span class="Identifier">append</span> x, 8/backspace - s:address:<span class="Identifier">array</span>:character<span class="Special"> <- </span>buffer-to-<span class="Identifier">array</span> x - 1:<span class="Identifier">array</span>:character/<span class="Special">raw <- </span><span class="Identifier">copy</span> *s + <span class="Constant">local-scope</span> + x:address:buffer<span class="Special"> <- </span>new-buffer <span class="Constant">3</span> + x<span class="Special"> <- </span>buffer-append x, <span class="Constant">97</span> <span class="Comment"># 'a'</span> + x<span class="Special"> <- </span>buffer-append x, <span class="Constant">98</span> <span class="Comment"># 'b'</span> + x<span class="Special"> <- </span>buffer-append x, <span class="Constant">8/backspace</span> + s:address:array:character<span class="Special"> <- </span>buffer-to-array x + <span class="Constant">1</span>:array:character/<span class="Special">raw <- </span>copy *s ] memory-should-contain [ - 1<span class="Special"> <- </span>1 <span class="Comment"># length</span> - 2<span class="Special"> <- </span>97 <span class="Comment"># contents</span> - 3<span class="Special"> <- </span>0 + <span class="Constant">1</span><span class="Special"> <- </span><span class="Constant">1</span> <span class="Comment"># length</span> + <span class="Constant">2</span><span class="Special"> <- </span><span class="Constant">97</span> <span class="Comment"># contents</span> + <span class="Constant">3</span><span class="Special"> <- </span><span class="Constant">0</span> ] ] <span class="Comment"># result:address:array:character <- integer-to-decimal-string n:number</span> -recipe integer-to-decimal-string [ - <span class="Underlined">local</span>-scope - n:number<span class="Special"> <- </span>next-ingredient +<span class="muRecipe">recipe</span> integer-to-decimal-string [ + <span class="Constant">local-scope</span> + n:number<span class="Special"> <- </span><span class="Constant">next-ingredient</span> <span class="Comment"># is it zero?</span> - { - break-if n - result:address:<span class="Identifier">array</span>:character<span class="Special"> <- </span><span class="Identifier">new</span> [0] - reply result - } + <span class="Delimiter">{</span> + <span class="muControl">break-if</span> n + result:address:array:character<span class="Special"> <- </span>new <span class="Constant">[0]</span> + <span class="muControl">reply</span> result + <span class="Delimiter">}</span> <span class="Comment"># save sign</span> - negate-result:boolean<span class="Special"> <- </span><span class="Identifier">copy</span> 0 - { - negative?:boolean<span class="Special"> <- </span>lesser-than n, 0 - break-unless negative? - negate-result<span class="Special"> <- </span><span class="Identifier">copy</span> 1 - n<span class="Special"> <- </span>multiply n, -1 - } + negate-result:boolean<span class="Special"> <- </span>copy <span class="Constant">0</span> + <span class="Delimiter">{</span> + negative?:boolean<span class="Special"> <- </span>lesser-than n, <span class="Constant">0</span> + <span class="muControl">break-unless</span> negative? + negate-result<span class="Special"> <- </span>copy <span class="Constant">1</span> + n<span class="Special"> <- </span>multiply n, <span class="Constant">-1</span> + <span class="Delimiter">}</span> <span class="Comment"># add digits from right to left into intermediate buffer</span> - tmp:address:buffer<span class="Special"> <- </span><span class="Identifier">new</span>-buffer 30 - digit-base:number<span class="Special"> <- </span><span class="Identifier">copy</span> 48 <span class="Comment"># '0'</span> - { - done?:boolean<span class="Special"> <- </span>equal n, 0 - break-if done? - n, digit:number<span class="Special"> <- </span><span class="Identifier">divide</span>-with-remainder n, 10 + tmp:address:buffer<span class="Special"> <- </span>new-buffer <span class="Constant">30</span> + digit-base:number<span class="Special"> <- </span>copy <span class="Constant">48</span> <span class="Comment"># '0'</span> + <span class="Delimiter">{</span> + done?:boolean<span class="Special"> <- </span>equal n, <span class="Constant">0</span> + <span class="muControl">break-if</span> done? + n, digit:number<span class="Special"> <- </span>divide-with-remainder n, <span class="Constant">10</span> c:character<span class="Special"> <- </span>add digit-base, digit - tmp:address:buffer<span class="Special"> <- </span>buffer-<span class="Identifier">append</span> tmp, c - loop - } + tmp:address:buffer<span class="Special"> <- </span>buffer-append tmp, c + <span class="muControl">loop</span> + <span class="Delimiter">}</span> <span class="Comment"># add sign</span> - { - break-unless negate-result:boolean - tmp<span class="Special"> <- </span>buffer-<span class="Identifier">append</span> tmp, 45 <span class="Comment"># '-'</span> - } + <span class="Delimiter">{</span> + <span class="muControl">break-unless</span> negate-result:boolean + tmp<span class="Special"> <- </span>buffer-append tmp, <span class="Constant">45</span> <span class="Comment"># '-'</span> + <span class="Delimiter">}</span> <span class="Comment"># reverse buffer into string result</span> - len:number<span class="Special"> <- </span>get *tmp, <span class="Identifier">length</span>:offset - buf:address:<span class="Identifier">array</span>:character<span class="Special"> <- </span>get *tmp, data:offset - result:address:<span class="Identifier">array</span>:character<span class="Special"> <- </span><span class="Identifier">new</span> character:<span class="Identifier">type</span>, len - i:number<span class="Special"> <- </span>subtract len, 1 <span class="Comment"># source index, decreasing</span> - j:number<span class="Special"> <- </span><span class="Identifier">copy</span> 0 <span class="Comment"># destination index, increasing</span> - { + len:number<span class="Special"> <- </span>get *tmp, <span class="Constant">length:offset</span> + buf:address:array:character<span class="Special"> <- </span>get *tmp, <span class="Constant">data:offset</span> + result:address:array:character<span class="Special"> <- </span>new <span class="Constant">character:type</span>, len + i:number<span class="Special"> <- </span>subtract len, <span class="Constant">1</span> <span class="Comment"># source index, decreasing</span> + j:number<span class="Special"> <- </span>copy <span class="Constant">0</span> <span class="Comment"># destination index, increasing</span> + <span class="Delimiter">{</span> <span class="Comment"># while i >= 0</span> - done?:boolean<span class="Special"> <- </span>lesser-than i, 0 - break-if done? + done?:boolean<span class="Special"> <- </span>lesser-than i, <span class="Constant">0</span> + <span class="muControl">break-if</span> done? <span class="Comment"># result[j] = tmp[i]</span> src:character<span class="Special"> <- </span>index *buf, i dest:address:character<span class="Special"> <- </span>index-address *result, j - *dest<span class="Special"> <- </span><span class="Identifier">copy</span> src - i<span class="Special"> <- </span>subtract i, 1 - j<span class="Special"> <- </span>add j, 1 - loop - } - reply result -] - -recipe buffer-to-<span class="Identifier">array</span> [ - <span class="Underlined">local</span>-scope - <span class="Identifier">in</span>:address:buffer<span class="Special"> <- </span>next-ingredient - { + *dest<span class="Special"> <- </span>copy src + i<span class="Special"> <- </span>subtract i, <span class="Constant">1</span> + j<span class="Special"> <- </span>add j, <span class="Constant">1</span> + <span class="muControl">loop</span> + <span class="Delimiter">}</span> + <span class="muControl">reply</span> result +] + +<span class="muRecipe">recipe</span> buffer-to-array [ + <span class="Constant">local-scope</span> + in:address:buffer<span class="Special"> <- </span><span class="Constant">next-ingredient</span> + <span class="Delimiter">{</span> <span class="Comment"># propagate null buffer</span> - break-if <span class="Identifier">in</span> - reply 0 - } - len:number<span class="Special"> <- </span>get *<span class="Identifier">in</span>, <span class="Identifier">length</span>:offset - s:address:<span class="Identifier">array</span>:character<span class="Special"> <- </span>get *<span class="Identifier">in</span>, data:offset + <span class="muControl">break-if</span> in + <span class="muControl">reply</span> <span class="Constant">0</span> + <span class="Delimiter">}</span> + len:number<span class="Special"> <- </span>get *in, <span class="Constant">length:offset</span> + s:address:array:character<span class="Special"> <- </span>get *in, <span class="Constant">data:offset</span> <span class="Comment"># we can't just return s because it is usually the wrong length</span> - result:address:<span class="Identifier">array</span>:character<span class="Special"> <- </span><span class="Identifier">new</span> character:<span class="Identifier">type</span>, len - i:number<span class="Special"> <- </span><span class="Identifier">copy</span> 0 - { + result:address:array:character<span class="Special"> <- </span>new <span class="Constant">character:type</span>, len + i:number<span class="Special"> <- </span>copy <span class="Constant">0</span> + <span class="Delimiter">{</span> done?:boolean<span class="Special"> <- </span>greater-or-equal i, len - break-if done? + <span class="muControl">break-if</span> done? src:character<span class="Special"> <- </span>index *s, i dest:address:character<span class="Special"> <- </span>index-address *result, i - *dest<span class="Special"> <- </span><span class="Identifier">copy</span> src - i<span class="Special"> <- </span>add i, 1 - loop - } - reply result + *dest<span class="Special"> <- </span>copy src + i<span class="Special"> <- </span>add i, <span class="Constant">1</span> + <span class="muControl">loop</span> + <span class="Delimiter">}</span> + <span class="muControl">reply</span> result ] -scenario integer-to-decimal-digit-zero [ +<span class="muScenario">scenario</span> integer-to-decimal-digit-zero [ run [ - 1:address:<span class="Identifier">array</span>:character/<span class="Special">raw <- </span>integer-to-decimal-string 0 - 2:<span class="Identifier">array</span>:character/<span class="Special">raw <- </span><span class="Identifier">copy</span> *1:address:<span class="Identifier">array</span>:character/<span class="Special">raw</span> + <span class="Constant">1</span>:address:array:character/<span class="Special">raw <- </span>integer-to-decimal-string <span class="Constant">0</span> + <span class="Constant">2</span>:array:character/<span class="Special">raw <- </span>copy *<span class="Constant">1</span>:address:array:character/<span class="Special">raw</span> ] memory-should-contain [ - 2:string<span class="Special"> <- </span>[0] + <span class="Constant">2</span>:string<span class="Special"> <- </span><span class="Constant">[0]</span> ] ] -scenario integer-to-decimal-digit-positive [ +<span class="muScenario">scenario</span> integer-to-decimal-digit-positive [ run [ - 1:address:<span class="Identifier">array</span>:character/<span class="Special">raw <- </span>integer-to-decimal-string 234 - 2:<span class="Identifier">array</span>:character/<span class="Special">raw <- </span><span class="Identifier">copy</span> *1:address:<span class="Identifier">array</span>:character/<span class="Special">raw</span> + <span class="Constant">1</span>:address:array:character/<span class="Special">raw <- </span>integer-to-decimal-string <span class="Constant">234</span> + <span class="Constant">2</span>:array:character/<span class="Special">raw <- </span>copy *<span class="Constant">1</span>:address:array:character/<span class="Special">raw</span> ] memory-should-contain [ - 2:string<span class="Special"> <- </span>[234] + <span class="Constant">2</span>:string<span class="Special"> <- </span><span class="Constant">[234]</span> ] ] -scenario integer-to-decimal-digit-negative [ +<span class="muScenario">scenario</span> integer-to-decimal-digit-negative [ run [ - 1:address:<span class="Identifier">array</span>:character/<span class="Special">raw <- </span>integer-to-decimal-string -1 - 2:<span class="Identifier">array</span>:character/<span class="Special">raw <- </span><span class="Identifier">copy</span> *1:address:<span class="Identifier">array</span>:character/<span class="Special">raw</span> + <span class="Constant">1</span>:address:array:character/<span class="Special">raw <- </span>integer-to-decimal-string <span class="Constant">-1</span> + <span class="Constant">2</span>:array:character/<span class="Special">raw <- </span>copy *<span class="Constant">1</span>:address:array:character/<span class="Special">raw</span> ] memory-should-contain [ - 2<span class="Special"> <- </span>2 - 3<span class="Special"> <- </span>45 <span class="Comment"># '-'</span> - 4<span class="Special"> <- </span>49 <span class="Comment"># '1'</span> + <span class="Constant">2</span><span class="Special"> <- </span><span class="Constant">2</span> + <span class="Constant">3</span><span class="Special"> <- </span><span class="Constant">45</span> <span class="Comment"># '-'</span> + <span class="Constant">4</span><span class="Special"> <- </span><span class="Constant">49</span> <span class="Comment"># '1'</span> ] ] <span class="Comment"># result:address:array:character <- string-append a:address:array:character, b:address:array:character</span> -recipe string-<span class="Identifier">append</span> [ - <span class="Underlined">local</span>-scope +<span class="muRecipe">recipe</span> string-append [ + <span class="Constant">local-scope</span> <span class="Comment"># result = new character[a.length + b.length]</span> - a:address:<span class="Identifier">array</span>:character<span class="Special"> <- </span>next-ingredient - a-len:number<span class="Special"> <- </span><span class="Identifier">length</span> *a - b:address:<span class="Identifier">array</span>:character<span class="Special"> <- </span>next-ingredient - b-len:number<span class="Special"> <- </span><span class="Identifier">length</span> *b + a:address:array:character<span class="Special"> <- </span><span class="Constant">next-ingredient</span> + a-len:number<span class="Special"> <- </span>length *a + b:address:array:character<span class="Special"> <- </span><span class="Constant">next-ingredient</span> + b-len:number<span class="Special"> <- </span>length *b result-len:number<span class="Special"> <- </span>add a-len, b-len - result:address:<span class="Identifier">array</span>:character<span class="Special"> <- </span><span class="Identifier">new</span> character:<span class="Identifier">type</span>, result-len + result:address:array:character<span class="Special"> <- </span>new <span class="Constant">character:type</span>, result-len <span class="Comment"># copy a into result</span> - result-idx:number<span class="Special"> <- </span><span class="Identifier">copy</span> 0 - i:number<span class="Special"> <- </span><span class="Identifier">copy</span> 0 - { + result-idx:number<span class="Special"> <- </span>copy <span class="Constant">0</span> + i:number<span class="Special"> <- </span>copy <span class="Constant">0</span> + <span class="Delimiter">{</span> <span class="Comment"># while i < a.length</span> a-done?:boolean<span class="Special"> <- </span>greater-or-equal i, a-len - break-if a-done? + <span class="muControl">break-if</span> a-done? <span class="Comment"># result[result-idx] = a[i]</span> out:address:character<span class="Special"> <- </span>index-address *result, result-idx - <span class="Identifier">in</span>:character<span class="Special"> <- </span>index *a, i - *out<span class="Special"> <- </span><span class="Identifier">copy</span> <span class="Identifier">in</span> - i<span class="Special"> <- </span>add i, 1 - result-idx<span class="Special"> <- </span>add result-idx, 1 - loop - } + in:character<span class="Special"> <- </span>index *a, i + *out<span class="Special"> <- </span>copy in + i<span class="Special"> <- </span>add i, <span class="Constant">1</span> + result-idx<span class="Special"> <- </span>add result-idx, <span class="Constant">1</span> + <span class="muControl">loop</span> + <span class="Delimiter">}</span> <span class="Comment"># copy b into result</span> - i<span class="Special"> <- </span><span class="Identifier">copy</span> 0 - { + i<span class="Special"> <- </span>copy <span class="Constant">0</span> + <span class="Delimiter">{</span> <span class="Comment"># while i < b.length</span> b-done?:boolean<span class="Special"> <- </span>greater-or-equal i, b-len - break-if b-done? + <span class="muControl">break-if</span> b-done? <span class="Comment"># result[result-idx] = a[i]</span> out:address:character<span class="Special"> <- </span>index-address *result, result-idx - <span class="Identifier">in</span>:character<span class="Special"> <- </span>index *b, i - *out<span class="Special"> <- </span><span class="Identifier">copy</span> <span class="Identifier">in</span> - i<span class="Special"> <- </span>add i, 1 - result-idx<span class="Special"> <- </span>add result-idx, 1 - loop - } - reply result + in:character<span class="Special"> <- </span>index *b, i + *out<span class="Special"> <- </span>copy in + i<span class="Special"> <- </span>add i, <span class="Constant">1</span> + result-idx<span class="Special"> <- </span>add result-idx, <span class="Constant">1</span> + <span class="muControl">loop</span> + <span class="Delimiter">}</span> + <span class="muControl">reply</span> result ] -scenario string-<span class="Identifier">append</span>-1 [ +<span class="muScenario">scenario</span> string-append-1 [ run [ - 1:address:<span class="Identifier">array</span>:character/<span class="Special">raw <- </span><span class="Identifier">new</span> [hello,] - 2:address:<span class="Identifier">array</span>:character/<span class="Special">raw <- </span><span class="Identifier">new</span> [ world!] - 3:address:<span class="Identifier">array</span>:character/<span class="Special">raw <- </span>string-<span class="Identifier">append</span> 1:address:<span class="Identifier">array</span>:character/<span class="Special">raw</span>, 2:address:<span class="Identifier">array</span>:character/<span class="Special">raw</span> - 4:<span class="Identifier">array</span>:character/<span class="Special">raw <- </span><span class="Identifier">copy</span> *3:address:<span class="Identifier">array</span>:character/<span class="Special">raw</span> + <span class="Constant">1</span>:address:array:character/<span class="Special">raw <- </span>new <span class="Constant">[hello,]</span> + <span class="Constant">2</span>:address:array:character/<span class="Special">raw <- </span>new <span class="Constant">[ world!]</span> + <span class="Constant">3</span>:address:array:character/<span class="Special">raw <- </span>string-append <span class="Constant">1</span>:address:array:character/<span class="Special">raw</span>, <span class="Constant">2</span>:address:array:character/<span class="Special">raw</span> + <span class="Constant">4</span>:array:character/<span class="Special">raw <- </span>copy *<span class="Constant">3</span>:address:array:character/<span class="Special">raw</span> ] memory-should-contain [ - 4:string<span class="Special"> <- </span>[hello, world!] + <span class="Constant">4</span>:string<span class="Special"> <- </span><span class="Constant">[hello, world!]</span> ] ] -scenario replace-character-<span class="Identifier">in</span>-string [ +<span class="muScenario">scenario</span> replace-character-in-string [ run [ - 1:address:<span class="Identifier">array</span>:character/<span class="Special">raw <- </span><span class="Identifier">new</span> [abc] - 1:address:<span class="Identifier">array</span>:character/<span class="Special">raw <- </span>string-replace 1:address:<span class="Identifier">array</span>:character/<span class="Special">raw</span>, 98/b, 122/z - 2:<span class="Identifier">array</span>:character/<span class="Special">raw <- </span><span class="Identifier">copy</span> *1:address:<span class="Identifier">array</span>:character/<span class="Special">raw</span> + <span class="Constant">1</span>:address:array:character/<span class="Special">raw <- </span>new <span class="Constant">[abc]</span> + <span class="Constant">1</span>:address:array:character/<span class="Special">raw <- </span>string-replace <span class="Constant">1</span>:address:array:character/<span class="Special">raw</span>, <span class="Constant">98/b</span>, <span class="Constant">122/z</span> + <span class="Constant">2</span>:array:character/<span class="Special">raw <- </span>copy *<span class="Constant">1</span>:address:array:character/<span class="Special">raw</span> ] memory-should-contain [ - 2:string<span class="Special"> <- </span>[azc] + <span class="Constant">2</span>:string<span class="Special"> <- </span><span class="Constant">[azc]</span> ] ] -recipe string-replace [ - <span class="Underlined">local</span>-scope - s:address:<span class="Identifier">array</span>:character<span class="Special"> <- </span>next-ingredient - oldc:character<span class="Special"> <- </span>next-ingredient - newc:character<span class="Special"> <- </span>next-ingredient - from:number<span class="Special"> <- </span>next-ingredient - len:number<span class="Special"> <- </span><span class="Identifier">length</span> *s +<span class="muRecipe">recipe</span> string-replace [ + <span class="Constant">local-scope</span> + s:address:array:character<span class="Special"> <- </span><span class="Constant">next-ingredient</span> + oldc:character<span class="Special"> <- </span><span class="Constant">next-ingredient</span> + newc:character<span class="Special"> <- </span><span class="Constant">next-ingredient</span> + from:number<span class="Special"> <- </span><span class="Constant">next-ingredient</span> + len:number<span class="Special"> <- </span>length *s i:number<span class="Special"> <- </span>find-next s, oldc, from done?:boolean<span class="Special"> <- </span>greater-or-equal i, len - reply-if done?, s/same-as-ingredient:0 + <span class="muControl">reply-if</span> done?, s/same-as-ingredient:<span class="Constant">0</span> dest:address:character<span class="Special"> <- </span>index-address *s, i - *dest<span class="Special"> <- </span><span class="Identifier">copy</span> newc - i<span class="Special"> <- </span>add i, 1 + *dest<span class="Special"> <- </span>copy newc + i<span class="Special"> <- </span>add i, <span class="Constant">1</span> s<span class="Special"> <- </span>string-replace s, oldc, newc, i - reply s/same-as-ingredient:0 + <span class="muControl">reply</span> s/same-as-ingredient:<span class="Constant">0</span> ] -scenario replace-character-at-start [ +<span class="muScenario">scenario</span> replace-character-at-start [ run [ - 1:address:<span class="Identifier">array</span>:character/<span class="Special">raw <- </span><span class="Identifier">new</span> [abc] - 1:address:<span class="Identifier">array</span>:character/<span class="Special">raw <- </span>string-replace 1:address:<span class="Identifier">array</span>:character/<span class="Special">raw</span>, 97/a, 122/z - 2:<span class="Identifier">array</span>:character/<span class="Special">raw <- </span><span class="Identifier">copy</span> *1:address:<span class="Identifier">array</span>:character/<span class="Special">raw</span> + <span class="Constant">1</span>:address:array:character/<span class="Special">raw <- </span>new <span class="Constant">[abc]</span> + <span class="Constant">1</span>:address:array:character/<span class="Special">raw <- </span>string-replace <span class="Constant">1</span>:address:array:character/<span class="Special">raw</span>, <span class="Constant">97/a</span>, <span class="Constant">122/z</span> + <span class="Constant">2</span>:array:character/<span class="Special">raw <- </span>copy *<span class="Constant">1</span>:address:array:character/<span class="Special">raw</span> ] memory-should-contain [ - 2:string<span class="Special"> <- </span>[zbc] + <span class="Constant">2</span>:string<span class="Special"> <- </span><span class="Constant">[zbc]</span> ] ] -scenario replace-character-at-end [ +<span class="muScenario">scenario</span> replace-character-at-end [ run [ - 1:address:<span class="Identifier">array</span>:character/<span class="Special">raw <- </span><span class="Identifier">new</span> [abc] - 1:address:<span class="Identifier">array</span>:character/<span class="Special">raw <- </span>string-replace 1:address:<span class="Identifier">array</span>:character/<span class="Special">raw</span>, 99/c, 122/z - 2:<span class="Identifier">array</span>:character/<span class="Special">raw <- </span><span class="Identifier">copy</span> *1:address:<span class="Identifier">array</span>:character/<span class="Special">raw</span> + <span class="Constant">1</span>:address:array:character/<span class="Special">raw <- </span>new <span class="Constant">[abc]</span> + <span class="Constant">1</span>:address:array:character/<span class="Special">raw <- </span>string-replace <span class="Constant">1</span>:address:array:character/<span class="Special">raw</span>, <span class="Constant">99/c</span>, <span class="Constant">122/z</span> + <span class="Constant">2</span>:array:character/<span class="Special">raw <- </span>copy *<span class="Constant">1</span>:address:array:character/<span class="Special">raw</span> ] memory-should-contain [ - 2:string<span class="Special"> <- </span>[abz] + <span class="Constant">2</span>:string<span class="Special"> <- </span><span class="Constant">[abz]</span> ] ] -scenario replace-character-missing [ +<span class="muScenario">scenario</span> replace-character-missing [ run [ - 1:address:<span class="Identifier">array</span>:character/<span class="Special">raw <- </span><span class="Identifier">new</span> [abc] - 1:address:<span class="Identifier">array</span>:character/<span class="Special">raw <- </span>string-replace 1:address:<span class="Identifier">array</span>:character/<span class="Special">raw</span>, 100/d, 122/z - 2:<span class="Identifier">array</span>:character/<span class="Special">raw <- </span><span class="Identifier">copy</span> *1:address:<span class="Identifier">array</span>:character/<span class="Special">raw</span> + <span class="Constant">1</span>:address:array:character/<span class="Special">raw <- </span>new <span class="Constant">[abc]</span> + <span class="Constant">1</span>:address:array:character/<span class="Special">raw <- </span>string-replace <span class="Constant">1</span>:address:array:character/<span class="Special">raw</span>, <span class="Constant">100/d</span>, <span class="Constant">122/z</span> + <span class="Constant">2</span>:array:character/<span class="Special">raw <- </span>copy *<span class="Constant">1</span>:address:array:character/<span class="Special">raw</span> ] memory-should-contain [ - 2:string<span class="Special"> <- </span>[abc] + <span class="Constant">2</span>:string<span class="Special"> <- </span><span class="Constant">[abc]</span> ] ] -scenario replace-all-characters [ +<span class="muScenario">scenario</span> replace-all-characters [ run [ - 1:address:<span class="Identifier">array</span>:character/<span class="Special">raw <- </span><span class="Identifier">new</span> [banana] - 1:address:<span class="Identifier">array</span>:character/<span class="Special">raw <- </span>string-replace 1:address:<span class="Identifier">array</span>:character/<span class="Special">raw</span>, 97/a, 122/z - 2:<span class="Identifier">array</span>:character/<span class="Special">raw <- </span><span class="Identifier">copy</span> *1:address:<span class="Identifier">array</span>:character/<span class="Special">raw</span> + <span class="Constant">1</span>:address:array:character/<span class="Special">raw <- </span>new <span class="Constant">[banana]</span> + <span class="Constant">1</span>:address:array:character/<span class="Special">raw <- </span>string-replace <span class="Constant">1</span>:address:array:character/<span class="Special">raw</span>, <span class="Constant">97/a</span>, <span class="Constant">122/z</span> + <span class="Constant">2</span>:array:character/<span class="Special">raw <- </span>copy *<span class="Constant">1</span>:address:array:character/<span class="Special">raw</span> ] memory-should-contain [ - 2:string<span class="Special"> <- </span>[bznznz] + <span class="Constant">2</span>:string<span class="Special"> <- </span><span class="Constant">[bznznz]</span> ] ] <span class="Comment"># replace underscores in first with remaining args</span> <span class="Comment"># result:address:array:character <- interpolate template:address:array:character, ...</span> -recipe <span class="Identifier">interpolate</span> [ - <span class="Underlined">local</span>-scope - template:address:<span class="Identifier">array</span>:character<span class="Special"> <- </span>next-ingredient +<span class="muRecipe">recipe</span> interpolate [ + <span class="Constant">local-scope</span> + template:address:array:character<span class="Special"> <- </span><span class="Constant">next-ingredient</span> <span class="Comment"># compute result-len, space to allocate for result</span> - tem-len:number<span class="Special"> <- </span><span class="Identifier">length</span> *template - result-len:number<span class="Special"> <- </span><span class="Identifier">copy</span> tem-len - { + tem-len:number<span class="Special"> <- </span>length *template + result-len:number<span class="Special"> <- </span>copy tem-len + <span class="Delimiter">{</span> <span class="Comment"># while arg received</span> - a:address:<span class="Identifier">array</span>:character, <span class="Identifier">arg</span>-received?:boolean<span class="Special"> <- </span>next-ingredient - break-unless <span class="Identifier">arg</span>-received? + a:address:array:character, arg-received?:boolean<span class="Special"> <- </span><span class="Constant">next-ingredient</span> + <span class="muControl">break-unless</span> arg-received? <span class="Comment"># result-len = result-len + arg.length - 1 (for the 'underscore' being replaced)</span> - a-len:number<span class="Special"> <- </span><span class="Identifier">length</span> *a + a-len:number<span class="Special"> <- </span>length *a result-len<span class="Special"> <- </span>add result-len, a-len - result-len<span class="Special"> <- </span>subtract result-len, 1 - loop - } + result-len<span class="Special"> <- </span>subtract result-len, <span class="Constant">1</span> + <span class="muControl">loop</span> + <span class="Delimiter">}</span> rewind-ingredients - _<span class="Special"> <- </span>next-ingredient <span class="Comment"># skip template</span> - result:address:<span class="Identifier">array</span>:character<span class="Special"> <- </span><span class="Identifier">new</span> character:<span class="Identifier">type</span>, result-len + _<span class="Special"> <- </span><span class="Constant">next-ingredient</span> <span class="Comment"># skip template</span> + result:address:array:character<span class="Special"> <- </span>new <span class="Constant">character:type</span>, result-len <span class="Comment"># repeatedly copy sections of template and 'holes' into result</span> - result-idx:number<span class="Special"> <- </span><span class="Identifier">copy</span> 0 - i:number<span class="Special"> <- </span><span class="Identifier">copy</span> 0 - { + result-idx:number<span class="Special"> <- </span>copy <span class="Constant">0</span> + i:number<span class="Special"> <- </span>copy <span class="Constant">0</span> + <span class="Delimiter">{</span> <span class="Comment"># while arg received</span> - a:address:<span class="Identifier">array</span>:character, <span class="Identifier">arg</span>-received?:boolean<span class="Special"> <- </span>next-ingredient - break-unless <span class="Identifier">arg</span>-received? + a:address:array:character, arg-received?:boolean<span class="Special"> <- </span><span class="Constant">next-ingredient</span> + <span class="muControl">break-unless</span> arg-received? <span class="Comment"># copy template into result until '_'</span> - { + <span class="Delimiter">{</span> <span class="Comment"># while i < template.length</span> tem-done?:boolean<span class="Special"> <- </span>greater-or-equal i, tem-len - break-if tem-done?, +done:label + <span class="muControl">break-if</span> tem-done?, <span class="Constant">+done:label</span> <span class="Comment"># while template[i] != '_'</span> - <span class="Identifier">in</span>:character<span class="Special"> <- </span>index *template, i - underscore?:boolean<span class="Special"> <- </span>equal <span class="Identifier">in</span>, 95/_ - break-if underscore? + in:character<span class="Special"> <- </span>index *template, i + underscore?:boolean<span class="Special"> <- </span>equal in, <span class="Constant">95/_</span> + <span class="muControl">break-if</span> underscore? <span class="Comment"># result[result-idx] = template[i]</span> out:address:character<span class="Special"> <- </span>index-address *result, result-idx - *out<span class="Special"> <- </span><span class="Identifier">copy</span> <span class="Identifier">in</span> - i<span class="Special"> <- </span>add i, 1 - result-idx<span class="Special"> <- </span>add result-idx, 1 - loop - } + *out<span class="Special"> <- </span>copy in + i<span class="Special"> <- </span>add i, <span class="Constant">1</span> + result-idx<span class="Special"> <- </span>add result-idx, <span class="Constant">1</span> + <span class="muControl">loop</span> + <span class="Delimiter">}</span> <span class="Comment"># copy 'a' into result</span> - j:number<span class="Special"> <- </span><span class="Identifier">copy</span> 0 - { + j:number<span class="Special"> <- </span>copy <span class="Constant">0</span> + <span class="Delimiter">{</span> <span class="Comment"># while j < a.length</span> - <span class="Identifier">arg</span>-done?:boolean<span class="Special"> <- </span>greater-or-equal j, a-len - break-if <span class="Identifier">arg</span>-done? + arg-done?:boolean<span class="Special"> <- </span>greater-or-equal j, a-len + <span class="muControl">break-if</span> arg-done? <span class="Comment"># result[result-idx] = a[j]</span> - <span class="Identifier">in</span>:character<span class="Special"> <- </span>index *a, j + in:character<span class="Special"> <- </span>index *a, j out:address:character<span class="Special"> <- </span>index-address *result, result-idx - *out<span class="Special"> <- </span><span class="Identifier">copy</span> <span class="Identifier">in</span> - j<span class="Special"> <- </span>add j, 1 - result-idx<span class="Special"> <- </span>add result-idx, 1 - loop - } + *out<span class="Special"> <- </span>copy in + j<span class="Special"> <- </span>add j, <span class="Constant">1</span> + result-idx<span class="Special"> <- </span>add result-idx, <span class="Constant">1</span> + <span class="muControl">loop</span> + <span class="Delimiter">}</span> <span class="Comment"># skip '_' in template</span> - i<span class="Special"> <- </span>add i, 1 - loop <span class="Comment"># interpolate next arg</span> - } - +done + i<span class="Special"> <- </span>add i, <span class="Constant">1</span> + <span class="muControl">loop</span> <span class="Comment"># interpolate next arg</span> + <span class="Delimiter">}</span> +<span class="Constant"> +done</span> <span class="Comment"># done with holes; copy rest of template directly into result</span> - { + <span class="Delimiter">{</span> <span class="Comment"># while i < template.length</span> tem-done?:boolean<span class="Special"> <- </span>greater-or-equal i, tem-len - break-if tem-done? + <span class="muControl">break-if</span> tem-done? <span class="Comment"># result[result-idx] = template[i]</span> - <span class="Identifier">in</span>:character<span class="Special"> <- </span>index *template, i + in:character<span class="Special"> <- </span>index *template, i out:address:character<span class="Special"> <- </span>index-address *result, result-idx:number - *out<span class="Special"> <- </span><span class="Identifier">copy</span> <span class="Identifier">in</span> - i<span class="Special"> <- </span>add i, 1 - result-idx<span class="Special"> <- </span>add result-idx, 1 - loop - } - reply result + *out<span class="Special"> <- </span>copy in + i<span class="Special"> <- </span>add i, <span class="Constant">1</span> + result-idx<span class="Special"> <- </span>add result-idx, <span class="Constant">1</span> + <span class="muControl">loop</span> + <span class="Delimiter">}</span> + <span class="muControl">reply</span> result ] -scenario <span class="Identifier">interpolate</span>-works [ +<span class="muScenario">scenario</span> interpolate-works [ run [ - 1:address:<span class="Identifier">array</span>:character/<span class="Special">raw <- </span><span class="Identifier">new</span> [abc _] - 2:address:<span class="Identifier">array</span>:character/<span class="Special">raw <- </span><span class="Identifier">new</span> [def] - 3:address:<span class="Identifier">array</span>:character/<span class="Special">raw <- </span><span class="Identifier">interpolate</span> 1:address:<span class="Identifier">array</span>:character/<span class="Special">raw</span>, 2:address:<span class="Identifier">array</span>:character/<span class="Special">raw</span> - 4:<span class="Identifier">array</span>:character/<span class="Special">raw <- </span><span class="Identifier">copy</span> *3:address:<span class="Identifier">array</span>:character/<span class="Special">raw</span> + <span class="Constant">1</span>:address:array:character/<span class="Special">raw <- </span>new <span class="Constant">[abc _]</span> + <span class="Constant">2</span>:address:array:character/<span class="Special">raw <- </span>new <span class="Constant">[def]</span> + <span class="Constant">3</span>:address:array:character/<span class="Special">raw <- </span>interpolate <span class="Constant">1</span>:address:array:character/<span class="Special">raw</span>, <span class="Constant">2</span>:address:array:character/<span class="Special">raw</span> + <span class="Constant">4</span>:array:character/<span class="Special">raw <- </span>copy *<span class="Constant">3</span>:address:array:character/<span class="Special">raw</span> ] memory-should-contain [ - 4:string<span class="Special"> <- </span>[abc def] + <span class="Constant">4</span>:string<span class="Special"> <- </span><span class="Constant">[abc def]</span> ] ] -scenario <span class="Identifier">interpolate</span>-at-start [ +<span class="muScenario">scenario</span> interpolate-at-start [ run [ - 1:address:<span class="Identifier">array</span>:character/<span class="Special">raw <- </span><span class="Identifier">new</span> [_, hello!] - 2:address:<span class="Identifier">array</span>:character/<span class="Special">raw <- </span><span class="Identifier">new</span> [abc] - 3:address:<span class="Identifier">array</span>:character/<span class="Special">raw <- </span><span class="Identifier">interpolate</span> 1:address:<span class="Identifier">array</span>:character/<span class="Special">raw</span>, 2:address:<span class="Identifier">array</span>:character/<span class="Special">raw</span> - 4:<span class="Identifier">array</span>:character/<span class="Special">raw <- </span><span class="Identifier">copy</span> *3:address:<span class="Identifier">array</span>:character/<span class="Special">raw</span> + <span class="Constant">1</span>:address:array:character/<span class="Special">raw <- </span>new <span class="Constant">[_, hello!]</span> + <span class="Constant">2</span>:address:array:character/<span class="Special">raw <- </span>new <span class="Constant">[abc]</span> + <span class="Constant">3</span>:address:array:character/<span class="Special">raw <- </span>interpolate <span class="Constant">1</span>:address:array:character/<span class="Special">raw</span>, <span class="Constant">2</span>:address:array:character/<span class="Special">raw</span> + <span class="Constant">4</span>:array:character/<span class="Special">raw <- </span>copy *<span class="Constant">3</span>:address:array:character/<span class="Special">raw</span> ] memory-should-contain [ - 4:string<span class="Special"> <- </span>[abc, hello!] - 16<span class="Special"> <- </span>0 <span class="Comment"># out of bounds</span> + <span class="Constant">4</span>:string<span class="Special"> <- </span><span class="Constant">[abc, hello!]</span> + <span class="Constant">16</span><span class="Special"> <- </span><span class="Constant">0</span> <span class="Comment"># out of bounds</span> ] ] -scenario <span class="Identifier">interpolate</span>-at-end [ +<span class="muScenario">scenario</span> interpolate-at-end [ run [ - 1:address:<span class="Identifier">array</span>:character/<span class="Special">raw <- </span><span class="Identifier">new</span> [hello, _] - 2:address:<span class="Identifier">array</span>:character/<span class="Special">raw <- </span><span class="Identifier">new</span> [abc] - 3:address:<span class="Identifier">array</span>:character/<span class="Special">raw <- </span><span class="Identifier">interpolate</span> 1:address:<span class="Identifier">array</span>:character/<span class="Special">raw</span>, 2:address:<span class="Identifier">array</span>:character/<span class="Special">raw</span> - 4:<span class="Identifier">array</span>:character/<span class="Special">raw <- </span><span class="Identifier">copy</span> *3:address:<span class="Identifier">array</span>:character/<span class="Special">raw</span> + <span class="Constant">1</span>:address:array:character/<span class="Special">raw <- </span>new <span class="Constant">[hello, _]</span> + <span class="Constant">2</span>:address:array:character/<span class="Special">raw <- </span>new <span class="Constant">[abc]</span> + <span class="Constant">3</span>:address:array:character/<span class="Special">raw <- </span>interpolate <span class="Constant">1</span>:address:array:character/<span class="Special">raw</span>, <span class="Constant">2</span>:address:array:character/<span class="Special">raw</span> + <span class="Constant">4</span>:array:character/<span class="Special">raw <- </span>copy *<span class="Constant">3</span>:address:array:character/<span class="Special">raw</span> ] memory-should-contain [ - 4:string<span class="Special"> <- </span>[hello, abc] + <span class="Constant">4</span>:string<span class="Special"> <- </span><span class="Constant">[hello, abc]</span> ] ] <span class="Comment"># result:boolean <- space? c:character</span> -recipe space? [ - <span class="Underlined">local</span>-scope - c:character<span class="Special"> <- </span>next-ingredient +<span class="muRecipe">recipe</span> space? [ + <span class="Constant">local-scope</span> + c:character<span class="Special"> <- </span><span class="Constant">next-ingredient</span> <span class="Comment"># most common case first</span> - result:boolean<span class="Special"> <- </span>equal c, 32/space - jump-if result +reply:label - result<span class="Special"> <- </span>equal c, 10/newline - jump-if result, +reply:label - result<span class="Special"> <- </span>equal c, 9/tab - jump-if result, +reply:label - result<span class="Special"> <- </span>equal c, 13/carriage-<span class="Identifier">return</span> - jump-if result, +reply:label + result:boolean<span class="Special"> <- </span>equal c, <span class="Constant">32/space</span> + <span class="muControl">jump-if</span> result <span class="Constant">+reply:label</span> + result<span class="Special"> <- </span>equal c, <span class="Constant">10/newline</span> + <span class="muControl">jump-if</span> result, <span class="Constant">+reply:label</span> + result<span class="Special"> <- </span>equal c, <span class="Constant">9/tab</span> + <span class="muControl">jump-if</span> result, <span class="Constant">+reply:label</span> + result<span class="Special"> <- </span>equal c, <span class="Constant">13/carriage-return</span> + <span class="muControl">jump-if</span> result, <span class="Constant">+reply:label</span> <span class="Comment"># remaining uncommon cases in sorted order</span> <span class="Comment"># <a href="http://unicode.org">http://unicode.org</a> code-points in unicode-set Z and Pattern_White_Space</span> - result<span class="Special"> <- </span>equal c, 11/ctrl-k - jump-if result, +reply:label - result<span class="Special"> <- </span>equal c, 12/ctrl-l - jump-if result, +reply:label - result<span class="Special"> <- </span>equal c, 133/ctrl-0085 - jump-if result, +reply:label - result<span class="Special"> <- </span>equal c, 160/no-break-space - jump-if result, +reply:label - result<span class="Special"> <- </span>equal c, 5760/ogham-space-mark - jump-if result, +reply:label - result<span class="Special"> <- </span>equal c, 8192/en-quad - jump-if result, +reply:label - result<span class="Special"> <- </span>equal c, 8193/em-quad - jump-if result, +reply:label - result<span class="Special"> <- </span>equal c, 8194/en-space - jump-if result, +reply:label - result<span class="Special"> <- </span>equal c, 8195/em-space - jump-if result, +reply:label - result<span class="Special"> <- </span>equal c, 8196/three-per-em-space - jump-if result, +reply:label - result<span class="Special"> <- </span>equal c, 8197/four-per-em-space - jump-if result, +reply:label - result<span class="Special"> <- </span>equal c, 8198/six-per-em-space - jump-if result, +reply:label - result<span class="Special"> <- </span>equal c, 8199/figure-space - jump-if result, +reply:label - result<span class="Special"> <- </span>equal c, 8200/punctuation-space - jump-if result, +reply:label - result<span class="Special"> <- </span>equal c, 8201/thin-space - jump-if result, +reply:label - result<span class="Special"> <- </span>equal c, 8202/hair-space - jump-if result, +reply:label - result<span class="Special"> <- </span>equal c, 8206/left-to-right - jump-if result, +reply:label - result<span class="Special"> <- </span>equal c, 8207/right-to-left - jump-if result, +reply:label - result<span class="Special"> <- </span>equal c, 8232/line-separator - jump-if result, +reply:label - result<span class="Special"> <- </span>equal c, 8233/paragraph-separator - jump-if result, +reply:label - result<span class="Special"> <- </span>equal c, 8239/narrow-no-break-space - jump-if result, +reply:label - result<span class="Special"> <- </span>equal c, 8287/medium-mathematical-space - jump-if result, +reply:label - result<span class="Special"> <- </span>equal c, 12288/ideographic-space - jump-if result, +reply:label - +reply - reply result + result<span class="Special"> <- </span>equal c, <span class="Constant">11/ctrl-k</span> + <span class="muControl">jump-if</span> result, <span class="Constant">+reply:label</span> + result<span class="Special"> <- </span>equal c, <span class="Constant">12/ctrl-l</span> + <span class="muControl">jump-if</span> result, <span class="Constant">+reply:label</span> + result<span class="Special"> <- </span>equal c, <span class="Constant">133/ctrl-0085</span> + <span class="muControl">jump-if</span> result, <span class="Constant">+reply:label</span> + result<span class="Special"> <- </span>equal c, <span class="Constant">160/no-break-space</span> + <span class="muControl">jump-if</span> result, <span class="Constant">+reply:label</span> + result<span class="Special"> <- </span>equal c, <span class="Constant">5760/ogham-space-mark</span> + <span class="muControl">jump-if</span> result, <span class="Constant">+reply:label</span> + result<span class="Special"> <- </span>equal c, <span class="Constant">8192/en-quad</span> + <span class="muControl">jump-if</span> result, <span class="Constant">+reply:label</span> + result<span class="Special"> <- </span>equal c, <span class="Constant">8193/em-quad</span> + <span class="muControl">jump-if</span> result, <span class="Constant">+reply:label</span> + result<span class="Special"> <- </span>equal c, <span class="Constant">8194/en-space</span> + <span class="muControl">jump-if</span> result, <span class="Constant">+reply:label</span> + result<span class="Special"> <- </span>equal c, <span class="Constant">8195/em-space</span> + <span class="muControl">jump-if</span> result, <span class="Constant">+reply:label</span> + result<span class="Special"> <- </span>equal c, <span class="Constant">8196/three-per-em-space</span> + <span class="muControl">jump-if</span> result, <span class="Constant">+reply:label</span> + result<span class="Special"> <- </span>equal c, <span class="Constant">8197/four-per-em-space</span> + <span class="muControl">jump-if</span> result, <span class="Constant">+reply:label</span> + result<span class="Special"> <- </span>equal c, <span class="Constant">8198/six-per-em-space</span> + <span class="muControl">jump-if</span> result, <span class="Constant">+reply:label</span> + result<span class="Special"> <- </span>equal c, <span class="Constant">8199/figure-space</span> + <span class="muControl">jump-if</span> result, <span class="Constant">+reply:label</span> + result<span class="Special"> <- </span>equal c, <span class="Constant">8200/punctuation-space</span> + <span class="muControl">jump-if</span> result, <span class="Constant">+reply:label</span> + result<span class="Special"> <- </span>equal c, <span class="Constant">8201/thin-space</span> + <span class="muControl">jump-if</span> result, <span class="Constant">+reply:label</span> + result<span class="Special"> <- </span>equal c, <span class="Constant">8202/hair-space</span> + <span class="muControl">jump-if</span> result, <span class="Constant">+reply:label</span> + result<span class="Special"> <- </span>equal c, <span class="Constant">8206/left-to-right</span> + <span class="muControl">jump-if</span> result, <span class="Constant">+reply:label</span> + result<span class="Special"> <- </span>equal c, <span class="Constant">8207/right-to-left</span> + <span class="muControl">jump-if</span> result, <span class="Constant">+reply:label</span> + result<span class="Special"> <- </span>equal c, <span class="Constant">8232/line-separator</span> + <span class="muControl">jump-if</span> result, <span class="Constant">+reply:label</span> + result<span class="Special"> <- </span>equal c, <span class="Constant">8233/paragraph-separator</span> + <span class="muControl">jump-if</span> result, <span class="Constant">+reply:label</span> + result<span class="Special"> <- </span>equal c, <span class="Constant">8239/narrow-no-break-space</span> + <span class="muControl">jump-if</span> result, <span class="Constant">+reply:label</span> + result<span class="Special"> <- </span>equal c, <span class="Constant">8287/medium-mathematical-space</span> + <span class="muControl">jump-if</span> result, <span class="Constant">+reply:label</span> + result<span class="Special"> <- </span>equal c, <span class="Constant">12288/ideographic-space</span> + <span class="muControl">jump-if</span> result, <span class="Constant">+reply:label</span> +<span class="Constant"> +reply</span> + <span class="muControl">reply</span> result ] <span class="Comment"># result:address:array:character <- trim s:address:array:character</span> -recipe trim [ - <span class="Underlined">local</span>-scope - s:address:<span class="Identifier">array</span>:character<span class="Special"> <- </span>next-ingredient - len:number<span class="Special"> <- </span><span class="Identifier">length</span> *s +<span class="muRecipe">recipe</span> trim [ + <span class="Constant">local-scope</span> + s:address:array:character<span class="Special"> <- </span><span class="Constant">next-ingredient</span> + len:number<span class="Special"> <- </span>length *s <span class="Comment"># left trim: compute start</span> - start:number<span class="Special"> <- </span><span class="Identifier">copy</span> 0 - { - { + start:number<span class="Special"> <- </span>copy <span class="Constant">0</span> + <span class="Delimiter">{</span> + <span class="Delimiter">{</span> at-end?:boolean<span class="Special"> <- </span>greater-or-equal start, len - break-unless at-end? - result:address:<span class="Identifier">array</span>:character<span class="Special"> <- </span><span class="Identifier">new</span> character:<span class="Identifier">type</span>, 0 - reply result - } + <span class="muControl">break-unless</span> at-end? + result:address:array:character<span class="Special"> <- </span>new <span class="Constant">character:type</span>, <span class="Constant">0</span> + <span class="muControl">reply</span> result + <span class="Delimiter">}</span> curr:character<span class="Special"> <- </span>index *s, start whitespace?:boolean<span class="Special"> <- </span>space? curr - break-unless whitespace? - start<span class="Special"> <- </span>add start, 1 - loop - } + <span class="muControl">break-unless</span> whitespace? + start<span class="Special"> <- </span>add start, <span class="Constant">1</span> + <span class="muControl">loop</span> + <span class="Delimiter">}</span> <span class="Comment"># right trim: compute end</span> - end:number<span class="Special"> <- </span>subtract len, 1 - { + end:number<span class="Special"> <- </span>subtract len, <span class="Constant">1</span> + <span class="Delimiter">{</span> not-at-start?:boolean<span class="Special"> <- </span>greater-than end, start - <span class="Identifier">assert</span> not-at-start?, [end ran up against start] + assert not-at-start?, <span class="Constant">[end ran up against start]</span> curr:character<span class="Special"> <- </span>index *s, end whitespace?:boolean<span class="Special"> <- </span>space? curr - break-unless whitespace? - end<span class="Special"> <- </span>subtract end, 1 - loop - } + <span class="muControl">break-unless</span> whitespace? + end<span class="Special"> <- </span>subtract end, <span class="Constant">1</span> + <span class="muControl">loop</span> + <span class="Delimiter">}</span> <span class="Comment"># result = new character[end+1 - start]</span> - <span class="Identifier">new</span>-len:number<span class="Special"> <- </span>subtract end, start, -1 - result:address:<span class="Identifier">array</span>:character<span class="Special"> <- </span><span class="Identifier">new</span> character:<span class="Identifier">type</span>, <span class="Identifier">new</span>-len + new-len:number<span class="Special"> <- </span>subtract end, start, <span class="Constant">-1</span> + result:address:array:character<span class="Special"> <- </span>new <span class="Constant">character:type</span>, new-len <span class="Comment"># copy the untrimmed parts between start and end</span> - i:number<span class="Special"> <- </span><span class="Identifier">copy</span> start - j:number<span class="Special"> <- </span><span class="Identifier">copy</span> 0 - { + i:number<span class="Special"> <- </span>copy start + j:number<span class="Special"> <- </span>copy <span class="Constant">0</span> + <span class="Delimiter">{</span> <span class="Comment"># while i <= end</span> done?:boolean<span class="Special"> <- </span>greater-than i, end - break-if done? + <span class="muControl">break-if</span> done? <span class="Comment"># result[j] = s[i]</span> src:character<span class="Special"> <- </span>index *s, i dest:address:character<span class="Special"> <- </span>index-address *result, j - *dest<span class="Special"> <- </span><span class="Identifier">copy</span> src - i<span class="Special"> <- </span>add i, 1 - j<span class="Special"> <- </span>add j, 1 - loop - } - reply result + *dest<span class="Special"> <- </span>copy src + i<span class="Special"> <- </span>add i, <span class="Constant">1</span> + j<span class="Special"> <- </span>add j, <span class="Constant">1</span> + <span class="muControl">loop</span> + <span class="Delimiter">}</span> + <span class="muControl">reply</span> result ] -scenario trim-unmodified [ +<span class="muScenario">scenario</span> trim-unmodified [ run [ - 1:address:<span class="Identifier">array</span>:character<span class="Special"> <- </span><span class="Identifier">new</span> [abc] - 2:address:<span class="Identifier">array</span>:character<span class="Special"> <- </span>trim 1:address:<span class="Identifier">array</span>:character - 3:<span class="Identifier">array</span>:character<span class="Special"> <- </span><span class="Identifier">copy</span> *2:address:<span class="Identifier">array</span>:character + <span class="Constant">1</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[abc]</span> + <span class="Constant">2</span>:address:array:character<span class="Special"> <- </span>trim <span class="Constant">1</span>:address:array:character + <span class="Constant">3</span>:array:character<span class="Special"> <- </span>copy *<span class="Constant">2</span>:address:array:character ] memory-should-contain [ - 3:string<span class="Special"> <- </span>[abc] + <span class="Constant">3</span>:string<span class="Special"> <- </span><span class="Constant">[abc]</span> ] ] -scenario trim-left [ +<span class="muScenario">scenario</span> trim-left [ run [ - 1:address:<span class="Identifier">array</span>:character<span class="Special"> <- </span><span class="Identifier">new</span> [ abc] - 2:address:<span class="Identifier">array</span>:character<span class="Special"> <- </span>trim 1:address:<span class="Identifier">array</span>:character - 3:<span class="Identifier">array</span>:character<span class="Special"> <- </span><span class="Identifier">copy</span> *2:address:<span class="Identifier">array</span>:character + <span class="Constant">1</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[ abc]</span> + <span class="Constant">2</span>:address:array:character<span class="Special"> <- </span>trim <span class="Constant">1</span>:address:array:character + <span class="Constant">3</span>:array:character<span class="Special"> <- </span>copy *<span class="Constant">2</span>:address:array:character ] memory-should-contain [ - 3:string<span class="Special"> <- </span>[abc] + <span class="Constant">3</span>:string<span class="Special"> <- </span><span class="Constant">[abc]</span> ] ] -scenario trim-right [ +<span class="muScenario">scenario</span> trim-right [ run [ - 1:address:<span class="Identifier">array</span>:character<span class="Special"> <- </span><span class="Identifier">new</span> [abc ] - 2:address:<span class="Identifier">array</span>:character<span class="Special"> <- </span>trim 1:address:<span class="Identifier">array</span>:character - 3:<span class="Identifier">array</span>:character<span class="Special"> <- </span><span class="Identifier">copy</span> *2:address:<span class="Identifier">array</span>:character + <span class="Constant">1</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[abc ]</span> + <span class="Constant">2</span>:address:array:character<span class="Special"> <- </span>trim <span class="Constant">1</span>:address:array:character + <span class="Constant">3</span>:array:character<span class="Special"> <- </span>copy *<span class="Constant">2</span>:address:array:character ] memory-should-contain [ - 3:string<span class="Special"> <- </span>[abc] + <span class="Constant">3</span>:string<span class="Special"> <- </span><span class="Constant">[abc]</span> ] ] -scenario trim-left-right [ +<span class="muScenario">scenario</span> trim-left-right [ run [ - 1:address:<span class="Identifier">array</span>:character<span class="Special"> <- </span><span class="Identifier">new</span> [ abc ] - 2:address:<span class="Identifier">array</span>:character<span class="Special"> <- </span>trim 1:address:<span class="Identifier">array</span>:character - 3:<span class="Identifier">array</span>:character<span class="Special"> <- </span><span class="Identifier">copy</span> *2:address:<span class="Identifier">array</span>:character + <span class="Constant">1</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[ abc ]</span> + <span class="Constant">2</span>:address:array:character<span class="Special"> <- </span>trim <span class="Constant">1</span>:address:array:character + <span class="Constant">3</span>:array:character<span class="Special"> <- </span>copy *<span class="Constant">2</span>:address:array:character ] memory-should-contain [ - 3:string<span class="Special"> <- </span>[abc] + <span class="Constant">3</span>:string<span class="Special"> <- </span><span class="Constant">[abc]</span> ] ] -scenario trim-newline-tab [ +<span class="muScenario">scenario</span> trim-newline-tab [ run [ - 1:address:<span class="Identifier">array</span>:character<span class="Special"> <- </span><span class="Identifier">new</span> [ abc -] - 2:address:<span class="Identifier">array</span>:character<span class="Special"> <- </span>trim 1:address:<span class="Identifier">array</span>:character - 3:<span class="Identifier">array</span>:character<span class="Special"> <- </span><span class="Identifier">copy</span> *2:address:<span class="Identifier">array</span>:character + <span class="Constant">1</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[ abc</span> +<span class="Constant">]</span> + <span class="Constant">2</span>:address:array:character<span class="Special"> <- </span>trim <span class="Constant">1</span>:address:array:character + <span class="Constant">3</span>:array:character<span class="Special"> <- </span>copy *<span class="Constant">2</span>:address:array:character ] memory-should-contain [ - 3:string<span class="Special"> <- </span>[abc] + <span class="Constant">3</span>:string<span class="Special"> <- </span><span class="Constant">[abc]</span> ] ] <span class="Comment"># next-index:number <- find-next text:address:array:character, pattern:character, idx:number</span> -recipe find-next [ - <span class="Underlined">local</span>-scope - text:address:<span class="Identifier">array</span>:character<span class="Special"> <- </span>next-ingredient - pattern:character<span class="Special"> <- </span>next-ingredient - idx:number<span class="Special"> <- </span>next-ingredient - len:number<span class="Special"> <- </span><span class="Identifier">length</span> *text - { +<span class="muRecipe">recipe</span> find-next [ + <span class="Constant">local-scope</span> + text:address:array:character<span class="Special"> <- </span><span class="Constant">next-ingredient</span> + pattern:character<span class="Special"> <- </span><span class="Constant">next-ingredient</span> + idx:number<span class="Special"> <- </span><span class="Constant">next-ingredient</span> + len:number<span class="Special"> <- </span>length *text + <span class="Delimiter">{</span> eof?:boolean<span class="Special"> <- </span>greater-or-equal idx, len - break-if eof? + <span class="muControl">break-if</span> eof? curr:character<span class="Special"> <- </span>index *text, idx found?:boolean<span class="Special"> <- </span>equal curr, pattern - break-if found? - idx<span class="Special"> <- </span>add idx, 1 - loop - } - reply idx + <span class="muControl">break-if</span> found? + idx<span class="Special"> <- </span>add idx, <span class="Constant">1</span> + <span class="muControl">loop</span> + <span class="Delimiter">}</span> + <span class="muControl">reply</span> idx ] -scenario string-find-next [ +<span class="muScenario">scenario</span> string-find-next [ run [ - 1:address:<span class="Identifier">array</span>:character<span class="Special"> <- </span><span class="Identifier">new</span> [a/b] - 2:number<span class="Special"> <- </span>find-next 1:address:<span class="Identifier">array</span>:character, 47/slash, 0/start-index + <span class="Constant">1</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[a/b]</span> + <span class="Constant">2</span>:number<span class="Special"> <- </span>find-next <span class="Constant">1</span>:address:array:character, <span class="Constant">47/slash</span>, <span class="Constant">0/start-index</span> ] memory-should-contain [ - 2<span class="Special"> <- </span>1 + <span class="Constant">2</span><span class="Special"> <- </span><span class="Constant">1</span> ] ] -scenario string-find-next-empty [ +<span class="muScenario">scenario</span> string-find-next-empty [ run [ - 1:address:<span class="Identifier">array</span>:character<span class="Special"> <- </span><span class="Identifier">new</span> [] - 2:number<span class="Special"> <- </span>find-next 1:address:<span class="Identifier">array</span>:character, 47/slash, 0/start-index + <span class="Constant">1</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[]</span> + <span class="Constant">2</span>:number<span class="Special"> <- </span>find-next <span class="Constant">1</span>:address:array:character, <span class="Constant">47/slash</span>, <span class="Constant">0/start-index</span> ] memory-should-contain [ - 2<span class="Special"> <- </span>0 + <span class="Constant">2</span><span class="Special"> <- </span><span class="Constant">0</span> ] ] -scenario string-find-next-initial [ +<span class="muScenario">scenario</span> string-find-next-initial [ run [ - 1:address:<span class="Identifier">array</span>:character<span class="Special"> <- </span><span class="Identifier">new</span> [/abc] - 2:number<span class="Special"> <- </span>find-next 1:address:<span class="Identifier">array</span>:character, 47/slash, 0/start-index + <span class="Constant">1</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[/abc]</span> + <span class="Constant">2</span>:number<span class="Special"> <- </span>find-next <span class="Constant">1</span>:address:array:character, <span class="Constant">47/slash</span>, <span class="Constant">0/start-index</span> ] memory-should-contain [ - 2<span class="Special"> <- </span>0 <span class="Comment"># prefix match</span> + <span class="Constant">2</span><span class="Special"> <- </span><span class="Constant">0</span> <span class="Comment"># prefix match</span> ] ] -scenario string-find-next-final [ +<span class="muScenario">scenario</span> string-find-next-final [ run [ - 1:address:<span class="Identifier">array</span>:character<span class="Special"> <- </span><span class="Identifier">new</span> [abc/] - 2:number<span class="Special"> <- </span>find-next 1:address:<span class="Identifier">array</span>:character, 47/slash, 0/start-index + <span class="Constant">1</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[abc/]</span> + <span class="Constant">2</span>:number<span class="Special"> <- </span>find-next <span class="Constant">1</span>:address:array:character, <span class="Constant">47/slash</span>, <span class="Constant">0/start-index</span> ] memory-should-contain [ - 2<span class="Special"> <- </span>3 <span class="Comment"># suffix match</span> + <span class="Constant">2</span><span class="Special"> <- </span><span class="Constant">3</span> <span class="Comment"># suffix match</span> ] ] -scenario string-find-next-missing [ +<span class="muScenario">scenario</span> string-find-next-missing [ run [ - 1:address:<span class="Identifier">array</span>:character<span class="Special"> <- </span><span class="Identifier">new</span> [abc] - 2:number<span class="Special"> <- </span>find-next 1:address:<span class="Identifier">array</span>:character, 47/slash, 0/start-index + <span class="Constant">1</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[abc]</span> + <span class="Constant">2</span>:number<span class="Special"> <- </span>find-next <span class="Constant">1</span>:address:array:character, <span class="Constant">47/slash</span>, <span class="Constant">0/start-index</span> ] memory-should-contain [ - 2<span class="Special"> <- </span>3 <span class="Comment"># no match</span> + <span class="Constant">2</span><span class="Special"> <- </span><span class="Constant">3</span> <span class="Comment"># no match</span> ] ] -scenario string-find-next-invalid-index [ +<span class="muScenario">scenario</span> string-find-next-invalid-index [ run [ - 1:address:<span class="Identifier">array</span>:character<span class="Special"> <- </span><span class="Identifier">new</span> [abc] - 2:number<span class="Special"> <- </span>find-next 1:address:<span class="Identifier">array</span>:character, 47/slash, 4/start-index + <span class="Constant">1</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[abc]</span> + <span class="Constant">2</span>:number<span class="Special"> <- </span>find-next <span class="Constant">1</span>:address:array:character, <span class="Constant">47/slash</span>, <span class="Constant">4/start-index</span> ] memory-should-contain [ - 2<span class="Special"> <- </span>4 <span class="Comment"># no change</span> + <span class="Constant">2</span><span class="Special"> <- </span><span class="Constant">4</span> <span class="Comment"># no change</span> ] ] -scenario string-find-next-first [ +<span class="muScenario">scenario</span> string-find-next-first [ run [ - 1:address:<span class="Identifier">array</span>:character<span class="Special"> <- </span><span class="Identifier">new</span> [ab/c/] - 2:number<span class="Special"> <- </span>find-next 1:address:<span class="Identifier">array</span>:character, 47/slash, 0/start-index + <span class="Constant">1</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[ab/c/]</span> + <span class="Constant">2</span>:number<span class="Special"> <- </span>find-next <span class="Constant">1</span>:address:array:character, <span class="Constant">47/slash</span>, <span class="Constant">0/start-index</span> ] memory-should-contain [ - 2<span class="Special"> <- </span>2 <span class="Comment"># first '/' of multiple</span> + <span class="Constant">2</span><span class="Special"> <- </span><span class="Constant">2</span> <span class="Comment"># first '/' of multiple</span> ] ] -scenario string-find-next-second [ +<span class="muScenario">scenario</span> string-find-next-second [ run [ - 1:address:<span class="Identifier">array</span>:character<span class="Special"> <- </span><span class="Identifier">new</span> [ab/c/] - 2:number<span class="Special"> <- </span>find-next 1:address:<span class="Identifier">array</span>:character, 47/slash, 3/start-index + <span class="Constant">1</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[ab/c/]</span> + <span class="Constant">2</span>:number<span class="Special"> <- </span>find-next <span class="Constant">1</span>:address:array:character, <span class="Constant">47/slash</span>, <span class="Constant">3/start-index</span> ] memory-should-contain [ - 2<span class="Special"> <- </span>4 <span class="Comment"># second '/' of multiple</span> + <span class="Constant">2</span><span class="Special"> <- </span><span class="Constant">4</span> <span class="Comment"># second '/' of multiple</span> ] ] <span class="Comment"># next-index:number <- find-substring text:address:array:character, pattern:address:array:character, idx:number</span> <span class="Comment"># like find-next, but searches for multiple characters</span> <span class="Comment"># fairly dumb algorithm</span> -recipe find-<span class="Identifier">substring</span> [ - <span class="Underlined">local</span>-scope - text:address:<span class="Identifier">array</span>:character<span class="Special"> <- </span>next-ingredient - pattern:address:<span class="Identifier">array</span>:character<span class="Special"> <- </span>next-ingredient - idx:number<span class="Special"> <- </span>next-ingredient - first:character<span class="Special"> <- </span>index *pattern, 0 +<span class="muRecipe">recipe</span> find-substring [ + <span class="Constant">local-scope</span> + text:address:array:character<span class="Special"> <- </span><span class="Constant">next-ingredient</span> + pattern:address:array:character<span class="Special"> <- </span><span class="Constant">next-ingredient</span> + idx:number<span class="Special"> <- </span><span class="Constant">next-ingredient</span> + first:character<span class="Special"> <- </span>index *pattern, <span class="Constant">0</span> <span class="Comment"># repeatedly check for match at current idx</span> - len:number<span class="Special"> <- </span><span class="Identifier">length</span> *text - { + len:number<span class="Special"> <- </span>length *text + <span class="Delimiter">{</span> <span class="Comment"># does some unnecessary work checking for substrings even when there isn't enough of text left</span> done?:boolean<span class="Special"> <- </span>greater-or-equal idx, len - break-if done? - found?:boolean<span class="Special"> <- </span><span class="Identifier">match</span>-at text, pattern, idx - break-if found? - idx<span class="Special"> <- </span>add idx, 1 + <span class="muControl">break-if</span> done? + found?:boolean<span class="Special"> <- </span>match-at text, pattern, idx + <span class="muControl">break-if</span> found? + idx<span class="Special"> <- </span>add idx, <span class="Constant">1</span> <span class="Comment"># optimization: skip past indices that definitely won't match</span> idx<span class="Special"> <- </span>find-next text, first, idx - loop - } - reply idx + <span class="muControl">loop</span> + <span class="Delimiter">}</span> + <span class="muControl">reply</span> idx ] -scenario find-<span class="Identifier">substring</span>-1 [ +<span class="muScenario">scenario</span> find-substring-1 [ run [ - 1:address:<span class="Identifier">array</span>:character<span class="Special"> <- </span><span class="Identifier">new</span> [abc] - 2:address:<span class="Identifier">array</span>:character<span class="Special"> <- </span><span class="Identifier">new</span> [bc] - 3:number<span class="Special"> <- </span>find-<span class="Identifier">substring</span> 1:address:<span class="Identifier">array</span>:character, 2:address:<span class="Identifier">array</span>:character, 0 + <span class="Constant">1</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[abc]</span> + <span class="Constant">2</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[bc]</span> + <span class="Constant">3</span>:number<span class="Special"> <- </span>find-substring <span class="Constant">1</span>:address:array:character, <span class="Constant">2</span>:address:array:character, <span class="Constant">0</span> ] memory-should-contain [ - 3<span class="Special"> <- </span>1 + <span class="Constant">3</span><span class="Special"> <- </span><span class="Constant">1</span> ] ] -scenario find-<span class="Identifier">substring</span>-2 [ +<span class="muScenario">scenario</span> find-substring-2 [ run [ - 1:address:<span class="Identifier">array</span>:character<span class="Special"> <- </span><span class="Identifier">new</span> [abcd] - 2:address:<span class="Identifier">array</span>:character<span class="Special"> <- </span><span class="Identifier">new</span> [bc] - 3:number<span class="Special"> <- </span>find-<span class="Identifier">substring</span> 1:address:<span class="Identifier">array</span>:character, 2:address:<span class="Identifier">array</span>:character, 1 + <span class="Constant">1</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[abcd]</span> + <span class="Constant">2</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[bc]</span> + <span class="Constant">3</span>:number<span class="Special"> <- </span>find-substring <span class="Constant">1</span>:address:array:character, <span class="Constant">2</span>:address:array:character, <span class="Constant">1</span> ] memory-should-contain [ - 3<span class="Special"> <- </span>1 + <span class="Constant">3</span><span class="Special"> <- </span><span class="Constant">1</span> ] ] -scenario find-<span class="Identifier">substring</span>-no-<span class="Identifier">match</span> [ +<span class="muScenario">scenario</span> find-substring-no-match [ run [ - 1:address:<span class="Identifier">array</span>:character<span class="Special"> <- </span><span class="Identifier">new</span> [abc] - 2:address:<span class="Identifier">array</span>:character<span class="Special"> <- </span><span class="Identifier">new</span> [bd] - 3:number<span class="Special"> <- </span>find-<span class="Identifier">substring</span> 1:address:<span class="Identifier">array</span>:character, 2:address:<span class="Identifier">array</span>:character, 0 + <span class="Constant">1</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[abc]</span> + <span class="Constant">2</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[bd]</span> + <span class="Constant">3</span>:number<span class="Special"> <- </span>find-substring <span class="Constant">1</span>:address:array:character, <span class="Constant">2</span>:address:array:character, <span class="Constant">0</span> ] memory-should-contain [ - 3<span class="Special"> <- </span>3 <span class="Comment"># not found</span> + <span class="Constant">3</span><span class="Special"> <- </span><span class="Constant">3</span> <span class="Comment"># not found</span> ] ] -scenario find-<span class="Identifier">substring</span>-suffix-<span class="Identifier">match</span> [ +<span class="muScenario">scenario</span> find-substring-suffix-match [ run [ - 1:address:<span class="Identifier">array</span>:character<span class="Special"> <- </span><span class="Identifier">new</span> [abcd] - 2:address:<span class="Identifier">array</span>:character<span class="Special"> <- </span><span class="Identifier">new</span> [cd] - 3:number<span class="Special"> <- </span>find-<span class="Identifier">substring</span> 1:address:<span class="Identifier">array</span>:character, 2:address:<span class="Identifier">array</span>:character, 0 + <span class="Constant">1</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[abcd]</span> + <span class="Constant">2</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[cd]</span> + <span class="Constant">3</span>:number<span class="Special"> <- </span>find-substring <span class="Constant">1</span>:address:array:character, <span class="Constant">2</span>:address:array:character, <span class="Constant">0</span> ] memory-should-contain [ - 3<span class="Special"> <- </span>2 + <span class="Constant">3</span><span class="Special"> <- </span><span class="Constant">2</span> ] ] -scenario find-<span class="Identifier">substring</span>-suffix-<span class="Identifier">match</span>-2 [ +<span class="muScenario">scenario</span> find-substring-suffix-match-2 [ run [ - 1:address:<span class="Identifier">array</span>:character<span class="Special"> <- </span><span class="Identifier">new</span> [abcd] - 2:address:<span class="Identifier">array</span>:character<span class="Special"> <- </span><span class="Identifier">new</span> [cde] - 3:number<span class="Special"> <- </span>find-<span class="Identifier">substring</span> 1:address:<span class="Identifier">array</span>:character, 2:address:<span class="Identifier">array</span>:character, 0 + <span class="Constant">1</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[abcd]</span> + <span class="Constant">2</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[cde]</span> + <span class="Constant">3</span>:number<span class="Special"> <- </span>find-substring <span class="Constant">1</span>:address:array:character, <span class="Constant">2</span>:address:array:character, <span class="Constant">0</span> ] memory-should-contain [ - 3<span class="Special"> <- </span>4 <span class="Comment"># not found</span> + <span class="Constant">3</span><span class="Special"> <- </span><span class="Constant">4</span> <span class="Comment"># not found</span> ] ] <span class="Comment"># result:boolean <- match-at text:address:array:character, pattern:address:array:character, idx:number</span> <span class="Comment"># checks if substring matches at index 'idx'</span> -recipe <span class="Identifier">match</span>-at [ - <span class="Underlined">local</span>-scope - text:address:<span class="Identifier">array</span>:character<span class="Special"> <- </span>next-ingredient - pattern:address:<span class="Identifier">array</span>:character<span class="Special"> <- </span>next-ingredient - idx:number<span class="Special"> <- </span>next-ingredient - pattern-len:number<span class="Special"> <- </span><span class="Identifier">length</span> *pattern +<span class="muRecipe">recipe</span> match-at [ + <span class="Constant">local-scope</span> + text:address:array:character<span class="Special"> <- </span><span class="Constant">next-ingredient</span> + pattern:address:array:character<span class="Special"> <- </span><span class="Constant">next-ingredient</span> + idx:number<span class="Special"> <- </span><span class="Constant">next-ingredient</span> + pattern-len:number<span class="Special"> <- </span>length *pattern <span class="Comment"># check that there's space left for the pattern</span> - { - x:number<span class="Special"> <- </span><span class="Identifier">length</span> *text + <span class="Delimiter">{</span> + x:number<span class="Special"> <- </span>length *text x<span class="Special"> <- </span>subtract x, pattern-len enough-room?:boolean<span class="Special"> <- </span>lesser-or-equal idx, x - break-if enough-room? - reply 0/not-found - } + <span class="muControl">break-if</span> enough-room? + <span class="muControl">reply</span> <span class="Constant">0/not-found</span> + <span class="Delimiter">}</span> <span class="Comment"># check each character of pattern</span> - pattern-idx:number<span class="Special"> <- </span><span class="Identifier">copy</span> 0 - { + pattern-idx:number<span class="Special"> <- </span>copy <span class="Constant">0</span> + <span class="Delimiter">{</span> done?:boolean<span class="Special"> <- </span>greater-or-equal pattern-idx, pattern-len - break-if done? + <span class="muControl">break-if</span> done? c:character<span class="Special"> <- </span>index *text, idx - <span class="Identifier">exp</span>:character<span class="Special"> <- </span>index *pattern, pattern-idx - { - <span class="Identifier">match</span>?:boolean<span class="Special"> <- </span>equal c, <span class="Identifier">exp</span> - break-if <span class="Identifier">match</span>? - reply 0/not-found - } - idx<span class="Special"> <- </span>add idx, 1 - pattern-idx<span class="Special"> <- </span>add pattern-idx, 1 - loop - } - reply 1/found -] - -scenario <span class="Identifier">match</span>-at-checks-<span class="Identifier">substring</span>-at-index [ + exp:character<span class="Special"> <- </span>index *pattern, pattern-idx + <span class="Delimiter">{</span> + match?:boolean<span class="Special"> <- </span>equal c, exp + <span class="muControl">break-if</span> match? + <span class="muControl">reply</span> <span class="Constant">0/not-found</span> + <span class="Delimiter">}</span> + idx<span class="Special"> <- </span>add idx, <span class="Constant">1</span> + pattern-idx<span class="Special"> <- </span>add pattern-idx, <span class="Constant">1</span> + <span class="muControl">loop</span> + <span class="Delimiter">}</span> + <span class="muControl">reply</span> <span class="Constant">1/found</span> +] + +<span class="muScenario">scenario</span> match-at-checks-substring-at-index [ run [ - 1:address:<span class="Identifier">array</span>:character<span class="Special"> <- </span><span class="Identifier">new</span> [abc] - 2:address:<span class="Identifier">array</span>:character<span class="Special"> <- </span><span class="Identifier">new</span> [ab] - 3:boolean<span class="Special"> <- </span><span class="Identifier">match</span>-at 1:address:<span class="Identifier">array</span>:character, 2:address:<span class="Identifier">array</span>:character, 0 + <span class="Constant">1</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[abc]</span> + <span class="Constant">2</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[ab]</span> + <span class="Constant">3</span>:boolean<span class="Special"> <- </span>match-at <span class="Constant">1</span>:address:array:character, <span class="Constant">2</span>:address:array:character, <span class="Constant">0</span> ] memory-should-contain [ - 3<span class="Special"> <- </span>1 <span class="Comment"># match found</span> + <span class="Constant">3</span><span class="Special"> <- </span><span class="Constant">1</span> <span class="Comment"># match found</span> ] ] -scenario <span class="Identifier">match</span>-at-reflexive [ +<span class="muScenario">scenario</span> match-at-reflexive [ run [ - 1:address:<span class="Identifier">array</span>:character<span class="Special"> <- </span><span class="Identifier">new</span> [abc] - 3:boolean<span class="Special"> <- </span><span class="Identifier">match</span>-at 1:address:<span class="Identifier">array</span>:character, 1:address:<span class="Identifier">array</span>:character, 0 + <span class="Constant">1</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[abc]</span> + <span class="Constant">3</span>:boolean<span class="Special"> <- </span>match-at <span class="Constant">1</span>:address:array:character, <span class="Constant">1</span>:address:array:character, <span class="Constant">0</span> ] memory-should-contain [ - 3<span class="Special"> <- </span>1 <span class="Comment"># match found</span> + <span class="Constant">3</span><span class="Special"> <- </span><span class="Constant">1</span> <span class="Comment"># match found</span> ] ] -scenario <span class="Identifier">match</span>-at-outside-bounds [ +<span class="muScenario">scenario</span> match-at-outside-bounds [ run [ - 1:address:<span class="Identifier">array</span>:character<span class="Special"> <- </span><span class="Identifier">new</span> [abc] - 2:address:<span class="Identifier">array</span>:character<span class="Special"> <- </span><span class="Identifier">new</span> [a] - 3:boolean<span class="Special"> <- </span><span class="Identifier">match</span>-at 1:address:<span class="Identifier">array</span>:character, 2:address:<span class="Identifier">array</span>:character, 4 + <span class="Constant">1</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[abc]</span> + <span class="Constant">2</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[a]</span> + <span class="Constant">3</span>:boolean<span class="Special"> <- </span>match-at <span class="Constant">1</span>:address:array:character, <span class="Constant">2</span>:address:array:character, <span class="Constant">4</span> ] memory-should-contain [ - 3<span class="Special"> <- </span>0 <span class="Comment"># never matches</span> + <span class="Constant">3</span><span class="Special"> <- </span><span class="Constant">0</span> <span class="Comment"># never matches</span> ] ] -scenario <span class="Identifier">match</span>-at-empty-pattern [ +<span class="muScenario">scenario</span> match-at-empty-pattern [ run [ - 1:address:<span class="Identifier">array</span>:character<span class="Special"> <- </span><span class="Identifier">new</span> [abc] - 2:address:<span class="Identifier">array</span>:character<span class="Special"> <- </span><span class="Identifier">new</span> [] - 3:boolean<span class="Special"> <- </span><span class="Identifier">match</span>-at 1:address:<span class="Identifier">array</span>:character, 2:address:<span class="Identifier">array</span>:character, 0 + <span class="Constant">1</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[abc]</span> + <span class="Constant">2</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[]</span> + <span class="Constant">3</span>:boolean<span class="Special"> <- </span>match-at <span class="Constant">1</span>:address:array:character, <span class="Constant">2</span>:address:array:character, <span class="Constant">0</span> ] memory-should-contain [ - 3<span class="Special"> <- </span>1 <span class="Comment"># always matches empty pattern given a valid index</span> + <span class="Constant">3</span><span class="Special"> <- </span><span class="Constant">1</span> <span class="Comment"># always matches empty pattern given a valid index</span> ] ] -scenario <span class="Identifier">match</span>-at-empty-pattern-outside-bound [ +<span class="muScenario">scenario</span> match-at-empty-pattern-outside-bound [ run [ - 1:address:<span class="Identifier">array</span>:character<span class="Special"> <- </span><span class="Identifier">new</span> [abc] - 2:address:<span class="Identifier">array</span>:character<span class="Special"> <- </span><span class="Identifier">new</span> [] - 3:boolean<span class="Special"> <- </span><span class="Identifier">match</span>-at 1:address:<span class="Identifier">array</span>:character, 2:address:<span class="Identifier">array</span>:character, 4 + <span class="Constant">1</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[abc]</span> + <span class="Constant">2</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[]</span> + <span class="Constant">3</span>:boolean<span class="Special"> <- </span>match-at <span class="Constant">1</span>:address:array:character, <span class="Constant">2</span>:address:array:character, <span class="Constant">4</span> ] memory-should-contain [ - 3<span class="Special"> <- </span>0 <span class="Comment"># no match</span> + <span class="Constant">3</span><span class="Special"> <- </span><span class="Constant">0</span> <span class="Comment"># no match</span> ] ] -scenario <span class="Identifier">match</span>-at-empty-text [ +<span class="muScenario">scenario</span> match-at-empty-text [ run [ - 1:address:<span class="Identifier">array</span>:character<span class="Special"> <- </span><span class="Identifier">new</span> [] - 2:address:<span class="Identifier">array</span>:character<span class="Special"> <- </span><span class="Identifier">new</span> [abc] - 3:boolean<span class="Special"> <- </span><span class="Identifier">match</span>-at 1:address:<span class="Identifier">array</span>:character, 2:address:<span class="Identifier">array</span>:character, 0 + <span class="Constant">1</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[]</span> + <span class="Constant">2</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[abc]</span> + <span class="Constant">3</span>:boolean<span class="Special"> <- </span>match-at <span class="Constant">1</span>:address:array:character, <span class="Constant">2</span>:address:array:character, <span class="Constant">0</span> ] memory-should-contain [ - 3<span class="Special"> <- </span>0 <span class="Comment"># no match</span> + <span class="Constant">3</span><span class="Special"> <- </span><span class="Constant">0</span> <span class="Comment"># no match</span> ] ] -scenario <span class="Identifier">match</span>-at-empty-against-empty [ +<span class="muScenario">scenario</span> match-at-empty-against-empty [ run [ - 1:address:<span class="Identifier">array</span>:character<span class="Special"> <- </span><span class="Identifier">new</span> [] - 3:boolean<span class="Special"> <- </span><span class="Identifier">match</span>-at 1:address:<span class="Identifier">array</span>:character, 1:address:<span class="Identifier">array</span>:character, 0 + <span class="Constant">1</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[]</span> + <span class="Constant">3</span>:boolean<span class="Special"> <- </span>match-at <span class="Constant">1</span>:address:array:character, <span class="Constant">1</span>:address:array:character, <span class="Constant">0</span> ] memory-should-contain [ - 3<span class="Special"> <- </span>1 <span class="Comment"># matches because pattern is also empty</span> + <span class="Constant">3</span><span class="Special"> <- </span><span class="Constant">1</span> <span class="Comment"># matches because pattern is also empty</span> ] ] -scenario <span class="Identifier">match</span>-at-inside-bounds [ +<span class="muScenario">scenario</span> match-at-inside-bounds [ run [ - 1:address:<span class="Identifier">array</span>:character<span class="Special"> <- </span><span class="Identifier">new</span> [abc] - 2:address:<span class="Identifier">array</span>:character<span class="Special"> <- </span><span class="Identifier">new</span> [bc] - 3:boolean<span class="Special"> <- </span><span class="Identifier">match</span>-at 1:address:<span class="Identifier">array</span>:character, 2:address:<span class="Identifier">array</span>:character, 1 + <span class="Constant">1</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[abc]</span> + <span class="Constant">2</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[bc]</span> + <span class="Constant">3</span>:boolean<span class="Special"> <- </span>match-at <span class="Constant">1</span>:address:array:character, <span class="Constant">2</span>:address:array:character, <span class="Constant">1</span> ] memory-should-contain [ - 3<span class="Special"> <- </span>1 <span class="Comment"># matches inner substring</span> + <span class="Constant">3</span><span class="Special"> <- </span><span class="Constant">1</span> <span class="Comment"># matches inner substring</span> ] ] -scenario <span class="Identifier">match</span>-at-inside-bounds-2 [ +<span class="muScenario">scenario</span> match-at-inside-bounds-2 [ run [ - 1:address:<span class="Identifier">array</span>:character<span class="Special"> <- </span><span class="Identifier">new</span> [abc] - 2:address:<span class="Identifier">array</span>:character<span class="Special"> <- </span><span class="Identifier">new</span> [bc] - 3:boolean<span class="Special"> <- </span><span class="Identifier">match</span>-at 1:address:<span class="Identifier">array</span>:character, 2:address:<span class="Identifier">array</span>:character, 0 + <span class="Constant">1</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[abc]</span> + <span class="Constant">2</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[bc]</span> + <span class="Constant">3</span>:boolean<span class="Special"> <- </span>match-at <span class="Constant">1</span>:address:array:character, <span class="Constant">2</span>:address:array:character, <span class="Constant">0</span> ] memory-should-contain [ - 3<span class="Special"> <- </span>0 <span class="Comment"># no match</span> + <span class="Constant">3</span><span class="Special"> <- </span><span class="Constant">0</span> <span class="Comment"># no match</span> ] ] <span class="Comment"># result:address:array:address:array:character <- split s:address:array:character, delim:character</span> -recipe <span class="Identifier">split</span> [ - <span class="Underlined">local</span>-scope - s:address:<span class="Identifier">array</span>:character<span class="Special"> <- </span>next-ingredient - delim:character<span class="Special"> <- </span>next-ingredient +<span class="muRecipe">recipe</span> split [ + <span class="Constant">local-scope</span> + s:address:array:character<span class="Special"> <- </span><span class="Constant">next-ingredient</span> + delim:character<span class="Special"> <- </span><span class="Constant">next-ingredient</span> <span class="Comment"># empty string? return empty array</span> - len:number<span class="Special"> <- </span><span class="Identifier">length</span> *s - { - empty?:boolean<span class="Special"> <- </span>equal len, 0 - break-unless empty? - result:address:<span class="Identifier">array</span>:address:<span class="Identifier">array</span>:character<span class="Special"> <- </span><span class="Identifier">new</span> location:<span class="Identifier">type</span>, 0 - reply result - } + len:number<span class="Special"> <- </span>length *s + <span class="Delimiter">{</span> + empty?:boolean<span class="Special"> <- </span>equal len, <span class="Constant">0</span> + <span class="muControl">break-unless</span> empty? + result:address:array:address:array:character<span class="Special"> <- </span>new <span class="Constant">location:type</span>, <span class="Constant">0</span> + <span class="muControl">reply</span> result + <span class="Delimiter">}</span> <span class="Comment"># count #pieces we need room for</span> - count:number<span class="Special"> <- </span><span class="Identifier">copy</span> 1 <span class="Comment"># n delimiters = n+1 pieces</span> - idx:number<span class="Special"> <- </span><span class="Identifier">copy</span> 0 - { + count:number<span class="Special"> <- </span>copy <span class="Constant">1</span> <span class="Comment"># n delimiters = n+1 pieces</span> + idx:number<span class="Special"> <- </span>copy <span class="Constant">0</span> + <span class="Delimiter">{</span> idx<span class="Special"> <- </span>find-next s, delim, idx done?:boolean<span class="Special"> <- </span>greater-or-equal idx, len - break-if done? - idx<span class="Special"> <- </span>add idx, 1 - count<span class="Special"> <- </span>add count, 1 - loop - } + <span class="muControl">break-if</span> done? + idx<span class="Special"> <- </span>add idx, <span class="Constant">1</span> + count<span class="Special"> <- </span>add count, <span class="Constant">1</span> + <span class="muControl">loop</span> + <span class="Delimiter">}</span> <span class="Comment"># allocate space</span> - result:address:<span class="Identifier">array</span>:address:<span class="Identifier">array</span>:character<span class="Special"> <- </span><span class="Identifier">new</span> location:<span class="Identifier">type</span>, count + result:address:array:address:array:character<span class="Special"> <- </span>new <span class="Constant">location:type</span>, count <span class="Comment"># repeatedly copy slices start..end until delimiter into result[curr-result]</span> - curr-result:number<span class="Special"> <- </span><span class="Identifier">copy</span> 0 - start:number<span class="Special"> <- </span><span class="Identifier">copy</span> 0 - { + curr-result:number<span class="Special"> <- </span>copy <span class="Constant">0</span> + start:number<span class="Special"> <- </span>copy <span class="Constant">0</span> + <span class="Delimiter">{</span> <span class="Comment"># while next delim exists</span> done?:boolean<span class="Special"> <- </span>greater-or-equal start, len - break-if done? + <span class="muControl">break-if</span> done? end:number<span class="Special"> <- </span>find-next s, delim, start <span class="Comment"># copy start..end into result[curr-result]</span> - dest:address:address:<span class="Identifier">array</span>:character<span class="Special"> <- </span>index-address *result, curr-result - *dest<span class="Special"> <- </span>string-<span class="Identifier">copy</span> s, start, end + dest:address:address:array:character<span class="Special"> <- </span>index-address *result, curr-result + *dest<span class="Special"> <- </span>string-copy s, start, end <span class="Comment"># slide over to next slice</span> - start<span class="Special"> <- </span>add end, 1 - curr-result<span class="Special"> <- </span>add curr-result, 1 - loop - } - reply result + start<span class="Special"> <- </span>add end, <span class="Constant">1</span> + curr-result<span class="Special"> <- </span>add curr-result, <span class="Constant">1</span> + <span class="muControl">loop</span> + <span class="Delimiter">}</span> + <span class="muControl">reply</span> result ] -scenario string-<span class="Identifier">split</span>-1 [ +<span class="muScenario">scenario</span> string-split-1 [ run [ - 1:address:<span class="Identifier">array</span>:character<span class="Special"> <- </span><span class="Identifier">new</span> [a/b] - 2:address:<span class="Identifier">array</span>:address:<span class="Identifier">array</span>:character<span class="Special"> <- </span><span class="Identifier">split</span> 1:address:<span class="Identifier">array</span>:character, 47/slash - 3:number<span class="Special"> <- </span><span class="Identifier">length</span> *2:address:<span class="Identifier">array</span>:address:<span class="Identifier">array</span>:character - 4:address:<span class="Identifier">array</span>:character<span class="Special"> <- </span>index *2:address:<span class="Identifier">array</span>:address:<span class="Identifier">array</span>:character, 0 - 5:address:<span class="Identifier">array</span>:character<span class="Special"> <- </span>index *2:address:<span class="Identifier">array</span>:address:<span class="Identifier">array</span>:character, 1 - 10:<span class="Identifier">array</span>:character<span class="Special"> <- </span><span class="Identifier">copy</span> *4:address:<span class="Identifier">array</span>:character - 20:<span class="Identifier">array</span>:character<span class="Special"> <- </span><span class="Identifier">copy</span> *5:address:<span class="Identifier">array</span>:character + <span class="Constant">1</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[a/b]</span> + <span class="Constant">2</span>:address:array:address:array:character<span class="Special"> <- </span>split <span class="Constant">1</span>:address:array:character, <span class="Constant">47/slash</span> + <span class="Constant">3</span>:number<span class="Special"> <- </span>length *<span class="Constant">2</span>:address:array:address:array:character + <span class="Constant">4</span>:address:array:character<span class="Special"> <- </span>index *<span class="Constant">2</span>:address:array:address:array:character, <span class="Constant">0</span> + <span class="Constant">5</span>:address:array:character<span class="Special"> <- </span>index *<span class="Constant">2</span>:address:array:address:array:character, <span class="Constant">1</span> + <span class="Constant">10</span>:array:character<span class="Special"> <- </span>copy *<span class="Constant">4</span>:address:array:character + <span class="Constant">20</span>:array:character<span class="Special"> <- </span>copy *<span class="Constant">5</span>:address:array:character ] memory-should-contain [ - 3<span class="Special"> <- </span>2 <span class="Comment"># length of result</span> - 10:string<span class="Special"> <- </span>[a] - 20:string<span class="Special"> <- </span>[b] + <span class="Constant">3</span><span class="Special"> <- </span><span class="Constant">2</span> <span class="Comment"># length of result</span> + <span class="Constant">10</span>:string<span class="Special"> <- </span><span class="Constant">[a]</span> + <span class="Constant">20</span>:string<span class="Special"> <- </span><span class="Constant">[b]</span> ] ] -scenario string-<span class="Identifier">split</span>-2 [ +<span class="muScenario">scenario</span> string-split-2 [ run [ - 1:address:<span class="Identifier">array</span>:character<span class="Special"> <- </span><span class="Identifier">new</span> [a/b/c] - 2:address:<span class="Identifier">array</span>:address:<span class="Identifier">array</span>:character<span class="Special"> <- </span><span class="Identifier">split</span> 1:address:<span class="Identifier">array</span>:character, 47/slash - 3:number<span class="Special"> <- </span><span class="Identifier">length</span> *2:address:<span class="Identifier">array</span>:address:<span class="Identifier">array</span>:character - 4:address:<span class="Identifier">array</span>:character<span class="Special"> <- </span>index *2:address:<span class="Identifier">array</span>:address:<span class="Identifier">array</span>:character, 0 - 5:address:<span class="Identifier">array</span>:character<span class="Special"> <- </span>index *2:address:<span class="Identifier">array</span>:address:<span class="Identifier">array</span>:character, 1 - 6:address:<span class="Identifier">array</span>:character<span class="Special"> <- </span>index *2:address:<span class="Identifier">array</span>:address:<span class="Identifier">array</span>:character, 2 - 10:<span class="Identifier">array</span>:character<span class="Special"> <- </span><span class="Identifier">copy</span> *4:address:<span class="Identifier">array</span>:character - 20:<span class="Identifier">array</span>:character<span class="Special"> <- </span><span class="Identifier">copy</span> *5:address:<span class="Identifier">array</span>:character - 30:<span class="Identifier">array</span>:character<span class="Special"> <- </span><span class="Identifier">copy</span> *6:address:<span class="Identifier">array</span>:character + <span class="Constant">1</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[a/b/c]</span> + <span class="Constant">2</span>:address:array:address:array:character<span class="Special"> <- </span>split <span class="Constant">1</span>:address:array:character, <span class="Constant">47/slash</span> + <span class="Constant">3</span>:number<span class="Special"> <- </span>length *<span class="Constant">2</span>:address:array:address:array:character + <span class="Constant">4</span>:address:array:character<span class="Special"> <- </span>index *<span class="Constant">2</span>:address:array:address:array:character, <span class="Constant">0</span> + <span class="Constant">5</span>:address:array:character<span class="Special"> <- </span>index *<span class="Constant">2</span>:address:array:address:array:character, <span class="Constant">1</span> + <span class="Constant">6</span>:address:array:character<span class="Special"> <- </span>index *<span class="Constant">2</span>:address:array:address:array:character, <span class="Constant">2</span> + <span class="Constant">10</span>:array:character<span class="Special"> <- </span>copy *<span class="Constant">4</span>:address:array:character + <span class="Constant">20</span>:array:character<span class="Special"> <- </span>copy *<span class="Constant">5</span>:address:array:character + <span class="Constant">30</span>:array:character<span class="Special"> <- </span>copy *<span class="Constant">6</span>:address:array:character ] memory-should-contain [ - 3<span class="Special"> <- </span>3 <span class="Comment"># length of result</span> - 10:string<span class="Special"> <- </span>[a] - 20:string<span class="Special"> <- </span>[b] - 30:string<span class="Special"> <- </span>[c] + <span class="Constant">3</span><span class="Special"> <- </span><span class="Constant">3</span> <span class="Comment"># length of result</span> + <span class="Constant">10</span>:string<span class="Special"> <- </span><span class="Constant">[a]</span> + <span class="Constant">20</span>:string<span class="Special"> <- </span><span class="Constant">[b]</span> + <span class="Constant">30</span>:string<span class="Special"> <- </span><span class="Constant">[c]</span> ] ] -scenario string-<span class="Identifier">split</span>-missing [ +<span class="muScenario">scenario</span> string-split-missing [ run [ - 1:address:<span class="Identifier">array</span>:character<span class="Special"> <- </span><span class="Identifier">new</span> [abc] - 2:address:<span class="Identifier">array</span>:address:<span class="Identifier">array</span>:character<span class="Special"> <- </span><span class="Identifier">split</span> 1:address:<span class="Identifier">array</span>:character, 47/slash - 3:number<span class="Special"> <- </span><span class="Identifier">length</span> *2:address:<span class="Identifier">array</span>:address:<span class="Identifier">array</span>:character - 4:address:<span class="Identifier">array</span>:character<span class="Special"> <- </span>index *2:address:<span class="Identifier">array</span>:address:<span class="Identifier">array</span>:character, 0 - 10:<span class="Identifier">array</span>:character<span class="Special"> <- </span><span class="Identifier">copy</span> *4:address:<span class="Identifier">array</span>:character + <span class="Constant">1</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[abc]</span> + <span class="Constant">2</span>:address:array:address:array:character<span class="Special"> <- </span>split <span class="Constant">1</span>:address:array:character, <span class="Constant">47/slash</span> + <span class="Constant">3</span>:number<span class="Special"> <- </span>length *<span class="Constant">2</span>:address:array:address:array:character + <span class="Constant">4</span>:address:array:character<span class="Special"> <- </span>index *<span class="Constant">2</span>:address:array:address:array:character, <span class="Constant">0</span> + <span class="Constant">10</span>:array:character<span class="Special"> <- </span>copy *<span class="Constant">4</span>:address:array:character ] memory-should-contain [ - 3<span class="Special"> <- </span>1 <span class="Comment"># length of result</span> - 10:string<span class="Special"> <- </span>[abc] + <span class="Constant">3</span><span class="Special"> <- </span><span class="Constant">1</span> <span class="Comment"># length of result</span> + <span class="Constant">10</span>:string<span class="Special"> <- </span><span class="Constant">[abc]</span> ] ] -scenario string-<span class="Identifier">split</span>-empty [ +<span class="muScenario">scenario</span> string-split-empty [ run [ - 1:address:<span class="Identifier">array</span>:character<span class="Special"> <- </span><span class="Identifier">new</span> [] - 2:address:<span class="Identifier">array</span>:address:<span class="Identifier">array</span>:character<span class="Special"> <- </span><span class="Identifier">split</span> 1:address:<span class="Identifier">array</span>:character, 47/slash - 3:number<span class="Special"> <- </span><span class="Identifier">length</span> *2:address:<span class="Identifier">array</span>:address:<span class="Identifier">array</span>:character + <span class="Constant">1</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[]</span> + <span class="Constant">2</span>:address:array:address:array:character<span class="Special"> <- </span>split <span class="Constant">1</span>:address:array:character, <span class="Constant">47/slash</span> + <span class="Constant">3</span>:number<span class="Special"> <- </span>length *<span class="Constant">2</span>:address:array:address:array:character ] memory-should-contain [ - 3<span class="Special"> <- </span>0 <span class="Comment"># empty result</span> + <span class="Constant">3</span><span class="Special"> <- </span><span class="Constant">0</span> <span class="Comment"># empty result</span> ] ] -scenario string-<span class="Identifier">split</span>-empty-piece [ +<span class="muScenario">scenario</span> string-split-empty-piece [ run [ - 1:address:<span class="Identifier">array</span>:character<span class="Special"> <- </span><span class="Identifier">new</span> [a/b<span class="Comment">//c]</span> - 2:address:<span class="Identifier">array</span>:address:<span class="Identifier">array</span>:character<span class="Special"> <- </span><span class="Identifier">split</span> 1:address:<span class="Identifier">array</span>:character, 47/slash - 3:number<span class="Special"> <- </span><span class="Identifier">length</span> *2:address:<span class="Identifier">array</span>:address:<span class="Identifier">array</span>:character - 4:address:<span class="Identifier">array</span>:character<span class="Special"> <- </span>index *2:address:<span class="Identifier">array</span>:address:<span class="Identifier">array</span>:character, 0 - 5:address:<span class="Identifier">array</span>:character<span class="Special"> <- </span>index *2:address:<span class="Identifier">array</span>:address:<span class="Identifier">array</span>:character, 1 - 6:address:<span class="Identifier">array</span>:character<span class="Special"> <- </span>index *2:address:<span class="Identifier">array</span>:address:<span class="Identifier">array</span>:character, 2 - 7:address:<span class="Identifier">array</span>:character<span class="Special"> <- </span>index *2:address:<span class="Identifier">array</span>:address:<span class="Identifier">array</span>:character, 3 - 10:<span class="Identifier">array</span>:character<span class="Special"> <- </span><span class="Identifier">copy</span> *4:address:<span class="Identifier">array</span>:character - 20:<span class="Identifier">array</span>:character<span class="Special"> <- </span><span class="Identifier">copy</span> *5:address:<span class="Identifier">array</span>:character - 30:<span class="Identifier">array</span>:character<span class="Special"> <- </span><span class="Identifier">copy</span> *6:address:<span class="Identifier">array</span>:character - 40:<span class="Identifier">array</span>:character<span class="Special"> <- </span><span class="Identifier">copy</span> *7:address:<span class="Identifier">array</span>:character + <span class="Constant">1</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[a/b//c]</span> + <span class="Constant">2</span>:address:array:address:array:character<span class="Special"> <- </span>split <span class="Constant">1</span>:address:array:character, <span class="Constant">47/slash</span> + <span class="Constant">3</span>:number<span class="Special"> <- </span>length *<span class="Constant">2</span>:address:array:address:array:character + <span class="Constant">4</span>:address:array:character<span class="Special"> <- </span>index *<span class="Constant">2</span>:address:array:address:array:character, <span class="Constant">0</span> + <span class="Constant">5</span>:address:array:character<span class="Special"> <- </span>index *<span class="Constant">2</span>:address:array:address:array:character, <span class="Constant">1</span> + <span class="Constant">6</span>:address:array:character<span class="Special"> <- </span>index *<span class="Constant">2</span>:address:array:address:array:character, <span class="Constant">2</span> + <span class="Constant">7</span>:address:array:character<span class="Special"> <- </span>index *<span class="Constant">2</span>:address:array:address:array:character, <span class="Constant">3</span> + <span class="Constant">10</span>:array:character<span class="Special"> <- </span>copy *<span class="Constant">4</span>:address:array:character + <span class="Constant">20</span>:array:character<span class="Special"> <- </span>copy *<span class="Constant">5</span>:address:array:character + <span class="Constant">30</span>:array:character<span class="Special"> <- </span>copy *<span class="Constant">6</span>:address:array:character + <span class="Constant">40</span>:array:character<span class="Special"> <- </span>copy *<span class="Constant">7</span>:address:array:character ] memory-should-contain [ - 3<span class="Special"> <- </span>4 <span class="Comment"># length of result</span> - 10:string<span class="Special"> <- </span>[a] - 20:string<span class="Special"> <- </span>[b] - 30:string<span class="Special"> <- </span>[] - 40:string<span class="Special"> <- </span>[c] + <span class="Constant">3</span><span class="Special"> <- </span><span class="Constant">4</span> <span class="Comment"># length of result</span> + <span class="Constant">10</span>:string<span class="Special"> <- </span><span class="Constant">[a]</span> + <span class="Constant">20</span>:string<span class="Special"> <- </span><span class="Constant">[b]</span> + <span class="Constant">30</span>:string<span class="Special"> <- </span><span class="Constant">[]</span> + <span class="Constant">40</span>:string<span class="Special"> <- </span><span class="Constant">[c]</span> ] ] <span class="Comment"># x:address:array:character, y:address:array:character <- split-first text:address:array:character, delim:character</span> -recipe <span class="Identifier">split</span>-first [ - <span class="Underlined">local</span>-scope - text:address:<span class="Identifier">array</span>:character<span class="Special"> <- </span>next-ingredient - delim:character<span class="Special"> <- </span>next-ingredient +<span class="muRecipe">recipe</span> split-first [ + <span class="Constant">local-scope</span> + text:address:array:character<span class="Special"> <- </span><span class="Constant">next-ingredient</span> + delim:character<span class="Special"> <- </span><span class="Constant">next-ingredient</span> <span class="Comment"># empty string? return empty strings</span> - len:number<span class="Special"> <- </span><span class="Identifier">length</span> *text - { - empty?:boolean<span class="Special"> <- </span>equal len, 0 - break-unless empty? - x:address:<span class="Identifier">array</span>:character<span class="Special"> <- </span><span class="Identifier">new</span> [] - y:address:<span class="Identifier">array</span>:character<span class="Special"> <- </span><span class="Identifier">new</span> [] - reply x, y - } - idx:number<span class="Special"> <- </span>find-next text, delim, 0 - x:address:<span class="Identifier">array</span>:character<span class="Special"> <- </span>string-<span class="Identifier">copy</span> text, 0, idx - idx<span class="Special"> <- </span>add idx, 1 - y:address:<span class="Identifier">array</span>:character<span class="Special"> <- </span>string-<span class="Identifier">copy</span> text, idx, len - reply x, y -] - -scenario string-<span class="Identifier">split</span>-first [ + len:number<span class="Special"> <- </span>length *text + <span class="Delimiter">{</span> + empty?:boolean<span class="Special"> <- </span>equal len, <span class="Constant">0</span> + <span class="muControl">break-unless</span> empty? + x:address:array:character<span class="Special"> <- </span>new <span class="Constant">[]</span> + y:address:array:character<span class="Special"> <- </span>new <span class="Constant">[]</span> + <span class="muControl">reply</span> x, y + <span class="Delimiter">}</span> + idx:number<span class="Special"> <- </span>find-next text, delim, <span class="Constant">0</span> + x:address:array:character<span class="Special"> <- </span>string-copy text, <span class="Constant">0</span>, idx + idx<span class="Special"> <- </span>add idx, <span class="Constant">1</span> + y:address:array:character<span class="Special"> <- </span>string-copy text, idx, len + <span class="muControl">reply</span> x, y +] + +<span class="muScenario">scenario</span> string-split-first [ run [ - 1:address:<span class="Identifier">array</span>:character<span class="Special"> <- </span><span class="Identifier">new</span> [a/b] - 2:address:<span class="Identifier">array</span>:character, 3:address:<span class="Identifier">array</span>:character<span class="Special"> <- </span><span class="Identifier">split</span>-first 1:address:<span class="Identifier">array</span>:character, 47/slash - 10:<span class="Identifier">array</span>:character<span class="Special"> <- </span><span class="Identifier">copy</span> *2:address:<span class="Identifier">array</span>:character - 20:<span class="Identifier">array</span>:character<span class="Special"> <- </span><span class="Identifier">copy</span> *3:address:<span class="Identifier">array</span>:character + <span class="Constant">1</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[a/b]</span> + <span class="Constant">2</span>:address:array:character, <span class="Constant">3</span>:address:array:character<span class="Special"> <- </span>split-first <span class="Constant">1</span>:address:array:character, <span class="Constant">47/slash</span> + <span class="Constant">10</span>:array:character<span class="Special"> <- </span>copy *<span class="Constant">2</span>:address:array:character + <span class="Constant">20</span>:array:character<span class="Special"> <- </span>copy *<span class="Constant">3</span>:address:array:character ] memory-should-contain [ - 10:string<span class="Special"> <- </span>[a] - 20:string<span class="Special"> <- </span>[b] + <span class="Constant">10</span>:string<span class="Special"> <- </span><span class="Constant">[a]</span> + <span class="Constant">20</span>:string<span class="Special"> <- </span><span class="Constant">[b]</span> ] ] <span class="Comment"># result:address:array:character <- string-copy buf:address:array:character, start:number, end:number</span> <span class="Comment"># todo: make this generic</span> -recipe string-<span class="Identifier">copy</span> [ - <span class="Underlined">local</span>-scope - buf:address:<span class="Identifier">array</span>:character<span class="Special"> <- </span>next-ingredient - start:number<span class="Special"> <- </span>next-ingredient - end:number<span class="Special"> <- </span>next-ingredient +<span class="muRecipe">recipe</span> string-copy [ + <span class="Constant">local-scope</span> + buf:address:array:character<span class="Special"> <- </span><span class="Constant">next-ingredient</span> + start:number<span class="Special"> <- </span><span class="Constant">next-ingredient</span> + end:number<span class="Special"> <- </span><span class="Constant">next-ingredient</span> <span class="Comment"># if end is out of bounds, trim it</span> - len:number<span class="Special"> <- </span><span class="Identifier">length</span> *buf - end:number<span class="Special"> <- </span><span class="Identifier">min</span> len, end + len:number<span class="Special"> <- </span>length *buf + end:number<span class="Special"> <- </span>min len, end <span class="Comment"># allocate space for result</span> len<span class="Special"> <- </span>subtract end, start - result:address:<span class="Identifier">array</span>:character<span class="Special"> <- </span><span class="Identifier">new</span> character:<span class="Identifier">type</span>, len + result:address:array:character<span class="Special"> <- </span>new <span class="Constant">character:type</span>, len <span class="Comment"># copy start..end into result[curr-result]</span> - src-idx:number<span class="Special"> <- </span><span class="Identifier">copy</span> start - dest-idx:number<span class="Special"> <- </span><span class="Identifier">copy</span> 0 - { + src-idx:number<span class="Special"> <- </span>copy start + dest-idx:number<span class="Special"> <- </span>copy <span class="Constant">0</span> + <span class="Delimiter">{</span> done?:boolean<span class="Special"> <- </span>greater-or-equal src-idx, end - break-if done? + <span class="muControl">break-if</span> done? src:character<span class="Special"> <- </span>index *buf, src-idx dest:address:character<span class="Special"> <- </span>index-address *result, dest-idx - *dest<span class="Special"> <- </span><span class="Identifier">copy</span> src - src-idx<span class="Special"> <- </span>add src-idx, 1 - dest-idx<span class="Special"> <- </span>add dest-idx, 1 - loop - } - reply result + *dest<span class="Special"> <- </span>copy src + src-idx<span class="Special"> <- </span>add src-idx, <span class="Constant">1</span> + dest-idx<span class="Special"> <- </span>add dest-idx, <span class="Constant">1</span> + <span class="muControl">loop</span> + <span class="Delimiter">}</span> + <span class="muControl">reply</span> result ] -scenario string-<span class="Identifier">copy</span>-copies-<span class="Identifier">substring</span> [ +<span class="muScenario">scenario</span> string-copy-copies-substring [ run [ - 1:address:<span class="Identifier">array</span>:character<span class="Special"> <- </span><span class="Identifier">new</span> [abc] - 2:address:<span class="Identifier">array</span>:character<span class="Special"> <- </span>string-<span class="Identifier">copy</span> 1:address:<span class="Identifier">array</span>:character, 1, 3 - 3:<span class="Identifier">array</span>:character<span class="Special"> <- </span><span class="Identifier">copy</span> *2:address:<span class="Identifier">array</span>:character + <span class="Constant">1</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[abc]</span> + <span class="Constant">2</span>:address:array:character<span class="Special"> <- </span>string-copy <span class="Constant">1</span>:address:array:character, <span class="Constant">1</span>, <span class="Constant">3</span> + <span class="Constant">3</span>:array:character<span class="Special"> <- </span>copy *<span class="Constant">2</span>:address:array:character ] memory-should-contain [ - 3:string<span class="Special"> <- </span>[bc] + <span class="Constant">3</span>:string<span class="Special"> <- </span><span class="Constant">[bc]</span> ] ] -scenario string-<span class="Identifier">copy</span>-out-of-bounds [ +<span class="muScenario">scenario</span> string-copy-out-of-bounds [ run [ - 1:address:<span class="Identifier">array</span>:character<span class="Special"> <- </span><span class="Identifier">new</span> [abc] - 2:address:<span class="Identifier">array</span>:character<span class="Special"> <- </span>string-<span class="Identifier">copy</span> 1:address:<span class="Identifier">array</span>:character, 2, 4 - 3:<span class="Identifier">array</span>:character<span class="Special"> <- </span><span class="Identifier">copy</span> *2:address:<span class="Identifier">array</span>:character + <span class="Constant">1</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[abc]</span> + <span class="Constant">2</span>:address:array:character<span class="Special"> <- </span>string-copy <span class="Constant">1</span>:address:array:character, <span class="Constant">2</span>, <span class="Constant">4</span> + <span class="Constant">3</span>:array:character<span class="Special"> <- </span>copy *<span class="Constant">2</span>:address:array:character ] memory-should-contain [ - 3:string<span class="Special"> <- </span>[c] + <span class="Constant">3</span>:string<span class="Special"> <- </span><span class="Constant">[c]</span> ] ] -scenario string-<span class="Identifier">copy</span>-out-of-bounds-2 [ +<span class="muScenario">scenario</span> string-copy-out-of-bounds-2 [ run [ - 1:address:<span class="Identifier">array</span>:character<span class="Special"> <- </span><span class="Identifier">new</span> [abc] - 2:address:<span class="Identifier">array</span>:character<span class="Special"> <- </span>string-<span class="Identifier">copy</span> 1:address:<span class="Identifier">array</span>:character, 3, 3 - 3:<span class="Identifier">array</span>:character<span class="Special"> <- </span><span class="Identifier">copy</span> *2:address:<span class="Identifier">array</span>:character + <span class="Constant">1</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[abc]</span> + <span class="Constant">2</span>:address:array:character<span class="Special"> <- </span>string-copy <span class="Constant">1</span>:address:array:character, <span class="Constant">3</span>, <span class="Constant">3</span> + <span class="Constant">3</span>:array:character<span class="Special"> <- </span>copy *<span class="Constant">2</span>:address:array:character ] memory-should-contain [ - 3:string<span class="Special"> <- </span>[] - ] -] - -recipe <span class="Identifier">min</span> [ - <span class="Underlined">local</span>-scope - x:number<span class="Special"> <- </span>next-ingredient - y:number<span class="Special"> <- </span>next-ingredient - { - <span class="Identifier">return</span>-x?:boolean<span class="Special"> <- </span>lesser-than x, y - break-if <span class="Identifier">return</span>-x? - reply y - } - reply x -] - -recipe <span class="Identifier">max</span> [ - <span class="Underlined">local</span>-scope - x:number<span class="Special"> <- </span>next-ingredient - y:number<span class="Special"> <- </span>next-ingredient - { - <span class="Identifier">return</span>-x?:boolean<span class="Special"> <- </span>greater-than x, y - break-if <span class="Identifier">return</span>-x? - reply y - } - reply x + <span class="Constant">3</span>:string<span class="Special"> <- </span><span class="Constant">[]</span> + ] +] + +<span class="muRecipe">recipe</span> min [ + <span class="Constant">local-scope</span> + x:number<span class="Special"> <- </span><span class="Constant">next-ingredient</span> + y:number<span class="Special"> <- </span><span class="Constant">next-ingredient</span> + <span class="Delimiter">{</span> + return-x?:boolean<span class="Special"> <- </span>lesser-than x, y + <span class="muControl">break-if</span> return-x? + <span class="muControl">reply</span> y + <span class="Delimiter">}</span> + <span class="muControl">reply</span> x +] + +<span class="muRecipe">recipe</span> max [ + <span class="Constant">local-scope</span> + x:number<span class="Special"> <- </span><span class="Constant">next-ingredient</span> + y:number<span class="Special"> <- </span><span class="Constant">next-ingredient</span> + <span class="Delimiter">{</span> + return-x?:boolean<span class="Special"> <- </span>greater-than x, y + <span class="muControl">break-if</span> return-x? + <span class="muControl">reply</span> y + <span class="Delimiter">}</span> + <span class="muControl">reply</span> x ] </pre> </body> diff --git a/html/061channel.mu.html b/html/061channel.mu.html index 0823083a..a52d34f3 100644 --- a/html/061channel.mu.html +++ b/html/061channel.mu.html @@ -13,11 +13,15 @@ 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; } +.muData { color: #ffff00; } .SalientComment { color: #00ffff; } -.Underlined { color: #c000c0; text-decoration: underline; } +.muRecipe { color: #ff8700; } .Comment { color: #9090ff; } +.Constant { color: #00a0a0; } .Special { color: #ff6060; } -.Identifier { color: #804000; } +.Delimiter { color: #a04060; } +.muControl { color: #c0a020; } --> </style> @@ -30,27 +34,27 @@ body { font-family: monospace; color: #eeeeee; background-color: #080808; } <body> <pre id='vimCodeElement'> <span class="Comment"># Mu synchronizes using channels rather than locks, like Erlang and Go.</span> -# +<span class="Comment">#</span> <span class="Comment"># The two ends of a channel will usually belong to different routines, but</span> <span class="Comment"># each end should only be used by a single one. Don't try to read from or</span> <span class="Comment"># write to it from multiple routines at once.</span> -# +<span class="Comment">#</span> <span class="Comment"># The key property of channels is that writing to a full channel or reading</span> <span class="Comment"># from an empty one will put the current routine in 'waiting' state until the</span> <span class="Comment"># operation can be completed.</span> -scenario channel [ +<span class="muScenario">scenario</span> channel [ run [ - 1:address:channel<span class="Special"> <- </span><span class="Identifier">new</span>-channel 3/capacity - 1:address:channel<span class="Special"> <- </span><span class="Identifier">write</span> 1:address:channel, 34 - 2:number, 1:address:channel<span class="Special"> <- </span><span class="Identifier">read</span> 1:address:channel + <span class="Constant">1</span>:address:channel<span class="Special"> <- </span>new-channel <span class="Constant">3/capacity</span> + <span class="Constant">1</span>:address:channel<span class="Special"> <- </span>write <span class="Constant">1</span>:address:channel, <span class="Constant">34</span> + <span class="Constant">2</span>:number, <span class="Constant">1</span>:address:channel<span class="Special"> <- </span>read <span class="Constant">1</span>:address:channel ] memory-should-contain [ - 2<span class="Special"> <- </span>34 + <span class="Constant">2</span><span class="Special"> <- </span><span class="Constant">34</span> ] ] -container channel [ +<span class="muData">container</span> channel [ <span class="Comment"># To avoid locking, writer and reader will never write to the same location.</span> <span class="Comment"># So channels will include fields in pairs, one for the writer and one for the</span> <span class="Comment"># reader.</span> @@ -59,344 +63,344 @@ container channel [ <span class="Comment"># A circular buffer contains values from index first-full up to (but not</span> <span class="Comment"># including) index first-empty. The reader always modifies it at first-full,</span> <span class="Comment"># while the writer always modifies it at first-empty.</span> - data:address:<span class="Identifier">array</span>:location + data:address:array:location ] <span class="Comment"># result:address:channel <- new-channel capacity:number</span> -recipe <span class="Identifier">new</span>-channel [ - <span class="Underlined">local</span>-scope +<span class="muRecipe">recipe</span> new-channel [ + <span class="Constant">local-scope</span> <span class="Comment"># result = new channel</span> - result:address:channel<span class="Special"> <- </span><span class="Identifier">new</span> channel:<span class="Identifier">type</span> + result:address:channel<span class="Special"> <- </span>new <span class="Constant">channel:type</span> <span class="Comment"># result.first-full = 0</span> - full:address:number<span class="Special"> <- </span>get-address *result, first-full:offset - *full<span class="Special"> <- </span><span class="Identifier">copy</span> 0 + full:address:number<span class="Special"> <- </span>get-address *result, <span class="Constant">first-full:offset</span> + *full<span class="Special"> <- </span>copy <span class="Constant">0</span> <span class="Comment"># result.first-free = 0</span> - free:address:number<span class="Special"> <- </span>get-address *result, first-free:offset - *free<span class="Special"> <- </span><span class="Identifier">copy</span> 0 + free:address:number<span class="Special"> <- </span>get-address *result, <span class="Constant">first-free:offset</span> + *free<span class="Special"> <- </span>copy <span class="Constant">0</span> <span class="Comment"># result.data = new location[ingredient+1]</span> - capacity:number<span class="Special"> <- </span>next-ingredient - capacity<span class="Special"> <- </span>add capacity, 1 <span class="Comment"># unused slot for 'full?' below</span> - dest:address:address:<span class="Identifier">array</span>:location<span class="Special"> <- </span>get-address *result, data:offset - *dest<span class="Special"> <- </span><span class="Identifier">new</span> location:<span class="Identifier">type</span>, capacity - reply result + capacity:number<span class="Special"> <- </span><span class="Constant">next-ingredient</span> + capacity<span class="Special"> <- </span>add capacity, <span class="Constant">1</span> <span class="Comment"># unused slot for 'full?' below</span> + dest:address:address:array:location<span class="Special"> <- </span>get-address *result, <span class="Constant">data:offset</span> + *dest<span class="Special"> <- </span>new <span class="Constant">location:type</span>, capacity + <span class="muControl">reply</span> result ] <span class="Comment"># chan <- write chan:address:channel, val:location</span> -recipe <span class="Identifier">write</span> [ - <span class="Underlined">local</span>-scope - chan:address:channel<span class="Special"> <- </span>next-ingredient - <span class="Identifier">val</span>:location<span class="Special"> <- </span>next-ingredient - { +<span class="muRecipe">recipe</span> write [ + <span class="Constant">local-scope</span> + chan:address:channel<span class="Special"> <- </span><span class="Constant">next-ingredient</span> + val:location<span class="Special"> <- </span><span class="Constant">next-ingredient</span> + <span class="Delimiter">{</span> <span class="Comment"># block if chan is full</span> full:boolean<span class="Special"> <- </span>channel-full? chan - break-unless full - full-address:address:number<span class="Special"> <- </span>get-address *chan, first-full:offset + <span class="muControl">break-unless</span> full + full-address:address:number<span class="Special"> <- </span>get-address *chan, <span class="Constant">first-full:offset</span> wait-for-location *full-address - } + <span class="Delimiter">}</span> <span class="Comment"># store val</span> - circular-buffer:address:<span class="Identifier">array</span>:location<span class="Special"> <- </span>get *chan, data:offset - free:address:number<span class="Special"> <- </span>get-address *chan, first-free:offset + circular-buffer:address:array:location<span class="Special"> <- </span>get *chan, <span class="Constant">data:offset</span> + free:address:number<span class="Special"> <- </span>get-address *chan, <span class="Constant">first-free:offset</span> dest:address:location<span class="Special"> <- </span>index-address *circular-buffer, *free - *dest<span class="Special"> <- </span><span class="Identifier">copy</span> <span class="Identifier">val</span> + *dest<span class="Special"> <- </span>copy val <span class="Comment"># mark its slot as filled</span> - *free<span class="Special"> <- </span>add *free, 1 - { + *free<span class="Special"> <- </span>add *free, <span class="Constant">1</span> + <span class="Delimiter">{</span> <span class="Comment"># wrap free around to 0 if necessary</span> - len:number<span class="Special"> <- </span><span class="Identifier">length</span> *circular-buffer + len:number<span class="Special"> <- </span>length *circular-buffer at-end?:boolean<span class="Special"> <- </span>greater-or-equal *free, len - break-unless at-end? - *free<span class="Special"> <- </span><span class="Identifier">copy</span> 0 - } - reply chan/same-as-ingredient:0 + <span class="muControl">break-unless</span> at-end? + *free<span class="Special"> <- </span>copy <span class="Constant">0</span> + <span class="Delimiter">}</span> + <span class="muControl">reply</span> chan/same-as-ingredient:<span class="Constant">0</span> ] <span class="Comment"># result:location, chan <- read chan:address:channel</span> -recipe <span class="Identifier">read</span> [ - <span class="Underlined">local</span>-scope - chan:address:channel<span class="Special"> <- </span>next-ingredient - { +<span class="muRecipe">recipe</span> read [ + <span class="Constant">local-scope</span> + chan:address:channel<span class="Special"> <- </span><span class="Constant">next-ingredient</span> + <span class="Delimiter">{</span> <span class="Comment"># block if chan is empty</span> empty?:boolean<span class="Special"> <- </span>channel-empty? chan - break-unless empty? - free-address:address:number<span class="Special"> <- </span>get-address *chan, first-free:offset + <span class="muControl">break-unless</span> empty? + free-address:address:number<span class="Special"> <- </span>get-address *chan, <span class="Constant">first-free:offset</span> wait-for-location *free-address - } + <span class="Delimiter">}</span> <span class="Comment"># read result</span> - full:address:number<span class="Special"> <- </span>get-address *chan, first-full:offset - circular-buffer:address:<span class="Identifier">array</span>:location<span class="Special"> <- </span>get *chan, data:offset + full:address:number<span class="Special"> <- </span>get-address *chan, <span class="Constant">first-full:offset</span> + circular-buffer:address:array:location<span class="Special"> <- </span>get *chan, <span class="Constant">data:offset</span> result:location<span class="Special"> <- </span>index *circular-buffer, *full <span class="Comment"># mark its slot as empty</span> - *full<span class="Special"> <- </span>add *full, 1 - { + *full<span class="Special"> <- </span>add *full, <span class="Constant">1</span> + <span class="Delimiter">{</span> <span class="Comment"># wrap full around to 0 if necessary</span> - len:number<span class="Special"> <- </span><span class="Identifier">length</span> *circular-buffer + len:number<span class="Special"> <- </span>length *circular-buffer at-end?:boolean<span class="Special"> <- </span>greater-or-equal *full, len - break-unless at-end? - *full<span class="Special"> <- </span><span class="Identifier">copy</span> 0 - } - reply result, chan/same-as-ingredient:0 + <span class="muControl">break-unless</span> at-end? + *full<span class="Special"> <- </span>copy <span class="Constant">0</span> + <span class="Delimiter">}</span> + <span class="muControl">reply</span> result, chan/same-as-ingredient:<span class="Constant">0</span> ] -recipe clear-channel [ - <span class="Underlined">local</span>-scope - chan:address:channel<span class="Special"> <- </span>next-ingredient - { +<span class="muRecipe">recipe</span> clear-channel [ + <span class="Constant">local-scope</span> + chan:address:channel<span class="Special"> <- </span><span class="Constant">next-ingredient</span> + <span class="Delimiter">{</span> empty?:boolean<span class="Special"> <- </span>channel-empty? chan - break-if empty? - _, chan<span class="Special"> <- </span><span class="Identifier">read</span> chan - } - reply chan/same-as-ingredient:0 + <span class="muControl">break-if</span> empty? + _, chan<span class="Special"> <- </span>read chan + <span class="Delimiter">}</span> + <span class="muControl">reply</span> chan/same-as-ingredient:<span class="Constant">0</span> ] -scenario channel-initialization [ +<span class="muScenario">scenario</span> channel-initialization [ run [ - 1:address:channel<span class="Special"> <- </span><span class="Identifier">new</span>-channel 3/capacity - 2:number<span class="Special"> <- </span>get *1:address:channel, first-full:offset - 3:number<span class="Special"> <- </span>get *1:address:channel, first-free:offset + <span class="Constant">1</span>:address:channel<span class="Special"> <- </span>new-channel <span class="Constant">3/capacity</span> + <span class="Constant">2</span>:number<span class="Special"> <- </span>get *<span class="Constant">1</span>:address:channel, <span class="Constant">first-full:offset</span> + <span class="Constant">3</span>:number<span class="Special"> <- </span>get *<span class="Constant">1</span>:address:channel, <span class="Constant">first-free:offset</span> ] memory-should-contain [ - 2<span class="Special"> <- </span>0 <span class="Comment"># first-full</span> - 3<span class="Special"> <- </span>0 <span class="Comment"># first-free</span> + <span class="Constant">2</span><span class="Special"> <- </span><span class="Constant">0</span> <span class="Comment"># first-full</span> + <span class="Constant">3</span><span class="Special"> <- </span><span class="Constant">0</span> <span class="Comment"># first-free</span> ] ] -scenario channel-<span class="Identifier">write</span>-increments-free [ +<span class="muScenario">scenario</span> channel-write-increments-free [ run [ - 1:address:channel<span class="Special"> <- </span><span class="Identifier">new</span>-channel 3/capacity - 1:address:channel<span class="Special"> <- </span><span class="Identifier">write</span> 1:address:channel, 34 - 2:number<span class="Special"> <- </span>get *1:address:channel, first-full:offset - 3:number<span class="Special"> <- </span>get *1:address:channel, first-free:offset + <span class="Constant">1</span>:address:channel<span class="Special"> <- </span>new-channel <span class="Constant">3/capacity</span> + <span class="Constant">1</span>:address:channel<span class="Special"> <- </span>write <span class="Constant">1</span>:address:channel, <span class="Constant">34</span> + <span class="Constant">2</span>:number<span class="Special"> <- </span>get *<span class="Constant">1</span>:address:channel, <span class="Constant">first-full:offset</span> + <span class="Constant">3</span>:number<span class="Special"> <- </span>get *<span class="Constant">1</span>:address:channel, <span class="Constant">first-free:offset</span> ] memory-should-contain [ - 2<span class="Special"> <- </span>0 <span class="Comment"># first-full</span> - 3<span class="Special"> <- </span>1 <span class="Comment"># first-free</span> + <span class="Constant">2</span><span class="Special"> <- </span><span class="Constant">0</span> <span class="Comment"># first-full</span> + <span class="Constant">3</span><span class="Special"> <- </span><span class="Constant">1</span> <span class="Comment"># first-free</span> ] ] -scenario channel-<span class="Identifier">read</span>-increments-full [ +<span class="muScenario">scenario</span> channel-read-increments-full [ run [ - 1:address:channel<span class="Special"> <- </span><span class="Identifier">new</span>-channel 3/capacity - 1:address:channel<span class="Special"> <- </span><span class="Identifier">write</span> 1:address:channel, 34 - _, 1:address:channel<span class="Special"> <- </span><span class="Identifier">read</span> 1:address:channel - 2:number<span class="Special"> <- </span>get *1:address:channel, first-full:offset - 3:number<span class="Special"> <- </span>get *1:address:channel, first-free:offset + <span class="Constant">1</span>:address:channel<span class="Special"> <- </span>new-channel <span class="Constant">3/capacity</span> + <span class="Constant">1</span>:address:channel<span class="Special"> <- </span>write <span class="Constant">1</span>:address:channel, <span class="Constant">34</span> + _, <span class="Constant">1</span>:address:channel<span class="Special"> <- </span>read <span class="Constant">1</span>:address:channel + <span class="Constant">2</span>:number<span class="Special"> <- </span>get *<span class="Constant">1</span>:address:channel, <span class="Constant">first-full:offset</span> + <span class="Constant">3</span>:number<span class="Special"> <- </span>get *<span class="Constant">1</span>:address:channel, <span class="Constant">first-free:offset</span> ] memory-should-contain [ - 2<span class="Special"> <- </span>1 <span class="Comment"># first-full</span> - 3<span class="Special"> <- </span>1 <span class="Comment"># first-free</span> + <span class="Constant">2</span><span class="Special"> <- </span><span class="Constant">1</span> <span class="Comment"># first-full</span> + <span class="Constant">3</span><span class="Special"> <- </span><span class="Constant">1</span> <span class="Comment"># first-free</span> ] ] -scenario channel-wrap [ +<span class="muScenario">scenario</span> channel-wrap [ run [ <span class="Comment"># channel with just 1 slot</span> - 1:address:channel<span class="Special"> <- </span><span class="Identifier">new</span>-channel 1/capacity + <span class="Constant">1</span>:address:channel<span class="Special"> <- </span>new-channel <span class="Constant">1/capacity</span> <span class="Comment"># write and read a value</span> - 1:address:channel<span class="Special"> <- </span><span class="Identifier">write</span> 1:address:channel, 34 - _, 1:address:channel<span class="Special"> <- </span><span class="Identifier">read</span> 1:address:channel + <span class="Constant">1</span>:address:channel<span class="Special"> <- </span>write <span class="Constant">1</span>:address:channel, <span class="Constant">34</span> + _, <span class="Constant">1</span>:address:channel<span class="Special"> <- </span>read <span class="Constant">1</span>:address:channel <span class="Comment"># first-free will now be 1</span> - 2:number<span class="Special"> <- </span>get *1:address:channel, first-free:offset - 3:number<span class="Special"> <- </span>get *1:address:channel, first-free:offset + <span class="Constant">2</span>:number<span class="Special"> <- </span>get *<span class="Constant">1</span>:address:channel, <span class="Constant">first-free:offset</span> + <span class="Constant">3</span>:number<span class="Special"> <- </span>get *<span class="Constant">1</span>:address:channel, <span class="Constant">first-free:offset</span> <span class="Comment"># write second value, verify that first-free wraps</span> - 1:address:channel<span class="Special"> <- </span><span class="Identifier">write</span> 1:address:channel, 34 - 4:number<span class="Special"> <- </span>get *1:address:channel, first-free:offset + <span class="Constant">1</span>:address:channel<span class="Special"> <- </span>write <span class="Constant">1</span>:address:channel, <span class="Constant">34</span> + <span class="Constant">4</span>:number<span class="Special"> <- </span>get *<span class="Constant">1</span>:address:channel, <span class="Constant">first-free:offset</span> <span class="Comment"># read second value, verify that first-full wraps</span> - _, 1:address:channel<span class="Special"> <- </span><span class="Identifier">read</span> 1:address:channel - 5:number<span class="Special"> <- </span>get *1:address:channel, first-full:offset + _, <span class="Constant">1</span>:address:channel<span class="Special"> <- </span>read <span class="Constant">1</span>:address:channel + <span class="Constant">5</span>:number<span class="Special"> <- </span>get *<span class="Constant">1</span>:address:channel, <span class="Constant">first-full:offset</span> ] memory-should-contain [ - 2<span class="Special"> <- </span>1 <span class="Comment"># first-free after first write</span> - 3<span class="Special"> <- </span>1 <span class="Comment"># first-full after first read</span> - 4<span class="Special"> <- </span>0 <span class="Comment"># first-free after second write, wrapped</span> - 5<span class="Special"> <- </span>0 <span class="Comment"># first-full after second read, wrapped</span> + <span class="Constant">2</span><span class="Special"> <- </span><span class="Constant">1</span> <span class="Comment"># first-free after first write</span> + <span class="Constant">3</span><span class="Special"> <- </span><span class="Constant">1</span> <span class="Comment"># first-full after first read</span> + <span class="Constant">4</span><span class="Special"> <- </span><span class="Constant">0</span> <span class="Comment"># first-free after second write, wrapped</span> + <span class="Constant">5</span><span class="Special"> <- </span><span class="Constant">0</span> <span class="Comment"># first-full after second read, wrapped</span> ] ] <span class="SalientComment">## helpers</span> <span class="Comment"># An empty channel has first-empty and first-full both at the same value.</span> -recipe channel-empty? [ - <span class="Underlined">local</span>-scope - chan:address:channel<span class="Special"> <- </span>next-ingredient +<span class="muRecipe">recipe</span> channel-empty? [ + <span class="Constant">local-scope</span> + chan:address:channel<span class="Special"> <- </span><span class="Constant">next-ingredient</span> <span class="Comment"># return chan.first-full == chan.first-free</span> - full:number<span class="Special"> <- </span>get *chan, first-full:offset - free:number<span class="Special"> <- </span>get *chan, first-free:offset + full:number<span class="Special"> <- </span>get *chan, <span class="Constant">first-full:offset</span> + free:number<span class="Special"> <- </span>get *chan, <span class="Constant">first-free:offset</span> result:boolean<span class="Special"> <- </span>equal full, free - reply result + <span class="muControl">reply</span> result ] <span class="Comment"># A full channel has first-empty just before first-full, wasting one slot.</span> <span class="Comment"># (Other alternatives: <a href="https://en.wikipedia.org/wiki/Circular_buffer#Full_.2F_Empty_Buffer_Distinction)">https://en.wikipedia.org/wiki/Circular_buffer#Full_.2F_Empty_Buffer_Distinction)</a></span> -recipe channel-full? [ - <span class="Underlined">local</span>-scope - chan:address:channel<span class="Special"> <- </span>next-ingredient +<span class="muRecipe">recipe</span> channel-full? [ + <span class="Constant">local-scope</span> + chan:address:channel<span class="Special"> <- </span><span class="Constant">next-ingredient</span> <span class="Comment"># tmp = chan.first-free + 1</span> - tmp:number<span class="Special"> <- </span>get *chan, first-free:offset - tmp<span class="Special"> <- </span>add tmp, 1 - { + tmp:number<span class="Special"> <- </span>get *chan, <span class="Constant">first-free:offset</span> + tmp<span class="Special"> <- </span>add tmp, <span class="Constant">1</span> + <span class="Delimiter">{</span> <span class="Comment"># if tmp == chan.capacity, tmp = 0</span> len:number<span class="Special"> <- </span>channel-capacity chan at-end?:boolean<span class="Special"> <- </span>greater-or-equal tmp, len - break-unless at-end? - tmp<span class="Special"> <- </span><span class="Identifier">copy</span> 0 - } + <span class="muControl">break-unless</span> at-end? + tmp<span class="Special"> <- </span>copy <span class="Constant">0</span> + <span class="Delimiter">}</span> <span class="Comment"># return chan.first-full == tmp</span> - full:number<span class="Special"> <- </span>get *chan, first-full:offset + full:number<span class="Special"> <- </span>get *chan, <span class="Constant">first-full:offset</span> result:boolean<span class="Special"> <- </span>equal full, tmp - reply result + <span class="muControl">reply</span> result ] <span class="Comment"># result:number <- channel-capacity chan:address:channel</span> -recipe channel-capacity [ - <span class="Underlined">local</span>-scope - chan:address:channel<span class="Special"> <- </span>next-ingredient - q:address:<span class="Identifier">array</span>:location<span class="Special"> <- </span>get *chan, data:offset - result:number<span class="Special"> <- </span><span class="Identifier">length</span> *q - reply result +<span class="muRecipe">recipe</span> channel-capacity [ + <span class="Constant">local-scope</span> + chan:address:channel<span class="Special"> <- </span><span class="Constant">next-ingredient</span> + q:address:array:location<span class="Special"> <- </span>get *chan, <span class="Constant">data:offset</span> + result:number<span class="Special"> <- </span>length *q + <span class="muControl">reply</span> result ] -scenario channel-<span class="Identifier">new</span>-empty-not-full [ +<span class="muScenario">scenario</span> channel-new-empty-not-full [ run [ - 1:address:channel<span class="Special"> <- </span><span class="Identifier">new</span>-channel 3/capacity - 2:boolean<span class="Special"> <- </span>channel-empty? 1:address:channel - 3:boolean<span class="Special"> <- </span>channel-full? 1:address:channel + <span class="Constant">1</span>:address:channel<span class="Special"> <- </span>new-channel <span class="Constant">3/capacity</span> + <span class="Constant">2</span>:boolean<span class="Special"> <- </span>channel-empty? <span class="Constant">1</span>:address:channel + <span class="Constant">3</span>:boolean<span class="Special"> <- </span>channel-full? <span class="Constant">1</span>:address:channel ] memory-should-contain [ - 2<span class="Special"> <- </span>1 <span class="Comment"># empty?</span> - 3<span class="Special"> <- </span>0 <span class="Comment"># full?</span> + <span class="Constant">2</span><span class="Special"> <- </span><span class="Constant">1</span> <span class="Comment"># empty?</span> + <span class="Constant">3</span><span class="Special"> <- </span><span class="Constant">0</span> <span class="Comment"># full?</span> ] ] -scenario channel-<span class="Identifier">write</span>-not-empty [ +<span class="muScenario">scenario</span> channel-write-not-empty [ run [ - 1:address:channel<span class="Special"> <- </span><span class="Identifier">new</span>-channel 3/capacity - 1:address:channel<span class="Special"> <- </span><span class="Identifier">write</span> 1:address:channel, 34 - 2:boolean<span class="Special"> <- </span>channel-empty? 1:address:channel - 3:boolean<span class="Special"> <- </span>channel-full? 1:address:channel + <span class="Constant">1</span>:address:channel<span class="Special"> <- </span>new-channel <span class="Constant">3/capacity</span> + <span class="Constant">1</span>:address:channel<span class="Special"> <- </span>write <span class="Constant">1</span>:address:channel, <span class="Constant">34</span> + <span class="Constant">2</span>:boolean<span class="Special"> <- </span>channel-empty? <span class="Constant">1</span>:address:channel + <span class="Constant">3</span>:boolean<span class="Special"> <- </span>channel-full? <span class="Constant">1</span>:address:channel ] memory-should-contain [ - 2<span class="Special"> <- </span>0 <span class="Comment"># empty?</span> - 3<span class="Special"> <- </span>0 <span class="Comment"># full?</span> + <span class="Constant">2</span><span class="Special"> <- </span><span class="Constant">0</span> <span class="Comment"># empty?</span> + <span class="Constant">3</span><span class="Special"> <- </span><span class="Constant">0</span> <span class="Comment"># full?</span> ] ] -scenario channel-<span class="Identifier">write</span>-full [ +<span class="muScenario">scenario</span> channel-write-full [ run [ - 1:address:channel<span class="Special"> <- </span><span class="Identifier">new</span>-channel 1/capacity - 1:address:channel<span class="Special"> <- </span><span class="Identifier">write</span> 1:address:channel, 34 - 2:boolean<span class="Special"> <- </span>channel-empty? 1:address:channel - 3:boolean<span class="Special"> <- </span>channel-full? 1:address:channel + <span class="Constant">1</span>:address:channel<span class="Special"> <- </span>new-channel <span class="Constant">1/capacity</span> + <span class="Constant">1</span>:address:channel<span class="Special"> <- </span>write <span class="Constant">1</span>:address:channel, <span class="Constant">34</span> + <span class="Constant">2</span>:boolean<span class="Special"> <- </span>channel-empty? <span class="Constant">1</span>:address:channel + <span class="Constant">3</span>:boolean<span class="Special"> <- </span>channel-full? <span class="Constant">1</span>:address:channel ] memory-should-contain [ - 2<span class="Special"> <- </span>0 <span class="Comment"># empty?</span> - 3<span class="Special"> <- </span>1 <span class="Comment"># full?</span> + <span class="Constant">2</span><span class="Special"> <- </span><span class="Constant">0</span> <span class="Comment"># empty?</span> + <span class="Constant">3</span><span class="Special"> <- </span><span class="Constant">1</span> <span class="Comment"># full?</span> ] ] -scenario channel-<span class="Identifier">read</span>-not-full [ +<span class="muScenario">scenario</span> channel-read-not-full [ run [ - 1:address:channel<span class="Special"> <- </span><span class="Identifier">new</span>-channel 1/capacity - 1:address:channel<span class="Special"> <- </span><span class="Identifier">write</span> 1:address:channel, 34 - _, 1:address:channel<span class="Special"> <- </span><span class="Identifier">read</span> 1:address:channel - 2:boolean<span class="Special"> <- </span>channel-empty? 1:address:channel - 3:boolean<span class="Special"> <- </span>channel-full? 1:address:channel + <span class="Constant">1</span>:address:channel<span class="Special"> <- </span>new-channel <span class="Constant">1/capacity</span> + <span class="Constant">1</span>:address:channel<span class="Special"> <- </span>write <span class="Constant">1</span>:address:channel, <span class="Constant">34</span> + _, <span class="Constant">1</span>:address:channel<span class="Special"> <- </span>read <span class="Constant">1</span>:address:channel + <span class="Constant">2</span>:boolean<span class="Special"> <- </span>channel-empty? <span class="Constant">1</span>:address:channel + <span class="Constant">3</span>:boolean<span class="Special"> <- </span>channel-full? <span class="Constant">1</span>:address:channel ] memory-should-contain [ - 2<span class="Special"> <- </span>1 <span class="Comment"># empty?</span> - 3<span class="Special"> <- </span>0 <span class="Comment"># full?</span> + <span class="Constant">2</span><span class="Special"> <- </span><span class="Constant">1</span> <span class="Comment"># empty?</span> + <span class="Constant">3</span><span class="Special"> <- </span><span class="Constant">0</span> <span class="Comment"># full?</span> ] ] <span class="Comment"># helper for channels of characters in particular</span> <span class="Comment"># out <- buffer-lines in:address:channel, out:address:channel</span> -recipe buffer-lines [ - <span class="Underlined">local</span>-scope - <span class="Identifier">in</span>:address:channel<span class="Special"> <- </span>next-ingredient - out:address:channel<span class="Special"> <- </span>next-ingredient +<span class="muRecipe">recipe</span> buffer-lines [ + <span class="Constant">local-scope</span> + in:address:channel<span class="Special"> <- </span><span class="Constant">next-ingredient</span> + out:address:channel<span class="Special"> <- </span><span class="Constant">next-ingredient</span> <span class="Comment"># repeat forever</span> - { - line:address:buffer<span class="Special"> <- </span><span class="Identifier">new</span>-buffer, 30 + <span class="Delimiter">{</span> + line:address:buffer<span class="Special"> <- </span>new-buffer, <span class="Constant">30</span> <span class="Comment"># read characters from 'in' until newline, copy into line</span> - { - +next-character - c:character, <span class="Identifier">in</span><span class="Special"> <- </span><span class="Identifier">read</span> <span class="Identifier">in</span> + <span class="Delimiter">{</span> +<span class="Constant"> +next-character</span> + c:character, in<span class="Special"> <- </span>read in <span class="Comment"># drop a character on backspace</span> - { + <span class="Delimiter">{</span> <span class="Comment"># special-case: if it's a backspace</span> - backspace?:boolean<span class="Special"> <- </span>equal c, 8 - break-unless backspace? + backspace?:boolean<span class="Special"> <- </span>equal c, <span class="Constant">8</span> + <span class="muControl">break-unless</span> backspace? <span class="Comment"># drop previous character</span> - { - buffer-<span class="Identifier">length</span>:address:number<span class="Special"> <- </span>get-address *line, <span class="Identifier">length</span>:offset - buffer-empty?:boolean<span class="Special"> <- </span>equal *buffer-<span class="Identifier">length</span>, 0 - break-if buffer-empty? - *buffer-<span class="Identifier">length</span><span class="Special"> <- </span>subtract *buffer-<span class="Identifier">length</span>, 1 - } + <span class="Delimiter">{</span> + buffer-length:address:number<span class="Special"> <- </span>get-address *line, <span class="Constant">length:offset</span> + buffer-empty?:boolean<span class="Special"> <- </span>equal *buffer-length, <span class="Constant">0</span> + <span class="muControl">break-if</span> buffer-empty? + *buffer-length<span class="Special"> <- </span>subtract *buffer-length, <span class="Constant">1</span> + <span class="Delimiter">}</span> <span class="Comment"># and don't append this one</span> - loop +next-character:label - } + <span class="muControl">loop</span> <span class="Constant">+next-character:label</span> + <span class="Delimiter">}</span> <span class="Comment"># append anything else</span> - line<span class="Special"> <- </span>buffer-<span class="Identifier">append</span> line, c - line-done?:boolean<span class="Special"> <- </span>equal c, 10/newline - break-if line-done? + line<span class="Special"> <- </span>buffer-append line, c + line-done?:boolean<span class="Special"> <- </span>equal c, <span class="Constant">10/newline</span> + <span class="muControl">break-if</span> line-done? <span class="Comment"># stop buffering on eof (currently only generated by fake console)</span> - eof?:boolean<span class="Special"> <- </span>equal c, 0/eof - break-if eof? - loop - } + eof?:boolean<span class="Special"> <- </span>equal c, <span class="Constant">0/eof</span> + <span class="muControl">break-if</span> eof? + <span class="muControl">loop</span> + <span class="Delimiter">}</span> <span class="Comment"># copy line into 'out'</span> - i:number<span class="Special"> <- </span><span class="Identifier">copy</span> 0 - line-contents:address:<span class="Identifier">array</span>:character<span class="Special"> <- </span>get *line, data:offset - <span class="Identifier">max</span>:number<span class="Special"> <- </span>get *line, <span class="Identifier">length</span>:offset - { - done?:boolean<span class="Special"> <- </span>greater-or-equal i, <span class="Identifier">max</span> - break-if done? + i:number<span class="Special"> <- </span>copy <span class="Constant">0</span> + line-contents:address:array:character<span class="Special"> <- </span>get *line, <span class="Constant">data:offset</span> + max:number<span class="Special"> <- </span>get *line, <span class="Constant">length:offset</span> + <span class="Delimiter">{</span> + done?:boolean<span class="Special"> <- </span>greater-or-equal i, max + <span class="muControl">break-if</span> done? c:character<span class="Special"> <- </span>index *line-contents, i - out<span class="Special"> <- </span><span class="Identifier">write</span> out, c - i<span class="Special"> <- </span>add i, 1 - loop - } - loop - } - reply out/same-as-ingredient:1 + out<span class="Special"> <- </span>write out, c + i<span class="Special"> <- </span>add i, <span class="Constant">1</span> + <span class="muControl">loop</span> + <span class="Delimiter">}</span> + <span class="muControl">loop</span> + <span class="Delimiter">}</span> + <span class="muControl">reply</span> out/same-as-ingredient:<span class="Constant">1</span> ] -scenario buffer-lines-blocks-until-newline [ +<span class="muScenario">scenario</span> buffer-lines-blocks-until-newline [ run [ - 1:address:channel/stdin<span class="Special"> <- </span><span class="Identifier">new</span>-channel 10/capacity - 2:address:channel/buffered-stdin<span class="Special"> <- </span><span class="Identifier">new</span>-channel 10/capacity - 3:boolean<span class="Special"> <- </span>channel-empty? 2:address:channel/buffered-stdin - <span class="Identifier">assert</span> 3:boolean, [ -F buffer-lines-blocks-until-newline: channel should be empty after init] + <span class="Constant">1</span>:address:channel/stdin<span class="Special"> <- </span>new-channel <span class="Constant">10/capacity</span> + <span class="Constant">2</span>:address:channel/buffered-stdin<span class="Special"> <- </span>new-channel <span class="Constant">10/capacity</span> + <span class="Constant">3</span>:boolean<span class="Special"> <- </span>channel-empty? <span class="Constant">2</span>:address:channel/buffered-stdin + assert <span class="Constant">3</span>:boolean, [ +F buffer-lines-blocks-until-newline: channel should be empty <span class="muRecipe">after</span> init] <span class="Comment"># buffer stdin into buffered-stdin, try to read from buffered-stdin</span> - 4:number/buffer-routine<span class="Special"> <- </span>start-running buffer-lines:recipe, 1:address:channel/stdin, 2:address:channel/buffered-stdin - wait-for-routine 4:number/buffer-routine - 5:boolean<span class="Special"> <- </span>channel-empty? 2:address:channel/buffered-stdin - <span class="Identifier">assert</span> 5:boolean, [ -F buffer-lines-blocks-until-newline: channel should be empty after buffer-lines bring-up] + <span class="Constant">4</span>:number/buffer-routine<span class="Special"> <- </span>start-running <span class="Constant">buffer-lines:recipe</span>, <span class="Constant">1</span>:address:channel/stdin, <span class="Constant">2</span>:address:channel/buffered-stdin + wait-for-routine <span class="Constant">4</span>:number/buffer-routine + <span class="Constant">5</span>:boolean<span class="Special"> <- </span>channel-empty? <span class="Constant">2</span>:address:channel/buffered-stdin + assert <span class="Constant">5</span>:boolean, [ +F buffer-lines-blocks-until-newline: channel should be empty <span class="muRecipe">after</span> buffer-lines bring-up] <span class="Comment"># write 'a'</span> - 1:address:channel<span class="Special"> <- </span><span class="Identifier">write</span> 1:address:channel, 97/a - restart 4:number/buffer-routine - wait-for-routine 4:number/buffer-routine - 6:boolean<span class="Special"> <- </span>channel-empty? 2:address:channel/buffered-stdin - <span class="Identifier">assert</span> 6:boolean, [ -F buffer-lines-blocks-until-newline: channel should be empty after writing 'a'] + <span class="Constant">1</span>:address:channel<span class="Special"> <- </span>write <span class="Constant">1</span>:address:channel, <span class="Constant">97/a</span> + restart <span class="Constant">4</span>:number/buffer-routine + wait-for-routine <span class="Constant">4</span>:number/buffer-routine + <span class="Constant">6</span>:boolean<span class="Special"> <- </span>channel-empty? <span class="Constant">2</span>:address:channel/buffered-stdin + assert <span class="Constant">6</span>:boolean, [ +F buffer-lines-blocks-until-newline: channel should be empty <span class="muRecipe">after</span> writing 'a'] <span class="Comment"># write 'b'</span> - 1:address:channel<span class="Special"> <- </span><span class="Identifier">write</span> 1:address:channel, 98/b - restart 4:number/buffer-routine - wait-for-routine 4:number/buffer-routine - 7:boolean<span class="Special"> <- </span>channel-empty? 2:address:channel/buffered-stdin - <span class="Identifier">assert</span> 7:boolean, [ -F buffer-lines-blocks-until-newline: channel should be empty after writing 'b'] + <span class="Constant">1</span>:address:channel<span class="Special"> <- </span>write <span class="Constant">1</span>:address:channel, <span class="Constant">98/b</span> + restart <span class="Constant">4</span>:number/buffer-routine + wait-for-routine <span class="Constant">4</span>:number/buffer-routine + <span class="Constant">7</span>:boolean<span class="Special"> <- </span>channel-empty? <span class="Constant">2</span>:address:channel/buffered-stdin + assert <span class="Constant">7</span>:boolean, [ +F buffer-lines-blocks-until-newline: channel should be empty <span class="muRecipe">after</span> writing 'b'] <span class="Comment"># write newline</span> - 1:address:channel<span class="Special"> <- </span><span class="Identifier">write</span> 1:address:channel, 10/newline - restart 4:number/buffer-routine - wait-for-routine 4:number/buffer-routine - 8:boolean<span class="Special"> <- </span>channel-empty? 2:address:channel/buffered-stdin - 9:boolean/completed?<span class="Special"> <- </span>not 8:boolean - <span class="Identifier">assert</span> 9:boolean/completed?, [ -F buffer-lines-blocks-until-newline: channel should contain data after writing newline] - trace 1, [test], [reached end] + <span class="Constant">1</span>:address:channel<span class="Special"> <- </span>write <span class="Constant">1</span>:address:channel, <span class="Constant">10/newline</span> + restart <span class="Constant">4</span>:number/buffer-routine + wait-for-routine <span class="Constant">4</span>:number/buffer-routine + <span class="Constant">8</span>:boolean<span class="Special"> <- </span>channel-empty? <span class="Constant">2</span>:address:channel/buffered-stdin + <span class="Constant">9</span>:boolean/completed?<span class="Special"> <- </span>not <span class="Constant">8</span>:boolean + assert <span class="Constant">9</span>:boolean/completed?, [ +F buffer-lines-blocks-until-newline: channel should contain data <span class="muRecipe">after</span> writing newline] + trace <span class="Constant">1</span>, <span class="Constant">[test]</span>, <span class="Constant">[reached end]</span> ] trace-should-contain [ test: reached end diff --git a/html/062array.mu.html b/html/062array.mu.html index 350f8d6a..b65da102 100644 --- a/html/062array.mu.html +++ b/html/062array.mu.html @@ -13,10 +13,13 @@ 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; } -.Underlined { color: #c000c0; text-decoration: underline; } +.muScenario { color: #00af00; } +.muRecipe { color: #ff8700; } .Comment { color: #9090ff; } +.Constant { color: #00a0a0; } .Special { color: #ff6060; } -.Identifier { color: #804000; } +.Delimiter { color: #a04060; } +.muControl { color: #c0a020; } --> </style> @@ -28,45 +31,45 @@ body { font-family: monospace; color: #eeeeee; background-color: #080808; } </head> <body> <pre id='vimCodeElement'> -scenario <span class="Identifier">array</span>-from-<span class="Identifier">args</span> [ +<span class="muScenario">scenario</span> array-from-args [ run [ - 1:address:<span class="Identifier">array</span>:location<span class="Special"> <- </span><span class="Identifier">new</span>-<span class="Identifier">array</span> 0, 1, 2 - 2:<span class="Identifier">array</span>:location<span class="Special"> <- </span><span class="Identifier">copy</span> *1:address:<span class="Identifier">array</span>:location + <span class="Constant">1</span>:address:array:location<span class="Special"> <- </span>new-array <span class="Constant">0</span>, <span class="Constant">1</span>, <span class="Constant">2</span> + <span class="Constant">2</span>:array:location<span class="Special"> <- </span>copy *<span class="Constant">1</span>:address:array:location ] memory-should-contain [ - 2<span class="Special"> <- </span>3 <span class="Comment"># array length</span> - 3<span class="Special"> <- </span>0 - 4<span class="Special"> <- </span>1 - 5<span class="Special"> <- </span>2 + <span class="Constant">2</span><span class="Special"> <- </span><span class="Constant">3</span> <span class="Comment"># array length</span> + <span class="Constant">3</span><span class="Special"> <- </span><span class="Constant">0</span> + <span class="Constant">4</span><span class="Special"> <- </span><span class="Constant">1</span> + <span class="Constant">5</span><span class="Special"> <- </span><span class="Constant">2</span> ] ] <span class="Comment"># create an array out of a list of scalar args</span> -recipe <span class="Identifier">new</span>-<span class="Identifier">array</span> [ - <span class="Underlined">local</span>-scope - capacity:number<span class="Special"> <- </span><span class="Identifier">copy</span> 0 - { +<span class="muRecipe">recipe</span> new-array [ + <span class="Constant">local-scope</span> + capacity:number<span class="Special"> <- </span>copy <span class="Constant">0</span> + <span class="Delimiter">{</span> <span class="Comment"># while read curr-value</span> - curr-value:location, exists?:boolean<span class="Special"> <- </span>next-ingredient - break-unless exists? - capacity<span class="Special"> <- </span>add capacity, 1 - loop - } - result:address:<span class="Identifier">array</span>:location<span class="Special"> <- </span><span class="Identifier">new</span> location:<span class="Identifier">type</span>, capacity + curr-value:location, exists?:boolean<span class="Special"> <- </span><span class="Constant">next-ingredient</span> + <span class="muControl">break-unless</span> exists? + capacity<span class="Special"> <- </span>add capacity, <span class="Constant">1</span> + <span class="muControl">loop</span> + <span class="Delimiter">}</span> + result:address:array:location<span class="Special"> <- </span>new <span class="Constant">location:type</span>, capacity rewind-ingredients - i:number<span class="Special"> <- </span><span class="Identifier">copy</span> 0 - { + i:number<span class="Special"> <- </span>copy <span class="Constant">0</span> + <span class="Delimiter">{</span> <span class="Comment"># while read curr-value</span> done?:boolean<span class="Special"> <- </span>greater-or-equal i, capacity - break-if done? - curr-value:location, exists?:boolean<span class="Special"> <- </span>next-ingredient - <span class="Identifier">assert</span> exists?, [<span class="Identifier">error</span> <span class="Identifier">in</span> rewinding ingredients to <span class="Identifier">new</span>-<span class="Identifier">array</span>] + <span class="muControl">break-if</span> done? + curr-value:location, exists?:boolean<span class="Special"> <- </span><span class="Constant">next-ingredient</span> + assert exists?, <span class="Constant">[error in rewinding ingredients to new-array]</span> tmp:address:location<span class="Special"> <- </span>index-address *result, i - *tmp<span class="Special"> <- </span><span class="Identifier">copy</span> curr-value - i<span class="Special"> <- </span>add i, 1 - loop - } - reply result + *tmp<span class="Special"> <- </span>copy curr-value + i<span class="Special"> <- </span>add i, <span class="Constant">1</span> + <span class="muControl">loop</span> + <span class="Delimiter">}</span> + <span class="muControl">reply</span> result ] </pre> </body> diff --git a/html/063list.mu.html b/html/063list.mu.html index 320049a1..a4c4e02e 100644 --- a/html/063list.mu.html +++ b/html/063list.mu.html @@ -13,10 +13,13 @@ 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; } -.Special { color: #ff6060; } +.muRecipe { color: #ff8700; } +.muData { color: #ffff00; } +.muScenario { color: #00af00; } .Comment { color: #9090ff; } -.Underlined { color: #c000c0; text-decoration: underline; } -.Identifier { color: #804000; } +.Constant { color: #00a0a0; } +.Special { color: #ff6060; } +.muControl { color: #c0a020; } --> </style> @@ -29,62 +32,62 @@ body { font-family: monospace; color: #eeeeee; background-color: #080808; } <body> <pre id='vimCodeElement'> <span class="Comment"># A list links up multiple objects together to make them easier to manage.</span> -# +<span class="Comment">#</span> <span class="Comment"># Try to make all objects in a single list of the same type, it'll help avoid bugs.</span> <span class="Comment"># If you want to store multiple types in a single list, use an exclusive-container.</span> -container list [ +<span class="muData">container</span> list [ value:location next:address:list ] <span class="Comment"># result:address:list <- push x:location, in:address:list</span> -recipe push [ - <span class="Underlined">local</span>-scope - x:location<span class="Special"> <- </span>next-ingredient - <span class="Identifier">in</span>:address:list<span class="Special"> <- </span>next-ingredient - result:address:list<span class="Special"> <- </span><span class="Identifier">new</span> list:<span class="Identifier">type</span> - <span class="Identifier">val</span>:address:location<span class="Special"> <- </span>get-address *result, value:offset - *<span class="Identifier">val</span><span class="Special"> <- </span><span class="Identifier">copy</span> x - next:address:address:list<span class="Special"> <- </span>get-address *result, next:offset - *next<span class="Special"> <- </span><span class="Identifier">copy</span> <span class="Identifier">in</span> - reply result +<span class="muRecipe">recipe</span> push [ + <span class="Constant">local-scope</span> + x:location<span class="Special"> <- </span><span class="Constant">next-ingredient</span> + in:address:list<span class="Special"> <- </span><span class="Constant">next-ingredient</span> + result:address:list<span class="Special"> <- </span>new <span class="Constant">list:type</span> + val:address:location<span class="Special"> <- </span>get-address *result, <span class="Constant">value:offset</span> + *val<span class="Special"> <- </span>copy x + next:address:address:list<span class="Special"> <- </span>get-address *result, <span class="Constant">next:offset</span> + *next<span class="Special"> <- </span>copy in + <span class="muControl">reply</span> result ] <span class="Comment"># result:location <- first in:address:list</span> -recipe first [ - <span class="Underlined">local</span>-scope - <span class="Identifier">in</span>:address:list<span class="Special"> <- </span>next-ingredient - result:location<span class="Special"> <- </span>get *<span class="Identifier">in</span>, value:offset - reply result +<span class="muRecipe">recipe</span> first [ + <span class="Constant">local-scope</span> + in:address:list<span class="Special"> <- </span><span class="Constant">next-ingredient</span> + result:location<span class="Special"> <- </span>get *in, <span class="Constant">value:offset</span> + <span class="muControl">reply</span> result ] <span class="Comment"># result:address:list <- rest in:address:list</span> -recipe rest [ - <span class="Underlined">local</span>-scope - <span class="Identifier">in</span>:address:list<span class="Special"> <- </span>next-ingredient - result:address:list<span class="Special"> <- </span>get *<span class="Identifier">in</span>, next:offset - reply result +<span class="muRecipe">recipe</span> rest [ + <span class="Constant">local-scope</span> + in:address:list<span class="Special"> <- </span><span class="Constant">next-ingredient</span> + result:address:list<span class="Special"> <- </span>get *in, <span class="Constant">next:offset</span> + <span class="muControl">reply</span> result ] -scenario list-handling [ +<span class="muScenario">scenario</span> list-handling [ run [ - 1:address:list<span class="Special"> <- </span><span class="Identifier">copy</span> 0 - 1:address:list<span class="Special"> <- </span>push 3, 1:address:list - 1:address:list<span class="Special"> <- </span>push 4, 1:address:list - 1:address:list<span class="Special"> <- </span>push 5, 1:address:list - 2:number<span class="Special"> <- </span>first 1:address:list - 1:address:list<span class="Special"> <- </span>rest 1:address:list - 3:number<span class="Special"> <- </span>first 1:address:list - 1:address:list<span class="Special"> <- </span>rest 1:address:list - 4:number<span class="Special"> <- </span>first 1:address:list - 1:address:list<span class="Special"> <- </span>rest 1:address:list + <span class="Constant">1</span>:address:list<span class="Special"> <- </span>copy <span class="Constant">0</span> + <span class="Constant">1</span>:address:list<span class="Special"> <- </span>push <span class="Constant">3</span>, <span class="Constant">1</span>:address:list + <span class="Constant">1</span>:address:list<span class="Special"> <- </span>push <span class="Constant">4</span>, <span class="Constant">1</span>:address:list + <span class="Constant">1</span>:address:list<span class="Special"> <- </span>push <span class="Constant">5</span>, <span class="Constant">1</span>:address:list + <span class="Constant">2</span>:number<span class="Special"> <- </span>first <span class="Constant">1</span>:address:list + <span class="Constant">1</span>:address:list<span class="Special"> <- </span>rest <span class="Constant">1</span>:address:list + <span class="Constant">3</span>:number<span class="Special"> <- </span>first <span class="Constant">1</span>:address:list + <span class="Constant">1</span>:address:list<span class="Special"> <- </span>rest <span class="Constant">1</span>:address:list + <span class="Constant">4</span>:number<span class="Special"> <- </span>first <span class="Constant">1</span>:address:list + <span class="Constant">1</span>:address:list<span class="Special"> <- </span>rest <span class="Constant">1</span>:address:list ] memory-should-contain [ - 1<span class="Special"> <- </span>0 <span class="Comment"># empty to empty, dust to dust..</span> - 2<span class="Special"> <- </span>5 - 3<span class="Special"> <- </span>4 - 4<span class="Special"> <- </span>3 + <span class="Constant">1</span><span class="Special"> <- </span><span class="Constant">0</span> <span class="Comment"># empty to empty, dust to dust..</span> + <span class="Constant">2</span><span class="Special"> <- </span><span class="Constant">5</span> + <span class="Constant">3</span><span class="Special"> <- </span><span class="Constant">4</span> + <span class="Constant">4</span><span class="Special"> <- </span><span class="Constant">3</span> ] ] </pre> diff --git a/html/065duplex_list.mu.html b/html/065duplex_list.mu.html index a0744bef..bf7634a0 100644 --- a/html/065duplex_list.mu.html +++ b/html/065duplex_list.mu.html @@ -13,10 +13,14 @@ 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; } -.Special { color: #ff6060; } +.muRecipe { color: #ff8700; } +.muData { color: #ffff00; } +.muScenario { color: #00af00; } .Comment { color: #9090ff; } -.Underlined { color: #c000c0; text-decoration: underline; } -.Identifier { color: #804000; } +.Constant { color: #00a0a0; } +.Special { color: #ff6060; } +.Delimiter { color: #a04060; } +.muControl { color: #c0a020; } --> </style> @@ -30,370 +34,370 @@ body { font-family: monospace; color: #eeeeee; background-color: #080808; } <pre id='vimCodeElement'> <span class="Comment"># A doubly linked list permits bidirectional traversal.</span> -container duplex-list [ +<span class="muData">container</span> duplex-list [ value:location next:address:duplex-list prev:address:duplex-list ] <span class="Comment"># result:address:duplex-list <- push-duplex x:location, in:address:duplex-list</span> -recipe push-duplex [ - <span class="Underlined">local</span>-scope - x:location<span class="Special"> <- </span>next-ingredient - <span class="Identifier">in</span>:address:duplex-list<span class="Special"> <- </span>next-ingredient - result:address:duplex-list<span class="Special"> <- </span><span class="Identifier">new</span> duplex-list:<span class="Identifier">type</span> - <span class="Identifier">val</span>:address:location<span class="Special"> <- </span>get-address *result, value:offset - *<span class="Identifier">val</span><span class="Special"> <- </span><span class="Identifier">copy</span> x - next:address:address:duplex-list<span class="Special"> <- </span>get-address *result, next:offset - *next<span class="Special"> <- </span><span class="Identifier">copy</span> <span class="Identifier">in</span> - reply-unless <span class="Identifier">in</span>, result - prev:address:address:duplex-list<span class="Special"> <- </span>get-address *<span class="Identifier">in</span>, prev:offset - *prev<span class="Special"> <- </span><span class="Identifier">copy</span> result - reply result +<span class="muRecipe">recipe</span> push-duplex [ + <span class="Constant">local-scope</span> + x:location<span class="Special"> <- </span><span class="Constant">next-ingredient</span> + in:address:duplex-list<span class="Special"> <- </span><span class="Constant">next-ingredient</span> + result:address:duplex-list<span class="Special"> <- </span>new <span class="Constant">duplex-list:type</span> + val:address:location<span class="Special"> <- </span>get-address *result, <span class="Constant">value:offset</span> + *val<span class="Special"> <- </span>copy x + next:address:address:duplex-list<span class="Special"> <- </span>get-address *result, <span class="Constant">next:offset</span> + *next<span class="Special"> <- </span>copy in + <span class="muControl">reply-unless</span> in, result + prev:address:address:duplex-list<span class="Special"> <- </span>get-address *in, <span class="Constant">prev:offset</span> + *prev<span class="Special"> <- </span>copy result + <span class="muControl">reply</span> result ] <span class="Comment"># result:location <- first-duplex in:address:duplex-list</span> -recipe first-duplex [ - <span class="Underlined">local</span>-scope - <span class="Identifier">in</span>:address:duplex-list<span class="Special"> <- </span>next-ingredient - reply-unless <span class="Identifier">in</span>, 0 - result:location<span class="Special"> <- </span>get *<span class="Identifier">in</span>, value:offset - reply result +<span class="muRecipe">recipe</span> first-duplex [ + <span class="Constant">local-scope</span> + in:address:duplex-list<span class="Special"> <- </span><span class="Constant">next-ingredient</span> + <span class="muControl">reply-unless</span> in, <span class="Constant">0</span> + result:location<span class="Special"> <- </span>get *in, <span class="Constant">value:offset</span> + <span class="muControl">reply</span> result ] <span class="Comment"># result:address:duplex-list <- next-duplex in:address:duplex-list</span> -recipe next-duplex [ - <span class="Underlined">local</span>-scope - <span class="Identifier">in</span>:address:duplex-list<span class="Special"> <- </span>next-ingredient - reply-unless <span class="Identifier">in</span>, 0 - result:address:duplex-list<span class="Special"> <- </span>get *<span class="Identifier">in</span>, next:offset - reply result +<span class="muRecipe">recipe</span> next-duplex [ + <span class="Constant">local-scope</span> + in:address:duplex-list<span class="Special"> <- </span><span class="Constant">next-ingredient</span> + <span class="muControl">reply-unless</span> in, <span class="Constant">0</span> + result:address:duplex-list<span class="Special"> <- </span>get *in, <span class="Constant">next:offset</span> + <span class="muControl">reply</span> result ] <span class="Comment"># result:address:duplex-list <- prev-duplex in:address:duplex-list</span> -recipe prev-duplex [ - <span class="Underlined">local</span>-scope - <span class="Identifier">in</span>:address:duplex-list<span class="Special"> <- </span>next-ingredient - reply-unless <span class="Identifier">in</span>, 0 - result:address:duplex-list<span class="Special"> <- </span>get *<span class="Identifier">in</span>, prev:offset - reply result +<span class="muRecipe">recipe</span> prev-duplex [ + <span class="Constant">local-scope</span> + in:address:duplex-list<span class="Special"> <- </span><span class="Constant">next-ingredient</span> + <span class="muControl">reply-unless</span> in, <span class="Constant">0</span> + result:address:duplex-list<span class="Special"> <- </span>get *in, <span class="Constant">prev:offset</span> + <span class="muControl">reply</span> result ] -scenario duplex-list-handling [ +<span class="muScenario">scenario</span> duplex-list-handling [ run [ <span class="Comment"># reserve locations 0, 1 and 2 to check for missing null check</span> - 1:number<span class="Special"> <- </span><span class="Identifier">copy</span> 34 - 2:number<span class="Special"> <- </span><span class="Identifier">copy</span> 35 - 3:address:duplex-list<span class="Special"> <- </span><span class="Identifier">copy</span> 0 - 3:address:duplex-list<span class="Special"> <- </span>push-duplex 3, 3:address:duplex-list - 3:address:duplex-list<span class="Special"> <- </span>push-duplex 4, 3:address:duplex-list - 3:address:duplex-list<span class="Special"> <- </span>push-duplex 5, 3:address:duplex-list - 4:address:duplex-list<span class="Special"> <- </span><span class="Identifier">copy</span> 3:address:duplex-list - 5:number<span class="Special"> <- </span>first-duplex 4:address:duplex-list - 4:address:duplex-list<span class="Special"> <- </span>next-duplex 4:address:duplex-list - 6:number<span class="Special"> <- </span>first-duplex 4:address:duplex-list - 4:address:duplex-list<span class="Special"> <- </span>next-duplex 4:address:duplex-list - 7:number<span class="Special"> <- </span>first-duplex 4:address:duplex-list - 8:address:duplex-list<span class="Special"> <- </span>next-duplex 4:address:duplex-list - 9:number<span class="Special"> <- </span>first-duplex 8:address:duplex-list - 10:address:duplex-list<span class="Special"> <- </span>next-duplex 8:address:duplex-list - 11:address:duplex-list<span class="Special"> <- </span>prev-duplex 8:address:duplex-list - 4:address:duplex-list<span class="Special"> <- </span>prev-duplex 4:address:duplex-list - 12:number<span class="Special"> <- </span>first-duplex 4:address:duplex-list - 4:address:duplex-list<span class="Special"> <- </span>prev-duplex 4:address:duplex-list - 13:number<span class="Special"> <- </span>first-duplex 4:address:duplex-list - 14:boolean<span class="Special"> <- </span>equal 3:address:duplex-list, 4:address:duplex-list + <span class="Constant">1</span>:number<span class="Special"> <- </span>copy <span class="Constant">34</span> + <span class="Constant">2</span>:number<span class="Special"> <- </span>copy <span class="Constant">35</span> + <span class="Constant">3</span>:address:duplex-list<span class="Special"> <- </span>copy <span class="Constant">0</span> + <span class="Constant">3</span>:address:duplex-list<span class="Special"> <- </span>push-duplex <span class="Constant">3</span>, <span class="Constant">3</span>:address:duplex-list + <span class="Constant">3</span>:address:duplex-list<span class="Special"> <- </span>push-duplex <span class="Constant">4</span>, <span class="Constant">3</span>:address:duplex-list + <span class="Constant">3</span>:address:duplex-list<span class="Special"> <- </span>push-duplex <span class="Constant">5</span>, <span class="Constant">3</span>:address:duplex-list + <span class="Constant">4</span>:address:duplex-list<span class="Special"> <- </span>copy <span class="Constant">3</span>:address:duplex-list + <span class="Constant">5</span>:number<span class="Special"> <- </span>first-duplex <span class="Constant">4</span>:address:duplex-list + <span class="Constant">4</span>:address:duplex-list<span class="Special"> <- </span>next-duplex <span class="Constant">4</span>:address:duplex-list + <span class="Constant">6</span>:number<span class="Special"> <- </span>first-duplex <span class="Constant">4</span>:address:duplex-list + <span class="Constant">4</span>:address:duplex-list<span class="Special"> <- </span>next-duplex <span class="Constant">4</span>:address:duplex-list + <span class="Constant">7</span>:number<span class="Special"> <- </span>first-duplex <span class="Constant">4</span>:address:duplex-list + <span class="Constant">8</span>:address:duplex-list<span class="Special"> <- </span>next-duplex <span class="Constant">4</span>:address:duplex-list + <span class="Constant">9</span>:number<span class="Special"> <- </span>first-duplex <span class="Constant">8</span>:address:duplex-list + <span class="Constant">10</span>:address:duplex-list<span class="Special"> <- </span>next-duplex <span class="Constant">8</span>:address:duplex-list + <span class="Constant">11</span>:address:duplex-list<span class="Special"> <- </span>prev-duplex <span class="Constant">8</span>:address:duplex-list + <span class="Constant">4</span>:address:duplex-list<span class="Special"> <- </span>prev-duplex <span class="Constant">4</span>:address:duplex-list + <span class="Constant">12</span>:number<span class="Special"> <- </span>first-duplex <span class="Constant">4</span>:address:duplex-list + <span class="Constant">4</span>:address:duplex-list<span class="Special"> <- </span>prev-duplex <span class="Constant">4</span>:address:duplex-list + <span class="Constant">13</span>:number<span class="Special"> <- </span>first-duplex <span class="Constant">4</span>:address:duplex-list + <span class="Constant">14</span>:boolean<span class="Special"> <- </span>equal <span class="Constant">3</span>:address:duplex-list, <span class="Constant">4</span>:address:duplex-list ] memory-should-contain [ - 0<span class="Special"> <- </span>0 <span class="Comment"># no modifications to null pointers</span> - 1<span class="Special"> <- </span>34 - 2<span class="Special"> <- </span>35 - 5<span class="Special"> <- </span>5 <span class="Comment"># scanning next</span> - 6<span class="Special"> <- </span>4 - 7<span class="Special"> <- </span>3 - 8<span class="Special"> <- </span>0 <span class="Comment"># null</span> - 9<span class="Special"> <- </span>0 <span class="Comment"># first of null</span> - 10<span class="Special"> <- </span>0 <span class="Comment"># next of null</span> - 11<span class="Special"> <- </span>0 <span class="Comment"># prev of null</span> - 12<span class="Special"> <- </span>4 <span class="Comment"># then start scanning prev</span> - 13<span class="Special"> <- </span>5 - 14<span class="Special"> <- </span>1 <span class="Comment"># list back at start</span> + <span class="Constant">0</span><span class="Special"> <- </span><span class="Constant">0</span> <span class="Comment"># no modifications to null pointers</span> + <span class="Constant">1</span><span class="Special"> <- </span><span class="Constant">34</span> + <span class="Constant">2</span><span class="Special"> <- </span><span class="Constant">35</span> + <span class="Constant">5</span><span class="Special"> <- </span><span class="Constant">5</span> <span class="Comment"># scanning next</span> + <span class="Constant">6</span><span class="Special"> <- </span><span class="Constant">4</span> + <span class="Constant">7</span><span class="Special"> <- </span><span class="Constant">3</span> + <span class="Constant">8</span><span class="Special"> <- </span><span class="Constant">0</span> <span class="Comment"># null</span> + <span class="Constant">9</span><span class="Special"> <- </span><span class="Constant">0</span> <span class="Comment"># first of null</span> + <span class="Constant">10</span><span class="Special"> <- </span><span class="Constant">0</span> <span class="Comment"># next of null</span> + <span class="Constant">11</span><span class="Special"> <- </span><span class="Constant">0</span> <span class="Comment"># prev of null</span> + <span class="Constant">12</span><span class="Special"> <- </span><span class="Constant">4</span> <span class="Comment"># then start scanning prev</span> + <span class="Constant">13</span><span class="Special"> <- </span><span class="Constant">5</span> + <span class="Constant">14</span><span class="Special"> <- </span><span class="Constant">1</span> <span class="Comment"># list back at start</span> ] ] <span class="Comment"># l:address:duplex-list <- insert-duplex x:location, in:address:duplex-list</span> <span class="Comment"># Inserts 'x' after 'in'. Returns some pointer into the list.</span> -recipe insert-duplex [ - <span class="Underlined">local</span>-scope - x:location<span class="Special"> <- </span>next-ingredient - <span class="Identifier">in</span>:address:duplex-list<span class="Special"> <- </span>next-ingredient - <span class="Identifier">new</span>-node:address:duplex-list<span class="Special"> <- </span><span class="Identifier">new</span> duplex-list:<span class="Identifier">type</span> - <span class="Identifier">val</span>:address:location<span class="Special"> <- </span>get-address *<span class="Identifier">new</span>-node, value:offset - *<span class="Identifier">val</span><span class="Special"> <- </span><span class="Identifier">copy</span> x - next-node:address:duplex-list<span class="Special"> <- </span>get *<span class="Identifier">in</span>, next:offset +<span class="muRecipe">recipe</span> insert-duplex [ + <span class="Constant">local-scope</span> + x:location<span class="Special"> <- </span><span class="Constant">next-ingredient</span> + in:address:duplex-list<span class="Special"> <- </span><span class="Constant">next-ingredient</span> + new-node:address:duplex-list<span class="Special"> <- </span>new <span class="Constant">duplex-list:type</span> + val:address:location<span class="Special"> <- </span>get-address *new-node, <span class="Constant">value:offset</span> + *val<span class="Special"> <- </span>copy x + next-node:address:duplex-list<span class="Special"> <- </span>get *in, <span class="Constant">next:offset</span> <span class="Comment"># in.next = new-node</span> - y:address:address:duplex-list<span class="Special"> <- </span>get-address *<span class="Identifier">in</span>, next:offset - *y<span class="Special"> <- </span><span class="Identifier">copy</span> <span class="Identifier">new</span>-node + y:address:address:duplex-list<span class="Special"> <- </span>get-address *in, <span class="Constant">next:offset</span> + *y<span class="Special"> <- </span>copy new-node <span class="Comment"># new-node.prev = in</span> - y<span class="Special"> <- </span>get-address *<span class="Identifier">new</span>-node, prev:offset - *y<span class="Special"> <- </span><span class="Identifier">copy</span> <span class="Identifier">in</span> + y<span class="Special"> <- </span>get-address *new-node, <span class="Constant">prev:offset</span> + *y<span class="Special"> <- </span>copy in <span class="Comment"># new-node.next = next-node</span> - y<span class="Special"> <- </span>get-address *<span class="Identifier">new</span>-node, next:offset - *y<span class="Special"> <- </span><span class="Identifier">copy</span> next-node + y<span class="Special"> <- </span>get-address *new-node, <span class="Constant">next:offset</span> + *y<span class="Special"> <- </span>copy next-node <span class="Comment"># if next-node is not null</span> - reply-unless next-node, <span class="Identifier">new</span>-node + <span class="muControl">reply-unless</span> next-node, new-node <span class="Comment"># next-node.prev = new-node</span> - y<span class="Special"> <- </span>get-address *next-node, prev:offset - *y<span class="Special"> <- </span><span class="Identifier">copy</span> <span class="Identifier">new</span>-node - reply <span class="Identifier">new</span>-node <span class="Comment"># just signalling something changed; don't rely on the result</span> + y<span class="Special"> <- </span>get-address *next-node, <span class="Constant">prev:offset</span> + *y<span class="Special"> <- </span>copy new-node + <span class="muControl">reply</span> new-node <span class="Comment"># just signalling something changed; don't rely on the result</span> ] -scenario inserting-into-duplex-list [ +<span class="muScenario">scenario</span> inserting-into-duplex-list [ run [ - 1:address:duplex-list<span class="Special"> <- </span><span class="Identifier">copy</span> 0 <span class="Comment"># 1 points to head of list</span> - 1:address:duplex-list<span class="Special"> <- </span>push-duplex 3, 1:address:duplex-list - 1:address:duplex-list<span class="Special"> <- </span>push-duplex 4, 1:address:duplex-list - 1:address:duplex-list<span class="Special"> <- </span>push-duplex 5, 1:address:duplex-list - 2:address:duplex-list<span class="Special"> <- </span>next-duplex 1:address:duplex-list <span class="Comment"># 2 points inside list</span> - 2:address:duplex-list<span class="Special"> <- </span>insert-duplex 6, 2:address:duplex-list + <span class="Constant">1</span>:address:duplex-list<span class="Special"> <- </span>copy <span class="Constant">0</span> <span class="Comment"># 1 points to head of list</span> + <span class="Constant">1</span>:address:duplex-list<span class="Special"> <- </span>push-duplex <span class="Constant">3</span>, <span class="Constant">1</span>:address:duplex-list + <span class="Constant">1</span>:address:duplex-list<span class="Special"> <- </span>push-duplex <span class="Constant">4</span>, <span class="Constant">1</span>:address:duplex-list + <span class="Constant">1</span>:address:duplex-list<span class="Special"> <- </span>push-duplex <span class="Constant">5</span>, <span class="Constant">1</span>:address:duplex-list + <span class="Constant">2</span>:address:duplex-list<span class="Special"> <- </span>next-duplex <span class="Constant">1</span>:address:duplex-list <span class="Comment"># 2 points inside list</span> + <span class="Constant">2</span>:address:duplex-list<span class="Special"> <- </span>insert-duplex <span class="Constant">6</span>, <span class="Constant">2</span>:address:duplex-list <span class="Comment"># check structure like before</span> - 2:address:duplex-list<span class="Special"> <- </span><span class="Identifier">copy</span> 1:address:duplex-list - 3:number<span class="Special"> <- </span>first-duplex 2:address:duplex-list - 2:address:duplex-list<span class="Special"> <- </span>next-duplex 2:address:duplex-list - 4:number<span class="Special"> <- </span>first-duplex 2:address:duplex-list - 2:address:duplex-list<span class="Special"> <- </span>next-duplex 2:address:duplex-list - 5:number<span class="Special"> <- </span>first-duplex 2:address:duplex-list - 2:address:duplex-list<span class="Special"> <- </span>next-duplex 2:address:duplex-list - 6:number<span class="Special"> <- </span>first-duplex 2:address:duplex-list - 2:address:duplex-list<span class="Special"> <- </span>prev-duplex 2:address:duplex-list - 7:number<span class="Special"> <- </span>first-duplex 2:address:duplex-list - 2:address:duplex-list<span class="Special"> <- </span>prev-duplex 2:address:duplex-list - 8:number<span class="Special"> <- </span>first-duplex 2:address:duplex-list - 2:address:duplex-list<span class="Special"> <- </span>prev-duplex 2:address:duplex-list - 9:number<span class="Special"> <- </span>first-duplex 2:address:duplex-list - 10:boolean<span class="Special"> <- </span>equal 1:address:duplex-list, 2:address:duplex-list + <span class="Constant">2</span>:address:duplex-list<span class="Special"> <- </span>copy <span class="Constant">1</span>:address:duplex-list + <span class="Constant">3</span>:number<span class="Special"> <- </span>first-duplex <span class="Constant">2</span>:address:duplex-list + <span class="Constant">2</span>:address:duplex-list<span class="Special"> <- </span>next-duplex <span class="Constant">2</span>:address:duplex-list + <span class="Constant">4</span>:number<span class="Special"> <- </span>first-duplex <span class="Constant">2</span>:address:duplex-list + <span class="Constant">2</span>:address:duplex-list<span class="Special"> <- </span>next-duplex <span class="Constant">2</span>:address:duplex-list + <span class="Constant">5</span>:number<span class="Special"> <- </span>first-duplex <span class="Constant">2</span>:address:duplex-list + <span class="Constant">2</span>:address:duplex-list<span class="Special"> <- </span>next-duplex <span class="Constant">2</span>:address:duplex-list + <span class="Constant">6</span>:number<span class="Special"> <- </span>first-duplex <span class="Constant">2</span>:address:duplex-list + <span class="Constant">2</span>:address:duplex-list<span class="Special"> <- </span>prev-duplex <span class="Constant">2</span>:address:duplex-list + <span class="Constant">7</span>:number<span class="Special"> <- </span>first-duplex <span class="Constant">2</span>:address:duplex-list + <span class="Constant">2</span>:address:duplex-list<span class="Special"> <- </span>prev-duplex <span class="Constant">2</span>:address:duplex-list + <span class="Constant">8</span>:number<span class="Special"> <- </span>first-duplex <span class="Constant">2</span>:address:duplex-list + <span class="Constant">2</span>:address:duplex-list<span class="Special"> <- </span>prev-duplex <span class="Constant">2</span>:address:duplex-list + <span class="Constant">9</span>:number<span class="Special"> <- </span>first-duplex <span class="Constant">2</span>:address:duplex-list + <span class="Constant">10</span>:boolean<span class="Special"> <- </span>equal <span class="Constant">1</span>:address:duplex-list, <span class="Constant">2</span>:address:duplex-list ] memory-should-contain [ - 3<span class="Special"> <- </span>5 <span class="Comment"># scanning next</span> - 4<span class="Special"> <- </span>4 - 5<span class="Special"> <- </span>6 <span class="Comment"># inserted element</span> - 6<span class="Special"> <- </span>3 - 7<span class="Special"> <- </span>6 <span class="Comment"># then prev</span> - 8<span class="Special"> <- </span>4 - 9<span class="Special"> <- </span>5 - 10<span class="Special"> <- </span>1 <span class="Comment"># list back at start</span> + <span class="Constant">3</span><span class="Special"> <- </span><span class="Constant">5</span> <span class="Comment"># scanning next</span> + <span class="Constant">4</span><span class="Special"> <- </span><span class="Constant">4</span> + <span class="Constant">5</span><span class="Special"> <- </span><span class="Constant">6</span> <span class="Comment"># inserted element</span> + <span class="Constant">6</span><span class="Special"> <- </span><span class="Constant">3</span> + <span class="Constant">7</span><span class="Special"> <- </span><span class="Constant">6</span> <span class="Comment"># then prev</span> + <span class="Constant">8</span><span class="Special"> <- </span><span class="Constant">4</span> + <span class="Constant">9</span><span class="Special"> <- </span><span class="Constant">5</span> + <span class="Constant">10</span><span class="Special"> <- </span><span class="Constant">1</span> <span class="Comment"># list back at start</span> ] ] -scenario inserting-at-end-of-duplex-list [ +<span class="muScenario">scenario</span> inserting-at-end-of-duplex-list [ run [ - 1:address:duplex-list<span class="Special"> <- </span><span class="Identifier">copy</span> 0 <span class="Comment"># 1 points to head of list</span> - 1:address:duplex-list<span class="Special"> <- </span>push-duplex 3, 1:address:duplex-list - 1:address:duplex-list<span class="Special"> <- </span>push-duplex 4, 1:address:duplex-list - 1:address:duplex-list<span class="Special"> <- </span>push-duplex 5, 1:address:duplex-list - 2:address:duplex-list<span class="Special"> <- </span>next-duplex 1:address:duplex-list <span class="Comment"># 2 points inside list</span> - 2:address:duplex-list<span class="Special"> <- </span>next-duplex 2:address:duplex-list <span class="Comment"># now at end of list</span> - 2:address:duplex-list<span class="Special"> <- </span>insert-duplex 6, 2:address:duplex-list + <span class="Constant">1</span>:address:duplex-list<span class="Special"> <- </span>copy <span class="Constant">0</span> <span class="Comment"># 1 points to head of list</span> + <span class="Constant">1</span>:address:duplex-list<span class="Special"> <- </span>push-duplex <span class="Constant">3</span>, <span class="Constant">1</span>:address:duplex-list + <span class="Constant">1</span>:address:duplex-list<span class="Special"> <- </span>push-duplex <span class="Constant">4</span>, <span class="Constant">1</span>:address:duplex-list + <span class="Constant">1</span>:address:duplex-list<span class="Special"> <- </span>push-duplex <span class="Constant">5</span>, <span class="Constant">1</span>:address:duplex-list + <span class="Constant">2</span>:address:duplex-list<span class="Special"> <- </span>next-duplex <span class="Constant">1</span>:address:duplex-list <span class="Comment"># 2 points inside list</span> + <span class="Constant">2</span>:address:duplex-list<span class="Special"> <- </span>next-duplex <span class="Constant">2</span>:address:duplex-list <span class="Comment"># now at end of list</span> + <span class="Constant">2</span>:address:duplex-list<span class="Special"> <- </span>insert-duplex <span class="Constant">6</span>, <span class="Constant">2</span>:address:duplex-list <span class="Comment"># check structure like before</span> - 2:address:duplex-list<span class="Special"> <- </span><span class="Identifier">copy</span> 1:address:duplex-list - 3:number<span class="Special"> <- </span>first-duplex 2:address:duplex-list - 2:address:duplex-list<span class="Special"> <- </span>next-duplex 2:address:duplex-list - 4:number<span class="Special"> <- </span>first-duplex 2:address:duplex-list - 2:address:duplex-list<span class="Special"> <- </span>next-duplex 2:address:duplex-list - 5:number<span class="Special"> <- </span>first-duplex 2:address:duplex-list - 2:address:duplex-list<span class="Special"> <- </span>next-duplex 2:address:duplex-list - 6:number<span class="Special"> <- </span>first-duplex 2:address:duplex-list - 2:address:duplex-list<span class="Special"> <- </span>prev-duplex 2:address:duplex-list - 7:number<span class="Special"> <- </span>first-duplex 2:address:duplex-list - 2:address:duplex-list<span class="Special"> <- </span>prev-duplex 2:address:duplex-list - 8:number<span class="Special"> <- </span>first-duplex 2:address:duplex-list - 2:address:duplex-list<span class="Special"> <- </span>prev-duplex 2:address:duplex-list - 9:number<span class="Special"> <- </span>first-duplex 2:address:duplex-list - 10:boolean<span class="Special"> <- </span>equal 1:address:duplex-list, 2:address:duplex-list + <span class="Constant">2</span>:address:duplex-list<span class="Special"> <- </span>copy <span class="Constant">1</span>:address:duplex-list + <span class="Constant">3</span>:number<span class="Special"> <- </span>first-duplex <span class="Constant">2</span>:address:duplex-list + <span class="Constant">2</span>:address:duplex-list<span class="Special"> <- </span>next-duplex <span class="Constant">2</span>:address:duplex-list + <span class="Constant">4</span>:number<span class="Special"> <- </span>first-duplex <span class="Constant">2</span>:address:duplex-list + <span class="Constant">2</span>:address:duplex-list<span class="Special"> <- </span>next-duplex <span class="Constant">2</span>:address:duplex-list + <span class="Constant">5</span>:number<span class="Special"> <- </span>first-duplex <span class="Constant">2</span>:address:duplex-list + <span class="Constant">2</span>:address:duplex-list<span class="Special"> <- </span>next-duplex <span class="Constant">2</span>:address:duplex-list + <span class="Constant">6</span>:number<span class="Special"> <- </span>first-duplex <span class="Constant">2</span>:address:duplex-list + <span class="Constant">2</span>:address:duplex-list<span class="Special"> <- </span>prev-duplex <span class="Constant">2</span>:address:duplex-list + <span class="Constant">7</span>:number<span class="Special"> <- </span>first-duplex <span class="Constant">2</span>:address:duplex-list + <span class="Constant">2</span>:address:duplex-list<span class="Special"> <- </span>prev-duplex <span class="Constant">2</span>:address:duplex-list + <span class="Constant">8</span>:number<span class="Special"> <- </span>first-duplex <span class="Constant">2</span>:address:duplex-list + <span class="Constant">2</span>:address:duplex-list<span class="Special"> <- </span>prev-duplex <span class="Constant">2</span>:address:duplex-list + <span class="Constant">9</span>:number<span class="Special"> <- </span>first-duplex <span class="Constant">2</span>:address:duplex-list + <span class="Constant">10</span>:boolean<span class="Special"> <- </span>equal <span class="Constant">1</span>:address:duplex-list, <span class="Constant">2</span>:address:duplex-list ] memory-should-contain [ - 3<span class="Special"> <- </span>5 <span class="Comment"># scanning next</span> - 4<span class="Special"> <- </span>4 - 5<span class="Special"> <- </span>3 - 6<span class="Special"> <- </span>6 <span class="Comment"># inserted element</span> - 7<span class="Special"> <- </span>3 <span class="Comment"># then prev</span> - 8<span class="Special"> <- </span>4 - 9<span class="Special"> <- </span>5 - 10<span class="Special"> <- </span>1 <span class="Comment"># list back at start</span> + <span class="Constant">3</span><span class="Special"> <- </span><span class="Constant">5</span> <span class="Comment"># scanning next</span> + <span class="Constant">4</span><span class="Special"> <- </span><span class="Constant">4</span> + <span class="Constant">5</span><span class="Special"> <- </span><span class="Constant">3</span> + <span class="Constant">6</span><span class="Special"> <- </span><span class="Constant">6</span> <span class="Comment"># inserted element</span> + <span class="Constant">7</span><span class="Special"> <- </span><span class="Constant">3</span> <span class="Comment"># then prev</span> + <span class="Constant">8</span><span class="Special"> <- </span><span class="Constant">4</span> + <span class="Constant">9</span><span class="Special"> <- </span><span class="Constant">5</span> + <span class="Constant">10</span><span class="Special"> <- </span><span class="Constant">1</span> <span class="Comment"># list back at start</span> ] ] -scenario inserting-after-start-of-duplex-list [ +<span class="muScenario">scenario</span> inserting-after-start-of-duplex-list [ run [ - 1:address:duplex-list<span class="Special"> <- </span><span class="Identifier">copy</span> 0 <span class="Comment"># 1 points to head of list</span> - 1:address:duplex-list<span class="Special"> <- </span>push-duplex 3, 1:address:duplex-list - 1:address:duplex-list<span class="Special"> <- </span>push-duplex 4, 1:address:duplex-list - 1:address:duplex-list<span class="Special"> <- </span>push-duplex 5, 1:address:duplex-list - 2:address:duplex-list<span class="Special"> <- </span>insert-duplex 6, 1:address:duplex-list + <span class="Constant">1</span>:address:duplex-list<span class="Special"> <- </span>copy <span class="Constant">0</span> <span class="Comment"># 1 points to head of list</span> + <span class="Constant">1</span>:address:duplex-list<span class="Special"> <- </span>push-duplex <span class="Constant">3</span>, <span class="Constant">1</span>:address:duplex-list + <span class="Constant">1</span>:address:duplex-list<span class="Special"> <- </span>push-duplex <span class="Constant">4</span>, <span class="Constant">1</span>:address:duplex-list + <span class="Constant">1</span>:address:duplex-list<span class="Special"> <- </span>push-duplex <span class="Constant">5</span>, <span class="Constant">1</span>:address:duplex-list + <span class="Constant">2</span>:address:duplex-list<span class="Special"> <- </span>insert-duplex <span class="Constant">6</span>, <span class="Constant">1</span>:address:duplex-list <span class="Comment"># check structure like before</span> - 2:address:duplex-list<span class="Special"> <- </span><span class="Identifier">copy</span> 1:address:duplex-list - 3:number<span class="Special"> <- </span>first-duplex 2:address:duplex-list - 2:address:duplex-list<span class="Special"> <- </span>next-duplex 2:address:duplex-list - 4:number<span class="Special"> <- </span>first-duplex 2:address:duplex-list - 2:address:duplex-list<span class="Special"> <- </span>next-duplex 2:address:duplex-list - 5:number<span class="Special"> <- </span>first-duplex 2:address:duplex-list - 2:address:duplex-list<span class="Special"> <- </span>next-duplex 2:address:duplex-list - 6:number<span class="Special"> <- </span>first-duplex 2:address:duplex-list - 2:address:duplex-list<span class="Special"> <- </span>prev-duplex 2:address:duplex-list - 7:number<span class="Special"> <- </span>first-duplex 2:address:duplex-list - 2:address:duplex-list<span class="Special"> <- </span>prev-duplex 2:address:duplex-list - 8:number<span class="Special"> <- </span>first-duplex 2:address:duplex-list - 2:address:duplex-list<span class="Special"> <- </span>prev-duplex 2:address:duplex-list - 9:number<span class="Special"> <- </span>first-duplex 2:address:duplex-list - 10:boolean<span class="Special"> <- </span>equal 1:address:duplex-list, 2:address:duplex-list + <span class="Constant">2</span>:address:duplex-list<span class="Special"> <- </span>copy <span class="Constant">1</span>:address:duplex-list + <span class="Constant">3</span>:number<span class="Special"> <- </span>first-duplex <span class="Constant">2</span>:address:duplex-list + <span class="Constant">2</span>:address:duplex-list<span class="Special"> <- </span>next-duplex <span class="Constant">2</span>:address:duplex-list + <span class="Constant">4</span>:number<span class="Special"> <- </span>first-duplex <span class="Constant">2</span>:address:duplex-list + <span class="Constant">2</span>:address:duplex-list<span class="Special"> <- </span>next-duplex <span class="Constant">2</span>:address:duplex-list + <span class="Constant">5</span>:number<span class="Special"> <- </span>first-duplex <span class="Constant">2</span>:address:duplex-list + <span class="Constant">2</span>:address:duplex-list<span class="Special"> <- </span>next-duplex <span class="Constant">2</span>:address:duplex-list + <span class="Constant">6</span>:number<span class="Special"> <- </span>first-duplex <span class="Constant">2</span>:address:duplex-list + <span class="Constant">2</span>:address:duplex-list<span class="Special"> <- </span>prev-duplex <span class="Constant">2</span>:address:duplex-list + <span class="Constant">7</span>:number<span class="Special"> <- </span>first-duplex <span class="Constant">2</span>:address:duplex-list + <span class="Constant">2</span>:address:duplex-list<span class="Special"> <- </span>prev-duplex <span class="Constant">2</span>:address:duplex-list + <span class="Constant">8</span>:number<span class="Special"> <- </span>first-duplex <span class="Constant">2</span>:address:duplex-list + <span class="Constant">2</span>:address:duplex-list<span class="Special"> <- </span>prev-duplex <span class="Constant">2</span>:address:duplex-list + <span class="Constant">9</span>:number<span class="Special"> <- </span>first-duplex <span class="Constant">2</span>:address:duplex-list + <span class="Constant">10</span>:boolean<span class="Special"> <- </span>equal <span class="Constant">1</span>:address:duplex-list, <span class="Constant">2</span>:address:duplex-list ] memory-should-contain [ - 3<span class="Special"> <- </span>5 <span class="Comment"># scanning next</span> - 4<span class="Special"> <- </span>6 <span class="Comment"># inserted element</span> - 5<span class="Special"> <- </span>4 - 6<span class="Special"> <- </span>3 - 7<span class="Special"> <- </span>4 <span class="Comment"># then prev</span> - 8<span class="Special"> <- </span>6 - 9<span class="Special"> <- </span>5 - 10<span class="Special"> <- </span>1 <span class="Comment"># list back at start</span> + <span class="Constant">3</span><span class="Special"> <- </span><span class="Constant">5</span> <span class="Comment"># scanning next</span> + <span class="Constant">4</span><span class="Special"> <- </span><span class="Constant">6</span> <span class="Comment"># inserted element</span> + <span class="Constant">5</span><span class="Special"> <- </span><span class="Constant">4</span> + <span class="Constant">6</span><span class="Special"> <- </span><span class="Constant">3</span> + <span class="Constant">7</span><span class="Special"> <- </span><span class="Constant">4</span> <span class="Comment"># then prev</span> + <span class="Constant">8</span><span class="Special"> <- </span><span class="Constant">6</span> + <span class="Constant">9</span><span class="Special"> <- </span><span class="Constant">5</span> + <span class="Constant">10</span><span class="Special"> <- </span><span class="Constant">1</span> <span class="Comment"># list back at start</span> ] ] <span class="Comment"># l:address:duplex-list <- remove-duplex in:address:duplex-list</span> <span class="Comment"># Removes 'in' from its surrounding list. Returns some valid pointer into the</span> <span class="Comment"># rest of the list.</span> -# +<span class="Comment">#</span> <span class="Comment"># Returns null if and only if list is empty. Beware: in that case any pointers</span> <span class="Comment"># to the head are now invalid.</span> -recipe remove-duplex [ - <span class="Underlined">local</span>-scope - <span class="Identifier">in</span>:address:duplex-list<span class="Special"> <- </span>next-ingredient +<span class="muRecipe">recipe</span> remove-duplex [ + <span class="Constant">local-scope</span> + in:address:duplex-list<span class="Special"> <- </span><span class="Constant">next-ingredient</span> <span class="Comment"># if 'in' is null, return</span> - reply-unless <span class="Identifier">in</span>, <span class="Identifier">in</span> - next-node:address:duplex-list<span class="Special"> <- </span>get *<span class="Identifier">in</span>, next:offset - prev-node:address:duplex-list<span class="Special"> <- </span>get *<span class="Identifier">in</span>, prev:offset + <span class="muControl">reply-unless</span> in, in + next-node:address:duplex-list<span class="Special"> <- </span>get *in, <span class="Constant">next:offset</span> + prev-node:address:duplex-list<span class="Special"> <- </span>get *in, <span class="Constant">prev:offset</span> <span class="Comment"># null in's pointers</span> - x:address:address:duplex-list<span class="Special"> <- </span>get-address *<span class="Identifier">in</span>, next:offset - *x<span class="Special"> <- </span><span class="Identifier">copy</span> 0 - x<span class="Special"> <- </span>get-address *<span class="Identifier">in</span>, prev:offset - *x<span class="Special"> <- </span><span class="Identifier">copy</span> 0 - { + x:address:address:duplex-list<span class="Special"> <- </span>get-address *in, <span class="Constant">next:offset</span> + *x<span class="Special"> <- </span>copy <span class="Constant">0</span> + x<span class="Special"> <- </span>get-address *in, <span class="Constant">prev:offset</span> + *x<span class="Special"> <- </span>copy <span class="Constant">0</span> + <span class="Delimiter">{</span> <span class="Comment"># if next-node is not null</span> - break-unless next-node + <span class="muControl">break-unless</span> next-node <span class="Comment"># next-node.prev = prev-node</span> - x<span class="Special"> <- </span>get-address *next-node, prev:offset - *x<span class="Special"> <- </span><span class="Identifier">copy</span> prev-node - } - { + x<span class="Special"> <- </span>get-address *next-node, <span class="Constant">prev:offset</span> + *x<span class="Special"> <- </span>copy prev-node + <span class="Delimiter">}</span> + <span class="Delimiter">{</span> <span class="Comment"># if prev-node is not null</span> - break-unless prev-node + <span class="muControl">break-unless</span> prev-node <span class="Comment"># prev-node.next = next-node</span> - x<span class="Special"> <- </span>get-address *prev-node, next:offset - *x<span class="Special"> <- </span><span class="Identifier">copy</span> next-node - reply prev-node - } - reply next-node + x<span class="Special"> <- </span>get-address *prev-node, <span class="Constant">next:offset</span> + *x<span class="Special"> <- </span>copy next-node + <span class="muControl">reply</span> prev-node + <span class="Delimiter">}</span> + <span class="muControl">reply</span> next-node ] -scenario removing-from-duplex-list [ +<span class="muScenario">scenario</span> removing-from-duplex-list [ run [ - 1:address:duplex-list<span class="Special"> <- </span><span class="Identifier">copy</span> 0 <span class="Comment"># 1 points to head of list</span> - 1:address:duplex-list<span class="Special"> <- </span>push-duplex 3, 1:address:duplex-list - 1:address:duplex-list<span class="Special"> <- </span>push-duplex 4, 1:address:duplex-list - 1:address:duplex-list<span class="Special"> <- </span>push-duplex 5, 1:address:duplex-list - 2:address:duplex-list<span class="Special"> <- </span>next-duplex 1:address:duplex-list <span class="Comment"># 2 points at second element</span> - 2:address:duplex-list<span class="Special"> <- </span>remove-duplex 2:address:duplex-list - 3:boolean<span class="Special"> <- </span>equal 2:address:duplex-list, 0 + <span class="Constant">1</span>:address:duplex-list<span class="Special"> <- </span>copy <span class="Constant">0</span> <span class="Comment"># 1 points to head of list</span> + <span class="Constant">1</span>:address:duplex-list<span class="Special"> <- </span>push-duplex <span class="Constant">3</span>, <span class="Constant">1</span>:address:duplex-list + <span class="Constant">1</span>:address:duplex-list<span class="Special"> <- </span>push-duplex <span class="Constant">4</span>, <span class="Constant">1</span>:address:duplex-list + <span class="Constant">1</span>:address:duplex-list<span class="Special"> <- </span>push-duplex <span class="Constant">5</span>, <span class="Constant">1</span>:address:duplex-list + <span class="Constant">2</span>:address:duplex-list<span class="Special"> <- </span>next-duplex <span class="Constant">1</span>:address:duplex-list <span class="Comment"># 2 points at second element</span> + <span class="Constant">2</span>:address:duplex-list<span class="Special"> <- </span>remove-duplex <span class="Constant">2</span>:address:duplex-list + <span class="Constant">3</span>:boolean<span class="Special"> <- </span>equal <span class="Constant">2</span>:address:duplex-list, <span class="Constant">0</span> <span class="Comment"># check structure like before</span> - 2:address:duplex-list<span class="Special"> <- </span><span class="Identifier">copy</span> 1:address:duplex-list - 4:number<span class="Special"> <- </span>first-duplex 2:address:duplex-list - 2:address:duplex-list<span class="Special"> <- </span>next-duplex 2:address:duplex-list - 5:number<span class="Special"> <- </span>first-duplex 2:address:duplex-list - 6:address:duplex-list<span class="Special"> <- </span>next-duplex 2:address:duplex-list - 2:address:duplex-list<span class="Special"> <- </span>prev-duplex 2:address:duplex-list - 7:number<span class="Special"> <- </span>first-duplex 2:address:duplex-list - 8:boolean<span class="Special"> <- </span>equal 1:address:duplex-list, 2:address:duplex-list + <span class="Constant">2</span>:address:duplex-list<span class="Special"> <- </span>copy <span class="Constant">1</span>:address:duplex-list + <span class="Constant">4</span>:number<span class="Special"> <- </span>first-duplex <span class="Constant">2</span>:address:duplex-list + <span class="Constant">2</span>:address:duplex-list<span class="Special"> <- </span>next-duplex <span class="Constant">2</span>:address:duplex-list + <span class="Constant">5</span>:number<span class="Special"> <- </span>first-duplex <span class="Constant">2</span>:address:duplex-list + <span class="Constant">6</span>:address:duplex-list<span class="Special"> <- </span>next-duplex <span class="Constant">2</span>:address:duplex-list + <span class="Constant">2</span>:address:duplex-list<span class="Special"> <- </span>prev-duplex <span class="Constant">2</span>:address:duplex-list + <span class="Constant">7</span>:number<span class="Special"> <- </span>first-duplex <span class="Constant">2</span>:address:duplex-list + <span class="Constant">8</span>:boolean<span class="Special"> <- </span>equal <span class="Constant">1</span>:address:duplex-list, <span class="Constant">2</span>:address:duplex-list ] memory-should-contain [ - 3<span class="Special"> <- </span>0 <span class="Comment"># remove returned non-null</span> - 4<span class="Special"> <- </span>5 <span class="Comment"># scanning next, skipping deleted element</span> - 5<span class="Special"> <- </span>3 - 6<span class="Special"> <- </span>0 <span class="Comment"># no more elements</span> - 7<span class="Special"> <- </span>5 <span class="Comment"># prev of final element</span> - 8<span class="Special"> <- </span>1 <span class="Comment"># list back at start</span> + <span class="Constant">3</span><span class="Special"> <- </span><span class="Constant">0</span> <span class="Comment"># remove returned non-null</span> + <span class="Constant">4</span><span class="Special"> <- </span><span class="Constant">5</span> <span class="Comment"># scanning next, skipping deleted element</span> + <span class="Constant">5</span><span class="Special"> <- </span><span class="Constant">3</span> + <span class="Constant">6</span><span class="Special"> <- </span><span class="Constant">0</span> <span class="Comment"># no more elements</span> + <span class="Constant">7</span><span class="Special"> <- </span><span class="Constant">5</span> <span class="Comment"># prev of final element</span> + <span class="Constant">8</span><span class="Special"> <- </span><span class="Constant">1</span> <span class="Comment"># list back at start</span> ] ] -scenario removing-from-start-of-duplex-list [ +<span class="muScenario">scenario</span> removing-from-start-of-duplex-list [ run [ - 1:address:duplex-list<span class="Special"> <- </span><span class="Identifier">copy</span> 0 <span class="Comment"># 1 points to head of list</span> - 1:address:duplex-list<span class="Special"> <- </span>push-duplex 3, 1:address:duplex-list - 1:address:duplex-list<span class="Special"> <- </span>push-duplex 4, 1:address:duplex-list - 1:address:duplex-list<span class="Special"> <- </span>push-duplex 5, 1:address:duplex-list + <span class="Constant">1</span>:address:duplex-list<span class="Special"> <- </span>copy <span class="Constant">0</span> <span class="Comment"># 1 points to head of list</span> + <span class="Constant">1</span>:address:duplex-list<span class="Special"> <- </span>push-duplex <span class="Constant">3</span>, <span class="Constant">1</span>:address:duplex-list + <span class="Constant">1</span>:address:duplex-list<span class="Special"> <- </span>push-duplex <span class="Constant">4</span>, <span class="Constant">1</span>:address:duplex-list + <span class="Constant">1</span>:address:duplex-list<span class="Special"> <- </span>push-duplex <span class="Constant">5</span>, <span class="Constant">1</span>:address:duplex-list <span class="Comment"># removing from head? return value matters.</span> - 1:address:duplex-list<span class="Special"> <- </span>remove-duplex 1:address:duplex-list + <span class="Constant">1</span>:address:duplex-list<span class="Special"> <- </span>remove-duplex <span class="Constant">1</span>:address:duplex-list <span class="Comment"># check structure like before</span> - 2:address:duplex-list<span class="Special"> <- </span><span class="Identifier">copy</span> 1:address:duplex-list - 3:number<span class="Special"> <- </span>first-duplex 2:address:duplex-list - 2:address:duplex-list<span class="Special"> <- </span>next-duplex 2:address:duplex-list - 4:number<span class="Special"> <- </span>first-duplex 2:address:duplex-list - 5:address:duplex-list<span class="Special"> <- </span>next-duplex 2:address:duplex-list - 2:address:duplex-list<span class="Special"> <- </span>prev-duplex 2:address:duplex-list - 6:number<span class="Special"> <- </span>first-duplex 2:address:duplex-list - 7:boolean<span class="Special"> <- </span>equal 1:address:duplex-list, 2:address:duplex-list + <span class="Constant">2</span>:address:duplex-list<span class="Special"> <- </span>copy <span class="Constant">1</span>:address:duplex-list + <span class="Constant">3</span>:number<span class="Special"> <- </span>first-duplex <span class="Constant">2</span>:address:duplex-list + <span class="Constant">2</span>:address:duplex-list<span class="Special"> <- </span>next-duplex <span class="Constant">2</span>:address:duplex-list + <span class="Constant">4</span>:number<span class="Special"> <- </span>first-duplex <span class="Constant">2</span>:address:duplex-list + <span class="Constant">5</span>:address:duplex-list<span class="Special"> <- </span>next-duplex <span class="Constant">2</span>:address:duplex-list + <span class="Constant">2</span>:address:duplex-list<span class="Special"> <- </span>prev-duplex <span class="Constant">2</span>:address:duplex-list + <span class="Constant">6</span>:number<span class="Special"> <- </span>first-duplex <span class="Constant">2</span>:address:duplex-list + <span class="Constant">7</span>:boolean<span class="Special"> <- </span>equal <span class="Constant">1</span>:address:duplex-list, <span class="Constant">2</span>:address:duplex-list ] memory-should-contain [ - 3<span class="Special"> <- </span>4 <span class="Comment"># scanning next, skipping deleted element</span> - 4<span class="Special"> <- </span>3 - 5<span class="Special"> <- </span>0 <span class="Comment"># no more elements</span> - 6<span class="Special"> <- </span>4 <span class="Comment"># prev of final element</span> - 7<span class="Special"> <- </span>1 <span class="Comment"># list back at start</span> + <span class="Constant">3</span><span class="Special"> <- </span><span class="Constant">4</span> <span class="Comment"># scanning next, skipping deleted element</span> + <span class="Constant">4</span><span class="Special"> <- </span><span class="Constant">3</span> + <span class="Constant">5</span><span class="Special"> <- </span><span class="Constant">0</span> <span class="Comment"># no more elements</span> + <span class="Constant">6</span><span class="Special"> <- </span><span class="Constant">4</span> <span class="Comment"># prev of final element</span> + <span class="Constant">7</span><span class="Special"> <- </span><span class="Constant">1</span> <span class="Comment"># list back at start</span> ] ] -scenario removing-from-end-of-duplex-list [ +<span class="muScenario">scenario</span> removing-from-end-of-duplex-list [ run [ - 1:address:duplex-list<span class="Special"> <- </span><span class="Identifier">copy</span> 0 <span class="Comment"># 1 points to head of list</span> - 1:address:duplex-list<span class="Special"> <- </span>push-duplex 3, 1:address:duplex-list - 1:address:duplex-list<span class="Special"> <- </span>push-duplex 4, 1:address:duplex-list - 1:address:duplex-list<span class="Special"> <- </span>push-duplex 5, 1:address:duplex-list + <span class="Constant">1</span>:address:duplex-list<span class="Special"> <- </span>copy <span class="Constant">0</span> <span class="Comment"># 1 points to head of list</span> + <span class="Constant">1</span>:address:duplex-list<span class="Special"> <- </span>push-duplex <span class="Constant">3</span>, <span class="Constant">1</span>:address:duplex-list + <span class="Constant">1</span>:address:duplex-list<span class="Special"> <- </span>push-duplex <span class="Constant">4</span>, <span class="Constant">1</span>:address:duplex-list + <span class="Constant">1</span>:address:duplex-list<span class="Special"> <- </span>push-duplex <span class="Constant">5</span>, <span class="Constant">1</span>:address:duplex-list <span class="Comment"># delete last element</span> - 2:address:duplex-list<span class="Special"> <- </span>next-duplex 1:address:duplex-list - 2:address:duplex-list<span class="Special"> <- </span>next-duplex 2:address:duplex-list - 2:address:duplex-list<span class="Special"> <- </span>remove-duplex 2:address:duplex-list - 3:boolean<span class="Special"> <- </span>equal 2:address:duplex-list, 0 + <span class="Constant">2</span>:address:duplex-list<span class="Special"> <- </span>next-duplex <span class="Constant">1</span>:address:duplex-list + <span class="Constant">2</span>:address:duplex-list<span class="Special"> <- </span>next-duplex <span class="Constant">2</span>:address:duplex-list + <span class="Constant">2</span>:address:duplex-list<span class="Special"> <- </span>remove-duplex <span class="Constant">2</span>:address:duplex-list + <span class="Constant">3</span>:boolean<span class="Special"> <- </span>equal <span class="Constant">2</span>:address:duplex-list, <span class="Constant">0</span> <span class="Comment"># check structure like before</span> - 2:address:duplex-list<span class="Special"> <- </span><span class="Identifier">copy</span> 1:address:duplex-list - 4:number<span class="Special"> <- </span>first-duplex 2:address:duplex-list - 2:address:duplex-list<span class="Special"> <- </span>next-duplex 2:address:duplex-list - 5:number<span class="Special"> <- </span>first-duplex 2:address:duplex-list - 6:address:duplex-list<span class="Special"> <- </span>next-duplex 2:address:duplex-list - 2:address:duplex-list<span class="Special"> <- </span>prev-duplex 2:address:duplex-list - 7:number<span class="Special"> <- </span>first-duplex 2:address:duplex-list - 8:boolean<span class="Special"> <- </span>equal 1:address:duplex-list, 2:address:duplex-list + <span class="Constant">2</span>:address:duplex-list<span class="Special"> <- </span>copy <span class="Constant">1</span>:address:duplex-list + <span class="Constant">4</span>:number<span class="Special"> <- </span>first-duplex <span class="Constant">2</span>:address:duplex-list + <span class="Constant">2</span>:address:duplex-list<span class="Special"> <- </span>next-duplex <span class="Constant">2</span>:address:duplex-list + <span class="Constant">5</span>:number<span class="Special"> <- </span>first-duplex <span class="Constant">2</span>:address:duplex-list + <span class="Constant">6</span>:address:duplex-list<span class="Special"> <- </span>next-duplex <span class="Constant">2</span>:address:duplex-list + <span class="Constant">2</span>:address:duplex-list<span class="Special"> <- </span>prev-duplex <span class="Constant">2</span>:address:duplex-list + <span class="Constant">7</span>:number<span class="Special"> <- </span>first-duplex <span class="Constant">2</span>:address:duplex-list + <span class="Constant">8</span>:boolean<span class="Special"> <- </span>equal <span class="Constant">1</span>:address:duplex-list, <span class="Constant">2</span>:address:duplex-list ] memory-should-contain [ - 3<span class="Special"> <- </span>0 <span class="Comment"># remove returned non-null</span> - 4<span class="Special"> <- </span>5 <span class="Comment"># scanning next, skipping deleted element</span> - 5<span class="Special"> <- </span>4 - 6<span class="Special"> <- </span>0 <span class="Comment"># no more elements</span> - 7<span class="Special"> <- </span>5 <span class="Comment"># prev of final element</span> - 8<span class="Special"> <- </span>1 <span class="Comment"># list back at start</span> + <span class="Constant">3</span><span class="Special"> <- </span><span class="Constant">0</span> <span class="Comment"># remove returned non-null</span> + <span class="Constant">4</span><span class="Special"> <- </span><span class="Constant">5</span> <span class="Comment"># scanning next, skipping deleted element</span> + <span class="Constant">5</span><span class="Special"> <- </span><span class="Constant">4</span> + <span class="Constant">6</span><span class="Special"> <- </span><span class="Constant">0</span> <span class="Comment"># no more elements</span> + <span class="Constant">7</span><span class="Special"> <- </span><span class="Constant">5</span> <span class="Comment"># prev of final element</span> + <span class="Constant">8</span><span class="Special"> <- </span><span class="Constant">1</span> <span class="Comment"># list back at start</span> ] ] -scenario removing-from-singleton-list [ +<span class="muScenario">scenario</span> removing-from-singleton-list [ run [ - 1:address:duplex-list<span class="Special"> <- </span><span class="Identifier">copy</span> 0 <span class="Comment"># 1 points to singleton list</span> - 1:address:duplex-list<span class="Special"> <- </span>push-duplex 3, 1:address:duplex-list - 2:address:duplex-list<span class="Special"> <- </span>remove-duplex 1:address:duplex-list - 3:address:duplex-list<span class="Special"> <- </span>get *1:address:duplex-list, next:offset - 4:address:duplex-list<span class="Special"> <- </span>get *1:address:duplex-list, prev:offset + <span class="Constant">1</span>:address:duplex-list<span class="Special"> <- </span>copy <span class="Constant">0</span> <span class="Comment"># 1 points to singleton list</span> + <span class="Constant">1</span>:address:duplex-list<span class="Special"> <- </span>push-duplex <span class="Constant">3</span>, <span class="Constant">1</span>:address:duplex-list + <span class="Constant">2</span>:address:duplex-list<span class="Special"> <- </span>remove-duplex <span class="Constant">1</span>:address:duplex-list + <span class="Constant">3</span>:address:duplex-list<span class="Special"> <- </span>get *<span class="Constant">1</span>:address:duplex-list, <span class="Constant">next:offset</span> + <span class="Constant">4</span>:address:duplex-list<span class="Special"> <- </span>get *<span class="Constant">1</span>:address:duplex-list, <span class="Constant">prev:offset</span> ] memory-should-contain [ - 2<span class="Special"> <- </span>0 <span class="Comment"># remove returned null</span> - 3<span class="Special"> <- </span>0 <span class="Comment"># removed node is also detached</span> - 4<span class="Special"> <- </span>0 + <span class="Constant">2</span><span class="Special"> <- </span><span class="Constant">0</span> <span class="Comment"># remove returned null</span> + <span class="Constant">3</span><span class="Special"> <- </span><span class="Constant">0</span> <span class="Comment"># removed node is also detached</span> + <span class="Constant">4</span><span class="Special"> <- </span><span class="Constant">0</span> ] ] @@ -401,193 +405,193 @@ scenario removing-from-singleton-list [ <span class="Comment"># Remove values between 'start' and 'end' (both exclusive). Returns some valid</span> <span class="Comment"># pointer into the rest of the list.</span> <span class="Comment"># Also clear pointers back out from start/end for hygiene.</span> -recipe remove-duplex-between [ - <span class="Underlined">local</span>-scope - start:address:duplex-list<span class="Special"> <- </span>next-ingredient - end:address:duplex-list<span class="Special"> <- </span>next-ingredient - reply-unless start, start +<span class="muRecipe">recipe</span> remove-duplex-between [ + <span class="Constant">local-scope</span> + start:address:duplex-list<span class="Special"> <- </span><span class="Constant">next-ingredient</span> + end:address:duplex-list<span class="Special"> <- </span><span class="Constant">next-ingredient</span> + <span class="muControl">reply-unless</span> start, start <span class="Comment"># start->next->prev = 0</span> <span class="Comment"># start->next = end</span> - next:address:address:duplex-list<span class="Special"> <- </span>get-address *start, next:offset - nothing-to-<span class="Identifier">delete</span>?:boolean<span class="Special"> <- </span>equal *next, end - reply-if nothing-to-<span class="Identifier">delete</span>?, start - prev:address:address:duplex-list<span class="Special"> <- </span>get-address **next, prev:offset - *prev<span class="Special"> <- </span><span class="Identifier">copy</span> 0 - *next<span class="Special"> <- </span><span class="Identifier">copy</span> end - reply-unless end, start + next:address:address:duplex-list<span class="Special"> <- </span>get-address *start, <span class="Constant">next:offset</span> + nothing-to-delete?:boolean<span class="Special"> <- </span>equal *next, end + <span class="muControl">reply-if</span> nothing-to-delete?, start + prev:address:address:duplex-list<span class="Special"> <- </span>get-address **next, <span class="Constant">prev:offset</span> + *prev<span class="Special"> <- </span>copy <span class="Constant">0</span> + *next<span class="Special"> <- </span>copy end + <span class="muControl">reply-unless</span> end, start <span class="Comment"># end->prev->next = 0</span> <span class="Comment"># end->prev = start</span> - prev<span class="Special"> <- </span>get-address *end, prev:offset - next<span class="Special"> <- </span>get-address **prev, next:offset - *next<span class="Special"> <- </span><span class="Identifier">copy</span> 0 - *prev<span class="Special"> <- </span><span class="Identifier">copy</span> start - reply start + prev<span class="Special"> <- </span>get-address *end, <span class="Constant">prev:offset</span> + next<span class="Special"> <- </span>get-address **prev, <span class="Constant">next:offset</span> + *next<span class="Special"> <- </span>copy <span class="Constant">0</span> + *prev<span class="Special"> <- </span>copy start + <span class="muControl">reply</span> start ] -scenario remove-range [ +<span class="muScenario">scenario</span> remove-range [ <span class="Comment"># construct a duplex list with six elements [13, 14, 15, 16, 17, 18]</span> - 1:address:duplex-list<span class="Special"> <- </span><span class="Identifier">copy</span> 0 <span class="Comment"># 1 points to singleton list</span> - 1:address:duplex-list<span class="Special"> <- </span>push-duplex 18, 1:address:duplex-list - 1:address:duplex-list<span class="Special"> <- </span>push-duplex 17, 1:address:duplex-list - 1:address:duplex-list<span class="Special"> <- </span>push-duplex 16, 1:address:duplex-list - 1:address:duplex-list<span class="Special"> <- </span>push-duplex 15, 1:address:duplex-list - 1:address:duplex-list<span class="Special"> <- </span>push-duplex 14, 1:address:duplex-list - 1:address:duplex-list<span class="Special"> <- </span>push-duplex 13, 1:address:duplex-list + <span class="Constant">1</span>:address:duplex-list<span class="Special"> <- </span>copy <span class="Constant">0</span> <span class="Comment"># 1 points to singleton list</span> + <span class="Constant">1</span>:address:duplex-list<span class="Special"> <- </span>push-duplex <span class="Constant">18</span>, <span class="Constant">1</span>:address:duplex-list + <span class="Constant">1</span>:address:duplex-list<span class="Special"> <- </span>push-duplex <span class="Constant">17</span>, <span class="Constant">1</span>:address:duplex-list + <span class="Constant">1</span>:address:duplex-list<span class="Special"> <- </span>push-duplex <span class="Constant">16</span>, <span class="Constant">1</span>:address:duplex-list + <span class="Constant">1</span>:address:duplex-list<span class="Special"> <- </span>push-duplex <span class="Constant">15</span>, <span class="Constant">1</span>:address:duplex-list + <span class="Constant">1</span>:address:duplex-list<span class="Special"> <- </span>push-duplex <span class="Constant">14</span>, <span class="Constant">1</span>:address:duplex-list + <span class="Constant">1</span>:address:duplex-list<span class="Special"> <- </span>push-duplex <span class="Constant">13</span>, <span class="Constant">1</span>:address:duplex-list run [ <span class="Comment"># delete 16 onwards</span> <span class="Comment"># first pointer: to the third element</span> - 2:address:duplex-list<span class="Special"> <- </span>next-duplex 1:address:duplex-list - 2:address:duplex-list<span class="Special"> <- </span>next-duplex 2:address:duplex-list - remove-duplex-between 2:address:duplex-list, 0 + <span class="Constant">2</span>:address:duplex-list<span class="Special"> <- </span>next-duplex <span class="Constant">1</span>:address:duplex-list + <span class="Constant">2</span>:address:duplex-list<span class="Special"> <- </span>next-duplex <span class="Constant">2</span>:address:duplex-list + remove-duplex-between <span class="Constant">2</span>:address:duplex-list, <span class="Constant">0</span> <span class="Comment"># now check the list</span> - 4:number<span class="Special"> <- </span>get *1:address:duplex-list, value:offset - 5:address:duplex-list<span class="Special"> <- </span>next-duplex 1:address:duplex-list - 6:number<span class="Special"> <- </span>get *5:address:duplex-list, value:offset - 7:address:duplex-list<span class="Special"> <- </span>next-duplex 5:address:duplex-list - 8:number<span class="Special"> <- </span>get *7:address:duplex-list, value:offset - 9:address:duplex-list<span class="Special"> <- </span>next-duplex 7:address:duplex-list + <span class="Constant">4</span>:number<span class="Special"> <- </span>get *<span class="Constant">1</span>:address:duplex-list, <span class="Constant">value:offset</span> + <span class="Constant">5</span>:address:duplex-list<span class="Special"> <- </span>next-duplex <span class="Constant">1</span>:address:duplex-list + <span class="Constant">6</span>:number<span class="Special"> <- </span>get *<span class="Constant">5</span>:address:duplex-list, <span class="Constant">value:offset</span> + <span class="Constant">7</span>:address:duplex-list<span class="Special"> <- </span>next-duplex <span class="Constant">5</span>:address:duplex-list + <span class="Constant">8</span>:number<span class="Special"> <- </span>get *<span class="Constant">7</span>:address:duplex-list, <span class="Constant">value:offset</span> + <span class="Constant">9</span>:address:duplex-list<span class="Special"> <- </span>next-duplex <span class="Constant">7</span>:address:duplex-list ] memory-should-contain [ - 4<span class="Special"> <- </span>13 - 6<span class="Special"> <- </span>14 - 8<span class="Special"> <- </span>15 - 9<span class="Special"> <- </span>0 + <span class="Constant">4</span><span class="Special"> <- </span><span class="Constant">13</span> + <span class="Constant">6</span><span class="Special"> <- </span><span class="Constant">14</span> + <span class="Constant">8</span><span class="Special"> <- </span><span class="Constant">15</span> + <span class="Constant">9</span><span class="Special"> <- </span><span class="Constant">0</span> ] ] -scenario remove-range-to-end [ +<span class="muScenario">scenario</span> remove-range-to-end [ <span class="Comment"># construct a duplex list with six elements [13, 14, 15, 16, 17, 18]</span> - 1:address:duplex-list<span class="Special"> <- </span><span class="Identifier">copy</span> 0 <span class="Comment"># 1 points to singleton list</span> - 1:address:duplex-list<span class="Special"> <- </span>push-duplex 18, 1:address:duplex-list - 1:address:duplex-list<span class="Special"> <- </span>push-duplex 17, 1:address:duplex-list - 1:address:duplex-list<span class="Special"> <- </span>push-duplex 16, 1:address:duplex-list - 1:address:duplex-list<span class="Special"> <- </span>push-duplex 15, 1:address:duplex-list - 1:address:duplex-list<span class="Special"> <- </span>push-duplex 14, 1:address:duplex-list - 1:address:duplex-list<span class="Special"> <- </span>push-duplex 13, 1:address:duplex-list + <span class="Constant">1</span>:address:duplex-list<span class="Special"> <- </span>copy <span class="Constant">0</span> <span class="Comment"># 1 points to singleton list</span> + <span class="Constant">1</span>:address:duplex-list<span class="Special"> <- </span>push-duplex <span class="Constant">18</span>, <span class="Constant">1</span>:address:duplex-list + <span class="Constant">1</span>:address:duplex-list<span class="Special"> <- </span>push-duplex <span class="Constant">17</span>, <span class="Constant">1</span>:address:duplex-list + <span class="Constant">1</span>:address:duplex-list<span class="Special"> <- </span>push-duplex <span class="Constant">16</span>, <span class="Constant">1</span>:address:duplex-list + <span class="Constant">1</span>:address:duplex-list<span class="Special"> <- </span>push-duplex <span class="Constant">15</span>, <span class="Constant">1</span>:address:duplex-list + <span class="Constant">1</span>:address:duplex-list<span class="Special"> <- </span>push-duplex <span class="Constant">14</span>, <span class="Constant">1</span>:address:duplex-list + <span class="Constant">1</span>:address:duplex-list<span class="Special"> <- </span>push-duplex <span class="Constant">13</span>, <span class="Constant">1</span>:address:duplex-list run [ <span class="Comment"># delete 15, 16 and 17</span> <span class="Comment"># first pointer: to the third element</span> - 2:address:duplex-list<span class="Special"> <- </span>next-duplex 1:address:duplex-list + <span class="Constant">2</span>:address:duplex-list<span class="Special"> <- </span>next-duplex <span class="Constant">1</span>:address:duplex-list <span class="Comment"># second pointer: to the fifth element</span> - 3:address:duplex-list<span class="Special"> <- </span>next-duplex 2:address:duplex-list - 3:address:duplex-list<span class="Special"> <- </span>next-duplex 3:address:duplex-list - 3:address:duplex-list<span class="Special"> <- </span>next-duplex 3:address:duplex-list - 3:address:duplex-list<span class="Special"> <- </span>next-duplex 3:address:duplex-list - remove-duplex-between 2:address:duplex-list, 3:address:duplex-list + <span class="Constant">3</span>:address:duplex-list<span class="Special"> <- </span>next-duplex <span class="Constant">2</span>:address:duplex-list + <span class="Constant">3</span>:address:duplex-list<span class="Special"> <- </span>next-duplex <span class="Constant">3</span>:address:duplex-list + <span class="Constant">3</span>:address:duplex-list<span class="Special"> <- </span>next-duplex <span class="Constant">3</span>:address:duplex-list + <span class="Constant">3</span>:address:duplex-list<span class="Special"> <- </span>next-duplex <span class="Constant">3</span>:address:duplex-list + remove-duplex-between <span class="Constant">2</span>:address:duplex-list, <span class="Constant">3</span>:address:duplex-list <span class="Comment"># now check the list</span> - 4:number<span class="Special"> <- </span>get *1:address:duplex-list, value:offset - 5:address:duplex-list<span class="Special"> <- </span>next-duplex 1:address:duplex-list - 6:number<span class="Special"> <- </span>get *5:address:duplex-list, value:offset - 7:address:duplex-list<span class="Special"> <- </span>next-duplex 5:address:duplex-list - 8:number<span class="Special"> <- </span>get *7:address:duplex-list, value:offset - 9:address:duplex-list<span class="Special"> <- </span>next-duplex 7:address:duplex-list + <span class="Constant">4</span>:number<span class="Special"> <- </span>get *<span class="Constant">1</span>:address:duplex-list, <span class="Constant">value:offset</span> + <span class="Constant">5</span>:address:duplex-list<span class="Special"> <- </span>next-duplex <span class="Constant">1</span>:address:duplex-list + <span class="Constant">6</span>:number<span class="Special"> <- </span>get *<span class="Constant">5</span>:address:duplex-list, <span class="Constant">value:offset</span> + <span class="Constant">7</span>:address:duplex-list<span class="Special"> <- </span>next-duplex <span class="Constant">5</span>:address:duplex-list + <span class="Constant">8</span>:number<span class="Special"> <- </span>get *<span class="Constant">7</span>:address:duplex-list, <span class="Constant">value:offset</span> + <span class="Constant">9</span>:address:duplex-list<span class="Special"> <- </span>next-duplex <span class="Constant">7</span>:address:duplex-list ] memory-should-contain [ - 4<span class="Special"> <- </span>13 - 6<span class="Special"> <- </span>14 - 8<span class="Special"> <- </span>18 - 9<span class="Special"> <- </span>0 + <span class="Constant">4</span><span class="Special"> <- </span><span class="Constant">13</span> + <span class="Constant">6</span><span class="Special"> <- </span><span class="Constant">14</span> + <span class="Constant">8</span><span class="Special"> <- </span><span class="Constant">18</span> + <span class="Constant">9</span><span class="Special"> <- </span><span class="Constant">0</span> ] ] -scenario remove-range-empty [ +<span class="muScenario">scenario</span> remove-range-empty [ <span class="Comment"># construct a duplex list with six elements [13, 14, 15, 16, 17, 18]</span> - 1:address:duplex-list<span class="Special"> <- </span><span class="Identifier">copy</span> 0 <span class="Comment"># 1 points to singleton list</span> - 1:address:duplex-list<span class="Special"> <- </span>push-duplex 14, 1:address:duplex-list - 1:address:duplex-list<span class="Special"> <- </span>push-duplex 13, 1:address:duplex-list + <span class="Constant">1</span>:address:duplex-list<span class="Special"> <- </span>copy <span class="Constant">0</span> <span class="Comment"># 1 points to singleton list</span> + <span class="Constant">1</span>:address:duplex-list<span class="Special"> <- </span>push-duplex <span class="Constant">14</span>, <span class="Constant">1</span>:address:duplex-list + <span class="Constant">1</span>:address:duplex-list<span class="Special"> <- </span>push-duplex <span class="Constant">13</span>, <span class="Constant">1</span>:address:duplex-list run [ <span class="Comment"># delete 16 onwards</span> <span class="Comment"># first pointer: to the third element</span> - 2:address:duplex-list<span class="Special"> <- </span>next-duplex 1:address:duplex-list - remove-duplex-between 1:address:duplex-list, 2:address:duplex-list + <span class="Constant">2</span>:address:duplex-list<span class="Special"> <- </span>next-duplex <span class="Constant">1</span>:address:duplex-list + remove-duplex-between <span class="Constant">1</span>:address:duplex-list, <span class="Constant">2</span>:address:duplex-list <span class="Comment"># now check the list</span> - 4:number<span class="Special"> <- </span>get *1:address:duplex-list, value:offset - 5:address:duplex-list<span class="Special"> <- </span>next-duplex 1:address:duplex-list - 6:number<span class="Special"> <- </span>get *5:address:duplex-list, value:offset - 7:address:duplex-list<span class="Special"> <- </span>next-duplex 5:address:duplex-list + <span class="Constant">4</span>:number<span class="Special"> <- </span>get *<span class="Constant">1</span>:address:duplex-list, <span class="Constant">value:offset</span> + <span class="Constant">5</span>:address:duplex-list<span class="Special"> <- </span>next-duplex <span class="Constant">1</span>:address:duplex-list + <span class="Constant">6</span>:number<span class="Special"> <- </span>get *<span class="Constant">5</span>:address:duplex-list, <span class="Constant">value:offset</span> + <span class="Constant">7</span>:address:duplex-list<span class="Special"> <- </span>next-duplex <span class="Constant">5</span>:address:duplex-list ] memory-should-contain [ - 4<span class="Special"> <- </span>13 - 6<span class="Special"> <- </span>14 - 7<span class="Special"> <- </span>0 + <span class="Constant">4</span><span class="Special"> <- </span><span class="Constant">13</span> + <span class="Constant">6</span><span class="Special"> <- </span><span class="Constant">14</span> + <span class="Constant">7</span><span class="Special"> <- </span><span class="Constant">0</span> ] ] <span class="Comment"># l:address:duplex-list <- insert-duplex-range in:address:duplex-list, new:address:duplex-list</span> <span class="Comment"># Inserts list beginning at 'new' after 'in'. Returns some pointer into the list.</span> -recipe insert-duplex-range [ - <span class="Underlined">local</span>-scope - <span class="Identifier">in</span>:address:duplex-list<span class="Special"> <- </span>next-ingredient - start:address:duplex-list<span class="Special"> <- </span>next-ingredient - reply-unless <span class="Identifier">in</span>, <span class="Identifier">in</span> - reply-unless start, <span class="Identifier">in</span> - end:address:duplex-list<span class="Special"> <- </span><span class="Identifier">copy</span> start - { +<span class="muRecipe">recipe</span> insert-duplex-range [ + <span class="Constant">local-scope</span> + in: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> + <span class="muControl">reply-unless</span> in, in + <span class="muControl">reply-unless</span> start, in + end:address:duplex-list<span class="Special"> <- </span>copy start + <span class="Delimiter">{</span> next:address:duplex-list<span class="Special"> <- </span>next-duplex end - break-unless next - end<span class="Special"> <- </span><span class="Identifier">copy</span> next - loop - } - next:address:duplex-list<span class="Special"> <- </span>next-duplex <span class="Identifier">in</span> - dest:address:address:duplex-list<span class="Special"> <- </span>get-address *end, next:offset - *dest<span class="Special"> <- </span><span class="Identifier">copy</span> next - { - break-unless next - dest<span class="Special"> <- </span>get-address *next, prev:offset - *dest<span class="Special"> <- </span><span class="Identifier">copy</span> end - } - dest<span class="Special"> <- </span>get-address *<span class="Identifier">in</span>, next:offset - *dest<span class="Special"> <- </span><span class="Identifier">copy</span> start - dest<span class="Special"> <- </span>get-address *start, prev:offset - *dest<span class="Special"> <- </span><span class="Identifier">copy</span> <span class="Identifier">in</span> - reply <span class="Identifier">in</span> + <span class="muControl">break-unless</span> next + end<span class="Special"> <- </span>copy next + <span class="muControl">loop</span> + <span class="Delimiter">}</span> + next:address:duplex-list<span class="Special"> <- </span>next-duplex in + dest:address:address:duplex-list<span class="Special"> <- </span>get-address *end, <span class="Constant">next:offset</span> + *dest<span class="Special"> <- </span>copy next + <span class="Delimiter">{</span> + <span class="muControl">break-unless</span> next + dest<span class="Special"> <- </span>get-address *next, <span class="Constant">prev:offset</span> + *dest<span class="Special"> <- </span>copy end + <span class="Delimiter">}</span> + dest<span class="Special"> <- </span>get-address *in, <span class="Constant">next:offset</span> + *dest<span class="Special"> <- </span>copy start + dest<span class="Special"> <- </span>get-address *start, <span class="Constant">prev:offset</span> + *dest<span class="Special"> <- </span>copy in + <span class="muControl">reply</span> in ] -recipe <span class="Identifier">append</span>-duplex [ - <span class="Underlined">local</span>-scope - <span class="Identifier">in</span>:address:duplex-list<span class="Special"> <- </span>next-ingredient - <span class="Identifier">new</span>:address:duplex-list<span class="Special"> <- </span>next-ingredient - <span class="Identifier">last</span>:address:duplex-list<span class="Special"> <- </span><span class="Identifier">last</span>-duplex <span class="Identifier">in</span> - dest:address:address:duplex-list<span class="Special"> <- </span>get-address *<span class="Identifier">last</span>, next:offset - *dest<span class="Special"> <- </span><span class="Identifier">copy</span> <span class="Identifier">new</span> - reply-unless <span class="Identifier">new</span>, <span class="Identifier">in</span>/same-as-ingredient:0 - dest<span class="Special"> <- </span>get-address *<span class="Identifier">new</span>, prev:offset - *dest<span class="Special"> <- </span><span class="Identifier">copy</span> <span class="Identifier">last</span> - reply <span class="Identifier">in</span>/same-as-ingredient:0 +<span class="muRecipe">recipe</span> append-duplex [ + <span class="Constant">local-scope</span> + in:address:duplex-list<span class="Special"> <- </span><span class="Constant">next-ingredient</span> + new:address:duplex-list<span class="Special"> <- </span><span class="Constant">next-ingredient</span> + last:address:duplex-list<span class="Special"> <- </span>last-duplex in + dest:address:address:duplex-list<span class="Special"> <- </span>get-address *last, <span class="Constant">next:offset</span> + *dest<span class="Special"> <- </span>copy new + <span class="muControl">reply-unless</span> new, in/same-as-ingredient:<span class="Constant">0</span> + dest<span class="Special"> <- </span>get-address *new, <span class="Constant">prev:offset</span> + *dest<span class="Special"> <- </span>copy last + <span class="muControl">reply</span> in/same-as-ingredient:<span class="Constant">0</span> ] -recipe <span class="Identifier">last</span>-duplex [ - <span class="Underlined">local</span>-scope - <span class="Identifier">in</span>:address:duplex-list<span class="Special"> <- </span>next-ingredient - result:address:duplex-list<span class="Special"> <- </span><span class="Identifier">copy</span> <span class="Identifier">in</span> - { +<span class="muRecipe">recipe</span> last-duplex [ + <span class="Constant">local-scope</span> + in:address:duplex-list<span class="Special"> <- </span><span class="Constant">next-ingredient</span> + result:address:duplex-list<span class="Special"> <- </span>copy in + <span class="Delimiter">{</span> next:address:duplex-list<span class="Special"> <- </span>next-duplex result - break-unless next - result<span class="Special"> <- </span><span class="Identifier">copy</span> next - loop - } - reply result + <span class="muControl">break-unless</span> next + result<span class="Special"> <- </span>copy next + <span class="muControl">loop</span> + <span class="Delimiter">}</span> + <span class="muControl">reply</span> result ] <span class="Comment"># helper for debugging</span> -recipe dump-duplex-from [ - <span class="Underlined">local</span>-scope - x:address:duplex-list<span class="Special"> <- </span>next-ingredient - $<span class="Identifier">print</span> x, [: ] - { - break-unless x - c:character<span class="Special"> <- </span>get *x, value:offset - $<span class="Identifier">print</span> c, [ ] +<span class="muRecipe">recipe</span> dump-duplex-from [ + <span class="Constant">local-scope</span> + x:address:duplex-list<span class="Special"> <- </span><span class="Constant">next-ingredient</span> + $print x, <span class="Constant">[: ]</span> + <span class="Delimiter">{</span> + <span class="muControl">break-unless</span> x + c:character<span class="Special"> <- </span>get *x, <span class="Constant">value:offset</span> + $print c, <span class="Constant">[ ]</span> x<span class="Special"> <- </span>next-duplex x - { - <span class="Identifier">is</span>-newline?:boolean<span class="Special"> <- </span>equal c, 10/newline - break-unless <span class="Identifier">is</span>-newline? - $<span class="Identifier">print</span> 10/newline - $<span class="Identifier">print</span> x, [: ] - } - loop - } - $<span class="Identifier">print</span> 10/newline, [---], 10/newline + <span class="Delimiter">{</span> + is-newline?:boolean<span class="Special"> <- </span>equal c, <span class="Constant">10/newline</span> + <span class="muControl">break-unless</span> is-newline? + $print <span class="Constant">10/newline</span> + $print x, <span class="Constant">[: ]</span> + <span class="Delimiter">}</span> + <span class="muControl">loop</span> + <span class="Delimiter">}</span> + $print <span class="Constant">10/newline</span>, <span class="Constant">[---]</span>, <span class="Constant">10/newline</span> ] </pre> </body> diff --git a/html/066stream.mu.html b/html/066stream.mu.html index a43f8090..23a019f6 100644 --- a/html/066stream.mu.html +++ b/html/066stream.mu.html @@ -13,10 +13,12 @@ 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; } -.Special { color: #ff6060; } +.muRecipe { color: #ff8700; } +.muData { color: #ffff00; } .Comment { color: #9090ff; } -.Underlined { color: #c000c0; text-decoration: underline; } -.Identifier { color: #804000; } +.Constant { color: #00a0a0; } +.Special { color: #ff6060; } +.muControl { color: #c0a020; } --> </style> @@ -29,48 +31,48 @@ body { font-family: monospace; color: #eeeeee; background-color: #080808; } <body> <pre id='vimCodeElement'> <span class="Comment"># new type to help incrementally read strings</span> -container stream [ +<span class="muData">container</span> stream [ index:number - data:address:<span class="Identifier">array</span>:character + data:address:array:character ] -recipe <span class="Identifier">new</span>-stream [ - <span class="Underlined">local</span>-scope - result:address:stream<span class="Special"> <- </span><span class="Identifier">new</span> stream:<span class="Identifier">type</span> - i:address:number<span class="Special"> <- </span>get-address *result, index:offset - *i<span class="Special"> <- </span><span class="Identifier">copy</span> 0 - d:address:address:<span class="Identifier">array</span>:character<span class="Special"> <- </span>get-address *result, data:offset - *d<span class="Special"> <- </span>next-ingredient - reply result +<span class="muRecipe">recipe</span> new-stream [ + <span class="Constant">local-scope</span> + result:address:stream<span class="Special"> <- </span>new <span class="Constant">stream:type</span> + i:address:number<span class="Special"> <- </span>get-address *result, <span class="Constant">index:offset</span> + *i<span class="Special"> <- </span>copy <span class="Constant">0</span> + d:address:address:array:character<span class="Special"> <- </span>get-address *result, <span class="Constant">data:offset</span> + *d<span class="Special"> <- </span><span class="Constant">next-ingredient</span> + <span class="muControl">reply</span> result ] -recipe rewind-stream [ - <span class="Underlined">local</span>-scope - <span class="Identifier">in</span>:address:stream<span class="Special"> <- </span>next-ingredient - x:address:number<span class="Special"> <- </span>get-address *<span class="Identifier">in</span>, index:offset - *x<span class="Special"> <- </span><span class="Identifier">copy</span> 0 - reply <span class="Identifier">in</span>/same-as-<span class="Identifier">arg</span>:0 +<span class="muRecipe">recipe</span> rewind-stream [ + <span class="Constant">local-scope</span> + in:address:stream<span class="Special"> <- </span><span class="Constant">next-ingredient</span> + x:address:number<span class="Special"> <- </span>get-address *in, <span class="Constant">index:offset</span> + *x<span class="Special"> <- </span>copy <span class="Constant">0</span> + <span class="muControl">reply</span> in/same-as-arg:<span class="Constant">0</span> ] -recipe <span class="Identifier">read</span>-line [ - <span class="Underlined">local</span>-scope - <span class="Identifier">in</span>:address:stream<span class="Special"> <- </span>next-ingredient - idx:address:number<span class="Special"> <- </span>get-address *<span class="Identifier">in</span>, index:offset - s:address:<span class="Identifier">array</span>:character<span class="Special"> <- </span>get *<span class="Identifier">in</span>, data:offset - next-idx:number<span class="Special"> <- </span>find-next s, 10/newline, *idx - result:address:<span class="Identifier">array</span>:character<span class="Special"> <- </span>string-<span class="Identifier">copy</span> s, *idx, next-idx - *idx<span class="Special"> <- </span>add next-idx, 1 <span class="Comment"># skip newline</span> - reply result +<span class="muRecipe">recipe</span> read-line [ + <span class="Constant">local-scope</span> + in:address:stream<span class="Special"> <- </span><span class="Constant">next-ingredient</span> + idx:address:number<span class="Special"> <- </span>get-address *in, <span class="Constant">index:offset</span> + s:address:array:character<span class="Special"> <- </span>get *in, <span class="Constant">data:offset</span> + next-idx:number<span class="Special"> <- </span>find-next s, <span class="Constant">10/newline</span>, *idx + result:address:array:character<span class="Special"> <- </span>string-copy s, *idx, next-idx + *idx<span class="Special"> <- </span>add next-idx, <span class="Constant">1</span> <span class="Comment"># skip newline</span> + <span class="muControl">reply</span> result ] -recipe end-of-stream? [ - <span class="Underlined">local</span>-scope - <span class="Identifier">in</span>:address:stream<span class="Special"> <- </span>next-ingredient - idx:address:number<span class="Special"> <- </span>get *<span class="Identifier">in</span>, index:offset - s:address:<span class="Identifier">array</span>:character<span class="Special"> <- </span>get *<span class="Identifier">in</span>, data:offset - len:number<span class="Special"> <- </span><span class="Identifier">length</span> *s +<span class="muRecipe">recipe</span> end-of-stream? [ + <span class="Constant">local-scope</span> + in:address:stream<span class="Special"> <- </span><span class="Constant">next-ingredient</span> + idx:address:number<span class="Special"> <- </span>get *in, <span class="Constant">index:offset</span> + s:address:array:character<span class="Special"> <- </span>get *in, <span class="Constant">data:offset</span> + len:number<span class="Special"> <- </span>length *s result:boolean<span class="Special"> <- </span>greater-or-equal idx, len - reply result + <span class="muControl">reply</span> result ] </pre> </body> diff --git a/html/071print.mu.html b/html/071print.mu.html index ce70d068..c4334f55 100644 --- a/html/071print.mu.html +++ b/html/071print.mu.html @@ -13,10 +13,14 @@ 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; } -.Special { color: #ff6060; } +.muRecipe { color: #ff8700; } +.muData { color: #ffff00; } +.muScenario { color: #00af00; } .Comment { color: #9090ff; } -.Underlined { color: #c000c0; text-decoration: underline; } -.Identifier { color: #804000; } +.Constant { color: #00a0a0; } +.Special { color: #ff6060; } +.Delimiter { color: #a04060; } +.muControl { color: #c0a020; } --> </style> @@ -31,686 +35,686 @@ body { font-family: monospace; color: #eeeeee; background-color: #080808; } <span class="Comment"># Wrappers around print primitives that take a 'screen' object and are thus</span> <span class="Comment"># easier to test.</span> -container screen [ +<span class="muData">container</span> screen [ num-rows:number num-columns:number cursor-row:number cursor-column:number - data:address:<span class="Identifier">array</span>:screen-cell + data:address:array:screen-cell ] -container screen-cell [ +<span class="muData">container</span> screen-cell [ contents:character color:number ] -recipe <span class="Identifier">new</span>-fake-screen [ - <span class="Underlined">local</span>-scope - result:address:screen<span class="Special"> <- </span><span class="Identifier">new</span> screen:<span class="Identifier">type</span> - width:address:number<span class="Special"> <- </span>get-address *result, num-columns:offset - *width<span class="Special"> <- </span>next-ingredient - height:address:number<span class="Special"> <- </span>get-address *result, num-rows:offset - *height<span class="Special"> <- </span>next-ingredient - row:address:number<span class="Special"> <- </span>get-address *result, cursor-row:offset - *row<span class="Special"> <- </span><span class="Identifier">copy</span> 0 - column:address:number<span class="Special"> <- </span>get-address *result, cursor-column:offset - *column<span class="Special"> <- </span><span class="Identifier">copy</span> 0 +<span class="muRecipe">recipe</span> new-fake-screen [ + <span class="Constant">local-scope</span> + result:address:screen<span class="Special"> <- </span>new <span class="Constant">screen:type</span> + width:address:number<span class="Special"> <- </span>get-address *result, <span class="Constant">num-columns:offset</span> + *width<span class="Special"> <- </span><span class="Constant">next-ingredient</span> + height:address:number<span class="Special"> <- </span>get-address *result, <span class="Constant">num-rows:offset</span> + *height<span class="Special"> <- </span><span class="Constant">next-ingredient</span> + row:address:number<span class="Special"> <- </span>get-address *result, <span class="Constant">cursor-row:offset</span> + *row<span class="Special"> <- </span>copy <span class="Constant">0</span> + column:address:number<span class="Special"> <- </span>get-address *result, <span class="Constant">cursor-column:offset</span> + *column<span class="Special"> <- </span>copy <span class="Constant">0</span> bufsize:number<span class="Special"> <- </span>multiply *width, *height - buf:address:address:<span class="Identifier">array</span>:screen-cell<span class="Special"> <- </span>get-address *result, data:offset - *buf<span class="Special"> <- </span><span class="Identifier">new</span> screen-cell:<span class="Identifier">type</span>, bufsize + buf:address:address:array:screen-cell<span class="Special"> <- </span>get-address *result, <span class="Constant">data:offset</span> + *buf<span class="Special"> <- </span>new <span class="Constant">screen-cell:type</span>, bufsize clear-screen result - reply result + <span class="muControl">reply</span> result ] -recipe clear-screen [ - <span class="Underlined">local</span>-scope - sc:address:screen<span class="Special"> <- </span>next-ingredient +<span class="muRecipe">recipe</span> clear-screen [ + <span class="Constant">local-scope</span> + sc:address:screen<span class="Special"> <- </span><span class="Constant">next-ingredient</span> <span class="Comment"># if x exists</span> - { - break-unless sc + <span class="Delimiter">{</span> + <span class="muControl">break-unless</span> sc <span class="Comment"># clear fake screen</span> - buf:address:<span class="Identifier">array</span>:screen-cell<span class="Special"> <- </span>get *sc, data:offset - <span class="Identifier">max</span>:number<span class="Special"> <- </span><span class="Identifier">length</span> *buf - i:number<span class="Special"> <- </span><span class="Identifier">copy</span> 0 - { - done?:boolean<span class="Special"> <- </span>greater-or-equal i, <span class="Identifier">max</span> - break-if done? + buf:address:array:screen-cell<span class="Special"> <- </span>get *sc, <span class="Constant">data:offset</span> + max:number<span class="Special"> <- </span>length *buf + i:number<span class="Special"> <- </span>copy <span class="Constant">0</span> + <span class="Delimiter">{</span> + done?:boolean<span class="Special"> <- </span>greater-or-equal i, max + <span class="muControl">break-if</span> done? curr:address:screen-cell<span class="Special"> <- </span>index-address *buf, i - curr-<span class="Identifier">content</span>:address:character<span class="Special"> <- </span>get-address *curr, contents:offset - *curr-<span class="Identifier">content</span><span class="Special"> <- </span><span class="Identifier">copy</span> [ ] - curr-color:address:character<span class="Special"> <- </span>get-address *curr, color:offset - *curr-color<span class="Special"> <- </span><span class="Identifier">copy</span> 7/white - i<span class="Special"> <- </span>add i, 1 - loop - } + curr-content:address:character<span class="Special"> <- </span>get-address *curr, <span class="Constant">contents:offset</span> + *curr-content<span class="Special"> <- </span>copy <span class="Constant">[ ]</span> + curr-color:address:character<span class="Special"> <- </span>get-address *curr, <span class="Constant">color:offset</span> + *curr-color<span class="Special"> <- </span>copy <span class="Constant">7/white</span> + i<span class="Special"> <- </span>add i, <span class="Constant">1</span> + <span class="muControl">loop</span> + <span class="Delimiter">}</span> <span class="Comment"># reset cursor</span> - x:address:number<span class="Special"> <- </span>get-address *sc, cursor-row:offset - *x<span class="Special"> <- </span><span class="Identifier">copy</span> 0 - x<span class="Special"> <- </span>get-address *sc, cursor-column:offset - *x<span class="Special"> <- </span><span class="Identifier">copy</span> 0 - reply sc/same-as-ingredient:0 - } + x:address:number<span class="Special"> <- </span>get-address *sc, <span class="Constant">cursor-row:offset</span> + *x<span class="Special"> <- </span>copy <span class="Constant">0</span> + x<span class="Special"> <- </span>get-address *sc, <span class="Constant">cursor-column:offset</span> + *x<span class="Special"> <- </span>copy <span class="Constant">0</span> + <span class="muControl">reply</span> sc/same-as-ingredient:<span class="Constant">0</span> + <span class="Delimiter">}</span> <span class="Comment"># otherwise, real screen</span> clear-display - reply sc/same-as-ingredient:0 + <span class="muControl">reply</span> sc/same-as-ingredient:<span class="Constant">0</span> ] -recipe sync-screen [ - <span class="Underlined">local</span>-scope - sc:address:screen<span class="Special"> <- </span>next-ingredient - { - break-if sc +<span class="muRecipe">recipe</span> sync-screen [ + <span class="Constant">local-scope</span> + sc:address:screen<span class="Special"> <- </span><span class="Constant">next-ingredient</span> + <span class="Delimiter">{</span> + <span class="muControl">break-if</span> sc sync-display - } + <span class="Delimiter">}</span> <span class="Comment"># do nothing for fake screens</span> ] -recipe fake-screen-<span class="Identifier">is</span>-empty? [ - <span class="Underlined">local</span>-scope - sc:address:screen<span class="Special"> <- </span>next-ingredient - reply-unless sc, 1/true - buf:address:<span class="Identifier">array</span>:screen-cell<span class="Special"> <- </span>get *sc, data:offset - i:number<span class="Special"> <- </span><span class="Identifier">copy</span> 0 - len:number<span class="Special"> <- </span><span class="Identifier">length</span> *buf - { +<span class="muRecipe">recipe</span> fake-screen-is-empty? [ + <span class="Constant">local-scope</span> + sc:address:screen<span class="Special"> <- </span><span class="Constant">next-ingredient</span> + <span class="muControl">reply-unless</span> sc, <span class="Constant">1/true</span> + buf:address:array:screen-cell<span class="Special"> <- </span>get *sc, <span class="Constant">data:offset</span> + i:number<span class="Special"> <- </span>copy <span class="Constant">0</span> + len:number<span class="Special"> <- </span>length *buf + <span class="Delimiter">{</span> done?:boolean<span class="Special"> <- </span>greater-or-equal i, len - break-if done? + <span class="muControl">break-if</span> done? curr:screen-cell<span class="Special"> <- </span>index *buf, i - curr-contents:character<span class="Special"> <- </span>get curr, contents:offset - i<span class="Special"> <- </span>add i, 1 - loop-unless curr-contents + curr-contents:character<span class="Special"> <- </span>get curr, <span class="Constant">contents:offset</span> + i<span class="Special"> <- </span>add i, <span class="Constant">1</span> + <span class="muControl">loop-unless</span> curr-contents <span class="Comment"># not 0</span> - reply 0/false - } - reply 1/true + <span class="muControl">reply</span> <span class="Constant">0/false</span> + <span class="Delimiter">}</span> + <span class="muControl">reply</span> <span class="Constant">1/true</span> ] -recipe <span class="Identifier">print</span>-character [ - <span class="Underlined">local</span>-scope - sc:address:screen<span class="Special"> <- </span>next-ingredient - c:character<span class="Special"> <- </span>next-ingredient - color:number, color-found?:boolean<span class="Special"> <- </span>next-ingredient - { +<span class="muRecipe">recipe</span> print-character [ + <span class="Constant">local-scope</span> + sc:address:screen<span class="Special"> <- </span><span class="Constant">next-ingredient</span> + c:character<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> - break-if color-found? - color<span class="Special"> <- </span><span class="Identifier">copy</span> 7/white - } - bg-color:number, bg-color-found?:boolean<span class="Special"> <- </span>next-ingredient - { + <span class="muControl">break-if</span> color-found? + color<span class="Special"> <- </span>copy <span class="Constant">7/white</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="Comment"># default bg-color to black</span> - break-if bg-color-found? - bg-color<span class="Special"> <- </span><span class="Identifier">copy</span> 0/black - } - trace 90, [<span class="Identifier">print</span>-character], c - { + <span class="muControl">break-if</span> bg-color-found? + bg-color<span class="Special"> <- </span>copy <span class="Constant">0/black</span> + <span class="Delimiter">}</span> + trace <span class="Constant">90</span>, <span class="Constant">[print-character]</span>, c + <span class="Delimiter">{</span> <span class="Comment"># if x exists</span> <span class="Comment"># (handle special cases exactly like in the real screen)</span> - break-unless sc - width:number<span class="Special"> <- </span>get *sc, num-columns:offset - height:number<span class="Special"> <- </span>get *sc, num-rows:offset + <span class="muControl">break-unless</span> sc + width:number<span class="Special"> <- </span>get *sc, <span class="Constant">num-columns:offset</span> + height:number<span class="Special"> <- </span>get *sc, <span class="Constant">num-rows:offset</span> <span class="Comment"># if cursor is out of bounds, silently exit</span> - row:address:number<span class="Special"> <- </span>get-address *sc, cursor-row:offset - legal?:boolean<span class="Special"> <- </span>greater-or-equal *row, 0 - reply-unless legal?, sc + row:address:number<span class="Special"> <- </span>get-address *sc, <span class="Constant">cursor-row:offset</span> + legal?:boolean<span class="Special"> <- </span>greater-or-equal *row, <span class="Constant">0</span> + <span class="muControl">reply-unless</span> legal?, sc legal?<span class="Special"> <- </span>lesser-than *row, height - reply-unless legal?, sc - column:address:number<span class="Special"> <- </span>get-address *sc, cursor-column:offset - legal?<span class="Special"> <- </span>greater-or-equal *column, 0 - reply-unless legal?, sc + <span class="muControl">reply-unless</span> legal?, sc + column:address:number<span class="Special"> <- </span>get-address *sc, <span class="Constant">cursor-column:offset</span> + legal?<span class="Special"> <- </span>greater-or-equal *column, <span class="Constant">0</span> + <span class="muControl">reply-unless</span> legal?, sc legal?<span class="Special"> <- </span>lesser-than *column, width - reply-unless legal?, sc + <span class="muControl">reply-unless</span> legal?, sc <span class="Comment"># special-case: newline</span> - { - newline?:boolean<span class="Special"> <- </span>equal c, 10/newline - break-unless newline? - { + <span class="Delimiter">{</span> + newline?:boolean<span class="Special"> <- </span>equal c, <span class="Constant">10/newline</span> + <span class="muControl">break-unless</span> newline? + <span class="Delimiter">{</span> <span class="Comment"># unless cursor is already at bottom</span> - bottom:number<span class="Special"> <- </span>subtract height, 1 + bottom:number<span class="Special"> <- </span>subtract height, <span class="Constant">1</span> at-bottom?:boolean<span class="Special"> <- </span>greater-or-equal *row, bottom - break-if at-bottom? + <span class="muControl">break-if</span> at-bottom? <span class="Comment"># move it to the next row</span> - *column<span class="Special"> <- </span><span class="Identifier">copy</span> 0 - *row<span class="Special"> <- </span>add *row, 1 - } - reply sc/same-as-ingredient:0 - } + *column<span class="Special"> <- </span>copy <span class="Constant">0</span> + *row<span class="Special"> <- </span>add *row, <span class="Constant">1</span> + <span class="Delimiter">}</span> + <span class="muControl">reply</span> sc/same-as-ingredient:<span class="Constant">0</span> + <span class="Delimiter">}</span> <span class="Comment"># save character in fake screen</span> index:number<span class="Special"> <- </span>multiply *row, width index<span class="Special"> <- </span>add index, *column - buf:address:<span class="Identifier">array</span>:screen-cell<span class="Special"> <- </span>get *sc, data:offset - len:number<span class="Special"> <- </span><span class="Identifier">length</span> *buf + buf:address:array:screen-cell<span class="Special"> <- </span>get *sc, <span class="Constant">data:offset</span> + len:number<span class="Special"> <- </span>length *buf <span class="Comment"># special-case: backspace</span> - { - backspace?:boolean<span class="Special"> <- </span>equal c, 8 - break-unless backspace? - { + <span class="Delimiter">{</span> + backspace?:boolean<span class="Special"> <- </span>equal c, <span class="Constant">8</span> + <span class="muControl">break-unless</span> backspace? + <span class="Delimiter">{</span> <span class="Comment"># unless cursor is already at left margin</span> - at-left?:boolean<span class="Special"> <- </span>lesser-or-equal *column, 0 - break-if at-left? + at-left?:boolean<span class="Special"> <- </span>lesser-or-equal *column, <span class="Constant">0</span> + <span class="muControl">break-if</span> at-left? <span class="Comment"># clear previous location</span> - *column<span class="Special"> <- </span>subtract *column, 1 - index<span class="Special"> <- </span>subtract index, 1 + *column<span class="Special"> <- </span>subtract *column, <span class="Constant">1</span> + index<span class="Special"> <- </span>subtract index, <span class="Constant">1</span> cursor:address:screen-cell<span class="Special"> <- </span>index-address *buf, index - cursor-contents:address:character<span class="Special"> <- </span>get-address *cursor, contents:offset - *cursor-contents<span class="Special"> <- </span><span class="Identifier">copy</span> 32/space - cursor-color:address:number<span class="Special"> <- </span>get-address *cursor, color:offset - *cursor-color<span class="Special"> <- </span><span class="Identifier">copy</span> 7/white - } - reply sc/same-as-ingredient:0 - } + cursor-contents:address:character<span class="Special"> <- </span>get-address *cursor, <span class="Constant">contents:offset</span> + *cursor-contents<span class="Special"> <- </span>copy <span class="Constant">32/space</span> + cursor-color:address:number<span class="Special"> <- </span>get-address *cursor, <span class="Constant">color:offset</span> + *cursor-color<span class="Special"> <- </span>copy <span class="Constant">7/white</span> + <span class="Delimiter">}</span> + <span class="muControl">reply</span> sc/same-as-ingredient:<span class="Constant">0</span> + <span class="Delimiter">}</span> cursor:address:screen-cell<span class="Special"> <- </span>index-address *buf, index - cursor-contents:address:character<span class="Special"> <- </span>get-address *cursor, contents:offset - *cursor-contents<span class="Special"> <- </span><span class="Identifier">copy</span> c - cursor-color:address:number<span class="Special"> <- </span>get-address *cursor, color:offset - *cursor-color<span class="Special"> <- </span><span class="Identifier">copy</span> color + cursor-contents:address:character<span class="Special"> <- </span>get-address *cursor, <span class="Constant">contents:offset</span> + *cursor-contents<span class="Special"> <- </span>copy c + cursor-color:address:number<span class="Special"> <- </span>get-address *cursor, <span class="Constant">color:offset</span> + *cursor-color<span class="Special"> <- </span>copy color <span class="Comment"># increment column unless it's already all the way to the right</span> - { - right:number<span class="Special"> <- </span>subtract width, 1 + <span class="Delimiter">{</span> + right:number<span class="Special"> <- </span>subtract width, <span class="Constant">1</span> at-right?:boolean<span class="Special"> <- </span>greater-or-equal *column, right - break-if at-right? - *column<span class="Special"> <- </span>add *column, 1 - } - reply sc/same-as-ingredient:0 - } + <span class="muControl">break-if</span> at-right? + *column<span class="Special"> <- </span>add *column, <span class="Constant">1</span> + <span class="Delimiter">}</span> + <span class="muControl">reply</span> sc/same-as-ingredient:<span class="Constant">0</span> + <span class="Delimiter">}</span> <span class="Comment"># otherwise, real screen</span> - <span class="Identifier">print</span>-character-to-display c, color, bg-color - reply sc/same-as-ingredient:0 + print-character-to-display c, color, bg-color + <span class="muControl">reply</span> sc/same-as-ingredient:<span class="Constant">0</span> ] -scenario <span class="Identifier">print</span>-character-at-top-left [ +<span class="muScenario">scenario</span> print-character-at-top-left [ run [ - 1:address:screen<span class="Special"> <- </span><span class="Identifier">new</span>-fake-screen 3/width, 2/height - 1:address:screen<span class="Special"> <- </span><span class="Identifier">print</span>-character 1:address:screen, 97 <span class="Comment"># 'a'</span> - 2:address:<span class="Identifier">array</span>:screen-cell<span class="Special"> <- </span>get *1:address:screen, data:offset - 3:<span class="Identifier">array</span>:screen-cell<span class="Special"> <- </span><span class="Identifier">copy</span> *2:address:<span class="Identifier">array</span>:screen-cell + <span class="Constant">1</span>:address:screen<span class="Special"> <- </span>new-fake-screen <span class="Constant">3/width</span>, <span class="Constant">2/height</span> + <span class="Constant">1</span>:address:screen<span class="Special"> <- </span>print-character <span class="Constant">1</span>:address:screen, <span class="Constant">97</span> <span class="Comment"># 'a'</span> + <span class="Constant">2</span>:address:array:screen-cell<span class="Special"> <- </span>get *<span class="Constant">1</span>:address:screen, <span class="Constant">data:offset</span> + <span class="Constant">3</span>:array:screen-cell<span class="Special"> <- </span>copy *<span class="Constant">2</span>:address:array:screen-cell ] memory-should-contain [ - 3<span class="Special"> <- </span>6 <span class="Comment"># width*height</span> - 4<span class="Special"> <- </span>97 <span class="Comment"># 'a'</span> - 5<span class="Special"> <- </span>7 <span class="Comment"># white</span> - 6<span class="Special"> <- </span>0 + <span class="Constant">3</span><span class="Special"> <- </span><span class="Constant">6</span> <span class="Comment"># width*height</span> + <span class="Constant">4</span><span class="Special"> <- </span><span class="Constant">97</span> <span class="Comment"># 'a'</span> + <span class="Constant">5</span><span class="Special"> <- </span><span class="Constant">7</span> <span class="Comment"># white</span> + <span class="Constant">6</span><span class="Special"> <- </span><span class="Constant">0</span> ] ] -scenario <span class="Identifier">print</span>-character-color [ +<span class="muScenario">scenario</span> print-character-color [ run [ - 1:address:screen<span class="Special"> <- </span><span class="Identifier">new</span>-fake-screen 3/width, 2/height - 1:address:screen<span class="Special"> <- </span><span class="Identifier">print</span>-character 1:address:screen, 97/a, 1/red - 2:address:<span class="Identifier">array</span>:screen-cell<span class="Special"> <- </span>get *1:address:screen, data:offset - 3:<span class="Identifier">array</span>:screen-cell<span class="Special"> <- </span><span class="Identifier">copy</span> *2:address:<span class="Identifier">array</span>:screen-cell + <span class="Constant">1</span>:address:screen<span class="Special"> <- </span>new-fake-screen <span class="Constant">3/width</span>, <span class="Constant">2/height</span> + <span class="Constant">1</span>:address:screen<span class="Special"> <- </span>print-character <span class="Constant">1</span>:address:screen, <span class="Constant">97/a</span>, <span class="Constant">1/red</span> + <span class="Constant">2</span>:address:array:screen-cell<span class="Special"> <- </span>get *<span class="Constant">1</span>:address:screen, <span class="Constant">data:offset</span> + <span class="Constant">3</span>:array:screen-cell<span class="Special"> <- </span>copy *<span class="Constant">2</span>:address:array:screen-cell ] memory-should-contain [ - 3<span class="Special"> <- </span>6 <span class="Comment"># width*height</span> - 4<span class="Special"> <- </span>97 <span class="Comment"># 'a'</span> - 5<span class="Special"> <- </span>1 <span class="Comment"># red</span> - 6<span class="Special"> <- </span>0 + <span class="Constant">3</span><span class="Special"> <- </span><span class="Constant">6</span> <span class="Comment"># width*height</span> + <span class="Constant">4</span><span class="Special"> <- </span><span class="Constant">97</span> <span class="Comment"># 'a'</span> + <span class="Constant">5</span><span class="Special"> <- </span><span class="Constant">1</span> <span class="Comment"># red</span> + <span class="Constant">6</span><span class="Special"> <- </span><span class="Constant">0</span> ] ] -scenario <span class="Identifier">print</span>-backspace-character [ +<span class="muScenario">scenario</span> print-backspace-character [ run [ - 1:address:screen<span class="Special"> <- </span><span class="Identifier">new</span>-fake-screen 3/width, 2/height - 1:address:screen<span class="Special"> <- </span><span class="Identifier">print</span>-character 1:address:screen, 97 <span class="Comment"># 'a'</span> - 1:address:screen<span class="Special"> <- </span><span class="Identifier">print</span>-character 1:address:screen, 8 <span class="Comment"># backspace</span> - 2:number<span class="Special"> <- </span>get *1:address:screen, cursor-column:offset - 3:address:<span class="Identifier">array</span>:screen-cell<span class="Special"> <- </span>get *1:address:screen, data:offset - 4:<span class="Identifier">array</span>:screen-cell<span class="Special"> <- </span><span class="Identifier">copy</span> *3:address:<span class="Identifier">array</span>:screen-cell + <span class="Constant">1</span>:address:screen<span class="Special"> <- </span>new-fake-screen <span class="Constant">3/width</span>, <span class="Constant">2/height</span> + <span class="Constant">1</span>:address:screen<span class="Special"> <- </span>print-character <span class="Constant">1</span>:address:screen, <span class="Constant">97</span> <span class="Comment"># 'a'</span> + <span class="Constant">1</span>:address:screen<span class="Special"> <- </span>print-character <span class="Constant">1</span>:address:screen, <span class="Constant">8</span> <span class="Comment"># backspace</span> + <span class="Constant">2</span>:number<span class="Special"> <- </span>get *<span class="Constant">1</span>:address:screen, <span class="Constant">cursor-column:offset</span> + <span class="Constant">3</span>:address:array:screen-cell<span class="Special"> <- </span>get *<span class="Constant">1</span>:address:screen, <span class="Constant">data:offset</span> + <span class="Constant">4</span>:array:screen-cell<span class="Special"> <- </span>copy *<span class="Constant">3</span>:address:array:screen-cell ] memory-should-contain [ - 2<span class="Special"> <- </span>0 <span class="Comment"># cursor column</span> - 4<span class="Special"> <- </span>6 <span class="Comment"># width*height</span> - 5<span class="Special"> <- </span>32 <span class="Comment"># space, not 'a'</span> - 6<span class="Special"> <- </span>7 <span class="Comment"># white</span> - 7<span class="Special"> <- </span>0 + <span class="Constant">2</span><span class="Special"> <- </span><span class="Constant">0</span> <span class="Comment"># cursor column</span> + <span class="Constant">4</span><span class="Special"> <- </span><span class="Constant">6</span> <span class="Comment"># width*height</span> + <span class="Constant">5</span><span class="Special"> <- </span><span class="Constant">32</span> <span class="Comment"># space, not 'a'</span> + <span class="Constant">6</span><span class="Special"> <- </span><span class="Constant">7</span> <span class="Comment"># white</span> + <span class="Constant">7</span><span class="Special"> <- </span><span class="Constant">0</span> ] ] -scenario <span class="Identifier">print</span>-extra-backspace-character [ +<span class="muScenario">scenario</span> print-extra-backspace-character [ run [ - 1:address:screen<span class="Special"> <- </span><span class="Identifier">new</span>-fake-screen 3/width, 2/height - 1:address:screen<span class="Special"> <- </span><span class="Identifier">print</span>-character 1:address:screen, 97 <span class="Comment"># 'a'</span> - 1:address:screen<span class="Special"> <- </span><span class="Identifier">print</span>-character 1:address:screen, 8 <span class="Comment"># backspace</span> - 1:address:screen<span class="Special"> <- </span><span class="Identifier">print</span>-character 1:address:screen, 8 <span class="Comment"># backspace</span> - 2:number<span class="Special"> <- </span>get *1:address:screen, cursor-column:offset - 3:address:<span class="Identifier">array</span>:screen-cell<span class="Special"> <- </span>get *1:address:screen, data:offset - 4:<span class="Identifier">array</span>:screen-cell<span class="Special"> <- </span><span class="Identifier">copy</span> *3:address:<span class="Identifier">array</span>:screen-cell + <span class="Constant">1</span>:address:screen<span class="Special"> <- </span>new-fake-screen <span class="Constant">3/width</span>, <span class="Constant">2/height</span> + <span class="Constant">1</span>:address:screen<span class="Special"> <- </span>print-character <span class="Constant">1</span>:address:screen, <span class="Constant">97</span> <span class="Comment"># 'a'</span> + <span class="Constant">1</span>:address:screen<span class="Special"> <- </span>print-character <span class="Constant">1</span>:address:screen, <span class="Constant">8</span> <span class="Comment"># backspace</span> + <span class="Constant">1</span>:address:screen<span class="Special"> <- </span>print-character <span class="Constant">1</span>:address:screen, <span class="Constant">8</span> <span class="Comment"># backspace</span> + <span class="Constant">2</span>:number<span class="Special"> <- </span>get *<span class="Constant">1</span>:address:screen, <span class="Constant">cursor-column:offset</span> + <span class="Constant">3</span>:address:array:screen-cell<span class="Special"> <- </span>get *<span class="Constant">1</span>:address:screen, <span class="Constant">data:offset</span> + <span class="Constant">4</span>:array:screen-cell<span class="Special"> <- </span>copy *<span class="Constant">3</span>:address:array:screen-cell ] memory-should-contain [ - 2<span class="Special"> <- </span>0 <span class="Comment"># cursor column</span> - 4<span class="Special"> <- </span>6 <span class="Comment"># width*height</span> - 5<span class="Special"> <- </span>32 <span class="Comment"># space, not 'a'</span> - 6<span class="Special"> <- </span>7 <span class="Comment"># white</span> - 7<span class="Special"> <- </span>0 + <span class="Constant">2</span><span class="Special"> <- </span><span class="Constant">0</span> <span class="Comment"># cursor column</span> + <span class="Constant">4</span><span class="Special"> <- </span><span class="Constant">6</span> <span class="Comment"># width*height</span> + <span class="Constant">5</span><span class="Special"> <- </span><span class="Constant">32</span> <span class="Comment"># space, not 'a'</span> + <span class="Constant">6</span><span class="Special"> <- </span><span class="Constant">7</span> <span class="Comment"># white</span> + <span class="Constant">7</span><span class="Special"> <- </span><span class="Constant">0</span> ] ] -scenario <span class="Identifier">print</span>-at-right-margin [ +<span class="muScenario">scenario</span> print-at-right-margin [ run [ - 1:address:screen<span class="Special"> <- </span><span class="Identifier">new</span>-fake-screen 2/width, 2/height - 1:address:screen<span class="Special"> <- </span><span class="Identifier">print</span>-character 1:address:screen, 97 <span class="Comment"># 'a'</span> - 1:address:screen<span class="Special"> <- </span><span class="Identifier">print</span>-character 1:address:screen, 98 <span class="Comment"># 'b'</span> - 1:address:screen<span class="Special"> <- </span><span class="Identifier">print</span>-character 1:address:screen, 99 <span class="Comment"># 'c'</span> - 2:number<span class="Special"> <- </span>get *1:address:screen, cursor-column:offset - 3:address:<span class="Identifier">array</span>:screen-cell<span class="Special"> <- </span>get *1:address:screen, data:offset - 4:<span class="Identifier">array</span>:screen-cell<span class="Special"> <- </span><span class="Identifier">copy</span> *3:address:<span class="Identifier">array</span>:screen-cell + <span class="Constant">1</span>:address:screen<span class="Special"> <- </span>new-fake-screen <span class="Constant">2/width</span>, <span class="Constant">2/height</span> + <span class="Constant">1</span>:address:screen<span class="Special"> <- </span>print-character <span class="Constant">1</span>:address:screen, <span class="Constant">97</span> <span class="Comment"># 'a'</span> + <span class="Constant">1</span>:address:screen<span class="Special"> <- </span>print-character <span class="Constant">1</span>:address:screen, <span class="Constant">98</span> <span class="Comment"># 'b'</span> + <span class="Constant">1</span>:address:screen<span class="Special"> <- </span>print-character <span class="Constant">1</span>:address:screen, <span class="Constant">99</span> <span class="Comment"># 'c'</span> + <span class="Constant">2</span>:number<span class="Special"> <- </span>get *<span class="Constant">1</span>:address:screen, <span class="Constant">cursor-column:offset</span> + <span class="Constant">3</span>:address:array:screen-cell<span class="Special"> <- </span>get *<span class="Constant">1</span>:address:screen, <span class="Constant">data:offset</span> + <span class="Constant">4</span>:array:screen-cell<span class="Special"> <- </span>copy *<span class="Constant">3</span>:address:array:screen-cell ] memory-should-contain [ - 2<span class="Special"> <- </span>1 <span class="Comment"># cursor column</span> - 4<span class="Special"> <- </span>4 <span class="Comment"># width*height</span> - 5<span class="Special"> <- </span>97 <span class="Comment"># 'a'</span> - 6<span class="Special"> <- </span>7 <span class="Comment"># white</span> - 7<span class="Special"> <- </span>99 <span class="Comment"># 'c' over 'b'</span> - 8<span class="Special"> <- </span>7 <span class="Comment"># white</span> - 9<span class="Special"> <- </span>0 + <span class="Constant">2</span><span class="Special"> <- </span><span class="Constant">1</span> <span class="Comment"># cursor column</span> + <span class="Constant">4</span><span class="Special"> <- </span><span class="Constant">4</span> <span class="Comment"># width*height</span> + <span class="Constant">5</span><span class="Special"> <- </span><span class="Constant">97</span> <span class="Comment"># 'a'</span> + <span class="Constant">6</span><span class="Special"> <- </span><span class="Constant">7</span> <span class="Comment"># white</span> + <span class="Constant">7</span><span class="Special"> <- </span><span class="Constant">99</span> <span class="Comment"># 'c' over 'b'</span> + <span class="Constant">8</span><span class="Special"> <- </span><span class="Constant">7</span> <span class="Comment"># white</span> + <span class="Constant">9</span><span class="Special"> <- </span><span class="Constant">0</span> ] ] -scenario <span class="Identifier">print</span>-newline-character [ +<span class="muScenario">scenario</span> print-newline-character [ run [ - 1:address:screen<span class="Special"> <- </span><span class="Identifier">new</span>-fake-screen 3/width, 2/height - 1:address:screen<span class="Special"> <- </span><span class="Identifier">print</span>-character 1:address:screen, 97 <span class="Comment"># 'a'</span> - 1:address:screen<span class="Special"> <- </span><span class="Identifier">print</span>-character 1:address:screen, 10/newline - 2:number<span class="Special"> <- </span>get *1:address:screen, cursor-row:offset - 3:number<span class="Special"> <- </span>get *1:address:screen, cursor-column:offset - 4:address:<span class="Identifier">array</span>:screen-cell<span class="Special"> <- </span>get *1:address:screen, data:offset - 5:<span class="Identifier">array</span>:screen-cell<span class="Special"> <- </span><span class="Identifier">copy</span> *4:address:<span class="Identifier">array</span>:screen-cell + <span class="Constant">1</span>:address:screen<span class="Special"> <- </span>new-fake-screen <span class="Constant">3/width</span>, <span class="Constant">2/height</span> + <span class="Constant">1</span>:address:screen<span class="Special"> <- </span>print-character <span class="Constant">1</span>:address:screen, <span class="Constant">97</span> <span class="Comment"># 'a'</span> + <span class="Constant">1</span>:address:screen<span class="Special"> <- </span>print-character <span class="Constant">1</span>:address:screen, <span class="Constant">10/newline</span> + <span class="Constant">2</span>:number<span class="Special"> <- </span>get *<span class="Constant">1</span>:address:screen, <span class="Constant">cursor-row:offset</span> + <span class="Constant">3</span>:number<span class="Special"> <- </span>get *<span class="Constant">1</span>:address:screen, <span class="Constant">cursor-column:offset</span> + <span class="Constant">4</span>:address:array:screen-cell<span class="Special"> <- </span>get *<span class="Constant">1</span>:address:screen, <span class="Constant">data:offset</span> + <span class="Constant">5</span>:array:screen-cell<span class="Special"> <- </span>copy *<span class="Constant">4</span>:address:array:screen-cell ] memory-should-contain [ - 2<span class="Special"> <- </span>1 <span class="Comment"># cursor row</span> - 3<span class="Special"> <- </span>0 <span class="Comment"># cursor column</span> - 5<span class="Special"> <- </span>6 <span class="Comment"># width*height</span> - 6<span class="Special"> <- </span>97 <span class="Comment"># 'a'</span> - 7<span class="Special"> <- </span>7 <span class="Comment"># white</span> - 8<span class="Special"> <- </span>0 + <span class="Constant">2</span><span class="Special"> <- </span><span class="Constant">1</span> <span class="Comment"># cursor row</span> + <span class="Constant">3</span><span class="Special"> <- </span><span class="Constant">0</span> <span class="Comment"># cursor column</span> + <span class="Constant">5</span><span class="Special"> <- </span><span class="Constant">6</span> <span class="Comment"># width*height</span> + <span class="Constant">6</span><span class="Special"> <- </span><span class="Constant">97</span> <span class="Comment"># 'a'</span> + <span class="Constant">7</span><span class="Special"> <- </span><span class="Constant">7</span> <span class="Comment"># white</span> + <span class="Constant">8</span><span class="Special"> <- </span><span class="Constant">0</span> ] ] -scenario <span class="Identifier">print</span>-newline-at-bottom-line [ +<span class="muScenario">scenario</span> print-newline-at-bottom-line [ run [ - 1:address:screen<span class="Special"> <- </span><span class="Identifier">new</span>-fake-screen 3/width, 2/height - 1:address:screen<span class="Special"> <- </span><span class="Identifier">print</span>-character 1:address:screen, 10/newline - 1:address:screen<span class="Special"> <- </span><span class="Identifier">print</span>-character 1:address:screen, 10/newline - 1:address:screen<span class="Special"> <- </span><span class="Identifier">print</span>-character 1:address:screen, 10/newline - 2:number<span class="Special"> <- </span>get *1:address:screen, cursor-row:offset - 3:number<span class="Special"> <- </span>get *1:address:screen, cursor-column:offset + <span class="Constant">1</span>:address:screen<span class="Special"> <- </span>new-fake-screen <span class="Constant">3/width</span>, <span class="Constant">2/height</span> + <span class="Constant">1</span>:address:screen<span class="Special"> <- </span>print-character <span class="Constant">1</span>:address:screen, <span class="Constant">10/newline</span> + <span class="Constant">1</span>:address:screen<span class="Special"> <- </span>print-character <span class="Constant">1</span>:address:screen, <span class="Constant">10/newline</span> + <span class="Constant">1</span>:address:screen<span class="Special"> <- </span>print-character <span class="Constant">1</span>:address:screen, <span class="Constant">10/newline</span> + <span class="Constant">2</span>:number<span class="Special"> <- </span>get *<span class="Constant">1</span>:address:screen, <span class="Constant">cursor-row:offset</span> + <span class="Constant">3</span>:number<span class="Special"> <- </span>get *<span class="Constant">1</span>:address:screen, <span class="Constant">cursor-column:offset</span> ] memory-should-contain [ - 2<span class="Special"> <- </span>1 <span class="Comment"># cursor row</span> - 3<span class="Special"> <- </span>0 <span class="Comment"># cursor column</span> + <span class="Constant">2</span><span class="Special"> <- </span><span class="Constant">1</span> <span class="Comment"># cursor row</span> + <span class="Constant">3</span><span class="Special"> <- </span><span class="Constant">0</span> <span class="Comment"># cursor column</span> ] ] -scenario <span class="Identifier">print</span>-at-bottom-right [ +<span class="muScenario">scenario</span> print-at-bottom-right [ run [ - 1:address:screen<span class="Special"> <- </span><span class="Identifier">new</span>-fake-screen 2/width, 2/height - 1:address:screen<span class="Special"> <- </span><span class="Identifier">print</span>-character 1:address:screen, 10/newline - 1:address:screen<span class="Special"> <- </span><span class="Identifier">print</span>-character 1:address:screen, 97 <span class="Comment"># 'a'</span> - 1:address:screen<span class="Special"> <- </span><span class="Identifier">print</span>-character 1:address:screen, 98 <span class="Comment"># 'b'</span> - 1:address:screen<span class="Special"> <- </span><span class="Identifier">print</span>-character 1:address:screen, 99 <span class="Comment"># 'c'</span> - 1:address:screen<span class="Special"> <- </span><span class="Identifier">print</span>-character 1:address:screen, 10/newline - 1:address:screen<span class="Special"> <- </span><span class="Identifier">print</span>-character 1:address:screen, 100 <span class="Comment"># 'd'</span> - 2:number<span class="Special"> <- </span>get *1:address:screen, cursor-row:offset - 3:number<span class="Special"> <- </span>get *1:address:screen, cursor-column:offset - 4:address:<span class="Identifier">array</span>:screen-cell<span class="Special"> <- </span>get *1:address:screen, data:offset - 5:<span class="Identifier">array</span>:screen-cell<span class="Special"> <- </span><span class="Identifier">copy</span> *4:address:<span class="Identifier">array</span>:screen-cell + <span class="Constant">1</span>:address:screen<span class="Special"> <- </span>new-fake-screen <span class="Constant">2/width</span>, <span class="Constant">2/height</span> + <span class="Constant">1</span>:address:screen<span class="Special"> <- </span>print-character <span class="Constant">1</span>:address:screen, <span class="Constant">10/newline</span> + <span class="Constant">1</span>:address:screen<span class="Special"> <- </span>print-character <span class="Constant">1</span>:address:screen, <span class="Constant">97</span> <span class="Comment"># 'a'</span> + <span class="Constant">1</span>:address:screen<span class="Special"> <- </span>print-character <span class="Constant">1</span>:address:screen, <span class="Constant">98</span> <span class="Comment"># 'b'</span> + <span class="Constant">1</span>:address:screen<span class="Special"> <- </span>print-character <span class="Constant">1</span>:address:screen, <span class="Constant">99</span> <span class="Comment"># 'c'</span> + <span class="Constant">1</span>:address:screen<span class="Special"> <- </span>print-character <span class="Constant">1</span>:address:screen, <span class="Constant">10/newline</span> + <span class="Constant">1</span>:address:screen<span class="Special"> <- </span>print-character <span class="Constant">1</span>:address:screen, <span class="Constant">100</span> <span class="Comment"># 'd'</span> + <span class="Constant">2</span>:number<span class="Special"> <- </span>get *<span class="Constant">1</span>:address:screen, <span class="Constant">cursor-row:offset</span> + <span class="Constant">3</span>:number<span class="Special"> <- </span>get *<span class="Constant">1</span>:address:screen, <span class="Constant">cursor-column:offset</span> + <span class="Constant">4</span>:address:array:screen-cell<span class="Special"> <- </span>get *<span class="Constant">1</span>:address:screen, <span class="Constant">data:offset</span> + <span class="Constant">5</span>:array:screen-cell<span class="Special"> <- </span>copy *<span class="Constant">4</span>:address:array:screen-cell ] memory-should-contain [ - 2<span class="Special"> <- </span>1 <span class="Comment"># cursor row</span> - 3<span class="Special"> <- </span>1 <span class="Comment"># cursor column</span> - 5<span class="Special"> <- </span>4 <span class="Comment"># width*height</span> - 6<span class="Special"> <- </span>0 <span class="Comment"># unused</span> - 7<span class="Special"> <- </span>7 <span class="Comment"># white</span> - 8<span class="Special"> <- </span>0 <span class="Comment"># unused</span> - 9<span class="Special"> <- </span>7 <span class="Comment"># white</span> - 10<span class="Special"> <- </span>97 <span class="Comment"># 'a'</span> - 11<span class="Special"> <- </span>7 <span class="Comment"># white</span> - 12<span class="Special"> <- </span>100 <span class="Comment"># 'd' over 'b' and 'c' and newline</span> - 13<span class="Special"> <- </span>7 <span class="Comment"># white</span> - 14<span class="Special"> <- </span>0 + <span class="Constant">2</span><span class="Special"> <- </span><span class="Constant">1</span> <span class="Comment"># cursor row</span> + <span class="Constant">3</span><span class="Special"> <- </span><span class="Constant">1</span> <span class="Comment"># cursor column</span> + <span class="Constant">5</span><span class="Special"> <- </span><span class="Constant">4</span> <span class="Comment"># width*height</span> + <span class="Constant">6</span><span class="Special"> <- </span><span class="Constant">0</span> <span class="Comment"># unused</span> + <span class="Constant">7</span><span class="Special"> <- </span><span class="Constant">7</span> <span class="Comment"># white</span> + <span class="Constant">8</span><span class="Special"> <- </span><span class="Constant">0</span> <span class="Comment"># unused</span> + <span class="Constant">9</span><span class="Special"> <- </span><span class="Constant">7</span> <span class="Comment"># white</span> + <span class="Constant">10</span><span class="Special"> <- </span><span class="Constant">97</span> <span class="Comment"># 'a'</span> + <span class="Constant">11</span><span class="Special"> <- </span><span class="Constant">7</span> <span class="Comment"># white</span> + <span class="Constant">12</span><span class="Special"> <- </span><span class="Constant">100</span> <span class="Comment"># 'd' over 'b' and 'c' and newline</span> + <span class="Constant">13</span><span class="Special"> <- </span><span class="Constant">7</span> <span class="Comment"># white</span> + <span class="Constant">14</span><span class="Special"> <- </span><span class="Constant">0</span> ] ] -recipe clear-line [ - <span class="Underlined">local</span>-scope - sc:address:screen<span class="Special"> <- </span>next-ingredient +<span class="muRecipe">recipe</span> clear-line [ + <span class="Constant">local-scope</span> + sc:address:screen<span class="Special"> <- </span><span class="Constant">next-ingredient</span> <span class="Comment"># if x exists, clear line in fake screen</span> - { - break-unless sc - width:number<span class="Special"> <- </span>get *sc, num-columns:offset - column:address:number<span class="Special"> <- </span>get-address *sc, cursor-column:offset - original-column:number<span class="Special"> <- </span><span class="Identifier">copy</span> *column + <span class="Delimiter">{</span> + <span class="muControl">break-unless</span> sc + width:number<span class="Special"> <- </span>get *sc, <span class="Constant">num-columns:offset</span> + column:address:number<span class="Special"> <- </span>get-address *sc, <span class="Constant">cursor-column:offset</span> + original-column:number<span class="Special"> <- </span>copy *column <span class="Comment"># space over the entire line</span> - { - right:number<span class="Special"> <- </span>subtract width, 1 + <span class="Delimiter">{</span> + right:number<span class="Special"> <- </span>subtract width, <span class="Constant">1</span> done?:boolean<span class="Special"> <- </span>greater-or-equal *column, right - break-if done? - <span class="Identifier">print</span>-character sc, [ ] <span class="Comment"># implicitly updates 'column'</span> - loop - } + <span class="muControl">break-if</span> done? + print-character sc, <span class="Constant">[ ]</span> <span class="Comment"># implicitly updates 'column'</span> + <span class="muControl">loop</span> + <span class="Delimiter">}</span> <span class="Comment"># now back to where the cursor was</span> - *column<span class="Special"> <- </span><span class="Identifier">copy</span> original-column - reply sc/same-as-ingredient:0 - } + *column<span class="Special"> <- </span>copy original-column + <span class="muControl">reply</span> sc/same-as-ingredient:<span class="Constant">0</span> + <span class="Delimiter">}</span> <span class="Comment"># otherwise, real screen</span> clear-line-on-display - reply sc/same-as-ingredient:0 + <span class="muControl">reply</span> sc/same-as-ingredient:<span class="Constant">0</span> ] -recipe cursor-position [ - <span class="Underlined">local</span>-scope - sc:address:screen<span class="Special"> <- </span>next-ingredient +<span class="muRecipe">recipe</span> cursor-position [ + <span class="Constant">local-scope</span> + sc:address:screen<span class="Special"> <- </span><span class="Constant">next-ingredient</span> <span class="Comment"># if x exists, lookup cursor in fake screen</span> - { - break-unless sc - row:number<span class="Special"> <- </span>get *sc, cursor-row:offset - column:number<span class="Special"> <- </span>get *sc, cursor-column:offset - reply row, column, sc/same-as-ingredient:0 - } + <span class="Delimiter">{</span> + <span class="muControl">break-unless</span> sc + row:number<span class="Special"> <- </span>get *sc, <span class="Constant">cursor-row:offset</span> + column:number<span class="Special"> <- </span>get *sc, <span class="Constant">cursor-column:offset</span> + <span class="muControl">reply</span> row, column, sc/same-as-ingredient:<span class="Constant">0</span> + <span class="Delimiter">}</span> row, column<span class="Special"> <- </span>cursor-position-on-display - reply row, column, sc/same-as-ingredient:0 + <span class="muControl">reply</span> row, column, sc/same-as-ingredient:<span class="Constant">0</span> ] -recipe move-cursor [ - <span class="Underlined">local</span>-scope - sc:address:screen<span class="Special"> <- </span>next-ingredient - <span class="Identifier">new</span>-row:number<span class="Special"> <- </span>next-ingredient - <span class="Identifier">new</span>-column:number<span class="Special"> <- </span>next-ingredient +<span class="muRecipe">recipe</span> move-cursor [ + <span class="Constant">local-scope</span> + sc:address:screen<span class="Special"> <- </span><span class="Constant">next-ingredient</span> + new-row:number<span class="Special"> <- </span><span class="Constant">next-ingredient</span> + new-column:number<span class="Special"> <- </span><span class="Constant">next-ingredient</span> <span class="Comment"># if x exists, move cursor in fake screen</span> - { - break-unless sc - row:address:number<span class="Special"> <- </span>get-address *sc, cursor-row:offset - *row<span class="Special"> <- </span><span class="Identifier">copy</span> <span class="Identifier">new</span>-row - column:address:number<span class="Special"> <- </span>get-address *sc, cursor-column:offset - *column<span class="Special"> <- </span><span class="Identifier">copy</span> <span class="Identifier">new</span>-column - reply sc/same-as-ingredient:0 - } + <span class="Delimiter">{</span> + <span class="muControl">break-unless</span> sc + row:address:number<span class="Special"> <- </span>get-address *sc, <span class="Constant">cursor-row:offset</span> + *row<span class="Special"> <- </span>copy new-row + column:address:number<span class="Special"> <- </span>get-address *sc, <span class="Constant">cursor-column:offset</span> + *column<span class="Special"> <- </span>copy new-column + <span class="muControl">reply</span> sc/same-as-ingredient:<span class="Constant">0</span> + <span class="Delimiter">}</span> <span class="Comment"># otherwise, real screen</span> - move-cursor-on-display <span class="Identifier">new</span>-row, <span class="Identifier">new</span>-column - reply sc/same-as-ingredient:0 + move-cursor-on-display new-row, new-column + <span class="muControl">reply</span> sc/same-as-ingredient:<span class="Constant">0</span> ] -scenario clear-line-erases-printed-characters [ +<span class="muScenario">scenario</span> clear-line-erases-printed-characters [ run [ - 1:address:screen<span class="Special"> <- </span><span class="Identifier">new</span>-fake-screen 3/width, 2/height + <span class="Constant">1</span>:address:screen<span class="Special"> <- </span>new-fake-screen <span class="Constant">3/width</span>, <span class="Constant">2/height</span> <span class="Comment"># print a character</span> - 1:address:screen<span class="Special"> <- </span><span class="Identifier">print</span>-character 1:address:screen, 97 <span class="Comment"># 'a'</span> + <span class="Constant">1</span>:address:screen<span class="Special"> <- </span>print-character <span class="Constant">1</span>:address:screen, <span class="Constant">97</span> <span class="Comment"># 'a'</span> <span class="Comment"># move cursor to start of line</span> - 1:address:screen<span class="Special"> <- </span>move-cursor 1:address:screen, 0/row, 0/column + <span class="Constant">1</span>:address:screen<span class="Special"> <- </span>move-cursor <span class="Constant">1</span>:address:screen, <span class="Constant">0/row</span>, <span class="Constant">0/column</span> <span class="Comment"># clear line</span> - 1:address:screen<span class="Special"> <- </span>clear-line 1:address:screen - 2:address:<span class="Identifier">array</span>:screen-cell<span class="Special"> <- </span>get *1:address:screen, data:offset - 3:<span class="Identifier">array</span>:screen-cell<span class="Special"> <- </span><span class="Identifier">copy</span> *2:address:<span class="Identifier">array</span>:screen-cell + <span class="Constant">1</span>:address:screen<span class="Special"> <- </span>clear-line <span class="Constant">1</span>:address:screen + <span class="Constant">2</span>:address:array:screen-cell<span class="Special"> <- </span>get *<span class="Constant">1</span>:address:screen, <span class="Constant">data:offset</span> + <span class="Constant">3</span>:array:screen-cell<span class="Special"> <- </span>copy *<span class="Constant">2</span>:address:array:screen-cell ] <span class="Comment"># screen should be blank</span> memory-should-contain [ - 3<span class="Special"> <- </span>6 <span class="Comment"># width*height</span> - 4<span class="Special"> <- </span>0 - 5<span class="Special"> <- </span>7 - 6<span class="Special"> <- </span>0 - 7<span class="Special"> <- </span>7 - 8<span class="Special"> <- </span>0 - 9<span class="Special"> <- </span>7 - 10<span class="Special"> <- </span>0 - 11<span class="Special"> <- </span>7 - 12<span class="Special"> <- </span>0 - 13<span class="Special"> <- </span>7 - 14<span class="Special"> <- </span>0 - 15<span class="Special"> <- </span>7 + <span class="Constant">3</span><span class="Special"> <- </span><span class="Constant">6</span> <span class="Comment"># width*height</span> + <span class="Constant">4</span><span class="Special"> <- </span><span class="Constant">0</span> + <span class="Constant">5</span><span class="Special"> <- </span><span class="Constant">7</span> + <span class="Constant">6</span><span class="Special"> <- </span><span class="Constant">0</span> + <span class="Constant">7</span><span class="Special"> <- </span><span class="Constant">7</span> + <span class="Constant">8</span><span class="Special"> <- </span><span class="Constant">0</span> + <span class="Constant">9</span><span class="Special"> <- </span><span class="Constant">7</span> + <span class="Constant">10</span><span class="Special"> <- </span><span class="Constant">0</span> + <span class="Constant">11</span><span class="Special"> <- </span><span class="Constant">7</span> + <span class="Constant">12</span><span class="Special"> <- </span><span class="Constant">0</span> + <span class="Constant">13</span><span class="Special"> <- </span><span class="Constant">7</span> + <span class="Constant">14</span><span class="Special"> <- </span><span class="Constant">0</span> + <span class="Constant">15</span><span class="Special"> <- </span><span class="Constant">7</span> ] ] -recipe cursor-down [ - <span class="Underlined">local</span>-scope - sc:address:screen<span class="Special"> <- </span>next-ingredient +<span class="muRecipe">recipe</span> cursor-down [ + <span class="Constant">local-scope</span> + sc:address:screen<span class="Special"> <- </span><span class="Constant">next-ingredient</span> <span class="Comment"># if x exists, move cursor in fake screen</span> - { - break-unless sc - { + <span class="Delimiter">{</span> + <span class="muControl">break-unless</span> sc + <span class="Delimiter">{</span> <span class="Comment"># increment row unless it's already all the way down</span> - height:number<span class="Special"> <- </span>get *sc, num-rows:offset - row:address:number<span class="Special"> <- </span>get-address *sc, cursor-row:offset - <span class="Identifier">max</span>:number<span class="Special"> <- </span>subtract height, 1 - at-bottom?:boolean<span class="Special"> <- </span>greater-or-equal *row, <span class="Identifier">max</span> - break-if at-bottom? - *row<span class="Special"> <- </span>add *row, 1 - } - reply sc/same-as-ingredient:0 - } + height:number<span class="Special"> <- </span>get *sc, <span class="Constant">num-rows:offset</span> + row:address:number<span class="Special"> <- </span>get-address *sc, <span class="Constant">cursor-row:offset</span> + max:number<span class="Special"> <- </span>subtract height, <span class="Constant">1</span> + at-bottom?:boolean<span class="Special"> <- </span>greater-or-equal *row, max + <span class="muControl">break-if</span> at-bottom? + *row<span class="Special"> <- </span>add *row, <span class="Constant">1</span> + <span class="Delimiter">}</span> + <span class="muControl">reply</span> sc/same-as-ingredient:<span class="Constant">0</span> + <span class="Delimiter">}</span> <span class="Comment"># otherwise, real screen</span> move-cursor-down-on-display - reply sc/same-as-ingredient:0 + <span class="muControl">reply</span> sc/same-as-ingredient:<span class="Constant">0</span> ] -recipe cursor-up [ - <span class="Underlined">local</span>-scope - sc:address:screen<span class="Special"> <- </span>next-ingredient +<span class="muRecipe">recipe</span> cursor-up [ + <span class="Constant">local-scope</span> + sc:address:screen<span class="Special"> <- </span><span class="Constant">next-ingredient</span> <span class="Comment"># if x exists, move cursor in fake screen</span> - { - break-unless sc - { + <span class="Delimiter">{</span> + <span class="muControl">break-unless</span> sc + <span class="Delimiter">{</span> <span class="Comment"># decrement row unless it's already all the way up</span> - row:address:number<span class="Special"> <- </span>get-address *sc, cursor-row:offset - at-top?:boolean<span class="Special"> <- </span>lesser-or-equal *row, 0 - break-if at-top? - *row<span class="Special"> <- </span>subtract *row, 1 - } - reply sc/same-as-ingredient:0 - } + row:address:number<span class="Special"> <- </span>get-address *sc, <span class="Constant">cursor-row:offset</span> + at-top?:boolean<span class="Special"> <- </span>lesser-or-equal *row, <span class="Constant">0</span> + <span class="muControl">break-if</span> at-top? + *row<span class="Special"> <- </span>subtract *row, <span class="Constant">1</span> + <span class="Delimiter">}</span> + <span class="muControl">reply</span> sc/same-as-ingredient:<span class="Constant">0</span> + <span class="Delimiter">}</span> <span class="Comment"># otherwise, real screen</span> move-cursor-up-on-display - reply sc/same-as-ingredient:0 + <span class="muControl">reply</span> sc/same-as-ingredient:<span class="Constant">0</span> ] -recipe cursor-right [ - <span class="Underlined">local</span>-scope - sc:address:screen<span class="Special"> <- </span>next-ingredient +<span class="muRecipe">recipe</span> cursor-right [ + <span class="Constant">local-scope</span> + sc:address:screen<span class="Special"> <- </span><span class="Constant">next-ingredient</span> <span class="Comment"># if x exists, move cursor in fake screen</span> - { - break-unless sc - { + <span class="Delimiter">{</span> + <span class="muControl">break-unless</span> sc + <span class="Delimiter">{</span> <span class="Comment"># increment column unless it's already all the way to the right</span> - width:number<span class="Special"> <- </span>get *sc, num-columns:offset - column:address:number<span class="Special"> <- </span>get-address *sc, cursor-column:offset - <span class="Identifier">max</span>:number<span class="Special"> <- </span>subtract width, 1 - at-bottom?:boolean<span class="Special"> <- </span>greater-or-equal *column, <span class="Identifier">max</span> - break-if at-bottom? - *column<span class="Special"> <- </span>add *column, 1 - } - reply sc/same-as-ingredient:0 - } + width:number<span class="Special"> <- </span>get *sc, <span class="Constant">num-columns:offset</span> + column:address:number<span class="Special"> <- </span>get-address *sc, <span class="Constant">cursor-column:offset</span> + max:number<span class="Special"> <- </span>subtract width, <span class="Constant">1</span> + at-bottom?:boolean<span class="Special"> <- </span>greater-or-equal *column, max + <span class="muControl">break-if</span> at-bottom? + *column<span class="Special"> <- </span>add *column, <span class="Constant">1</span> + <span class="Delimiter">}</span> + <span class="muControl">reply</span> sc/same-as-ingredient:<span class="Constant">0</span> + <span class="Delimiter">}</span> <span class="Comment"># otherwise, real screen</span> move-cursor-right-on-display - reply sc/same-as-ingredient:0 + <span class="muControl">reply</span> sc/same-as-ingredient:<span class="Constant">0</span> ] -recipe cursor-left [ - <span class="Underlined">local</span>-scope - sc:address:screen<span class="Special"> <- </span>next-ingredient +<span class="muRecipe">recipe</span> cursor-left [ + <span class="Constant">local-scope</span> + sc:address:screen<span class="Special"> <- </span><span class="Constant">next-ingredient</span> <span class="Comment"># if x exists, move cursor in fake screen</span> - { - break-unless sc - { + <span class="Delimiter">{</span> + <span class="muControl">break-unless</span> sc + <span class="Delimiter">{</span> <span class="Comment"># decrement column unless it's already all the way to the left</span> - column:address:number<span class="Special"> <- </span>get-address *sc, cursor-column:offset - at-top?:boolean<span class="Special"> <- </span>lesser-or-equal *column, 0 - break-if at-top? - *column<span class="Special"> <- </span>subtract *column, 1 - } - reply sc/same-as-ingredient:0 - } + column:address:number<span class="Special"> <- </span>get-address *sc, <span class="Constant">cursor-column:offset</span> + at-top?:boolean<span class="Special"> <- </span>lesser-or-equal *column, <span class="Constant">0</span> + <span class="muControl">break-if</span> at-top? + *column<span class="Special"> <- </span>subtract *column, <span class="Constant">1</span> + <span class="Delimiter">}</span> + <span class="muControl">reply</span> sc/same-as-ingredient:<span class="Constant">0</span> + <span class="Delimiter">}</span> <span class="Comment"># otherwise, real screen</span> move-cursor-left-on-display - reply sc/same-as-ingredient:0 + <span class="muControl">reply</span> sc/same-as-ingredient:<span class="Constant">0</span> ] -recipe cursor-to-start-of-line [ - <span class="Underlined">local</span>-scope - sc:address:screen<span class="Special"> <- </span>next-ingredient +<span class="muRecipe">recipe</span> cursor-to-start-of-line [ + <span class="Constant">local-scope</span> + sc:address:screen<span class="Special"> <- </span><span class="Constant">next-ingredient</span> row:number, _, sc<span class="Special"> <- </span>cursor-position sc - column:number<span class="Special"> <- </span><span class="Identifier">copy</span> 0 + column:number<span class="Special"> <- </span>copy <span class="Constant">0</span> sc<span class="Special"> <- </span>move-cursor sc, row, column - reply sc/same-as-ingredient:0 + <span class="muControl">reply</span> sc/same-as-ingredient:<span class="Constant">0</span> ] -recipe cursor-to-next-line [ - <span class="Underlined">local</span>-scope - screen:address<span class="Special"> <- </span>next-ingredient +<span class="muRecipe">recipe</span> cursor-to-next-line [ + <span class="Constant">local-scope</span> + screen:address<span class="Special"> <- </span><span class="Constant">next-ingredient</span> screen<span class="Special"> <- </span>cursor-down screen screen<span class="Special"> <- </span>cursor-to-start-of-line screen - reply screen/same-as-ingredient:0 + <span class="muControl">reply</span> screen/same-as-ingredient:<span class="Constant">0</span> ] -recipe screen-width [ - <span class="Underlined">local</span>-scope - sc:address:screen<span class="Special"> <- </span>next-ingredient +<span class="muRecipe">recipe</span> screen-width [ + <span class="Constant">local-scope</span> + sc:address:screen<span class="Special"> <- </span><span class="Constant">next-ingredient</span> <span class="Comment"># if x exists, move cursor in fake screen</span> - { - break-unless sc - width:number<span class="Special"> <- </span>get *sc, num-columns:offset - reply width - } + <span class="Delimiter">{</span> + <span class="muControl">break-unless</span> sc + width:number<span class="Special"> <- </span>get *sc, <span class="Constant">num-columns:offset</span> + <span class="muControl">reply</span> width + <span class="Delimiter">}</span> <span class="Comment"># otherwise, real screen</span> width:number<span class="Special"> <- </span>display-width - reply width + <span class="muControl">reply</span> width ] -recipe screen-height [ - <span class="Underlined">local</span>-scope - sc:address:screen<span class="Special"> <- </span>next-ingredient +<span class="muRecipe">recipe</span> screen-height [ + <span class="Constant">local-scope</span> + sc:address:screen<span class="Special"> <- </span><span class="Constant">next-ingredient</span> <span class="Comment"># if x exists, move cursor in fake screen</span> - { - break-unless sc - height:number<span class="Special"> <- </span>get *sc, num-rows:offset - reply height - } + <span class="Delimiter">{</span> + <span class="muControl">break-unless</span> sc + height:number<span class="Special"> <- </span>get *sc, <span class="Constant">num-rows:offset</span> + <span class="muControl">reply</span> height + <span class="Delimiter">}</span> <span class="Comment"># otherwise, real screen</span> height:number<span class="Special"> <- </span>display-height - reply height + <span class="muControl">reply</span> height ] -recipe hide-cursor [ - <span class="Underlined">local</span>-scope - screen:address<span class="Special"> <- </span>next-ingredient +<span class="muRecipe">recipe</span> hide-cursor [ + <span class="Constant">local-scope</span> + screen:address<span class="Special"> <- </span><span class="Constant">next-ingredient</span> <span class="Comment"># if x exists (not real display), do nothing</span> - { - break-unless screen - reply screen - } + <span class="Delimiter">{</span> + <span class="muControl">break-unless</span> screen + <span class="muControl">reply</span> screen + <span class="Delimiter">}</span> <span class="Comment"># otherwise, real screen</span> hide-cursor-on-display - reply screen + <span class="muControl">reply</span> screen ] -recipe show-cursor [ - <span class="Underlined">local</span>-scope - screen:address<span class="Special"> <- </span>next-ingredient +<span class="muRecipe">recipe</span> show-cursor [ + <span class="Constant">local-scope</span> + screen:address<span class="Special"> <- </span><span class="Constant">next-ingredient</span> <span class="Comment"># if x exists (not real display), do nothing</span> - { - break-unless screen - reply screen - } + <span class="Delimiter">{</span> + <span class="muControl">break-unless</span> screen + <span class="muControl">reply</span> screen + <span class="Delimiter">}</span> <span class="Comment"># otherwise, real screen</span> show-cursor-on-display - reply screen + <span class="muControl">reply</span> screen ] -recipe hide-screen [ - <span class="Underlined">local</span>-scope - screen:address<span class="Special"> <- </span>next-ingredient +<span class="muRecipe">recipe</span> hide-screen [ + <span class="Constant">local-scope</span> + screen:address<span class="Special"> <- </span><span class="Constant">next-ingredient</span> <span class="Comment"># if x exists (not real display), do nothing</span> <span class="Comment"># todo: help test this</span> - { - break-unless screen - reply screen - } + <span class="Delimiter">{</span> + <span class="muControl">break-unless</span> screen + <span class="muControl">reply</span> screen + <span class="Delimiter">}</span> <span class="Comment"># otherwise, real screen</span> hide-display - reply screen + <span class="muControl">reply</span> screen ] -recipe show-screen [ - <span class="Underlined">local</span>-scope - screen:address<span class="Special"> <- </span>next-ingredient +<span class="muRecipe">recipe</span> show-screen [ + <span class="Constant">local-scope</span> + screen:address<span class="Special"> <- </span><span class="Constant">next-ingredient</span> <span class="Comment"># if x exists (not real display), do nothing</span> <span class="Comment"># todo: help test this</span> - { - break-unless screen - reply screen - } + <span class="Delimiter">{</span> + <span class="muControl">break-unless</span> screen + <span class="muControl">reply</span> screen + <span class="Delimiter">}</span> <span class="Comment"># otherwise, real screen</span> show-display - reply screen + <span class="muControl">reply</span> screen ] -recipe <span class="Identifier">print</span>-string [ - <span class="Underlined">local</span>-scope - screen:address<span class="Special"> <- </span>next-ingredient - s:address:<span class="Identifier">array</span>:character<span class="Special"> <- </span>next-ingredient - color:number, color-found?:boolean<span class="Special"> <- </span>next-ingredient - { +<span class="muRecipe">recipe</span> print-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> + 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> - break-if color-found? - color<span class="Special"> <- </span><span class="Identifier">copy</span> 7/white - } - bg-color:number, bg-color-found?:boolean<span class="Special"> <- </span>next-ingredient - { + <span class="muControl">break-if</span> color-found? + color<span class="Special"> <- </span>copy <span class="Constant">7/white</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="Comment"># default bg-color to black</span> - break-if bg-color-found? - bg-color<span class="Special"> <- </span><span class="Identifier">copy</span> 0/black - } - len:number<span class="Special"> <- </span><span class="Identifier">length</span> *s - i:number<span class="Special"> <- </span><span class="Identifier">copy</span> 0 - { + <span class="muControl">break-if</span> bg-color-found? + bg-color<span class="Special"> <- </span>copy <span class="Constant">0/black</span> + <span class="Delimiter">}</span> + len:number<span class="Special"> <- </span>length *s + i:number<span class="Special"> <- </span>copy <span class="Constant">0</span> + <span class="Delimiter">{</span> done?:boolean<span class="Special"> <- </span>greater-or-equal i, len - break-if done? + <span class="muControl">break-if</span> done? c:character<span class="Special"> <- </span>index *s, i - <span class="Identifier">print</span>-character screen, c, color, bg-color - i<span class="Special"> <- </span>add i, 1 - loop - } - reply screen/same-as-ingredient:0 + print-character screen, c, color, bg-color + i<span class="Special"> <- </span>add i, <span class="Constant">1</span> + <span class="muControl">loop</span> + <span class="Delimiter">}</span> + <span class="muControl">reply</span> screen/same-as-ingredient:<span class="Constant">0</span> ] -scenario <span class="Identifier">print</span>-string-stops-at-right-margin [ +<span class="muScenario">scenario</span> print-string-stops-at-right-margin [ run [ - 1:address:screen<span class="Special"> <- </span><span class="Identifier">new</span>-fake-screen 3/width, 2/height - 2:address:<span class="Identifier">array</span>:character<span class="Special"> <- </span><span class="Identifier">new</span> [abcd] - 1:address:screen<span class="Special"> <- </span><span class="Identifier">print</span>-string 1:address:screen, 2:address:<span class="Identifier">array</span>:character - 3:address:<span class="Identifier">array</span>:screen-cell<span class="Special"> <- </span>get *1:address:screen, data:offset - 4:<span class="Identifier">array</span>:screen-cell<span class="Special"> <- </span><span class="Identifier">copy</span> *3:address:<span class="Identifier">array</span>:screen-cell + <span class="Constant">1</span>:address:screen<span class="Special"> <- </span>new-fake-screen <span class="Constant">3/width</span>, <span class="Constant">2/height</span> + <span class="Constant">2</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[abcd]</span> + <span class="Constant">1</span>:address:screen<span class="Special"> <- </span>print-string <span class="Constant">1</span>:address:screen, <span class="Constant">2</span>:address:array:character + <span class="Constant">3</span>:address:array:screen-cell<span class="Special"> <- </span>get *<span class="Constant">1</span>:address:screen, <span class="Constant">data:offset</span> + <span class="Constant">4</span>:array:screen-cell<span class="Special"> <- </span>copy *<span class="Constant">3</span>:address:array:screen-cell ] memory-should-contain [ - 4<span class="Special"> <- </span>6 <span class="Comment"># width*height</span> - 5<span class="Special"> <- </span>97 <span class="Comment"># 'a'</span> - 6<span class="Special"> <- </span>7 <span class="Comment"># white</span> - 7<span class="Special"> <- </span>98 <span class="Comment"># 'b'</span> - 8<span class="Special"> <- </span>7 <span class="Comment"># white</span> - 9<span class="Special"> <- </span>100 <span class="Comment"># 'd' overwrites 'c'</span> - 10<span class="Special"> <- </span>7 <span class="Comment"># white</span> - 11<span class="Special"> <- </span>0 <span class="Comment"># unused</span> + <span class="Constant">4</span><span class="Special"> <- </span><span class="Constant">6</span> <span class="Comment"># width*height</span> + <span class="Constant">5</span><span class="Special"> <- </span><span class="Constant">97</span> <span class="Comment"># 'a'</span> + <span class="Constant">6</span><span class="Special"> <- </span><span class="Constant">7</span> <span class="Comment"># white</span> + <span class="Constant">7</span><span class="Special"> <- </span><span class="Constant">98</span> <span class="Comment"># 'b'</span> + <span class="Constant">8</span><span class="Special"> <- </span><span class="Constant">7</span> <span class="Comment"># white</span> + <span class="Constant">9</span><span class="Special"> <- </span><span class="Constant">100</span> <span class="Comment"># 'd' overwrites 'c'</span> + <span class="Constant">10</span><span class="Special"> <- </span><span class="Constant">7</span> <span class="Comment"># white</span> + <span class="Constant">11</span><span class="Special"> <- </span><span class="Constant">0</span> <span class="Comment"># unused</span> ] ] -recipe <span class="Identifier">print</span>-integer [ - <span class="Underlined">local</span>-scope - screen:address<span class="Special"> <- </span>next-ingredient - n:number<span class="Special"> <- </span>next-ingredient - color:number, color-found?:boolean<span class="Special"> <- </span>next-ingredient - { +<span class="muRecipe">recipe</span> print-integer [ + <span class="Constant">local-scope</span> + screen:address<span class="Special"> <- </span><span class="Constant">next-ingredient</span> + n: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> - break-if color-found? - color<span class="Special"> <- </span><span class="Identifier">copy</span> 7/white - } - bg-color:number, bg-color-found?:boolean<span class="Special"> <- </span>next-ingredient - { + <span class="muControl">break-if</span> color-found? + color<span class="Special"> <- </span>copy <span class="Constant">7/white</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="Comment"># default bg-color to black</span> - break-if bg-color-found? - bg-color<span class="Special"> <- </span><span class="Identifier">copy</span> 0/black - } + <span class="muControl">break-if</span> bg-color-found? + bg-color<span class="Special"> <- </span>copy <span class="Constant">0/black</span> + <span class="Delimiter">}</span> <span class="Comment"># todo: other bases besides decimal</span> - s:address:<span class="Identifier">array</span>:character<span class="Special"> <- </span>integer-to-decimal-string n - <span class="Identifier">print</span>-string screen, s, color, bg-color - reply screen/same-as-ingredient:0 + s:address:array:character<span class="Special"> <- </span>integer-to-decimal-string n + print-string screen, s, color, bg-color + <span class="muControl">reply</span> screen/same-as-ingredient:<span class="Constant">0</span> ] </pre> </body> diff --git a/html/073scenario_screen_test.mu.html b/html/073scenario_screen_test.mu.html index 556fe973..aa6f42b9 100644 --- a/html/073scenario_screen_test.mu.html +++ b/html/073scenario_screen_test.mu.html @@ -13,9 +13,10 @@ 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; } .Comment { color: #9090ff; } +.Constant { color: #00a0a0; } .Special { color: #ff6060; } -.Identifier { color: #804000; } --> </style> @@ -29,31 +30,31 @@ body { font-family: monospace; color: #eeeeee; background-color: #080808; } <pre id='vimCodeElement'> <span class="Comment"># To check our support for screens in scenarios, rewrite tests from print.mu</span> -scenario <span class="Identifier">print</span>-character-at-top-left-2 [ - <span class="Identifier">assume</span>-screen 3/width, 2/height +<span class="muScenario">scenario</span> print-character-at-top-left-2 [ + assume-screen <span class="Constant">3/width</span>, <span class="Constant">2/height</span> run [ - screen:address<span class="Special"> <- </span><span class="Identifier">print</span>-character screen:address, 97/a + screen:address<span class="Special"> <- </span>print-character screen:address, <span class="Constant">97/a</span> ] screen-should-contain [ - .a . - . . + <span class="Constant"> .a .</span> + <span class="Constant"> . .</span> ] ] -scenario clear-line-erases-printed-characters-2 [ - <span class="Identifier">assume</span>-screen 5/width, 3/height +<span class="muScenario">scenario</span> clear-line-erases-printed-characters-2 [ + assume-screen <span class="Constant">5/width</span>, <span class="Constant">3/height</span> run [ <span class="Comment"># print a character</span> - screen:address<span class="Special"> <- </span><span class="Identifier">print</span>-character screen:address, 97/a + screen:address<span class="Special"> <- </span>print-character screen:address, <span class="Constant">97/a</span> <span class="Comment"># move cursor to start of line</span> - screen:address<span class="Special"> <- </span>move-cursor screen:address, 0/row, 0/column + screen:address<span class="Special"> <- </span>move-cursor screen:address, <span class="Constant">0/row</span>, <span class="Constant">0/column</span> <span class="Comment"># clear line</span> screen:address<span class="Special"> <- </span>clear-line screen:address ] screen-should-contain [ - . . - . . - . . + <span class="Constant"> . .</span> + <span class="Constant"> . .</span> + <span class="Constant"> . .</span> ] ] </pre> diff --git a/html/074console.mu.html b/html/074console.mu.html index f2eb5552..191c33e8 100644 --- a/html/074console.mu.html +++ b/html/074console.mu.html @@ -13,10 +13,13 @@ 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; } -.Special { color: #ff6060; } +.muRecipe { color: #ff8700; } +.muData { color: #ffff00; } .Comment { color: #9090ff; } -.Underlined { color: #c000c0; text-decoration: underline; } -.Identifier { color: #804000; } +.Constant { color: #00a0a0; } +.Special { color: #ff6060; } +.Delimiter { color: #a04060; } +.muControl { color: #c0a020; } --> </style> @@ -31,7 +34,7 @@ body { font-family: monospace; color: #eeeeee; background-color: #080808; } <span class="Comment"># Wrappers around interaction primitives that take a potentially fake object</span> <span class="Comment"># and are thus easier to test.</span> -exclusive-container event [ +<span class="muData">exclusive-container</span> event [ text:character keycode:number <span class="Comment"># keys on keyboard without a unicode representation</span> touch:touch-event <span class="Comment"># mouse, track ball, etc.</span> @@ -39,107 +42,107 @@ exclusive-container event [ <span class="Comment"># update the assume-console handler if you add more variants</span> ] -container touch-event [ - <span class="Identifier">type</span>:number +<span class="muData">container</span> touch-event [ + type:number row:number column:number ] -container resize-event [ +<span class="muData">container</span> resize-event [ width:number height:number ] -container console [ +<span class="muData">container</span> console [ index:number - data:address:<span class="Identifier">array</span>:event + data:address:array:event ] -recipe <span class="Identifier">new</span>-fake-console [ - <span class="Underlined">local</span>-scope - result:address:console<span class="Special"> <- </span><span class="Identifier">new</span> console:<span class="Identifier">type</span> - buf:address:address:<span class="Identifier">array</span>:character<span class="Special"> <- </span>get-address *result, data:offset - *buf<span class="Special"> <- </span>next-ingredient - idx:address:number<span class="Special"> <- </span>get-address *result, index:offset - *idx<span class="Special"> <- </span><span class="Identifier">copy</span> 0 - reply result +<span class="muRecipe">recipe</span> new-fake-console [ + <span class="Constant">local-scope</span> + result:address:console<span class="Special"> <- </span>new <span class="Constant">console:type</span> + buf:address:address:array:character<span class="Special"> <- </span>get-address *result, <span class="Constant">data:offset</span> + *buf<span class="Special"> <- </span><span class="Constant">next-ingredient</span> + idx:address:number<span class="Special"> <- </span>get-address *result, <span class="Constant">index:offset</span> + *idx<span class="Special"> <- </span>copy <span class="Constant">0</span> + <span class="muControl">reply</span> result ] -recipe <span class="Identifier">read</span>-event [ - <span class="Underlined">local</span>-scope - x:address:console<span class="Special"> <- </span>next-ingredient - { - break-unless x - idx:address:number<span class="Special"> <- </span>get-address *x, index:offset - buf:address:<span class="Identifier">array</span>:event<span class="Special"> <- </span>get *x, data:offset - { - <span class="Identifier">max</span>:number<span class="Special"> <- </span><span class="Identifier">length</span> *buf - done?:boolean<span class="Special"> <- </span>greater-or-equal *idx, <span class="Identifier">max</span> - break-unless done? - dummy:address:event<span class="Special"> <- </span><span class="Identifier">new</span> event:<span class="Identifier">type</span> - reply *dummy, x/same-as-ingredient:0, 1/found, 1/<span class="Identifier">quit</span> - } +<span class="muRecipe">recipe</span> read-event [ + <span class="Constant">local-scope</span> + x:address:console<span class="Special"> <- </span><span class="Constant">next-ingredient</span> + <span class="Delimiter">{</span> + <span class="muControl">break-unless</span> x + idx:address:number<span class="Special"> <- </span>get-address *x, <span class="Constant">index:offset</span> + buf:address:array:event<span class="Special"> <- </span>get *x, <span class="Constant">data:offset</span> + <span class="Delimiter">{</span> + max:number<span class="Special"> <- </span>length *buf + done?:boolean<span class="Special"> <- </span>greater-or-equal *idx, max + <span class="muControl">break-unless</span> done? + dummy:address:event<span class="Special"> <- </span>new <span class="Constant">event:type</span> + <span class="muControl">reply</span> *dummy, x/same-as-ingredient:<span class="Constant">0</span>, <span class="Constant">1/found</span>, <span class="Constant">1/quit</span> + <span class="Delimiter">}</span> result:event<span class="Special"> <- </span>index *buf, *idx - *idx<span class="Special"> <- </span>add *idx, 1 - reply result, x/same-as-ingredient:0, 1/found, 0/<span class="Identifier">quit</span> - } + *idx<span class="Special"> <- </span>add *idx, <span class="Constant">1</span> + <span class="muControl">reply</span> result, x/same-as-ingredient:<span class="Constant">0</span>, <span class="Constant">1/found</span>, <span class="Constant">0/quit</span> + <span class="Delimiter">}</span> switch <span class="Comment"># real event source is infrequent; avoid polling it too much</span> result:event, found?:boolean<span class="Special"> <- </span>check-for-interaction - reply result, x/same-as-ingredient:0, found?, 0/<span class="Identifier">quit</span> + <span class="muControl">reply</span> result, x/same-as-ingredient:<span class="Constant">0</span>, found?, <span class="Constant">0/quit</span> ] <span class="Comment"># variant of read-event for just keyboard events. Discards everything that</span> <span class="Comment"># isn't unicode, so no arrow keys, page-up/page-down, etc. But you still get</span> <span class="Comment"># newlines, tabs, ctrl-d..</span> -recipe <span class="Identifier">read</span>-key [ - <span class="Underlined">local</span>-scope - console:address<span class="Special"> <- </span>next-ingredient - x:event, console, found?:boolean, <span class="Identifier">quit</span>?:boolean<span class="Special"> <- </span><span class="Identifier">read</span>-event console - reply-if <span class="Identifier">quit</span>?, 0, console/same-as-ingredient:0, found?, <span class="Identifier">quit</span>? - reply-unless found?, 0, console/same-as-ingredient:0, found?, <span class="Identifier">quit</span>? - c:address:character<span class="Special"> <- </span>maybe-convert x, text:variant - reply-unless c, 0, console/same-as-ingredient:0, 0/found, 0/<span class="Identifier">quit</span> - reply *c, console/same-as-ingredient:0, 1/found, 0/<span class="Identifier">quit</span> +<span class="muRecipe">recipe</span> read-key [ + <span class="Constant">local-scope</span> + console:address<span class="Special"> <- </span><span class="Constant">next-ingredient</span> + x:event, console, found?:boolean, quit?:boolean<span class="Special"> <- </span>read-event console + <span class="muControl">reply-if</span> quit?, <span class="Constant">0</span>, console/same-as-ingredient:<span class="Constant">0</span>, found?, quit? + <span class="muControl">reply-unless</span> found?, <span class="Constant">0</span>, console/same-as-ingredient:<span class="Constant">0</span>, found?, quit? + c:address:character<span class="Special"> <- </span>maybe-convert x, <span class="Constant">text:variant</span> + <span class="muControl">reply-unless</span> c, <span class="Constant">0</span>, console/same-as-ingredient:<span class="Constant">0</span>, <span class="Constant">0/found</span>, <span class="Constant">0/quit</span> + <span class="muControl">reply</span> *c, console/same-as-ingredient:<span class="Constant">0</span>, <span class="Constant">1/found</span>, <span class="Constant">0/quit</span> ] -recipe send-keys-to-channel [ - <span class="Underlined">local</span>-scope - console:address<span class="Special"> <- </span>next-ingredient - chan:address:channel<span class="Special"> <- </span>next-ingredient - screen:address<span class="Special"> <- </span>next-ingredient - { - c:character, console, found?:boolean, <span class="Identifier">quit</span>?:boolean<span class="Special"> <- </span><span class="Identifier">read</span>-key console - loop-unless found? - break-if <span class="Identifier">quit</span>? - <span class="Identifier">assert</span> c, [invalid event, expected text] - screen<span class="Special"> <- </span><span class="Identifier">print</span>-character screen, c - chan<span class="Special"> <- </span><span class="Identifier">write</span> chan, c - loop - } - reply console/same-as-ingredient:0, chan/same-as-ingredient:1, screen/same-as-ingredient:2 +<span class="muRecipe">recipe</span> send-keys-to-channel [ + <span class="Constant">local-scope</span> + console:address<span class="Special"> <- </span><span class="Constant">next-ingredient</span> + chan:address:channel<span class="Special"> <- </span><span class="Constant">next-ingredient</span> + screen:address<span class="Special"> <- </span><span class="Constant">next-ingredient</span> + <span class="Delimiter">{</span> + c:character, console, found?:boolean, quit?:boolean<span class="Special"> <- </span>read-key console + <span class="muControl">loop-unless</span> found? + <span class="muControl">break-if</span> quit? + assert c, <span class="Constant">[invalid event, expected text]</span> + screen<span class="Special"> <- </span>print-character screen, c + chan<span class="Special"> <- </span>write chan, c + <span class="muControl">loop</span> + <span class="Delimiter">}</span> + <span class="muControl">reply</span> console/same-as-ingredient:<span class="Constant">0</span>, chan/same-as-ingredient:<span class="Constant">1</span>, screen/same-as-ingredient:<span class="Constant">2</span> ] -recipe wait-for-event [ - <span class="Underlined">local</span>-scope - console:address<span class="Special"> <- </span>next-ingredient - { - _, console, found?:boolean<span class="Special"> <- </span><span class="Identifier">read</span>-event console - loop-unless found? - } - reply console/same-as-ingredient:0 +<span class="muRecipe">recipe</span> wait-for-event [ + <span class="Constant">local-scope</span> + console:address<span class="Special"> <- </span><span class="Constant">next-ingredient</span> + <span class="Delimiter">{</span> + _, console, found?:boolean<span class="Special"> <- </span>read-event console + <span class="muControl">loop-unless</span> found? + <span class="Delimiter">}</span> + <span class="muControl">reply</span> console/same-as-ingredient:<span class="Constant">0</span> ] <span class="Comment"># use this helper to skip rendering if there's lots of other events queued up</span> -recipe <span class="Identifier">has</span>-more-events? [ - <span class="Underlined">local</span>-scope - console:address<span class="Special"> <- </span>next-ingredient - { - break-unless console +<span class="muRecipe">recipe</span> has-more-events? [ + <span class="Constant">local-scope</span> + console:address<span class="Special"> <- </span><span class="Constant">next-ingredient</span> + <span class="Delimiter">{</span> + <span class="muControl">break-unless</span> console <span class="Comment"># fake consoles should be plenty fast; never skip</span> - reply 0/false - } + <span class="muControl">reply</span> <span class="Constant">0/false</span> + <span class="Delimiter">}</span> result:boolean<span class="Special"> <- </span>interactions-left? - reply result + <span class="muControl">reply</span> result ] </pre> </body> diff --git a/html/076scenario_console_test.mu.html b/html/076scenario_console_test.mu.html index 7b38078c..b33cb4cd 100644 --- a/html/076scenario_console_test.mu.html +++ b/html/076scenario_console_test.mu.html @@ -13,9 +13,10 @@ 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; } .Comment { color: #9090ff; } +.Constant { color: #00a0a0; } .Special { color: #ff6060; } -.Identifier { color: #804000; } --> </style> @@ -31,25 +32,25 @@ body { font-family: monospace; color: #eeeeee; background-color: #080808; } <span class="Comment"># scenario_console.mu</span> <span class="Comment"># Tests for console interface.</span> -scenario <span class="Identifier">read</span>-key-<span class="Identifier">in</span>-mu [ - <span class="Identifier">assume</span>-console [ - <span class="Identifier">type</span> [abc] +<span class="muScenario">scenario</span> read-key-in-mu [ + assume-console [ + type <span class="Constant">[abc]</span> ] run [ - 1:character, console:address, 2:boolean<span class="Special"> <- </span><span class="Identifier">read</span>-key console:address - 3:character, console:address, 4:boolean<span class="Special"> <- </span><span class="Identifier">read</span>-key console:address - 5:character, console:address, 6:boolean<span class="Special"> <- </span><span class="Identifier">read</span>-key console:address - 7:character, console:address, 8:boolean<span class="Special"> <- </span><span class="Identifier">read</span>-key console:address + <span class="Constant">1</span>:character, console:address, <span class="Constant">2</span>:boolean<span class="Special"> <- </span>read-key console:address + <span class="Constant">3</span>:character, console:address, <span class="Constant">4</span>:boolean<span class="Special"> <- </span>read-key console:address + <span class="Constant">5</span>:character, console:address, <span class="Constant">6</span>:boolean<span class="Special"> <- </span>read-key console:address + <span class="Constant">7</span>:character, console:address, <span class="Constant">8</span>:boolean<span class="Special"> <- </span>read-key console:address ] memory-should-contain [ - 1<span class="Special"> <- </span>97 <span class="Comment"># 'a'</span> - 2<span class="Special"> <- </span>1 - 3<span class="Special"> <- </span>98 <span class="Comment"># 'b'</span> - 4<span class="Special"> <- </span>1 - 5<span class="Special"> <- </span>99 <span class="Comment"># 'c'</span> - 6<span class="Special"> <- </span>1 - 7<span class="Special"> <- </span>0 <span class="Comment"># eof</span> - 8<span class="Special"> <- </span>1 + <span class="Constant">1</span><span class="Special"> <- </span><span class="Constant">97</span> <span class="Comment"># 'a'</span> + <span class="Constant">2</span><span class="Special"> <- </span><span class="Constant">1</span> + <span class="Constant">3</span><span class="Special"> <- </span><span class="Constant">98</span> <span class="Comment"># 'b'</span> + <span class="Constant">4</span><span class="Special"> <- </span><span class="Constant">1</span> + <span class="Constant">5</span><span class="Special"> <- </span><span class="Constant">99</span> <span class="Comment"># 'c'</span> + <span class="Constant">6</span><span class="Special"> <- </span><span class="Constant">1</span> + <span class="Constant">7</span><span class="Special"> <- </span><span class="Constant">0</span> <span class="Comment"># eof</span> + <span class="Constant">8</span><span class="Special"> <- </span><span class="Constant">1</span> ] ] </pre> diff --git a/html/callcc.mu.html b/html/callcc.mu.html index 805a182e..20ebd83c 100644 --- a/html/callcc.mu.html +++ b/html/callcc.mu.html @@ -13,9 +13,11 @@ 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; } +.muRecipe { color: #ff8700; } .Comment { color: #9090ff; } +.Constant { color: #00a0a0; } .Special { color: #ff6060; } -.Identifier { color: #804000; } +.muControl { color: #c0a020; } --> </style> @@ -29,20 +31,20 @@ body { font-family: monospace; color: #eeeeee; background-color: #080808; } <pre id='vimCodeElement'> <span class="Comment"># example program: saving and reusing call-stacks or continuations</span> -recipe main [ +<span class="muRecipe">recipe</span> main [ c:continuation<span class="Special"> <- </span>f - continue-from c <span class="Comment"># <-- ..when you hit this</span> + <span class="muControl">continue-from</span> c <span class="Comment"># <-- ..when you hit this</span> ] -recipe f [ +<span class="muRecipe">recipe</span> f [ c:continuation<span class="Special"> <- </span>g - reply c + <span class="muControl">reply</span> c ] -recipe g [ - c:continuation<span class="Special"> <- </span>current-continuation <span class="Comment"># <-- loop back to here</span> - $<span class="Identifier">print</span> 1 - reply c <span class="Comment"># threaded through unmodified after first iteration</span> +<span class="muRecipe">recipe</span> g [ + c:continuation<span class="Special"> <- </span><span class="muControl">current-continuation</span> <span class="Comment"># <-- loop back to here</span> + $print <span class="Constant">1</span> + <span class="muControl">reply</span> c <span class="Comment"># threaded through unmodified after first iteration</span> ] </pre> </body> diff --git a/html/channel.mu.html b/html/channel.mu.html index ce564ded..420eed5e 100644 --- a/html/channel.mu.html +++ b/html/channel.mu.html @@ -13,10 +13,12 @@ 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; } -.Special { color: #ff6060; } +.muRecipe { color: #ff8700; } .Comment { color: #9090ff; } -.Underlined { color: #c000c0; text-decoration: underline; } -.Identifier { color: #804000; } +.Constant { color: #00a0a0; } +.Special { color: #ff6060; } +.Delimiter { color: #a04060; } +.muControl { color: #c0a020; } --> </style> @@ -30,44 +32,44 @@ body { font-family: monospace; color: #eeeeee; background-color: #080808; } <pre id='vimCodeElement'> <span class="Comment"># example program: communicating between routines using channels</span> -recipe producer [ +<span class="muRecipe">recipe</span> producer [ <span class="Comment"># produce numbers 1 to 5 on a channel</span> - <span class="Underlined">local</span>-scope - chan:address:channel<span class="Special"> <- </span>next-ingredient + <span class="Constant">local-scope</span> + chan:address:channel<span class="Special"> <- </span><span class="Constant">next-ingredient</span> <span class="Comment"># n = 0</span> - n:number<span class="Special"> <- </span><span class="Identifier">copy</span> 0 - { - done?:boolean<span class="Special"> <- </span>lesser-than n, 5 - break-unless done? + n:number<span class="Special"> <- </span>copy <span class="Constant">0</span> + <span class="Delimiter">{</span> + done?:boolean<span class="Special"> <- </span>lesser-than n, <span class="Constant">5</span> + <span class="muControl">break-unless</span> done? <span class="Comment"># other threads might get between these prints</span> - $<span class="Identifier">print</span> [produce: ], n, [ -] - chan:address:channel<span class="Special"> <- </span><span class="Identifier">write</span> chan, n - n<span class="Special"> <- </span>add n, 1 - loop - } + $print <span class="Constant">[produce: ]</span>, n, <span class="Constant">[ </span> +<span class="Constant">]</span> + chan:address:channel<span class="Special"> <- </span>write chan, n + n<span class="Special"> <- </span>add n, <span class="Constant">1</span> + <span class="muControl">loop</span> + <span class="Delimiter">}</span> ] -recipe consumer [ +<span class="muRecipe">recipe</span> consumer [ <span class="Comment"># consume and print integers from a channel</span> - <span class="Underlined">local</span>-scope - chan:address:channel<span class="Special"> <- </span>next-ingredient - { + <span class="Constant">local-scope</span> + chan:address:channel<span class="Special"> <- </span><span class="Constant">next-ingredient</span> + <span class="Delimiter">{</span> <span class="Comment"># read an integer from the channel</span> - n:number, chan:address:channel<span class="Special"> <- </span><span class="Identifier">read</span> chan + n:number, chan:address:channel<span class="Special"> <- </span>read chan <span class="Comment"># other threads might get between these prints</span> - $<span class="Identifier">print</span> [consume: ], n:number, [ -] - loop - } + $print <span class="Constant">[consume: ]</span>, n:number, <span class="Constant">[ </span> +<span class="Constant">]</span> + <span class="muControl">loop</span> + <span class="Delimiter">}</span> ] -recipe main [ - <span class="Underlined">local</span>-scope - chan:address:channel<span class="Special"> <- </span><span class="Identifier">new</span>-channel 3 +<span class="muRecipe">recipe</span> main [ + <span class="Constant">local-scope</span> + chan:address:channel<span class="Special"> <- </span>new-channel <span class="Constant">3</span> <span class="Comment"># create two background 'routines' that communicate by a channel</span> - routine1:number<span class="Special"> <- </span>start-running producer:recipe, chan - routine2:number<span class="Special"> <- </span>start-running consumer:recipe, chan + routine1:number<span class="Special"> <- </span>start-running <span class="Constant">producer:recipe</span>, chan + routine2:number<span class="Special"> <- </span>start-running <span class="Constant">consumer:recipe</span>, chan wait-for-routine routine1 wait-for-routine routine2 ] diff --git a/html/chessboard.mu.html b/html/chessboard.mu.html index 75e01db0..56b4842e 100644 --- a/html/chessboard.mu.html +++ b/html/chessboard.mu.html @@ -13,12 +13,16 @@ 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; } +.muRecipe { color: #ff8700; } +.muData { color: #ffff00; } .SalientComment { color: #00ffff; } -.CommentedCode { color: #6c6c6c; } -.Underlined { color: #c000c0; text-decoration: underline; } +.muScenario { color: #00af00; } .Comment { color: #9090ff; } +.Constant { color: #00a0a0; } .Special { color: #ff6060; } -.Identifier { color: #804000; } +.CommentedCode { color: #6c6c6c; } +.Delimiter { color: #a04060; } +.muControl { color: #c0a020; } --> </style> @@ -34,195 +38,195 @@ body { font-family: monospace; color: #eeeeee; background-color: #080808; } <span class="Comment"># display the position after each move.</span> <span class="Comment"># recipes are mu's names for functions</span> -recipe main [ +<span class="muRecipe">recipe</span> main [ open-console <span class="Comment"># take control of screen, keyboard and mouse</span> <span class="Comment"># The chessboard recipe takes keyboard and screen objects as 'ingredients'.</span> - # + <span class="Comment">#</span> <span class="Comment"># In mu it is good form (though not required) to explicitly show the</span> <span class="Comment"># hardware you rely on.</span> - # + <span class="Comment">#</span> <span class="Comment"># The chessboard also returns the same keyboard and screen objects. In mu it</span> <span class="Comment"># is good form to not modify ingredients of a recipe unless they are also</span> <span class="Comment"># results. Here we clearly modify both keyboard and screen, so we return</span> <span class="Comment"># both.</span> - # + <span class="Comment">#</span> <span class="Comment"># Here the console and screen are both 0, which usually indicates real</span> <span class="Comment"># hardware rather than a fake for testing as you'll see below.</span> - 0/screen, 0/console<span class="Special"> <- </span>chessboard 0/screen, 0/console + <span class="Constant">0/screen</span>, <span class="Constant">0/console</span><span class="Special"> <- </span>chessboard <span class="Constant">0/screen</span>, <span class="Constant">0/console</span> close-console <span class="Comment"># cleanup screen, keyboard and mouse</span> ] <span class="SalientComment">## But enough about mu. Here's what it looks like to run the chessboard program.</span> -scenario <span class="Identifier">print</span>-board-and-<span class="Identifier">read</span>-move [ +<span class="muScenario">scenario</span> print-board-and-read-move [ $close-trace <span class="Comment"># administrivia: most scenarios save and check traces, but this one gets too large/slow</span> <span class="Comment"># we'll make the screen really wide because the program currently prints out a long line</span> - <span class="Identifier">assume</span>-screen 120/width, 20/height + assume-screen <span class="Constant">120/width</span>, <span class="Constant">20/height</span> <span class="Comment"># initialize keyboard to type in a move</span> - <span class="Identifier">assume</span>-console [ - <span class="Identifier">type</span> [a2-a4 -] + assume-console [ + type <span class="Constant">[a2-a4</span> +<span class="Constant">]</span> ] run [ screen:address, console:address<span class="Special"> <- </span>chessboard screen:address, console:address <span class="Comment"># icon for the cursor</span> - screen<span class="Special"> <- </span><span class="Identifier">print</span>-character screen, 9251/␣ + screen<span class="Special"> <- </span>print-character screen, <span class="Constant">9251/␣</span> ] screen-should-contain [ <span class="Comment"># 1 2 3 4 5 6 7 8 9 10 11</span> <span class="Comment"># 012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789</span> - .Stupid text-mode chessboard. White pieces <span class="Identifier">in</span> uppercase; black pieces <span class="Identifier">in</span> lowercase. No checking for legal moves. . - . . - .8 | r n b q k b n r . - .7 | p p p p p p p p . - .6 | . - .5 | . - .4 | P . - .3 | . - .2 | P P P P P P P . - .1 | R N B Q K B N R . - . +---------------- . - . a b c d e f g h . - . . - .Type <span class="Identifier">in</span> your move as <from square>-<to square>. For example: 'a2-a4'. Then press <enter>. . - . . - .Hit 'q' to exit. . - . . - .move: ␣ . - . . - . . + <span class="Constant"> .Stupid text-mode chessboard. White pieces in uppercase; black pieces in lowercase. No checking for legal moves. .</span> + <span class="Constant"> . .</span> + <span class="Constant"> .8 | r n b q k b n r .</span> + <span class="Constant"> .7 | p p p p p p p p .</span> + <span class="Constant"> .6 | .</span> + <span class="Constant"> .5 | .</span> + <span class="Constant"> .4 | P .</span> + <span class="Constant"> .3 | .</span> + <span class="Constant"> .2 | P P P P P P P .</span> + <span class="Constant"> .1 | R N B Q K B N R .</span> + <span class="Constant"> . +---------------- .</span> + <span class="Constant"> . a b c d e f g h .</span> + <span class="Constant"> . .</span> + <span class="Constant"> .Type in your move as <from square>-<to square>. For example: 'a2-a4'. Then press <enter>. .</span> + <span class="Constant"> . .</span> + <span class="Constant"> .Hit 'q' to exit. .</span> + <span class="Constant"> . .</span> + <span class="Constant"> .move: ␣ .</span> + <span class="Constant"> . .</span> + <span class="Constant"> . .</span> ] ] <span class="SalientComment">## Here's how 'chessboard' is implemented.</span> -recipe chessboard [ - <span class="Underlined">local</span>-scope - screen:address<span class="Special"> <- </span>next-ingredient - console:address<span class="Special"> <- </span>next-ingredient - board:address:<span class="Identifier">array</span>:address:<span class="Identifier">array</span>:character<span class="Special"> <- </span>initial-position +<span class="muRecipe">recipe</span> chessboard [ + <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> + board:address:array:address:array:character<span class="Special"> <- </span>initial-position <span class="Comment"># hook up stdin</span> - stdin:address:channel<span class="Special"> <- </span><span class="Identifier">new</span>-channel 10/capacity - start-running send-keys-to-channel:recipe, console, stdin, screen + stdin:address:channel<span class="Special"> <- </span>new-channel <span class="Constant">10/capacity</span> + start-running <span class="Constant">send-keys-to-channel:recipe</span>, console, stdin, screen <span class="Comment"># buffer lines in stdin</span> - buffered-stdin:address:channel<span class="Special"> <- </span><span class="Identifier">new</span>-channel 10/capacity - start-running buffer-lines:recipe, stdin, buffered-stdin - { - msg:address:<span class="Identifier">array</span>:character<span class="Special"> <- </span><span class="Identifier">new</span> [Stupid text-mode chessboard. White pieces <span class="Identifier">in</span> uppercase; black pieces <span class="Identifier">in</span> lowercase. No checking for legal moves. -] - <span class="Identifier">print</span>-string screen, msg + buffered-stdin:address:channel<span class="Special"> <- </span>new-channel <span class="Constant">10/capacity</span> + start-running <span class="Constant">buffer-lines:recipe</span>, stdin, buffered-stdin + <span class="Delimiter">{</span> + msg:address:array:character<span class="Special"> <- </span>new <span class="Constant">[Stupid text-mode chessboard. White pieces in uppercase; black pieces in lowercase. No checking for legal moves.</span> +<span class="Constant">]</span> + print-string screen, msg cursor-to-next-line screen - <span class="Identifier">print</span>-board screen, board + print-board screen, board cursor-to-next-line screen - msg<span class="Special"> <- </span><span class="Identifier">new</span> [Type <span class="Identifier">in</span> your move as <from square>-<to square>. For example: 'a2-a4'. Then press <enter>. -] - <span class="Identifier">print</span>-string screen, msg + msg<span class="Special"> <- </span>new <span class="Constant">[Type in your move as <from square>-<to square>. For example: 'a2-a4'. Then press <enter>.</span> +<span class="Constant">]</span> + print-string screen, msg cursor-to-next-line screen - msg<span class="Special"> <- </span><span class="Identifier">new</span> [Hit 'q' to exit. -] - <span class="Identifier">print</span>-string screen, msg - { + msg<span class="Special"> <- </span>new <span class="Constant">[Hit 'q' to exit.</span> +<span class="Constant">]</span> + print-string screen, msg + <span class="Delimiter">{</span> cursor-to-next-line screen - msg<span class="Special"> <- </span><span class="Identifier">new</span> [move: ] - <span class="Identifier">print</span>-string screen, msg - m:address:move, <span class="Identifier">quit</span>:boolean, <span class="Identifier">error</span>:boolean<span class="Special"> <- </span><span class="Identifier">read</span>-move buffered-stdin, screen - break-if <span class="Identifier">quit</span>, +<span class="Identifier">quit</span>:label + msg<span class="Special"> <- </span>new <span class="Constant">[move: ]</span> + print-string screen, msg + m:address:move, quit:boolean, error:boolean<span class="Special"> <- </span>read-move buffered-stdin, screen + <span class="muControl">break-if</span> quit, <span class="Constant">+quit:label</span> buffered-stdin<span class="Special"> <- </span>clear-channel buffered-stdin <span class="Comment"># cleanup after error. todo: test this?</span> - loop-if <span class="Identifier">error</span> - } + <span class="muControl">loop-if</span> error + <span class="Delimiter">}</span> board<span class="Special"> <- </span>make-move board, m clear-screen screen - loop - } - +<span class="Identifier">quit</span> + <span class="muControl">loop</span> + <span class="Delimiter">}</span> +<span class="Constant"> +quit</span> ] <span class="SalientComment">## a board is an array of files, a file is an array of characters (squares)</span> -recipe <span class="Identifier">new</span>-board [ - <span class="Underlined">local</span>-scope - initial-position:address:<span class="Identifier">array</span>:number<span class="Special"> <- </span>next-ingredient +<span class="muRecipe">recipe</span> new-board [ + <span class="Constant">local-scope</span> + initial-position:address:array:number<span class="Special"> <- </span><span class="Constant">next-ingredient</span> <span class="Comment"># assert(length(initial-position) == 64)</span> - len:number<span class="Special"> <- </span><span class="Identifier">length</span> *initial-position - correct-<span class="Identifier">length</span>?:boolean<span class="Special"> <- </span>equal len, 64 - <span class="Identifier">assert</span> correct-<span class="Identifier">length</span>?, [chessboard had incorrect size] + len:number<span class="Special"> <- </span>length *initial-position + correct-length?:boolean<span class="Special"> <- </span>equal len, <span class="Constant">64</span> + assert correct-length?, <span class="Constant">[chessboard had incorrect size]</span> <span class="Comment"># board is an array of pointers to files; file is an array of characters</span> - board:address:<span class="Identifier">array</span>:address:<span class="Identifier">array</span>:character<span class="Special"> <- </span><span class="Identifier">new</span> location:<span class="Identifier">type</span>, 8 - col:number<span class="Special"> <- </span><span class="Identifier">copy</span> 0 - { - done?:boolean<span class="Special"> <- </span>equal col, 8 - break-if done? - file:address:address:<span class="Identifier">array</span>:character<span class="Special"> <- </span>index-address *board, col - *file<span class="Special"> <- </span><span class="Identifier">new</span>-file initial-position, col - col<span class="Special"> <- </span>add col, 1 - loop - } - reply board + board:address:array:address:array:character<span class="Special"> <- </span>new <span class="Constant">location:type</span>, <span class="Constant">8</span> + col:number<span class="Special"> <- </span>copy <span class="Constant">0</span> + <span class="Delimiter">{</span> + done?:boolean<span class="Special"> <- </span>equal col, <span class="Constant">8</span> + <span class="muControl">break-if</span> done? + file:address:address:array:character<span class="Special"> <- </span>index-address *board, col + *file<span class="Special"> <- </span>new-file initial-position, col + col<span class="Special"> <- </span>add col, <span class="Constant">1</span> + <span class="muControl">loop</span> + <span class="Delimiter">}</span> + <span class="muControl">reply</span> board ] -recipe <span class="Identifier">new</span>-file [ - <span class="Underlined">local</span>-scope - position:address:<span class="Identifier">array</span>:number<span class="Special"> <- </span>next-ingredient - index:number<span class="Special"> <- </span>next-ingredient - index<span class="Special"> <- </span>multiply index, 8 - result:address:<span class="Identifier">array</span>:character<span class="Special"> <- </span><span class="Identifier">new</span> character:<span class="Identifier">type</span>, 8 - row:number<span class="Special"> <- </span><span class="Identifier">copy</span> 0 - { - done?:boolean<span class="Special"> <- </span>equal row, 8 - break-if done? +<span class="muRecipe">recipe</span> new-file [ + <span class="Constant">local-scope</span> + position:address:array:number<span class="Special"> <- </span><span class="Constant">next-ingredient</span> + index:number<span class="Special"> <- </span><span class="Constant">next-ingredient</span> + index<span class="Special"> <- </span>multiply index, <span class="Constant">8</span> + result:address:array:character<span class="Special"> <- </span>new <span class="Constant">character:type</span>, <span class="Constant">8</span> + row:number<span class="Special"> <- </span>copy <span class="Constant">0</span> + <span class="Delimiter">{</span> + done?:boolean<span class="Special"> <- </span>equal row, <span class="Constant">8</span> + <span class="muControl">break-if</span> done? dest:address:character<span class="Special"> <- </span>index-address *result, row *dest<span class="Special"> <- </span>index *position, index - row<span class="Special"> <- </span>add row, 1 - index<span class="Special"> <- </span>add index, 1 - loop - } - reply result + row<span class="Special"> <- </span>add row, <span class="Constant">1</span> + index<span class="Special"> <- </span>add index, <span class="Constant">1</span> + <span class="muControl">loop</span> + <span class="Delimiter">}</span> + <span class="muControl">reply</span> result ] -recipe <span class="Identifier">print</span>-board [ - <span class="Underlined">local</span>-scope - screen:address<span class="Special"> <- </span>next-ingredient - board:address:<span class="Identifier">array</span>:address:<span class="Identifier">array</span>:character<span class="Special"> <- </span>next-ingredient - row:number<span class="Special"> <- </span><span class="Identifier">copy</span> 7 <span class="Comment"># start printing from the top of the board</span> +<span class="muRecipe">recipe</span> print-board [ + <span class="Constant">local-scope</span> + screen:address<span class="Special"> <- </span><span class="Constant">next-ingredient</span> + board:address:array:address:array:character<span class="Special"> <- </span><span class="Constant">next-ingredient</span> + row:number<span class="Special"> <- </span>copy <span class="Constant">7</span> <span class="Comment"># start printing from the top of the board</span> <span class="Comment"># print each row</span> - { - done?:boolean<span class="Special"> <- </span>lesser-than row, 0 - break-if done? + <span class="Delimiter">{</span> + done?:boolean<span class="Special"> <- </span>lesser-than row, <span class="Constant">0</span> + <span class="muControl">break-if</span> done? <span class="Comment"># print rank number as a legend</span> - rank:number<span class="Special"> <- </span>add row, 1 - <span class="Identifier">print</span>-integer screen, rank - s:address:<span class="Identifier">array</span>:character<span class="Special"> <- </span><span class="Identifier">new</span> [ | ] - <span class="Identifier">print</span>-string screen, s + rank:number<span class="Special"> <- </span>add row, <span class="Constant">1</span> + print-integer screen, rank + s:address:array:character<span class="Special"> <- </span>new <span class="Constant">[ | ]</span> + print-string screen, s <span class="Comment"># print each square in the row</span> - col:number<span class="Special"> <- </span><span class="Identifier">copy</span> 0 - { - done?:boolean<span class="Special"> <- </span>equal col:number, 8 - break-if done?:boolean - f:address:<span class="Identifier">array</span>:character<span class="Special"> <- </span>index *board, col + col:number<span class="Special"> <- </span>copy <span class="Constant">0</span> + <span class="Delimiter">{</span> + done?:boolean<span class="Special"> <- </span>equal col:number, <span class="Constant">8</span> + <span class="muControl">break-if</span> done?:boolean + f:address:array:character<span class="Special"> <- </span>index *board, col c:character<span class="Special"> <- </span>index *f, row - <span class="Identifier">print</span>-character screen, c - <span class="Identifier">print</span>-character screen, 32/space - col<span class="Special"> <- </span>add col, 1 - loop - } - row<span class="Special"> <- </span>subtract row, 1 + print-character screen, c + print-character screen, <span class="Constant">32/space</span> + col<span class="Special"> <- </span>add col, <span class="Constant">1</span> + <span class="muControl">loop</span> + <span class="Delimiter">}</span> + row<span class="Special"> <- </span>subtract row, <span class="Constant">1</span> cursor-to-next-line screen - loop - } + <span class="muControl">loop</span> + <span class="Delimiter">}</span> <span class="Comment"># print file letters as legend</span> - s<span class="Special"> <- </span><span class="Identifier">new</span> [ +----------------] - <span class="Identifier">print</span>-string screen, s + s<span class="Special"> <- </span>new <span class="Constant">[ +----------------]</span> + print-string screen, s screen<span class="Special"> <- </span>cursor-to-next-line screen - s<span class="Special"> <- </span><span class="Identifier">new</span> [ a b c d e f g h] - screen<span class="Special"> <- </span><span class="Identifier">print</span>-string screen, s + s<span class="Special"> <- </span>new <span class="Constant">[ a b c d e f g h]</span> + screen<span class="Special"> <- </span>print-string screen, s screen<span class="Special"> <- </span>cursor-to-next-line screen ] <span class="Comment"># board:address:array:address:array:character <- initial-position</span> -recipe initial-position [ - <span class="Underlined">local</span>-scope +<span class="muRecipe">recipe</span> initial-position [ + <span class="Constant">local-scope</span> <span class="Comment"># layout in memory (in raster order):</span> <span class="Comment"># R P _ _ _ _ p r</span> <span class="Comment"># N P _ _ _ _ p n</span> @@ -232,7 +236,7 @@ recipe initial-position [ <span class="Comment"># B P _ _ _ _ p B</span> <span class="Comment"># N P _ _ _ _ p n</span> <span class="Comment"># R P _ _ _ _ p r</span> - initial-position:address:<span class="Identifier">array</span>:number<span class="Special"> <- </span><span class="Identifier">new</span>-<span class="Identifier">array</span> 82/R, 80/P, 32/blank, 32/blank, 32/blank, 32/blank, 112/p, 114/r, 78/N, 80/P, 32/blank, 32/blank, 32/blank, 32/blank, 112/p, 110/n, 66/B, 80/P, 32/blank, 32/blank, 32/blank, 32/blank, 112/p, 98/b, 81/Q, 80/P, 32/blank, 32/blank, 32/blank, 32/blank, 112/p, 113/q, 75/K, 80/P, 32/blank, 32/blank, 32/blank, 32/blank, 112/p, 107/k, 66/B, 80/P, 32/blank, 32/blank, 32/blank, 32/blank, 112/p, 98/b, 78/N, 80/P, 32/blank, 32/blank, 32/blank, 32/blank, 112/p, 110/n, 82/R, 80/P, 32/blank, 32/blank, 32/blank, 32/blank, 112/p, 114/r + initial-position:address:array:number<span class="Special"> <- </span>new-array <span class="Constant">82/R</span>, <span class="Constant">80/P</span>, <span class="Constant">32/blank</span>, <span class="Constant">32/blank</span>, <span class="Constant">32/blank</span>, <span class="Constant">32/blank</span>, <span class="Constant">112/p</span>, <span class="Constant">114/r</span>, <span class="Constant">78/N</span>, <span class="Constant">80/P</span>, <span class="Constant">32/blank</span>, <span class="Constant">32/blank</span>, <span class="Constant">32/blank</span>, <span class="Constant">32/blank</span>, <span class="Constant">112/p</span>, <span class="Constant">110/n</span>, <span class="Constant">66/B</span>, <span class="Constant">80/P</span>, <span class="Constant">32/blank</span>, <span class="Constant">32/blank</span>, <span class="Constant">32/blank</span>, <span class="Constant">32/blank</span>, <span class="Constant">112/p</span>, <span class="Constant">98/b</span>, <span class="Constant">81/Q</span>, <span class="Constant">80/P</span>, <span class="Constant">32/blank</span>, <span class="Constant">32/blank</span>, <span class="Constant">32/blank</span>, <span class="Constant">32/blank</span>, <span class="Constant">112/p</span>, <span class="Constant">113/q</span>, <span class="Constant">75/K</span>, <span class="Constant">80/P</span>, <span class="Constant">32/blank</span>, <span class="Constant">32/blank</span>, <span class="Constant">32/blank</span>, <span class="Constant">32/blank</span>, <span class="Constant">112/p</span>, <span class="Constant">107/k</span>, <span class="Constant">66/B</span>, <span class="Constant">80/P</span>, <span class="Constant">32/blank</span>, <span class="Constant">32/blank</span>, <span class="Constant">32/blank</span>, <span class="Constant">32/blank</span>, <span class="Constant">112/p</span>, <span class="Constant">98/b</span>, <span class="Constant">78/N</span>, <span class="Constant">80/P</span>, <span class="Constant">32/blank</span>, <span class="Constant">32/blank</span>, <span class="Constant">32/blank</span>, <span class="Constant">32/blank</span>, <span class="Constant">112/p</span>, <span class="Constant">110/n</span>, <span class="Constant">82/R</span>, <span class="Constant">80/P</span>, <span class="Constant">32/blank</span>, <span class="Constant">32/blank</span>, <span class="Constant">32/blank</span>, <span class="Constant">32/blank</span>, <span class="Constant">112/p</span>, <span class="Constant">114/r</span> <span class="CommentedCode">#? 82/R, 80/P, 32/blank, 32/blank, 32/blank, 32/blank, 112/p, 114/r,</span> <span class="CommentedCode">#? 78/N, 80/P, 32/blank, 32/blank, 32/blank, 32/blank, 112/p, 110/n,</span> <span class="CommentedCode">#? 66/B, 80/P, 32/blank, 32/blank, 32/blank, 32/blank, 112/p, 98/b, </span> @@ -241,36 +245,36 @@ recipe initial-position [ <span class="CommentedCode">#? 66/B, 80/P, 32/blank, 32/blank, 32/blank, 32/blank, 112/p, 98/b,</span> <span class="CommentedCode">#? 78/N, 80/P, 32/blank, 32/blank, 32/blank, 32/blank, 112/p, 110/n,</span> <span class="CommentedCode">#? 82/R, 80/P, 32/blank, 32/blank, 32/blank, 32/blank, 112/p, 114/r</span> - board:address:<span class="Identifier">array</span>:address:<span class="Identifier">array</span>:character<span class="Special"> <- </span><span class="Identifier">new</span>-board initial-position - reply board + board:address:array:address:array:character<span class="Special"> <- </span>new-board initial-position + <span class="muControl">reply</span> board ] -scenario printing-the-board [ - <span class="Identifier">assume</span>-screen 30/width, 12/height +<span class="muScenario">scenario</span> printing-the-board [ + assume-screen <span class="Constant">30/width</span>, <span class="Constant">12/height</span> run [ - 1:address:<span class="Identifier">array</span>:address:<span class="Identifier">array</span>:character/board<span class="Special"> <- </span>initial-position - screen:address<span class="Special"> <- </span><span class="Identifier">print</span>-board screen:address, 1:address:<span class="Identifier">array</span>:address:<span class="Identifier">array</span>:character/board + <span class="Constant">1</span>:address:array:address:array:character/board<span class="Special"> <- </span>initial-position + screen:address<span class="Special"> <- </span>print-board screen:address, <span class="Constant">1</span>:address:array:address:array:character/board ] screen-should-contain [ <span class="Comment"># 012345678901234567890123456789</span> - .8 | r n b q k b n r . - .7 | p p p p p p p p . - .6 | . - .5 | . - .4 | . - .3 | . - .2 | P P P P P P P P . - .1 | R N B Q K B N R . - . +---------------- . - . a b c d e f g h . - . . - . . + <span class="Constant"> .8 | r n b q k b n r .</span> + <span class="Constant"> .7 | p p p p p p p p .</span> + <span class="Constant"> .6 | .</span> + <span class="Constant"> .5 | .</span> + <span class="Constant"> .4 | .</span> + <span class="Constant"> .3 | .</span> + <span class="Constant"> .2 | P P P P P P P P .</span> + <span class="Constant"> .1 | R N B Q K B N R .</span> + <span class="Constant"> . +---------------- .</span> + <span class="Constant"> . a b c d e f g h .</span> + <span class="Constant"> . .</span> + <span class="Constant"> . .</span> ] ] <span class="SalientComment">## data structure: move</span> -container move [ +<span class="muData">container</span> move [ <span class="Comment"># valid range: 0-7</span> from-file:number from-rank:number @@ -280,360 +284,360 @@ container move [ <span class="Comment"># result:address:move, quit?:boolean, error?:boolean <- read-move stdin:address:channel, screen:address</span> <span class="Comment"># prints only error messages to screen</span> -recipe <span class="Identifier">read</span>-move [ - <span class="Underlined">local</span>-scope - stdin:address:channel<span class="Special"> <- </span>next-ingredient - screen:address<span class="Special"> <- </span>next-ingredient - from-file:number, <span class="Identifier">quit</span>?:boolean, <span class="Identifier">error</span>?:boolean<span class="Special"> <- </span><span class="Identifier">read</span>-file stdin, screen - reply-if <span class="Identifier">quit</span>?, 0/dummy, <span class="Identifier">quit</span>?, <span class="Identifier">error</span>? - reply-if <span class="Identifier">error</span>?, 0/dummy, <span class="Identifier">quit</span>?, <span class="Identifier">error</span>? +<span class="muRecipe">recipe</span> read-move [ + <span class="Constant">local-scope</span> + stdin:address:channel<span class="Special"> <- </span><span class="Constant">next-ingredient</span> + screen:address<span class="Special"> <- </span><span class="Constant">next-ingredient</span> + from-file:number, quit?:boolean, error?:boolean<span class="Special"> <- </span>read-file stdin, screen + <span class="muControl">reply-if</span> quit?, <span class="Constant">0/dummy</span>, quit?, error? + <span class="muControl">reply-if</span> error?, <span class="Constant">0/dummy</span>, quit?, error? <span class="Comment"># construct the move object</span> - result:address:move<span class="Special"> <- </span><span class="Identifier">new</span> move:<span class="Identifier">type</span> - x:address:number<span class="Special"> <- </span>get-address *result, from-file:offset - *x<span class="Special"> <- </span><span class="Identifier">copy</span> from-file - x<span class="Special"> <- </span>get-address *result, from-rank:offset - *x, <span class="Identifier">quit</span>?, <span class="Identifier">error</span>?<span class="Special"> <- </span><span class="Identifier">read</span>-rank stdin, screen - reply-if <span class="Identifier">quit</span>?, 0/dummy, <span class="Identifier">quit</span>?, <span class="Identifier">error</span>? - reply-if <span class="Identifier">error</span>?, 0/dummy, <span class="Identifier">quit</span>?, <span class="Identifier">error</span>? - <span class="Identifier">error</span>?<span class="Special"> <- </span>expect-from-channel stdin, 45/dash, screen - reply-if <span class="Identifier">error</span>?, 0/dummy, 0/<span class="Identifier">quit</span>, <span class="Identifier">error</span>? - x<span class="Special"> <- </span>get-address *result, to-file:offset - *x, <span class="Identifier">quit</span>?, <span class="Identifier">error</span>?<span class="Special"> <- </span><span class="Identifier">read</span>-file stdin, screen - reply-if <span class="Identifier">quit</span>?:boolean, 0/dummy, <span class="Identifier">quit</span>?:boolean, <span class="Identifier">error</span>?:boolean - reply-if <span class="Identifier">error</span>?:boolean, 0/dummy, <span class="Identifier">quit</span>?:boolean, <span class="Identifier">error</span>?:boolean - x:address:number<span class="Special"> <- </span>get-address *result, to-rank:offset - *x, <span class="Identifier">quit</span>?, <span class="Identifier">error</span>?<span class="Special"> <- </span><span class="Identifier">read</span>-rank stdin, screen - reply-if <span class="Identifier">quit</span>?, 0/dummy, <span class="Identifier">quit</span>?, <span class="Identifier">error</span>? - reply-if <span class="Identifier">error</span>?, 0/dummy, <span class="Identifier">quit</span>?, <span class="Identifier">error</span>? - <span class="Identifier">error</span>?<span class="Special"> <- </span>expect-from-channel stdin, 10/newline, screen - reply-if <span class="Identifier">error</span>?, 0/dummy, 0/<span class="Identifier">quit</span>, <span class="Identifier">error</span>? - reply result, <span class="Identifier">quit</span>?, <span class="Identifier">error</span>? + result:address:move<span class="Special"> <- </span>new <span class="Constant">move:type</span> + x:address:number<span class="Special"> <- </span>get-address *result, <span class="Constant">from-file:offset</span> + *x<span class="Special"> <- </span>copy from-file + x<span class="Special"> <- </span>get-address *result, <span class="Constant">from-rank:offset</span> + *x, quit?, error?<span class="Special"> <- </span>read-rank stdin, screen + <span class="muControl">reply-if</span> quit?, <span class="Constant">0/dummy</span>, quit?, error? + <span class="muControl">reply-if</span> error?, <span class="Constant">0/dummy</span>, quit?, error? + error?<span class="Special"> <- </span>expect-from-channel stdin, <span class="Constant">45/dash</span>, screen + <span class="muControl">reply-if</span> error?, <span class="Constant">0/dummy</span>, <span class="Constant">0/quit</span>, error? + x<span class="Special"> <- </span>get-address *result, <span class="Constant">to-file:offset</span> + *x, quit?, error?<span class="Special"> <- </span>read-file stdin, screen + <span class="muControl">reply-if</span> quit?:boolean, <span class="Constant">0/dummy</span>, quit?:boolean, error?:boolean + <span class="muControl">reply-if</span> error?:boolean, <span class="Constant">0/dummy</span>, quit?:boolean, error?:boolean + x:address:number<span class="Special"> <- </span>get-address *result, <span class="Constant">to-rank:offset</span> + *x, quit?, error?<span class="Special"> <- </span>read-rank stdin, screen + <span class="muControl">reply-if</span> quit?, <span class="Constant">0/dummy</span>, quit?, error? + <span class="muControl">reply-if</span> error?, <span class="Constant">0/dummy</span>, quit?, error? + error?<span class="Special"> <- </span>expect-from-channel stdin, <span class="Constant">10/newline</span>, screen + <span class="muControl">reply-if</span> error?, <span class="Constant">0/dummy</span>, <span class="Constant">0/quit</span>, error? + <span class="muControl">reply</span> result, quit?, error? ] <span class="Comment"># file:number, quit:boolean, error:boolean <- read-file stdin:address:channel, screen:address</span> <span class="Comment"># valid values for file: 0-7</span> -recipe <span class="Identifier">read</span>-file [ - <span class="Underlined">local</span>-scope - stdin:address:channel<span class="Special"> <- </span>next-ingredient - screen:address<span class="Special"> <- </span>next-ingredient - c:character, stdin<span class="Special"> <- </span><span class="Identifier">read</span> stdin - { - q-pressed?:boolean<span class="Special"> <- </span>equal c, 81/Q - break-unless q-pressed? - reply 0/dummy, 1/<span class="Identifier">quit</span>, 0/<span class="Identifier">error</span> - } - { - q-pressed?<span class="Special"> <- </span>equal c, 113/q - break-unless q-pressed? - reply 0/dummy, 1/<span class="Identifier">quit</span>, 0/<span class="Identifier">error</span> - } - { - empty-fake-keyboard?:boolean<span class="Special"> <- </span>equal c, 0/eof - break-unless empty-fake-keyboard? - reply 0/dummy, 1/<span class="Identifier">quit</span>, 0/<span class="Identifier">error</span> - } - { - newline?:boolean<span class="Special"> <- </span>equal c, 10/newline - break-unless newline? - <span class="Identifier">error</span>-message:address:<span class="Identifier">array</span>:character<span class="Special"> <- </span><span class="Identifier">new</span> [that's not enough] - <span class="Identifier">print</span>-string screen, <span class="Identifier">error</span>-message - reply 0/dummy, 0/<span class="Identifier">quit</span>, 1/<span class="Identifier">error</span> - } - file:number<span class="Special"> <- </span>subtract c, 97/a +<span class="muRecipe">recipe</span> read-file [ + <span class="Constant">local-scope</span> + stdin:address:channel<span class="Special"> <- </span><span class="Constant">next-ingredient</span> + screen:address<span class="Special"> <- </span><span class="Constant">next-ingredient</span> + c:character, stdin<span class="Special"> <- </span>read stdin + <span class="Delimiter">{</span> + q-pressed?:boolean<span class="Special"> <- </span>equal c, <span class="Constant">81/Q</span> + <span class="muControl">break-unless</span> q-pressed? + <span class="muControl">reply</span> <span class="Constant">0/dummy</span>, <span class="Constant">1/quit</span>, <span class="Constant">0/error</span> + <span class="Delimiter">}</span> + <span class="Delimiter">{</span> + q-pressed?<span class="Special"> <- </span>equal c, <span class="Constant">113/q</span> + <span class="muControl">break-unless</span> q-pressed? + <span class="muControl">reply</span> <span class="Constant">0/dummy</span>, <span class="Constant">1/quit</span>, <span class="Constant">0/error</span> + <span class="Delimiter">}</span> + <span class="Delimiter">{</span> + empty-fake-keyboard?:boolean<span class="Special"> <- </span>equal c, <span class="Constant">0/eof</span> + <span class="muControl">break-unless</span> empty-fake-keyboard? + <span class="muControl">reply</span> <span class="Constant">0/dummy</span>, <span class="Constant">1/quit</span>, <span class="Constant">0/error</span> + <span class="Delimiter">}</span> + <span class="Delimiter">{</span> + newline?:boolean<span class="Special"> <- </span>equal c, <span class="Constant">10/newline</span> + <span class="muControl">break-unless</span> newline? + error-message:address:array:character<span class="Special"> <- </span>new <span class="Constant">[that's not enough]</span> + print-string screen, error-message + <span class="muControl">reply</span> <span class="Constant">0/dummy</span>, <span class="Constant">0/quit</span>, <span class="Constant">1/error</span> + <span class="Delimiter">}</span> + file:number<span class="Special"> <- </span>subtract c, <span class="Constant">97/a</span> <span class="Comment"># 'a' <= file <= 'h'</span> - { - above-<span class="Identifier">min</span>:boolean<span class="Special"> <- </span>greater-or-equal file, 0 - break-if above-<span class="Identifier">min</span> - <span class="Identifier">error</span>-message:address:<span class="Identifier">array</span>:character<span class="Special"> <- </span><span class="Identifier">new</span> [file too low: ] - <span class="Identifier">print</span>-string screen, <span class="Identifier">error</span>-message - <span class="Identifier">print</span>-character screen, c + <span class="Delimiter">{</span> + above-min:boolean<span class="Special"> <- </span>greater-or-equal file, <span class="Constant">0</span> + <span class="muControl">break-if</span> above-min + error-message:address:array:character<span class="Special"> <- </span>new <span class="Constant">[file too low: ]</span> + print-string screen, error-message + print-character screen, c cursor-to-next-line screen - reply 0/dummy, 0/<span class="Identifier">quit</span>, 1/<span class="Identifier">error</span> - } - { - below-<span class="Identifier">max</span>:boolean<span class="Special"> <- </span>lesser-than file, 8 - break-if below-<span class="Identifier">max</span> - <span class="Identifier">error</span>-message<span class="Special"> <- </span><span class="Identifier">new</span> [file too high: ] - <span class="Identifier">print</span>-string screen, <span class="Identifier">error</span>-message - <span class="Identifier">print</span>-character screen, c - reply 0/dummy, 0/<span class="Identifier">quit</span>, 1/<span class="Identifier">error</span> - } - reply file, 0/<span class="Identifier">quit</span>, 0/<span class="Identifier">error</span> + <span class="muControl">reply</span> <span class="Constant">0/dummy</span>, <span class="Constant">0/quit</span>, <span class="Constant">1/error</span> + <span class="Delimiter">}</span> + <span class="Delimiter">{</span> + below-max:boolean<span class="Special"> <- </span>lesser-than file, <span class="Constant">8</span> + <span class="muControl">break-if</span> below-max + error-message<span class="Special"> <- </span>new <span class="Constant">[file too high: ]</span> + print-string screen, error-message + print-character screen, c + <span class="muControl">reply</span> <span class="Constant">0/dummy</span>, <span class="Constant">0/quit</span>, <span class="Constant">1/error</span> + <span class="Delimiter">}</span> + <span class="muControl">reply</span> file, <span class="Constant">0/quit</span>, <span class="Constant">0/error</span> ] <span class="Comment"># rank:number <- read-rank stdin:address:channel, screen:address</span> <span class="Comment"># valid values: 0-7, -1 (quit), -2 (error)</span> -recipe <span class="Identifier">read</span>-rank [ - <span class="Underlined">local</span>-scope - stdin:address:channel<span class="Special"> <- </span>next-ingredient - screen:address<span class="Special"> <- </span>next-ingredient - c:character, stdin<span class="Special"> <- </span><span class="Identifier">read</span> stdin - { - q-pressed?:boolean<span class="Special"> <- </span>equal c, 8/Q - break-unless q-pressed? - reply 0/dummy, 1/<span class="Identifier">quit</span>, 0/<span class="Identifier">error</span> - } - { - q-pressed?<span class="Special"> <- </span>equal c, 113/q - break-unless q-pressed? - reply 0/dummy, 1/<span class="Identifier">quit</span>, 0/<span class="Identifier">error</span> - } - { - newline?:boolean<span class="Special"> <- </span>equal c, 10 <span class="Comment"># newline</span> - break-unless newline? - <span class="Identifier">error</span>-message:address:<span class="Identifier">array</span>:character<span class="Special"> <- </span><span class="Identifier">new</span> [that's not enough] - <span class="Identifier">print</span>-string screen, <span class="Identifier">error</span>-message - reply 0/dummy, 0/<span class="Identifier">quit</span>, 1/<span class="Identifier">error</span> - } - rank:number<span class="Special"> <- </span>subtract c, 49/'1' +<span class="muRecipe">recipe</span> read-rank [ + <span class="Constant">local-scope</span> + stdin:address:channel<span class="Special"> <- </span><span class="Constant">next-ingredient</span> + screen:address<span class="Special"> <- </span><span class="Constant">next-ingredient</span> + c:character, stdin<span class="Special"> <- </span>read stdin + <span class="Delimiter">{</span> + q-pressed?:boolean<span class="Special"> <- </span>equal c, <span class="Constant">8/Q</span> + <span class="muControl">break-unless</span> q-pressed? + <span class="muControl">reply</span> <span class="Constant">0/dummy</span>, <span class="Constant">1/quit</span>, <span class="Constant">0/error</span> + <span class="Delimiter">}</span> + <span class="Delimiter">{</span> + q-pressed?<span class="Special"> <- </span>equal c, <span class="Constant">113/q</span> + <span class="muControl">break-unless</span> q-pressed? + <span class="muControl">reply</span> <span class="Constant">0/dummy</span>, <span class="Constant">1/quit</span>, <span class="Constant">0/error</span> + <span class="Delimiter">}</span> + <span class="Delimiter">{</span> + newline?:boolean<span class="Special"> <- </span>equal c, <span class="Constant">10</span> <span class="Comment"># newline</span> + <span class="muControl">break-unless</span> newline? + error-message:address:array:character<span class="Special"> <- </span>new <span class="Constant">[that's not enough]</span> + print-string screen, error-message + <span class="muControl">reply</span> <span class="Constant">0/dummy</span>, <span class="Constant">0/quit</span>, <span class="Constant">1/error</span> + <span class="Delimiter">}</span> + rank:number<span class="Special"> <- </span>subtract c, <span class="Constant">49/'1'</span> <span class="Comment"># assert'1' <= rank <= '8'</span> - { - above-<span class="Identifier">min</span>:boolean<span class="Special"> <- </span>greater-or-equal rank, 0 - break-if above-<span class="Identifier">min</span> - <span class="Identifier">error</span>-message<span class="Special"> <- </span><span class="Identifier">new</span> [rank too low: ] - <span class="Identifier">print</span>-string screen, <span class="Identifier">error</span>-message - <span class="Identifier">print</span>-character screen, c - reply 0/dummy, 0/<span class="Identifier">quit</span>, 1/<span class="Identifier">error</span> - } - { - below-<span class="Identifier">max</span>:boolean<span class="Special"> <- </span>lesser-or-equal rank, 7 - break-if below-<span class="Identifier">max</span> - <span class="Identifier">error</span>-message<span class="Special"> <- </span><span class="Identifier">new</span> [rank too high: ] - <span class="Identifier">print</span>-string screen, <span class="Identifier">error</span>-message - <span class="Identifier">print</span>-character screen, c - reply 0/dummy, 0/<span class="Identifier">quit</span>, 1/<span class="Identifier">error</span> - } - reply rank, 0/<span class="Identifier">quit</span>, 0/<span class="Identifier">error</span> + <span class="Delimiter">{</span> + above-min:boolean<span class="Special"> <- </span>greater-or-equal rank, <span class="Constant">0</span> + <span class="muControl">break-if</span> above-min + error-message<span class="Special"> <- </span>new <span class="Constant">[rank too low: ]</span> + print-string screen, error-message + print-character screen, c + <span class="muControl">reply</span> <span class="Constant">0/dummy</span>, <span class="Constant">0/quit</span>, <span class="Constant">1/error</span> + <span class="Delimiter">}</span> + <span class="Delimiter">{</span> + below-max:boolean<span class="Special"> <- </span>lesser-or-equal rank, <span class="Constant">7</span> + <span class="muControl">break-if</span> below-max + error-message<span class="Special"> <- </span>new <span class="Constant">[rank too high: ]</span> + print-string screen, error-message + print-character screen, c + <span class="muControl">reply</span> <span class="Constant">0/dummy</span>, <span class="Constant">0/quit</span>, <span class="Constant">1/error</span> + <span class="Delimiter">}</span> + <span class="muControl">reply</span> rank, <span class="Constant">0/quit</span>, <span class="Constant">0/error</span> ] <span class="Comment"># read a character from the given channel and check that it's what we expect</span> <span class="Comment"># return true on error</span> -recipe expect-from-channel [ - <span class="Underlined">local</span>-scope - stdin:address:channel<span class="Special"> <- </span>next-ingredient - expected:character<span class="Special"> <- </span>next-ingredient - screen:address<span class="Special"> <- </span>next-ingredient - c:character, stdin<span class="Special"> <- </span><span class="Identifier">read</span> stdin - { - <span class="Identifier">match</span>?:boolean<span class="Special"> <- </span>equal c, expected - break-if <span class="Identifier">match</span>? - s:address:<span class="Identifier">array</span>:character<span class="Special"> <- </span><span class="Identifier">new</span> [expected character not found] - <span class="Identifier">print</span>-string screen, s - } - result:boolean<span class="Special"> <- </span>not <span class="Identifier">match</span>? - reply result +<span class="muRecipe">recipe</span> expect-from-channel [ + <span class="Constant">local-scope</span> + stdin:address:channel<span class="Special"> <- </span><span class="Constant">next-ingredient</span> + expected:character<span class="Special"> <- </span><span class="Constant">next-ingredient</span> + screen:address<span class="Special"> <- </span><span class="Constant">next-ingredient</span> + c:character, stdin<span class="Special"> <- </span>read stdin + <span class="Delimiter">{</span> + match?:boolean<span class="Special"> <- </span>equal c, expected + <span class="muControl">break-if</span> match? + s:address:array:character<span class="Special"> <- </span>new <span class="Constant">[expected character not found]</span> + print-string screen, s + <span class="Delimiter">}</span> + result:boolean<span class="Special"> <- </span>not match? + <span class="muControl">reply</span> result ] -scenario <span class="Identifier">read</span>-move-blocking [ - <span class="Identifier">assume</span>-screen 20/width, 2/height +<span class="muScenario">scenario</span> read-move-blocking [ + assume-screen <span class="Constant">20/width</span>, <span class="Constant">2/height</span> run [ - 1:address:channel<span class="Special"> <- </span><span class="Identifier">new</span>-channel 2 - 2:number/routine<span class="Special"> <- </span>start-running <span class="Identifier">read</span>-move:recipe, 1:address:channel, screen:address + <span class="Constant">1</span>:address:channel<span class="Special"> <- </span>new-channel <span class="Constant">2</span> + <span class="Constant">2</span>:number/routine<span class="Special"> <- </span>start-running <span class="Constant">read-move:recipe</span>, <span class="Constant">1</span>:address:channel, screen:address <span class="Comment"># 'read-move' is waiting for input</span> - wait-for-routine 2:number - 3:number<span class="Special"> <- </span>routine-state 2:number/<span class="Identifier">id</span> - 4:boolean/waiting?<span class="Special"> <- </span>equal 3:number/routine-state, 3/waiting - <span class="Identifier">assert</span> 4:boolean/waiting?, [ -F <span class="Identifier">read</span>-move-blocking: routine failed to pause after coming up (before any keys were pressed)] + wait-for-routine <span class="Constant">2</span>:number + <span class="Constant">3</span>:number<span class="Special"> <- </span>routine-state <span class="Constant">2</span>:number/id + <span class="Constant">4</span>:boolean/waiting?<span class="Special"> <- </span>equal <span class="Constant">3</span>:number/routine-state, <span class="Constant">3/waiting</span> + assert <span class="Constant">4</span>:boolean/waiting?, [ +F read-move-blocking: routine failed to pause <span class="muRecipe">after</span> coming up (<span class="muRecipe">before</span> any keys were pressed)] <span class="Comment"># press 'a'</span> - 1:address:channel<span class="Special"> <- </span><span class="Identifier">write</span> 1:address:channel, 97/a - restart 2:number/routine + <span class="Constant">1</span>:address:channel<span class="Special"> <- </span>write <span class="Constant">1</span>:address:channel, <span class="Constant">97/a</span> + restart <span class="Constant">2</span>:number/routine <span class="Comment"># 'read-move' still waiting for input</span> - wait-for-routine 2:number - 3:number<span class="Special"> <- </span>routine-state 2:number/<span class="Identifier">id</span> - 4:boolean/waiting?<span class="Special"> <- </span>equal 3:number/routine-state, 3/waiting - <span class="Identifier">assert</span> 4:boolean/waiting?, [ -F <span class="Identifier">read</span>-move-blocking: routine failed to pause after rank 'a'] + wait-for-routine <span class="Constant">2</span>:number + <span class="Constant">3</span>:number<span class="Special"> <- </span>routine-state <span class="Constant">2</span>:number/id + <span class="Constant">4</span>:boolean/waiting?<span class="Special"> <- </span>equal <span class="Constant">3</span>:number/routine-state, <span class="Constant">3/waiting</span> + assert <span class="Constant">4</span>:boolean/waiting?, [ +F read-move-blocking: routine failed to pause <span class="muRecipe">after</span> rank 'a'] <span class="Comment"># press '2'</span> - 1:address:channel<span class="Special"> <- </span><span class="Identifier">write</span> 1:address:channel, 50/'2' - restart 2:number/routine + <span class="Constant">1</span>:address:channel<span class="Special"> <- </span>write <span class="Constant">1</span>:address:channel, <span class="Constant">50/'2'</span> + restart <span class="Constant">2</span>:number/routine <span class="Comment"># 'read-move' still waiting for input</span> - wait-for-routine 2:number - 3:number<span class="Special"> <- </span>routine-state 2:number/<span class="Identifier">id</span> - 4:boolean/waiting?<span class="Special"> <- </span>equal 3:number/routine-state, 3/waiting - <span class="Identifier">assert</span> 4:boolean/waiting?, [ -F <span class="Identifier">read</span>-move-blocking: routine failed to pause after file 'a2'] + wait-for-routine <span class="Constant">2</span>:number + <span class="Constant">3</span>:number<span class="Special"> <- </span>routine-state <span class="Constant">2</span>:number/id + <span class="Constant">4</span>:boolean/waiting?<span class="Special"> <- </span>equal <span class="Constant">3</span>:number/routine-state, <span class="Constant">3/waiting</span> + assert <span class="Constant">4</span>:boolean/waiting?, [ +F read-move-blocking: routine failed to pause <span class="muRecipe">after</span> file 'a2'] <span class="Comment"># press '-'</span> - 1:address:channel<span class="Special"> <- </span><span class="Identifier">write</span> 1:address:channel, 45/'-' - restart 2:number/routine + <span class="Constant">1</span>:address:channel<span class="Special"> <- </span>write <span class="Constant">1</span>:address:channel, <span class="Constant">45/'-'</span> + restart <span class="Constant">2</span>:number/routine <span class="Comment"># 'read-move' still waiting for input</span> - wait-for-routine 2:number - 3:number<span class="Special"> <- </span>routine-state 2:number - 4:boolean/waiting?<span class="Special"> <- </span>equal 3:number/routine-state, 3/waiting - <span class="Identifier">assert</span> 4:boolean/waiting?/routine-state, [ -F <span class="Identifier">read</span>-move-blocking: routine failed to pause after hyphen 'a2-'] + wait-for-routine <span class="Constant">2</span>:number + <span class="Constant">3</span>:number<span class="Special"> <- </span>routine-state <span class="Constant">2</span>:number + <span class="Constant">4</span>:boolean/waiting?<span class="Special"> <- </span>equal <span class="Constant">3</span>:number/routine-state, <span class="Constant">3/waiting</span> + assert <span class="Constant">4</span>:boolean/waiting?/routine-state, [ +F read-move-blocking: routine failed to pause <span class="muRecipe">after</span> hyphen 'a2-'] <span class="Comment"># press 'a'</span> - 1:address:channel<span class="Special"> <- </span><span class="Identifier">write</span> 1:address:channel, 97/a - restart 2:number/routine + <span class="Constant">1</span>:address:channel<span class="Special"> <- </span>write <span class="Constant">1</span>:address:channel, <span class="Constant">97/a</span> + restart <span class="Constant">2</span>:number/routine <span class="Comment"># 'read-move' still waiting for input</span> - wait-for-routine 2:number - 3:number<span class="Special"> <- </span>routine-state 2:number - 4:boolean/waiting?<span class="Special"> <- </span>equal 3:number/routine-state, 3/waiting - <span class="Identifier">assert</span> 4:boolean/waiting?/routine-state, [ -F <span class="Identifier">read</span>-move-blocking: routine failed to pause after rank 'a2-a'] + wait-for-routine <span class="Constant">2</span>:number + <span class="Constant">3</span>:number<span class="Special"> <- </span>routine-state <span class="Constant">2</span>:number + <span class="Constant">4</span>:boolean/waiting?<span class="Special"> <- </span>equal <span class="Constant">3</span>:number/routine-state, <span class="Constant">3/waiting</span> + assert <span class="Constant">4</span>:boolean/waiting?/routine-state, [ +F read-move-blocking: routine failed to pause <span class="muRecipe">after</span> rank 'a2-a'] <span class="Comment"># press '4'</span> - 1:address:channel<span class="Special"> <- </span><span class="Identifier">write</span> 1:address:channel, 52/'4' - restart 2:number/routine + <span class="Constant">1</span>:address:channel<span class="Special"> <- </span>write <span class="Constant">1</span>:address:channel, <span class="Constant">52/'4'</span> + restart <span class="Constant">2</span>:number/routine <span class="Comment"># 'read-move' still waiting for input</span> - wait-for-routine 2:number - 3:number<span class="Special"> <- </span>routine-state 2:number - 4:boolean/waiting?<span class="Special"> <- </span>equal 3:number/routine-state, 3/waiting - <span class="Identifier">assert</span> 4:boolean/waiting?, [ -F <span class="Identifier">read</span>-move-blocking: routine failed to pause after file 'a2-a4'] + wait-for-routine <span class="Constant">2</span>:number + <span class="Constant">3</span>:number<span class="Special"> <- </span>routine-state <span class="Constant">2</span>:number + <span class="Constant">4</span>:boolean/waiting?<span class="Special"> <- </span>equal <span class="Constant">3</span>:number/routine-state, <span class="Constant">3/waiting</span> + assert <span class="Constant">4</span>:boolean/waiting?, [ +F read-move-blocking: routine failed to pause <span class="muRecipe">after</span> file 'a2-a4'] <span class="Comment"># press 'newline'</span> - 1:address:channel<span class="Special"> <- </span><span class="Identifier">write</span> 1:address:channel, 10 <span class="Comment"># newline</span> - restart 2:number/routine + <span class="Constant">1</span>:address:channel<span class="Special"> <- </span>write <span class="Constant">1</span>:address:channel, <span class="Constant">10</span> <span class="Comment"># newline</span> + restart <span class="Constant">2</span>:number/routine <span class="Comment"># 'read-move' now completes</span> - wait-for-routine 2:number - 3:number<span class="Special"> <- </span>routine-state 2:number - 4:boolean/completed?<span class="Special"> <- </span>equal 3:number/routine-state, 1/completed - <span class="Identifier">assert</span> 4:boolean/completed?, [ -F <span class="Identifier">read</span>-move-blocking: routine failed to terminate on newline] - trace 1, [test], [reached end] + wait-for-routine <span class="Constant">2</span>:number + <span class="Constant">3</span>:number<span class="Special"> <- </span>routine-state <span class="Constant">2</span>:number + <span class="Constant">4</span>:boolean/completed?<span class="Special"> <- </span>equal <span class="Constant">3</span>:number/routine-state, <span class="Constant">1/completed</span> + assert <span class="Constant">4</span>:boolean/completed?, [ +F read-move-blocking: routine failed to terminate on newline] + trace <span class="Constant">1</span>, <span class="Constant">[test]</span>, <span class="Constant">[reached end]</span> ] trace-should-contain [ test: reached end ] ] -scenario <span class="Identifier">read</span>-move-<span class="Identifier">quit</span> [ - <span class="Identifier">assume</span>-screen 20/width, 2/height +<span class="muScenario">scenario</span> read-move-quit [ + assume-screen <span class="Constant">20/width</span>, <span class="Constant">2/height</span> run [ - 1:address:channel<span class="Special"> <- </span><span class="Identifier">new</span>-channel 2 - 2:number/routine<span class="Special"> <- </span>start-running <span class="Identifier">read</span>-move:recipe, 1:address:channel, screen:address + <span class="Constant">1</span>:address:channel<span class="Special"> <- </span>new-channel <span class="Constant">2</span> + <span class="Constant">2</span>:number/routine<span class="Special"> <- </span>start-running <span class="Constant">read-move:recipe</span>, <span class="Constant">1</span>:address:channel, screen:address <span class="Comment"># 'read-move' is waiting for input</span> - wait-for-routine 2:number - 3:number<span class="Special"> <- </span>routine-state 2:number/<span class="Identifier">id</span> - 4:boolean/waiting?<span class="Special"> <- </span>equal 3:number/routine-state, 3/waiting - <span class="Identifier">assert</span> 4:boolean/waiting?, [ -F <span class="Identifier">read</span>-move-<span class="Identifier">quit</span>: routine failed to pause after coming up (before any keys were pressed)] + wait-for-routine <span class="Constant">2</span>:number + <span class="Constant">3</span>:number<span class="Special"> <- </span>routine-state <span class="Constant">2</span>:number/id + <span class="Constant">4</span>:boolean/waiting?<span class="Special"> <- </span>equal <span class="Constant">3</span>:number/routine-state, <span class="Constant">3/waiting</span> + assert <span class="Constant">4</span>:boolean/waiting?, [ +F read-move-quit: routine failed to pause <span class="muRecipe">after</span> coming up (<span class="muRecipe">before</span> any keys were pressed)] <span class="Comment"># press 'q'</span> - 1:address:channel<span class="Special"> <- </span><span class="Identifier">write</span> 1:address:channel, 113/q - restart 2:number/routine + <span class="Constant">1</span>:address:channel<span class="Special"> <- </span>write <span class="Constant">1</span>:address:channel, <span class="Constant">113/q</span> + restart <span class="Constant">2</span>:number/routine <span class="Comment"># 'read-move' completes</span> - wait-for-routine 2:number - 3:number<span class="Special"> <- </span>routine-state 2:number/<span class="Identifier">id</span> - 4:boolean/completed?<span class="Special"> <- </span>equal 3:number/routine-state, 1/completed - <span class="Identifier">assert</span> 4:boolean/completed?, [ -F <span class="Identifier">read</span>-move-<span class="Identifier">quit</span>: routine failed to terminate on 'q'] - trace 1, [test], [reached end] + wait-for-routine <span class="Constant">2</span>:number + <span class="Constant">3</span>:number<span class="Special"> <- </span>routine-state <span class="Constant">2</span>:number/id + <span class="Constant">4</span>:boolean/completed?<span class="Special"> <- </span>equal <span class="Constant">3</span>:number/routine-state, <span class="Constant">1/completed</span> + assert <span class="Constant">4</span>:boolean/completed?, [ +F read-move-quit: routine failed to terminate on 'q'] + trace <span class="Constant">1</span>, <span class="Constant">[test]</span>, <span class="Constant">[reached end]</span> ] trace-should-contain [ test: reached end ] ] -scenario <span class="Identifier">read</span>-move-illegal-file [ - <span class="Identifier">assume</span>-screen 20/width, 2/height +<span class="muScenario">scenario</span> read-move-illegal-file [ + assume-screen <span class="Constant">20/width</span>, <span class="Constant">2/height</span> run [ - 1:address:channel<span class="Special"> <- </span><span class="Identifier">new</span>-channel 2 - 2:number/routine<span class="Special"> <- </span>start-running <span class="Identifier">read</span>-move:recipe, 1:address:channel, screen:address + <span class="Constant">1</span>:address:channel<span class="Special"> <- </span>new-channel <span class="Constant">2</span> + <span class="Constant">2</span>:number/routine<span class="Special"> <- </span>start-running <span class="Constant">read-move:recipe</span>, <span class="Constant">1</span>:address:channel, screen:address <span class="Comment"># 'read-move' is waiting for input</span> - wait-for-routine 2:number - 3:number<span class="Special"> <- </span>routine-state 2:number/<span class="Identifier">id</span> - 4:boolean/waiting?<span class="Special"> <- </span>equal 3:number/routine-state, 3/waiting - <span class="Identifier">assert</span> 4:boolean/waiting?, [ -F <span class="Identifier">read</span>-move-file: routine failed to pause after coming up (before any keys were pressed)] - 1:address:channel<span class="Special"> <- </span><span class="Identifier">write</span> 1:address:channel, 50/'2' - restart 2:number/routine - wait-for-routine 2:number + wait-for-routine <span class="Constant">2</span>:number + <span class="Constant">3</span>:number<span class="Special"> <- </span>routine-state <span class="Constant">2</span>:number/id + <span class="Constant">4</span>:boolean/waiting?<span class="Special"> <- </span>equal <span class="Constant">3</span>:number/routine-state, <span class="Constant">3/waiting</span> + assert <span class="Constant">4</span>:boolean/waiting?, [ +F read-move-file: routine failed to pause <span class="muRecipe">after</span> coming up (<span class="muRecipe">before</span> any keys were pressed)] + <span class="Constant">1</span>:address:channel<span class="Special"> <- </span>write <span class="Constant">1</span>:address:channel, <span class="Constant">50/'2'</span> + restart <span class="Constant">2</span>:number/routine + wait-for-routine <span class="Constant">2</span>:number ] screen-should-contain [ - .file too low: 2 . - . . + <span class="Constant"> .file too low: 2 .</span> + <span class="Constant"> . .</span> ] ] -scenario <span class="Identifier">read</span>-move-illegal-rank [ - <span class="Identifier">assume</span>-screen 20/width, 2/height +<span class="muScenario">scenario</span> read-move-illegal-rank [ + assume-screen <span class="Constant">20/width</span>, <span class="Constant">2/height</span> run [ - 1:address:channel<span class="Special"> <- </span><span class="Identifier">new</span>-channel 2 - 2:number/routine<span class="Special"> <- </span>start-running <span class="Identifier">read</span>-move:recipe, 1:address:channel, screen:address + <span class="Constant">1</span>:address:channel<span class="Special"> <- </span>new-channel <span class="Constant">2</span> + <span class="Constant">2</span>:number/routine<span class="Special"> <- </span>start-running <span class="Constant">read-move:recipe</span>, <span class="Constant">1</span>:address:channel, screen:address <span class="Comment"># 'read-move' is waiting for input</span> - wait-for-routine 2:number - 3:number<span class="Special"> <- </span>routine-state 2:number/<span class="Identifier">id</span> - 4:boolean/waiting?<span class="Special"> <- </span>equal 3:number/routine-state, 3/waiting - <span class="Identifier">assert</span> 4:boolean/waiting?, [ -F <span class="Identifier">read</span>-move-file: routine failed to pause after coming up (before any keys were pressed)] - 1:address:channel<span class="Special"> <- </span><span class="Identifier">write</span> 1:address:channel, 97/a - 1:address:channel<span class="Special"> <- </span><span class="Identifier">write</span> 1:address:channel, 97/a - restart 2:number/routine - wait-for-routine 2:number + wait-for-routine <span class="Constant">2</span>:number + <span class="Constant">3</span>:number<span class="Special"> <- </span>routine-state <span class="Constant">2</span>:number/id + <span class="Constant">4</span>:boolean/waiting?<span class="Special"> <- </span>equal <span class="Constant">3</span>:number/routine-state, <span class="Constant">3/waiting</span> + assert <span class="Constant">4</span>:boolean/waiting?, [ +F read-move-file: routine failed to pause <span class="muRecipe">after</span> coming up (<span class="muRecipe">before</span> any keys were pressed)] + <span class="Constant">1</span>:address:channel<span class="Special"> <- </span>write <span class="Constant">1</span>:address:channel, <span class="Constant">97/a</span> + <span class="Constant">1</span>:address:channel<span class="Special"> <- </span>write <span class="Constant">1</span>:address:channel, <span class="Constant">97/a</span> + restart <span class="Constant">2</span>:number/routine + wait-for-routine <span class="Constant">2</span>:number ] screen-should-contain [ - .rank too high: a . - . . + <span class="Constant"> .rank too high: a .</span> + <span class="Constant"> . .</span> ] ] -scenario <span class="Identifier">read</span>-move-empty [ - <span class="Identifier">assume</span>-screen 20/width, 2/height +<span class="muScenario">scenario</span> read-move-empty [ + assume-screen <span class="Constant">20/width</span>, <span class="Constant">2/height</span> run [ - 1:address:channel<span class="Special"> <- </span><span class="Identifier">new</span>-channel 2 - 2:number/routine<span class="Special"> <- </span>start-running <span class="Identifier">read</span>-move:recipe, 1:address:channel, screen:address + <span class="Constant">1</span>:address:channel<span class="Special"> <- </span>new-channel <span class="Constant">2</span> + <span class="Constant">2</span>:number/routine<span class="Special"> <- </span>start-running <span class="Constant">read-move:recipe</span>, <span class="Constant">1</span>:address:channel, screen:address <span class="Comment"># 'read-move' is waiting for input</span> - wait-for-routine 2:number - 3:number<span class="Special"> <- </span>routine-state 2:number/<span class="Identifier">id</span> - 4:boolean/waiting?<span class="Special"> <- </span>equal 3:number/routine-state, 3/waiting - <span class="Identifier">assert</span> 4:boolean/waiting?, [ -F <span class="Identifier">read</span>-move-file: routine failed to pause after coming up (before any keys were pressed)] - 1:address:channel<span class="Special"> <- </span><span class="Identifier">write</span> 1:address:channel, 10/newline - 1:address:channel<span class="Special"> <- </span><span class="Identifier">write</span> 1:address:channel, 97/a - restart 2:number/routine - wait-for-routine 2:number + wait-for-routine <span class="Constant">2</span>:number + <span class="Constant">3</span>:number<span class="Special"> <- </span>routine-state <span class="Constant">2</span>:number/id + <span class="Constant">4</span>:boolean/waiting?<span class="Special"> <- </span>equal <span class="Constant">3</span>:number/routine-state, <span class="Constant">3/waiting</span> + assert <span class="Constant">4</span>:boolean/waiting?, [ +F read-move-file: routine failed to pause <span class="muRecipe">after</span> coming up (<span class="muRecipe">before</span> any keys were pressed)] + <span class="Constant">1</span>:address:channel<span class="Special"> <- </span>write <span class="Constant">1</span>:address:channel, <span class="Constant">10/newline</span> + <span class="Constant">1</span>:address:channel<span class="Special"> <- </span>write <span class="Constant">1</span>:address:channel, <span class="Constant">97/a</span> + restart <span class="Constant">2</span>:number/routine + wait-for-routine <span class="Constant">2</span>:number ] screen-should-contain [ - .that's not enough . - . . + <span class="Constant"> .that's not enough .</span> + <span class="Constant"> . .</span> ] ] -recipe make-move [ - <span class="Underlined">local</span>-scope - b:address:<span class="Identifier">array</span>:address:<span class="Identifier">array</span>:character<span class="Special"> <- </span>next-ingredient - m:address:move<span class="Special"> <- </span>next-ingredient - from-file:number<span class="Special"> <- </span>get *m, from-file:offset - from-rank:number<span class="Special"> <- </span>get *m, from-rank:offset - to-file:number<span class="Special"> <- </span>get *m, to-file:offset - to-rank:number<span class="Special"> <- </span>get *m, to-rank:offset - f:address:<span class="Identifier">array</span>:character<span class="Special"> <- </span>index *b, from-file +<span class="muRecipe">recipe</span> make-move [ + <span class="Constant">local-scope</span> + b:address:array:address:array:character<span class="Special"> <- </span><span class="Constant">next-ingredient</span> + m:address:move<span class="Special"> <- </span><span class="Constant">next-ingredient</span> + from-file:number<span class="Special"> <- </span>get *m, <span class="Constant">from-file:offset</span> + from-rank:number<span class="Special"> <- </span>get *m, <span class="Constant">from-rank:offset</span> + to-file:number<span class="Special"> <- </span>get *m, <span class="Constant">to-file:offset</span> + to-rank:number<span class="Special"> <- </span>get *m, <span class="Constant">to-rank:offset</span> + f:address:array:character<span class="Special"> <- </span>index *b, from-file src:address:character/square<span class="Special"> <- </span>index-address *f, from-rank f<span class="Special"> <- </span>index *b, to-file dest:address:character/square<span class="Special"> <- </span>index-address *f, to-rank - *dest<span class="Special"> <- </span><span class="Identifier">copy</span> *src - *src<span class="Special"> <- </span><span class="Identifier">copy</span> 32/space - reply b/same-as-ingredient:0 + *dest<span class="Special"> <- </span>copy *src + *src<span class="Special"> <- </span>copy <span class="Constant">32/space</span> + <span class="muControl">reply</span> b/same-as-ingredient:<span class="Constant">0</span> ] -scenario making-a-move [ - <span class="Identifier">assume</span>-screen 30/width, 12/height +<span class="muScenario">scenario</span> making-a-move [ + assume-screen <span class="Constant">30/width</span>, <span class="Constant">12/height</span> run [ - 2:address:<span class="Identifier">array</span>:address:<span class="Identifier">array</span>:character/board<span class="Special"> <- </span>initial-position - 3:address:move<span class="Special"> <- </span><span class="Identifier">new</span> move:<span class="Identifier">type</span> - 4:address:number<span class="Special"> <- </span>get-address *3:address:move, from-file:offset - *4:address:number<span class="Special"> <- </span><span class="Identifier">copy</span> 6/g - 5:address:number<span class="Special"> <- </span>get-address *3:address:move, from-rank:offset - *5:address:number<span class="Special"> <- </span><span class="Identifier">copy</span> 1/'2' - 6:address:number<span class="Special"> <- </span>get-address *3:address:move, to-file:offset - *6:address:number<span class="Special"> <- </span><span class="Identifier">copy</span> 6/g - 7:address:number<span class="Special"> <- </span>get-address *3:address:move, to-rank:offset - *7:address:number<span class="Special"> <- </span><span class="Identifier">copy</span> 3/'4' - 2:address:<span class="Identifier">array</span>:address:<span class="Identifier">array</span>:character/board<span class="Special"> <- </span>make-move 2:address:<span class="Identifier">array</span>:address:<span class="Identifier">array</span>:character/board, 3:address:move - screen:address<span class="Special"> <- </span><span class="Identifier">print</span>-board screen:address, 2:address:<span class="Identifier">array</span>:address:<span class="Identifier">array</span>:character/board + <span class="Constant">2</span>:address:array:address:array:character/board<span class="Special"> <- </span>initial-position + <span class="Constant">3</span>:address:move<span class="Special"> <- </span>new <span class="Constant">move:type</span> + <span class="Constant">4</span>:address:number<span class="Special"> <- </span>get-address *<span class="Constant">3</span>:address:move, <span class="Constant">from-file:offset</span> + *<span class="Constant">4</span>:address:number<span class="Special"> <- </span>copy <span class="Constant">6/g</span> + <span class="Constant">5</span>:address:number<span class="Special"> <- </span>get-address *<span class="Constant">3</span>:address:move, <span class="Constant">from-rank:offset</span> + *<span class="Constant">5</span>:address:number<span class="Special"> <- </span>copy <span class="Constant">1/'2'</span> + <span class="Constant">6</span>:address:number<span class="Special"> <- </span>get-address *<span class="Constant">3</span>:address:move, <span class="Constant">to-file:offset</span> + *<span class="Constant">6</span>:address:number<span class="Special"> <- </span>copy <span class="Constant">6/g</span> + <span class="Constant">7</span>:address:number<span class="Special"> <- </span>get-address *<span class="Constant">3</span>:address:move, <span class="Constant">to-rank:offset</span> + *<span class="Constant">7</span>:address:number<span class="Special"> <- </span>copy <span class="Constant">3/'4'</span> + <span class="Constant">2</span>:address:array:address:array:character/board<span class="Special"> <- </span>make-move <span class="Constant">2</span>:address:array:address:array:character/board, <span class="Constant">3</span>:address:move + screen:address<span class="Special"> <- </span>print-board screen:address, <span class="Constant">2</span>:address:array:address:array:character/board ] screen-should-contain [ <span class="Comment"># 012345678901234567890123456789</span> - .8 | r n b q k b n r . - .7 | p p p p p p p p . - .6 | . - .5 | . - .4 | P . - .3 | . - .2 | P P P P P P P . - .1 | R N B Q K B N R . - . +---------------- . - . a b c d e f g h . - . . + <span class="Constant"> .8 | r n b q k b n r .</span> + <span class="Constant"> .7 | p p p p p p p p .</span> + <span class="Constant"> .6 | .</span> + <span class="Constant"> .5 | .</span> + <span class="Constant"> .4 | P .</span> + <span class="Constant"> .3 | .</span> + <span class="Constant"> .2 | P P P P P P P .</span> + <span class="Constant"> .1 | R N B Q K B N R .</span> + <span class="Constant"> . +---------------- .</span> + <span class="Constant"> . a b c d e f g h .</span> + <span class="Constant"> . .</span> ] ] </pre> diff --git a/html/console.mu.html b/html/console.mu.html index 203cbd20..116fb450 100644 --- a/html/console.mu.html +++ b/html/console.mu.html @@ -13,9 +13,12 @@ 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; } +.muRecipe { color: #ff8700; } .Comment { color: #9090ff; } +.Delimiter { color: #a04060; } .Special { color: #ff6060; } -.Identifier { color: #804000; } +.Constant { color: #00a0a0; } +.muControl { color: #c0a020; } --> </style> @@ -28,19 +31,19 @@ body { font-family: monospace; color: #eeeeee; background-color: #080808; } <body> <pre id='vimCodeElement'> <span class="Comment"># example program: reading events from keyboard or mouse</span> -# +<span class="Comment">#</span> <span class="Comment"># Keeps printing 'a' until you press a key or click on the mouse.</span> -recipe main [ +<span class="muRecipe">recipe</span> main [ open-console - { + <span class="Delimiter">{</span> e:event, found?:boolean<span class="Special"> <- </span>check-for-interaction - break-if found? - <span class="Identifier">print</span>-character-to-display 97, 7/white - loop - } + <span class="muControl">break-if</span> found? + print-character-to-display <span class="Constant">97</span>, <span class="Constant">7/white</span> + <span class="muControl">loop</span> + <span class="Delimiter">}</span> close-console - $<span class="Identifier">print</span> e, 10/newline + $print e, <span class="Constant">10/newline</span> ] </pre> </body> diff --git a/html/counters.mu.html b/html/counters.mu.html index 45ca7a5d..9a02adca 100644 --- a/html/counters.mu.html +++ b/html/counters.mu.html @@ -13,10 +13,11 @@ 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; } -.Underlined { color: #c000c0; text-decoration: underline; } +.muRecipe { color: #ff8700; } .Comment { color: #9090ff; } +.Constant { color: #00a0a0; } .Special { color: #ff6060; } -.Identifier { color: #804000; } +.muControl { color: #c0a020; } --> </style> @@ -31,36 +32,36 @@ body { font-family: monospace; color: #eeeeee; background-color: #080808; } <span class="Comment"># example program: maintain multiple counters with isolated lexical scopes</span> <span class="Comment"># (spaces)</span> -recipe <span class="Identifier">new</span>-counter [ - default-space:address:<span class="Identifier">array</span>:location<span class="Special"> <- </span><span class="Identifier">new</span> location:<span class="Identifier">type</span>, 30 - n:number<span class="Special"> <- </span>next-ingredient - reply default-space +<span class="muRecipe">recipe</span> new-counter [ + <span class="Constant">default-space</span>:address:array:location<span class="Special"> <- </span>new <span class="Constant">location:type</span>, <span class="Constant">30</span> + n:number<span class="Special"> <- </span><span class="Constant">next-ingredient</span> + <span class="muControl">reply</span> <span class="Constant">default-space</span> ] -recipe increment-counter [ - <span class="Underlined">local</span>-scope - 0:address:<span class="Identifier">array</span>:location/names:<span class="Identifier">new</span>-counter<span class="Special"> <- </span>next-ingredient <span class="Comment"># setup outer space; it *must* come from 'new-counter'</span> - x:number<span class="Special"> <- </span>next-ingredient - n:number/space:1<span class="Special"> <- </span>add n:number/space:1, x - reply n:number/space:1 +<span class="muRecipe">recipe</span> increment-counter [ + <span class="Constant">local-scope</span> + <span class="Constant">0</span>:address:array:location/names:new-counter<span class="Special"> <- </span><span class="Constant">next-ingredient</span> <span class="Comment"># setup outer space; it *must* come from 'new-counter'</span> + x:number<span class="Special"> <- </span><span class="Constant">next-ingredient</span> + n:number/space:<span class="Constant">1</span><span class="Special"> <- </span>add n:number/space:<span class="Constant">1</span>, x + <span class="muControl">reply</span> n:number/space:<span class="Constant">1</span> ] -recipe main [ - <span class="Underlined">local</span>-scope +<span class="muRecipe">recipe</span> main [ + <span class="Constant">local-scope</span> <span class="Comment"># counter A</span> - a:address:<span class="Identifier">array</span>:location<span class="Special"> <- </span><span class="Identifier">new</span>-counter 34 + a:address:array:location<span class="Special"> <- </span>new-counter <span class="Constant">34</span> <span class="Comment"># counter B</span> - b:address:<span class="Identifier">array</span>:location<span class="Special"> <- </span><span class="Identifier">new</span>-counter 23 + b:address:array:location<span class="Special"> <- </span>new-counter <span class="Constant">23</span> <span class="Comment"># increment both by 2 but in different ways</span> - increment-counter a, 1 - b-value:number<span class="Special"> <- </span>increment-counter b, 2 - a-value:number<span class="Special"> <- </span>increment-counter a, 1 + increment-counter a, <span class="Constant">1</span> + b-value:number<span class="Special"> <- </span>increment-counter b, <span class="Constant">2</span> + a-value:number<span class="Special"> <- </span>increment-counter a, <span class="Constant">1</span> <span class="Comment"># check results</span> - $<span class="Identifier">print</span> [Contents of counters -] + $print <span class="Constant">[Contents of counters</span> +<span class="Constant">]</span> <span class="Comment"># trailing space in next line is to help with syntax highlighting</span> - $<span class="Identifier">print</span> [a: ], a-value, [ b: ], b-value, [ -] + $print <span class="Constant">[a: ]</span>, a-value, <span class="Constant">[ b: ]</span>, b-value, <span class="Constant">[ </span> +<span class="Constant">]</span> ] </pre> </body> diff --git a/html/display.mu.html b/html/display.mu.html index fea2d45a..ce820d27 100644 --- a/html/display.mu.html +++ b/html/display.mu.html @@ -13,9 +13,10 @@ 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; } +.muRecipe { color: #ff8700; } .Comment { color: #9090ff; } +.Constant { color: #00a0a0; } .Special { color: #ff6060; } -.Identifier { color: #804000; } --> </style> @@ -29,16 +30,16 @@ body { font-family: monospace; color: #eeeeee; background-color: #080808; } <pre id='vimCodeElement'> <span class="Comment"># example program: managing the display</span> -recipe main [ +<span class="muRecipe">recipe</span> main [ open-console - <span class="Identifier">print</span>-character-to-display 97, 1/red, 2/green - 1:number/<span class="Special">raw</span>, 2:number/<span class="Special">raw <- </span>cursor-position-on-display + print-character-to-display <span class="Constant">97</span>, <span class="Constant">1/red</span>, <span class="Constant">2/green</span> + <span class="Constant">1</span>:number/<span class="Special">raw</span>, <span class="Constant">2</span>:number/<span class="Special">raw <- </span>cursor-position-on-display wait-for-some-interaction clear-display - move-cursor-on-display 0, 4 - <span class="Identifier">print</span>-character-to-display 98 + move-cursor-on-display <span class="Constant">0</span>, <span class="Constant">4</span> + print-character-to-display <span class="Constant">98</span> wait-for-some-interaction - move-cursor-on-display 0, 0 + move-cursor-on-display <span class="Constant">0</span>, <span class="Constant">0</span> clear-line-on-display wait-for-some-interaction move-cursor-down-on-display diff --git a/html/edit.mu.html b/html/edit.mu.html deleted file mode 100644 index d50b41f2..00000000 --- a/html/edit.mu.html +++ /dev/null @@ -1,6555 +0,0 @@ -<!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; } -.muRecipe { color: #ff8700; } -.SalientComment { color: #00ffff; } -.muScenario { color: #00af00; } -.Comment { color: #9090ff; } -.Constant { color: #00a0a0; } -.Special { color: #ff6060; } -.CommentedCode { color: #6c6c6c; } -.Delimiter { color: #a04060; } -.muControl { color: #c0a020; } ---> -</style> - -<script type='text/javascript'> -<!-- - ---> -</script> -</head> -<body> -<pre id='vimCodeElement'> -<span class="Comment"># Environment for learning programming using mu: <a href="http://akkartik.name/post/mu">http://akkartik.name/post/mu</a></span> -<span class="Comment">#</span> -<span class="Comment"># Consists of one editor on the left for recipes and one on the right for the</span> -<span class="Comment"># sandbox.</span> - -<span class="muRecipe">recipe</span> main [ - <span class="Constant">local-scope</span> - open-console - initial-recipe:address:array:character<span class="Special"> <- </span>restore <span class="Constant">[recipes.mu]</span> - initial-sandbox:address:array:character<span class="Special"> <- </span>new <span class="Constant">[]</span> - hide-screen <span class="Constant">0/screen</span> - env:address:programming-environment-data<span class="Special"> <- </span>new-programming-environment <span class="Constant">0/screen</span>, initial-recipe, initial-sandbox - env<span class="Special"> <- </span>restore-sandboxes env - render-all <span class="Constant">0/screen</span>, env - event-loop <span class="Constant">0/screen</span>, <span class="Constant">0/console</span>, env - <span class="Comment"># never gets here</span> -] - -<span class="SalientComment">## the basic editor data structure, and how it displays text to the screen</span> - -<span class="muScenario">scenario</span> editor-initially-prints-string-to-screen [ - assume-screen <span class="Constant">10/width</span>, <span class="Constant">5/height</span> - run [ - <span class="Constant">1</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[abc]</span> - new-editor <span class="Constant">1</span>:address:array:character, screen:address, <span class="Constant">0/left</span>, <span class="Constant">10/right</span> - ] - screen-should-contain [ - <span class="Constant"> . .</span> - <span class="Constant"> .abc .</span> - <span class="Constant"> . .</span> - ] -] - -container editor-data [ - <span class="Comment"># editable text: doubly linked list of characters (head contains a special sentinel)</span> - data:address:duplex-list - top-of-screen:address:duplex-list - bottom-of-screen:address:duplex-list - <span class="Comment"># location before cursor inside data</span> - before-cursor:address:duplex-list - - <span class="Comment"># raw bounds of display area on screen</span> - <span class="Comment"># always displays from row 1 (leaving row 0 for a menu) and at most until bottom of screen</span> - left:number - right:number - <span class="Comment"># raw screen coordinates of cursor</span> - cursor-row:number - cursor-column:number -] - -<span class="Comment"># editor:address, screen <- 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<span class="Special"> <- </span>subtract right, <span class="Constant">1</span> - result:address:editor-data<span class="Special"> <- </span>new <span class="Constant">editor-data:type</span> - <span class="Comment"># initialize screen-related fields</span> - x:address:number<span class="Special"> <- </span>get-address *result, <span class="Constant">left:offset</span> - *x<span class="Special"> <- </span>copy left - x<span class="Special"> <- </span>get-address *result, <span class="Constant">right:offset</span> - *x<span class="Special"> <- </span>copy right - <span class="Comment"># initialize cursor</span> - x<span class="Special"> <- </span>get-address *result, <span class="Constant">cursor-row:offset</span> - *x<span class="Special"> <- </span>copy <span class="Constant">1/top</span> - x<span class="Special"> <- </span>get-address *result, <span class="Constant">cursor-column:offset</span> - *x<span class="Special"> <- </span>copy left - init:address:address:duplex-list<span class="Special"> <- </span>get-address *result, <span class="Constant">data:offset</span> - *init<span class="Special"> <- </span>push-duplex <span class="Constant">167/§</span>, <span class="Constant">0/tail</span> - top-of-screen:address:address:duplex-list<span class="Special"> <- </span>get-address *result, <span class="Constant">top-of-screen:offset</span> - *top-of-screen<span class="Special"> <- </span>copy *init - y:address:address:duplex-list<span class="Special"> <- </span>get-address *result, <span class="Constant">before-cursor:offset</span> - *y<span class="Special"> <- </span>copy *init - result<span class="Special"> <- </span>insert-text result, s - <span class="Comment"># initialize cursor to top of screen</span> - y<span class="Special"> <- </span>get-address *result, <span class="Constant">before-cursor:offset</span> - *y<span class="Special"> <- </span>copy *init - <span class="Comment"># initial render to screen, just for some old tests</span> - _, _, screen, result<span class="Special"> <- </span>render screen, result -<span class="Constant"> +editor-initialization</span> - <span class="muControl">reply</span> result -] - -<span class="muRecipe">recipe</span> insert-text [ - <span class="Constant">local-scope</span> - editor:address:editor-data<span class="Special"> <- </span><span class="Constant">next-ingredient</span> - text:address:array:character<span class="Special"> <- </span><span class="Constant">next-ingredient</span> - <span class="Comment"># early exit if text is empty</span> - <span class="muControl">reply-unless</span> text, editor/same-as-ingredient:<span class="Constant">0</span> - len:number<span class="Special"> <- </span>length *text - <span class="muControl">reply-unless</span> len, editor/same-as-ingredient:<span class="Constant">0</span> - idx:number<span class="Special"> <- </span>copy <span class="Constant">0</span> - <span class="Comment"># now we can start appending the rest, character by character</span> - curr:address:duplex-list<span class="Special"> <- </span>get *editor, <span class="Constant">data:offset</span> - <span class="Delimiter">{</span> - done?:boolean<span class="Special"> <- </span>greater-or-equal idx, len - <span class="muControl">break-if</span> done? - c:character<span class="Special"> <- </span>index *text, idx - insert-duplex c, curr - <span class="Comment"># next iter</span> - curr<span class="Special"> <- </span>next-duplex curr - idx<span class="Special"> <- </span>add idx, <span class="Constant">1</span> - <span class="muControl">loop</span> - <span class="Delimiter">}</span> - <span class="muControl">reply</span> editor/same-as-ingredient:<span class="Constant">0</span> -] - -<span class="muScenario">scenario</span> editor-initializes-without-data [ - assume-screen <span class="Constant">5/width</span>, <span class="Constant">3/height</span> - run [ - <span class="Constant">1</span>:address:editor-data<span class="Special"> <- </span>new-editor <span class="Constant">0/data</span>, screen:address, <span class="Constant">2/left</span>, <span class="Constant">5/right</span> - <span class="Constant">2</span>:editor-data<span class="Special"> <- </span>copy *<span class="Constant">1</span>:address:editor-data - ] - memory-should-contain [ - <span class="Comment"># 2 (data) <- just the § sentinel</span> - <span class="Comment"># 3 (top of screen) <- the § sentinel</span> - <span class="Constant">4</span><span class="Special"> <- </span><span class="Constant">0</span> <span class="Comment"># bottom-of-screen; null since text fits on screen</span> - <span class="Comment"># 5 (before cursor) <- the § sentinel</span> - <span class="Constant">6</span><span class="Special"> <- </span><span class="Constant">2</span> <span class="Comment"># left</span> - <span class="Constant">7</span><span class="Special"> <- </span><span class="Constant">4</span> <span class="Comment"># right (inclusive)</span> - <span class="Constant">8</span><span class="Special"> <- </span><span class="Constant">1</span> <span class="Comment"># cursor row</span> - <span class="Constant">9</span><span class="Special"> <- </span><span class="Constant">2</span> <span class="Comment"># cursor column</span> - ] - screen-should-contain [ - <span class="Constant"> . .</span> - <span class="Constant"> . .</span> - <span class="Constant"> . .</span> - ] -] - -<span class="Comment"># last-row:number, last-column:number, screen, editor <- render screen:address, editor:address:editor-data</span> -<span class="Comment">#</span> -<span class="Comment"># Assumes cursor should be at coordinates (cursor-row, cursor-column) and</span> -<span class="Comment"># updates before-cursor to match. Might also move coordinates if they're</span> -<span class="Comment"># outside text.</span> -<span class="muRecipe">recipe</span> render [ - <span class="Constant">local-scope</span> - screen:address<span class="Special"> <- </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, <span class="Constant">1/top</span>, screen/same-as-ingredient:<span class="Constant">0</span>, editor/same-as-ingredient:<span class="Constant">1</span> - left:number<span class="Special"> <- </span>get *editor, <span class="Constant">left:offset</span> - screen-height:number<span class="Special"> <- </span>screen-height screen - right:number<span class="Special"> <- </span>get *editor, <span class="Constant">right:offset</span> - <span class="Comment"># traversing editor</span> - curr:address:duplex-list<span class="Special"> <- </span>get *editor, <span class="Constant">top-of-screen:offset</span> - prev:address:duplex-list<span class="Special"> <- </span>copy curr <span class="Comment"># just in case curr becomes null and we can't compute prev-duplex</span> - curr<span class="Special"> <- </span>next-duplex curr - <span class="Comment"># traversing screen</span> -<span class="Constant"> +render-loop-initialization</span> - color:number<span class="Special"> <- </span>copy <span class="Constant">7/white</span> - row:number<span class="Special"> <- </span>copy <span class="Constant">1/top</span> - column:number<span class="Special"> <- </span>copy left - cursor-row:address:number<span class="Special"> <- </span>get-address *editor, <span class="Constant">cursor-row:offset</span> - cursor-column:address:number<span class="Special"> <- </span>get-address *editor, <span class="Constant">cursor-column:offset</span> - before-cursor:address:address:duplex-list<span class="Special"> <- </span>get-address *editor, <span class="Constant">before-cursor:offset</span> - screen<span class="Special"> <- </span>move-cursor screen, row, column - <span class="Delimiter">{</span> -<span class="Constant"> +next-character</span> - <span class="muControl">break-unless</span> curr - off-screen?:boolean<span class="Special"> <- </span>greater-or-equal row, screen-height - <span class="muControl">break-if</span> off-screen? - <span class="Comment"># update editor-data.before-cursor</span> - <span class="Comment"># Doing so at the start of each iteration ensures it stays one step behind</span> - <span class="Comment"># the current character.</span> - <span class="Delimiter">{</span> - at-cursor-row?:boolean<span class="Special"> <- </span>equal row, *cursor-row - <span class="muControl">break-unless</span> at-cursor-row? - at-cursor?:boolean<span class="Special"> <- </span>equal column, *cursor-column - <span class="muControl">break-unless</span> at-cursor? - *before-cursor<span class="Special"> <- </span>copy prev - <span class="Delimiter">}</span> - c:character<span class="Special"> <- </span>get *curr, <span class="Constant">value:offset</span> -<span class="Constant"> +character-c-received</span> - <span class="Delimiter">{</span> - <span class="Comment"># newline? move to left rather than 0</span> - newline?:boolean<span class="Special"> <- </span>equal c, <span class="Constant">10/newline</span> - <span class="muControl">break-unless</span> newline? - <span class="Comment"># adjust cursor if necessary</span> - <span class="Delimiter">{</span> - at-cursor-row?:boolean<span class="Special"> <- </span>equal row, *cursor-row - <span class="muControl">break-unless</span> at-cursor-row? - left-of-cursor?:boolean<span class="Special"> <- </span>lesser-than column, *cursor-column - <span class="muControl">break-unless</span> left-of-cursor? - *cursor-column<span class="Special"> <- </span>copy column - *before-cursor<span class="Special"> <- </span>prev-duplex curr - <span class="Delimiter">}</span> - <span class="Comment"># clear rest of line in this window</span> - clear-line-delimited screen, column, right - <span class="Comment"># skip to next line</span> - row<span class="Special"> <- </span>add row, <span class="Constant">1</span> - column<span class="Special"> <- </span>copy left - screen<span class="Special"> <- </span>move-cursor screen, row, column - curr<span class="Special"> <- </span>next-duplex curr - prev<span class="Special"> <- </span>next-duplex prev - <span class="muControl">loop</span> <span class="Constant">+next-character:label</span> - <span class="Delimiter">}</span> - <span class="Delimiter">{</span> - <span class="Comment"># at right? wrap. even if there's only one more letter left; we need</span> - <span class="Comment"># room for clicking on the cursor after it.</span> - at-right?:boolean<span class="Special"> <- </span>equal column, right - <span class="muControl">break-unless</span> at-right? - <span class="Comment"># print wrap icon</span> - print-character screen, <span class="Constant">8617/loop-back-to-left</span>, <span class="Constant">245/grey</span> - column<span class="Special"> <- </span>copy left - row<span class="Special"> <- </span>add row, <span class="Constant">1</span> - screen<span class="Special"> <- </span>move-cursor screen, row, column - <span class="Comment"># don't increment curr</span> - <span class="muControl">loop</span> <span class="Constant">+next-character:label</span> - <span class="Delimiter">}</span> - print-character screen, c, color - curr<span class="Special"> <- </span>next-duplex curr - prev<span class="Special"> <- </span>next-duplex prev - column<span class="Special"> <- </span>add column, <span class="Constant">1</span> - <span class="muControl">loop</span> - <span class="Delimiter">}</span> - <span class="Comment"># save first character off-screen</span> - bottom-of-screen:address:address:duplex-list<span class="Special"> <- </span>get-address *editor, <span class="Constant">bottom-of-screen:offset</span> - *bottom-of-screen<span class="Special"> <- </span>copy curr - <span class="Comment"># is cursor to the right of the last line? move to end</span> - <span class="Delimiter">{</span> - at-cursor-row?:boolean<span class="Special"> <- </span>equal row, *cursor-row - cursor-outside-line?:boolean<span class="Special"> <- </span>lesser-or-equal column, *cursor-column - before-cursor-on-same-line?:boolean<span class="Special"> <- </span>and at-cursor-row?, cursor-outside-line? - above-cursor-row?:boolean<span class="Special"> <- </span>lesser-than row, *cursor-row - before-cursor?:boolean<span class="Special"> <- </span>or before-cursor-on-same-line?, above-cursor-row? - <span class="muControl">break-unless</span> before-cursor? - *cursor-row<span class="Special"> <- </span>copy row - *cursor-column<span class="Special"> <- </span>copy column - *before-cursor<span class="Special"> <- </span>copy prev - <span class="Delimiter">}</span> - <span class="muControl">reply</span> row, column, screen/same-as-ingredient:<span class="Constant">0</span>, editor/same-as-ingredient:<span class="Constant">1</span> -] - -<span class="Comment"># row, screen <- 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<span class="Special"> <- </span>add row, <span class="Constant">1</span> - <span class="muControl">reply-unless</span> s, row/same-as-ingredient:<span class="Constant">5</span>, screen/same-as-ingredient:<span class="Constant">0</span> - column:number<span class="Special"> <- </span>copy left - screen<span class="Special"> <- </span>move-cursor screen, row, column - screen-height:number<span class="Special"> <- </span>screen-height screen - i:number<span class="Special"> <- </span>copy <span class="Constant">0</span> - len:number<span class="Special"> <- </span>length *s - <span class="Delimiter">{</span> -<span class="Constant"> +next-character</span> - done?:boolean<span class="Special"> <- </span>greater-or-equal i, len - <span class="muControl">break-if</span> done? - done?<span class="Special"> <- </span>greater-or-equal row, screen-height - <span class="muControl">break-if</span> done? - c:character<span class="Special"> <- </span>index *s, i - <span class="Delimiter">{</span> - <span class="Comment"># at right? wrap.</span> - at-right?:boolean<span class="Special"> <- </span>equal column, right - <span class="muControl">break-unless</span> at-right? - <span class="Comment"># print wrap icon</span> - print-character screen, <span class="Constant">8617/loop-back-to-left</span>, <span class="Constant">245/grey</span> - column<span class="Special"> <- </span>copy left - row<span class="Special"> <- </span>add row, <span class="Constant">1</span> - screen<span class="Special"> <- </span>move-cursor screen, row, column - <span class="muControl">loop</span> <span class="Constant">+next-character:label</span> <span class="Comment"># retry i</span> - <span class="Delimiter">}</span> - i<span class="Special"> <- </span>add i, <span class="Constant">1</span> - <span class="Delimiter">{</span> - <span class="Comment"># newline? move to left rather than 0</span> - newline?:boolean<span class="Special"> <- </span>equal c, <span class="Constant">10/newline</span> - <span class="muControl">break-unless</span> newline? - <span class="Comment"># clear rest of line in this window</span> - <span class="Delimiter">{</span> - done?:boolean<span class="Special"> <- </span>greater-than column, right - <span class="muControl">break-if</span> done? - print-character screen, <span class="Constant">32/space</span> - column<span class="Special"> <- </span>add column, <span class="Constant">1</span> - <span class="muControl">loop</span> - <span class="Delimiter">}</span> - row<span class="Special"> <- </span>add row, <span class="Constant">1</span> - column<span class="Special"> <- </span>copy left - screen<span class="Special"> <- </span>move-cursor screen, row, column - <span class="muControl">loop</span> <span class="Constant">+next-character:label</span> - <span class="Delimiter">}</span> - print-character screen, c, color - column<span class="Special"> <- </span>add column, <span class="Constant">1</span> - <span class="muControl">loop</span> - <span class="Delimiter">}</span> - <span class="Delimiter">{</span> - <span class="Comment"># clear rest of current line</span> - line-done?:boolean<span class="Special"> <- </span>greater-than column, right - <span class="muControl">break-if</span> line-done? - print-character screen, <span class="Constant">32/space</span> - column<span class="Special"> <- </span>add column, <span class="Constant">1</span> - <span class="muControl">loop</span> - <span class="Delimiter">}</span> - <span class="muControl">reply</span> row/same-as-ingredient:<span class="Constant">5</span>, screen/same-as-ingredient:<span class="Constant">0</span> -] - -<span class="muRecipe">recipe</span> clear-line-delimited [ - <span class="Constant">local-scope</span> - screen:address<span class="Special"> <- </span><span class="Constant">next-ingredient</span> - column:number<span class="Special"> <- </span><span class="Constant">next-ingredient</span> - right:number<span class="Special"> <- </span><span class="Constant">next-ingredient</span> - <span class="Delimiter">{</span> - done?:boolean<span class="Special"> <- </span>greater-than column, right - <span class="muControl">break-if</span> done? - print-character screen, <span class="Constant">32/space</span> - column<span class="Special"> <- </span>add column, <span class="Constant">1</span> - <span class="muControl">loop</span> - <span class="Delimiter">}</span> -] - -<span class="muRecipe">recipe</span> clear-screen-from [ - <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> - column:number<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> - <span class="Comment"># if it's the real screen, use the optimized primitive</span> - <span class="Delimiter">{</span> - <span class="muControl">break-if</span> screen - clear-display-from row, column, left, right - <span class="muControl">reply</span> screen/same-as-ingredient:<span class="Constant">0</span> - <span class="Delimiter">}</span> - <span class="Comment"># if not, go the slower route</span> - screen<span class="Special"> <- </span>move-cursor screen, row, column - clear-line-delimited screen, column, right - clear-rest-of-screen screen, row, left, right - <span class="muControl">reply</span> screen/same-as-ingredient:<span class="Constant">0</span> -] - -<span class="muRecipe">recipe</span> clear-rest-of-screen [ - <span class="Constant">local-scope</span> - screen:address<span class="Special"> <- </span><span class="Constant">next-ingredient</span> - row:number<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<span class="Special"> <- </span>add row, <span class="Constant">1</span> - screen<span class="Special"> <- </span>move-cursor screen, row, left - screen-height:number<span class="Special"> <- </span>screen-height screen - <span class="Delimiter">{</span> - at-bottom-of-screen?:boolean<span class="Special"> <- </span>greater-or-equal row, screen-height - <span class="muControl">break-if</span> at-bottom-of-screen? - screen<span class="Special"> <- </span>move-cursor screen, row, left - clear-line-delimited screen, left, right - row<span class="Special"> <- </span>add row, <span class="Constant">1</span> - <span class="muControl">loop</span> - <span class="Delimiter">}</span> -] - -<span class="muScenario">scenario</span> editor-initially-prints-multiple-lines [ - assume-screen <span class="Constant">5/width</span>, <span class="Constant">5/height</span> - run [ - s:address:array:character<span class="Special"> <- </span>new <span class="Constant">[abc</span> -<span class="Constant">def]</span> - new-editor s:address:array:character, screen:address, <span class="Constant">0/left</span>, <span class="Constant">5/right</span> - ] - screen-should-contain [ - <span class="Constant"> . .</span> - <span class="Constant"> .abc .</span> - <span class="Constant"> .def .</span> - <span class="Constant"> . .</span> - ] -] - -<span class="muScenario">scenario</span> editor-initially-handles-offsets [ - assume-screen <span class="Constant">5/width</span>, <span class="Constant">5/height</span> - run [ - s:address:array:character<span class="Special"> <- </span>new <span class="Constant">[abc]</span> - new-editor s:address:array:character, screen:address, <span class="Constant">1/left</span>, <span class="Constant">5/right</span> - ] - screen-should-contain [ - <span class="Constant"> . .</span> - <span class="Constant"> . abc .</span> - <span class="Constant"> . .</span> - ] -] - -<span class="muScenario">scenario</span> editor-initially-prints-multiple-lines-at-offset [ - assume-screen <span class="Constant">5/width</span>, <span class="Constant">5/height</span> - run [ - s:address:array:character<span class="Special"> <- </span>new <span class="Constant">[abc</span> -<span class="Constant">def]</span> - new-editor s:address:array:character, screen:address, <span class="Constant">1/left</span>, <span class="Constant">5/right</span> - ] - screen-should-contain [ - <span class="Constant"> . .</span> - <span class="Constant"> . abc .</span> - <span class="Constant"> . def .</span> - <span class="Constant"> . .</span> - ] -] - -<span class="muScenario">scenario</span> editor-initially-wraps-long-lines [ - assume-screen <span class="Constant">5/width</span>, <span class="Constant">5/height</span> - run [ - s:address:array:character<span class="Special"> <- </span>new <span class="Constant">[abc def]</span> - new-editor s:address:array:character, screen:address, <span class="Constant">0/left</span>, <span class="Constant">5/right</span> - ] - screen-should-contain [ - <span class="Constant"> . .</span> - <span class="Constant"> .abc ↩.</span> - <span class="Constant"> .def .</span> - <span class="Constant"> . .</span> - ] - screen-should-contain-in-color <span class="Constant">245/grey</span> [ - <span class="Constant"> . .</span> - <span class="Constant"> . ↩.</span> - <span class="Constant"> . .</span> - <span class="Constant"> . .</span> - ] -] - -<span class="muScenario">scenario</span> editor-initially-wraps-barely-long-lines [ - assume-screen <span class="Constant">5/width</span>, <span class="Constant">5/height</span> - run [ - s:address:array:character<span class="Special"> <- </span>new <span class="Constant">[abcde]</span> - new-editor s:address:array:character, screen:address, <span class="Constant">0/left</span>, <span class="Constant">5/right</span> - ] - <span class="Comment"># still wrap, even though the line would fit. We need room to click on the</span> - <span class="Comment"># end of the line</span> - screen-should-contain [ - <span class="Constant"> . .</span> -<span class="Constant"> .abcd↩.</span> - <span class="Constant"> .e .</span> - <span class="Constant"> . .</span> - ] - screen-should-contain-in-color <span class="Constant">245/grey</span> [ - <span class="Constant"> . .</span> - <span class="Constant"> . ↩.</span> - <span class="Constant"> . .</span> - <span class="Constant"> . .</span> - ] -] - -<span class="muScenario">scenario</span> editor-initializes-empty-text [ - assume-screen <span class="Constant">5/width</span>, <span class="Constant">5/height</span> - run [ - <span class="Constant">1</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[]</span> - <span class="Constant">2</span>:address:editor-data<span class="Special"> <- </span>new-editor <span class="Constant">1</span>:address:array:character, screen:address, <span class="Constant">0/left</span>, <span class="Constant">5/right</span> - <span class="Constant">3</span>:number<span class="Special"> <- </span>get *<span class="Constant">2</span>:address:editor-data, <span class="Constant">cursor-row:offset</span> - <span class="Constant">4</span>:number<span class="Special"> <- </span>get *<span class="Constant">2</span>:address:editor-data, <span class="Constant">cursor-column:offset</span> - ] - screen-should-contain [ - <span class="Constant"> . .</span> - <span class="Constant"> . .</span> - <span class="Constant"> . .</span> - ] - memory-should-contain [ - <span class="Constant">3</span><span class="Special"> <- </span><span class="Constant">1</span> <span class="Comment"># cursor row</span> - <span class="Constant">4</span><span class="Special"> <- </span><span class="Constant">0</span> <span class="Comment"># cursor column</span> - ] -] - -<span class="Comment"># just a little color for mu code</span> - -<span class="muScenario">scenario</span> render-colors-comments [ - assume-screen <span class="Constant">5/width</span>, <span class="Constant">5/height</span> - run [ - s:address:array:character<span class="Special"> <- </span>new <span class="Constant">[abc</span> -<span class="Constant"># de</span> -<span class="Constant">f]</span> - new-editor s:address:array:character, screen:address, <span class="Constant">0/left</span>, <span class="Constant">5/right</span> - ] - screen-should-contain [ - <span class="Constant"> . .</span> - <span class="Constant"> .abc .</span> - <span class="Constant"> .# de .</span> - <span class="Constant"> .f .</span> - <span class="Constant"> . .</span> - ] - screen-should-contain-in-color <span class="Constant">12/lightblue</span>, [ - <span class="Constant"> . .</span> - <span class="Constant"> . .</span> - <span class="Constant"> .# de .</span> - <span class="Constant"> . .</span> - <span class="Constant"> . .</span> - ] - screen-should-contain-in-color <span class="Constant">7/white</span>, [ - <span class="Constant"> . .</span> - <span class="Constant"> .abc .</span> - <span class="Constant"> . .</span> - <span class="Constant"> .f .</span> - <span class="Constant"> . .</span> - ] -] - -<span class="muRecipe">after</span> +character-c-received [ - color<span class="Special"> <- </span>get-color color, c -] - -<span class="Comment"># color <- get-color color:number, c:character</span> -<span class="Comment"># so far the previous color is all the information we need; that may change</span> -<span class="muRecipe">recipe</span> get-color [ - <span class="Constant">local-scope</span> - color:number<span class="Special"> <- </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, <span class="Constant">7/white</span> -<span class="CommentedCode">#? $print [character: ], c, 10/newline #? 1</span> - <span class="Comment"># if color is white and next character is '#', switch color to blue</span> - <span class="Delimiter">{</span> - <span class="muControl">break-unless</span> color-is-white? - starting-comment?:boolean<span class="Special"> <- </span>equal c, <span class="Constant">35/#</span> - <span class="muControl">break-unless</span> starting-comment? -<span class="CommentedCode">#? $print [switch color back to blue], 10/newline #? 1</span> - color<span class="Special"> <- </span>copy <span class="Constant">12/lightblue</span> - <span class="muControl">jump</span> <span class="Constant">+exit:label</span> - <span class="Delimiter">}</span> - <span class="Comment"># if color is blue and next character is newline, switch color to white</span> - <span class="Delimiter">{</span> - color-is-blue?:boolean<span class="Special"> <- </span>equal color, <span class="Constant">12/lightblue</span> - <span class="muControl">break-unless</span> color-is-blue? - ending-comment?:boolean<span class="Special"> <- </span>equal c, <span class="Constant">10/newline</span> - <span class="muControl">break-unless</span> ending-comment? -<span class="CommentedCode">#? $print [switch color back to white], 10/newline #? 1</span> - color<span class="Special"> <- </span>copy <span class="Constant">7/white</span> - <span class="muControl">jump</span> <span class="Constant">+exit:label</span> - <span class="Delimiter">}</span> - <span class="Comment"># if color is white (no comments) and next character is '<', switch color to red</span> - <span class="Delimiter">{</span> - <span class="muControl">break-unless</span> color-is-white? - starting-assignment?:boolean<span class="Special"> <- </span>equal c, <span class="Constant">60/<</span> - <span class="muControl">break-unless</span> starting-assignment? - color<span class="Special"> <- </span>copy <span class="Constant">1/red</span> - <span class="muControl">jump</span> <span class="Constant">+exit:label</span> - <span class="Delimiter">}</span> - <span class="Comment"># if color is red and next character is space, switch color to white</span> - <span class="Delimiter">{</span> - color-is-red?:boolean<span class="Special"> <- </span>equal color, <span class="Constant">1/red</span> - <span class="muControl">break-unless</span> color-is-red? - ending-assignment?:boolean<span class="Special"> <- </span>equal c, <span class="Constant">32/space</span> - <span class="muControl">break-unless</span> ending-assignment? - color<span class="Special"> <- </span>copy <span class="Constant">7/white</span> - <span class="muControl">jump</span> <span class="Constant">+exit:label</span> - <span class="Delimiter">}</span> - <span class="Comment"># otherwise no change</span> -<span class="Constant"> +exit</span> - <span class="muControl">reply</span> color -] - -<span class="muScenario">scenario</span> render-colors-assignment [ - assume-screen <span class="Constant">8/width</span>, <span class="Constant">5/height</span> - run [ - s:address:array:character<span class="Special"> <- </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/left</span>, <span class="Constant">8/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/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> 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 - <span class="muControl">loop-unless</span> found? - <span class="muControl">break-if</span> quit? <span class="Comment"># only in tests</span> - trace <span class="Constant">10</span>, <span class="Constant">[app]</span>, <span class="Constant">[next-event]</span> - <span class="Comment"># 'touch' event</span> - t:address:touch-event<span class="Special"> <- </span>maybe-convert e, <span class="Constant">touch:variant</span> - <span class="Delimiter">{</span> - <span class="muControl">break-unless</span> t - move-cursor-in-editor screen, editor, *t - <span class="muControl">loop</span> <span class="Constant">+next-event:label</span> - <span class="Delimiter">}</span> - <span class="Comment"># keyboard events</span> - <span class="Delimiter">{</span> - <span class="muControl">break-if</span> t - screen, editor, go-render?:boolean<span class="Special"> <- </span>handle-keyboard-event screen, editor, e - <span class="Delimiter">{</span> - <span class="muControl">break-unless</span> go-render? - editor-render screen, editor - <span class="Delimiter">}</span> - <span class="Delimiter">}</span> - <span class="muControl">loop</span> - <span class="Delimiter">}</span> -] - -<span class="Comment"># screen, editor, go-render?:boolean <- handle-keyboard-event screen:address, editor:address:editor-data, e:event</span> -<span class="Comment"># Process an event 'e' and try to minimally update the screen.</span> -<span class="Comment"># Set 'go-render?' to true to indicate the caller must perform a non-minimal update.</span> -<span class="muRecipe">recipe</span> handle-keyboard-event [ - <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> - e:event<span class="Special"> <- </span><span class="Constant">next-ingredient</span> - <span class="muControl">reply-unless</span> editor, screen/same-as-ingredient:<span class="Constant">0</span>, editor/same-as-ingredient:<span class="Constant">1</span>, <span class="Constant">0/no-more-render</span> - screen-width:number<span class="Special"> <- </span>screen-width screen - screen-height:number<span class="Special"> <- </span>screen-height screen - left:number<span class="Special"> <- </span>get *editor, <span class="Constant">left:offset</span> - right:number<span class="Special"> <- </span>get *editor, <span class="Constant">right:offset</span> - before-cursor:address:address:duplex-list<span class="Special"> <- </span>get-address *editor, <span class="Constant">before-cursor:offset</span> - cursor-row:address:number<span class="Special"> <- </span>get-address *editor, <span class="Constant">cursor-row:offset</span> - cursor-column:address:number<span class="Special"> <- </span>get-address *editor, <span class="Constant">cursor-column:offset</span> - save-row:number<span class="Special"> <- </span>copy *cursor-row - save-column:number<span class="Special"> <- </span>copy *cursor-column - <span class="Comment"># character</span> - <span class="Delimiter">{</span> - c:address:character<span class="Special"> <- </span>maybe-convert e, <span class="Constant">text:variant</span> - <span class="muControl">break-unless</span> c -<span class="CommentedCode">#? trace 10, [app], [handle-keyboard-event: special character] #? 1</span> - <span class="Comment"># exceptions for special characters go here</span> -<span class="Constant"> +handle-special-character</span> - <span class="Comment"># ignore any other special characters</span> - regular-character?:boolean<span class="Special"> <- </span>greater-or-equal *c, <span class="Constant">32/space</span> - newline?:boolean<span class="Special"> <- </span>equal *c, <span class="Constant">10/newline</span> - regular-character?<span class="Special"> <- </span>or regular-character?, newline? - <span class="muControl">reply-unless</span> regular-character?, screen/same-as-ingredient:<span class="Constant">0</span>, editor/same-as-ingredient:<span class="Constant">1</span>, <span class="Constant">0/no-more-render</span> - <span class="Comment"># otherwise type it in</span> - editor, screen, go-render?:boolean<span class="Special"> <- </span>insert-at-cursor editor, *c, screen - <span class="muControl">reply</span> screen/same-as-ingredient:<span class="Constant">0</span>, editor/same-as-ingredient:<span class="Constant">1</span>, go-render? - <span class="Delimiter">}</span> - <span class="Comment"># special key to modify the text or move the cursor</span> - k:address:number<span class="Special"> <- </span>maybe-convert e:event, <span class="Constant">keycode:variant</span> - assert k, <span class="Constant">[event was of unknown type; neither keyboard nor mouse]</span> - <span class="Comment"># handlers for each special key will go here</span> -<span class="Constant"> +handle-special-key</span> - <span class="muControl">reply</span> screen/same-as-ingredient:<span class="Constant">0</span>, editor/same-as-ingredient:<span class="Constant">1</span>, <span class="Constant">1/go-render</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, <span class="Constant">0/false</span> - click-column:number<span class="Special"> <- </span>get t, <span class="Constant">column:offset</span> - left:number<span class="Special"> <- </span>get *editor, <span class="Constant">left:offset</span> - too-far-left?:boolean<span class="Special"> <- </span>lesser-than click-column, left - <span class="muControl">reply-if</span> too-far-left?, <span class="Constant">0/false</span> - right:number<span class="Special"> <- </span>get *editor, <span class="Constant">right:offset</span> - too-far-right?:boolean<span class="Special"> <- </span>greater-than click-column, right - <span class="muControl">reply-if</span> too-far-right?, <span class="Constant">0/false</span> - <span class="Comment"># position cursor</span> -<span class="CommentedCode">#? trace 1, [print-character], [foo] #? 1</span> - click-row:number<span class="Special"> <- </span>get t, <span class="Constant">row:offset</span> - click-column:number<span class="Special"> <- </span>get t, <span class="Constant">column:offset</span> - editor<span class="Special"> <- </span>snap-cursor screen, editor, click-row, click-column -<span class="CommentedCode">#? trace 1, [print-character], [foo done] #? 1</span> - <span class="Comment"># gain focus</span> - <span class="muControl">reply</span> <span class="Constant">1/true</span> -] - -<span class="Comment"># editor <- snap-cursor screen:address, editor:address:editor-data, target-row:number, target-column:number</span> -<span class="Comment">#</span> -<span class="Comment"># Variant of 'render' that only moves the cursor (coordinates and</span> -<span class="Comment"># before-cursor). If it's past the end of a line, it 'slides' it left. If it's</span> -<span class="Comment"># past the last line it positions at end of last line.</span> -<span class="muRecipe">recipe</span> snap-cursor [ - <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> - target-row:number<span class="Special"> <- </span><span class="Constant">next-ingredient</span> - target-column:number<span class="Special"> <- </span><span class="Constant">next-ingredient</span> - <span class="muControl">reply-unless</span> editor, <span class="Constant">1/top</span>, editor/same-as-ingredient:<span class="Constant">1</span> - left:number<span class="Special"> <- </span>get *editor, <span class="Constant">left:offset</span> - right:number<span class="Special"> <- </span>get *editor, <span class="Constant">right:offset</span> - screen-height:number<span class="Special"> <- </span>screen-height screen - <span class="Comment"># count newlines until screen row</span> - curr:address:duplex-list<span class="Special"> <- </span>get *editor, <span class="Constant">top-of-screen:offset</span> - prev:address:duplex-list<span class="Special"> <- </span>copy curr <span class="Comment"># just in case curr becomes null and we can't compute prev-duplex</span> - curr<span class="Special"> <- </span>next-duplex curr - row:number<span class="Special"> <- </span>copy <span class="Constant">1/top</span> - column:number<span class="Special"> <- </span>copy left - cursor-row:address:number<span class="Special"> <- </span>get-address *editor, <span class="Constant">cursor-row:offset</span> - *cursor-row<span class="Special"> <- </span>copy target-row - cursor-column:address:number<span class="Special"> <- </span>get-address *editor, <span class="Constant">cursor-column:offset</span> - *cursor-column<span class="Special"> <- </span>copy target-column - before-cursor:address:address:duplex-list<span class="Special"> <- </span>get-address *editor, <span class="Constant">before-cursor:offset</span> - <span class="Delimiter">{</span> -<span class="Constant"> +next-character</span> - <span class="muControl">break-unless</span> curr - off-screen?:boolean<span class="Special"> <- </span>greater-or-equal row, screen-height - <span class="muControl">break-if</span> off-screen? - <span class="Comment"># update editor-data.before-cursor</span> - <span class="Comment"># Doing so at the start of each iteration ensures it stays one step behind</span> - <span class="Comment"># the current character.</span> - <span class="Delimiter">{</span> - at-cursor-row?:boolean<span class="Special"> <- </span>equal row, *cursor-row - <span class="muControl">break-unless</span> at-cursor-row? - at-cursor?:boolean<span class="Special"> <- </span>equal column, *cursor-column - <span class="muControl">break-unless</span> at-cursor? - *before-cursor<span class="Special"> <- </span>copy prev - <span class="Delimiter">}</span> - c:character<span class="Special"> <- </span>get *curr, <span class="Constant">value:offset</span> - <span class="Delimiter">{</span> - <span class="Comment"># newline? move to left rather than 0</span> - newline?:boolean<span class="Special"> <- </span>equal c, <span class="Constant">10/newline</span> - <span class="muControl">break-unless</span> newline? - <span class="Comment"># adjust cursor if necessary</span> - <span class="Delimiter">{</span> - at-cursor-row?:boolean<span class="Special"> <- </span>equal row, *cursor-row - <span class="muControl">break-unless</span> at-cursor-row? - left-of-cursor?:boolean<span class="Special"> <- </span>lesser-than column, *cursor-column - <span class="muControl">break-unless</span> left-of-cursor? - *cursor-column<span class="Special"> <- </span>copy column - *before-cursor<span class="Special"> <- </span>copy prev - <span class="Delimiter">}</span> - <span class="Comment"># skip to next line</span> - row<span class="Special"> <- </span>add row, <span class="Constant">1</span> - column<span class="Special"> <- </span>copy left - curr<span class="Special"> <- </span>next-duplex curr - prev<span class="Special"> <- </span>next-duplex prev - <span class="muControl">loop</span> <span class="Constant">+next-character:label</span> - <span class="Delimiter">}</span> - <span class="Delimiter">{</span> - <span class="Comment"># at right? wrap. even if there's only one more letter left; we need</span> - <span class="Comment"># room for clicking on the cursor after it.</span> - at-right?:boolean<span class="Special"> <- </span>equal column, right - <span class="muControl">break-unless</span> at-right? - column<span class="Special"> <- </span>copy left - row<span class="Special"> <- </span>add row, <span class="Constant">1</span> - <span class="Comment"># don't increment curr/prev</span> - <span class="muControl">loop</span> <span class="Constant">+next-character:label</span> - <span class="Delimiter">}</span> - curr<span class="Special"> <- </span>next-duplex curr - prev<span class="Special"> <- </span>next-duplex prev - column<span class="Special"> <- </span>add column, <span class="Constant">1</span> - <span class="muControl">loop</span> - <span class="Delimiter">}</span> - <span class="Comment"># is cursor to the right of the last line? move to end</span> - <span class="Delimiter">{</span> - at-cursor-row?:boolean<span class="Special"> <- </span>equal row, *cursor-row - cursor-outside-line?:boolean<span class="Special"> <- </span>lesser-or-equal column, *cursor-column - before-cursor-on-same-line?:boolean<span class="Special"> <- </span>and at-cursor-row?, cursor-outside-line? - above-cursor-row?:boolean<span class="Special"> <- </span>lesser-than row, *cursor-row - before-cursor?:boolean<span class="Special"> <- </span>or before-cursor-on-same-line?, above-cursor-row? - <span class="muControl">break-unless</span> before-cursor? - *cursor-row<span class="Special"> <- </span>copy row - *cursor-column<span class="Special"> <- </span>copy column - *before-cursor<span class="Special"> <- </span>copy prev - <span class="Delimiter">}</span> - <span class="muControl">reply</span> editor/same-as-ingredient:<span class="Constant">1</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> - before-cursor:address:address:duplex-list<span class="Special"> <- </span>get-address *editor, <span class="Constant">before-cursor:offset</span> - insert-duplex c, *before-cursor - *before-cursor<span class="Special"> <- </span>next-duplex *before-cursor - cursor-row:address:number<span class="Special"> <- </span>get-address *editor, <span class="Constant">cursor-row:offset</span> - cursor-column:address:number<span class="Special"> <- </span>get-address *editor, <span class="Constant">cursor-column:offset</span> - left:number<span class="Special"> <- </span>get *editor, <span class="Constant">left:offset</span> - right:number<span class="Special"> <- </span>get *editor, <span class="Constant">right:offset</span> - save-row:number<span class="Special"> <- </span>copy *cursor-row - save-column:number<span class="Special"> <- </span>copy *cursor-column - screen-width:number<span class="Special"> <- </span>screen-width screen - screen-height:number<span class="Special"> <- </span>screen-height screen - <span class="Comment"># occasionally we'll need to mess with the cursor</span> -<span class="Constant"> +insert-character-special-case</span> - <span class="Comment"># but mostly we'll just move the cursor right</span> - *cursor-column<span class="Special"> <- </span>add *cursor-column, <span class="Constant">1</span> - next:address:duplex-list<span class="Special"> <- </span>next-duplex *before-cursor - <span class="Delimiter">{</span> - <span class="Comment"># at end of all text? no need to scroll? just print the character and leave</span> - at-end?:boolean<span class="Special"> <- </span>equal next, <span class="Constant">0/null</span> - <span class="muControl">break-unless</span> at-end? - bottom:number<span class="Special"> <- </span>subtract screen-height, <span class="Constant">1</span> - at-bottom?:boolean<span class="Special"> <- </span>equal save-row, bottom - at-right?:boolean<span class="Special"> <- </span>equal save-column, right - overflow?:boolean<span class="Special"> <- </span>and at-bottom?, at-right? - <span class="muControl">break-if</span> overflow? - move-cursor screen, save-row, save-column - print-character screen, c - <span class="muControl">reply</span> editor/same-as-ingredient:<span class="Constant">0</span>, screen/same-as-ingredient:<span class="Constant">2</span>, <span class="Constant">0/no-more-render</span> - <span class="Delimiter">}</span> - <span class="Delimiter">{</span> - <span class="Comment"># not at right margin? print the character and rest of line</span> - <span class="muControl">break-unless</span> next - at-right?:boolean<span class="Special"> <- </span>greater-or-equal *cursor-column, screen-width - <span class="muControl">break-if</span> at-right? - curr:address:duplex-list<span class="Special"> <- </span>copy *before-cursor - move-cursor screen, save-row, save-column - curr-column:number<span class="Special"> <- </span>copy save-column - <span class="Delimiter">{</span> - <span class="Comment"># hit right margin? give up and let caller render</span> - at-right?:boolean<span class="Special"> <- </span>greater-or-equal curr-column, screen-width - <span class="muControl">reply-if</span> at-right?, editor/same-as-ingredient:<span class="Constant">0</span>, screen/same-as-ingredient:<span class="Constant">2</span>, <span class="Constant">1/go-render</span> - <span class="muControl">break-unless</span> curr - <span class="Comment"># newline? done.</span> - currc:character<span class="Special"> <- </span>get *curr, <span class="Constant">value:offset</span> - at-newline?:boolean<span class="Special"> <- </span>equal currc, <span class="Constant">10/newline</span> - <span class="muControl">break-if</span> at-newline? - print-character screen, currc - curr-column<span class="Special"> <- </span>add curr-column, <span class="Constant">1</span> - curr<span class="Special"> <- </span>next-duplex curr - <span class="muControl">loop</span> - <span class="Delimiter">}</span> - <span class="muControl">reply</span> editor/same-as-ingredient:<span class="Constant">0</span>, screen/same-as-ingredient:<span class="Constant">2</span>, <span class="Constant">0/no-more-render</span> - <span class="Delimiter">}</span> - <span class="muControl">reply</span> editor/same-as-ingredient:<span class="Constant">0</span>, screen/same-as-ingredient:<span class="Constant">2</span>, <span class="Constant">1/go-render</span> -] - -<span class="Comment"># helper for tests</span> -<span class="muRecipe">recipe</span> editor-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> - left:number<span class="Special"> <- </span>get *editor, <span class="Constant">left:offset</span> - right:number<span class="Special"> <- </span>get *editor, <span class="Constant">right:offset</span> - row:number, column:number<span class="Special"> <- </span>render screen, editor - clear-line-delimited screen, column, right - row<span class="Special"> <- </span>add row, <span class="Constant">1</span> - draw-horizontal screen, row, left, right, <span class="Constant">9480/horizontal-dotted</span> - row<span class="Special"> <- </span>add row, <span class="Constant">1</span> - clear-screen-from screen, row, left, left, right -] - -<span class="muScenario">scenario</span> editor-handles-empty-event-queue [ - assume-screen <span class="Constant">10/width</span>, <span class="Constant">5/height</span> - <span class="Constant">1</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[abc]</span> - <span class="Constant">2</span>:address:editor-data<span class="Special"> <- </span>new-editor <span class="Constant">1</span>:address:array:character, screen:address, <span class="Constant">0/left</span>, <span class="Constant">10/right</span> - editor-render screen, <span class="Constant">2</span>:address:editor-data - assume-console <span class="Constant">[]</span> - run [ - editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data - ] - screen-should-contain [ - <span class="Constant"> . .</span> - <span class="Constant"> .abc .</span> -<span class="Constant"> .┈┈┈┈┈┈┈┈┈┈.</span> - <span class="Constant"> . .</span> - ] -] - -<span class="muScenario">scenario</span> editor-handles-mouse-clicks [ - assume-screen <span class="Constant">10/width</span>, <span class="Constant">5/height</span> - <span class="Constant">1</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[abc]</span> - <span class="Constant">2</span>:address:editor-data<span class="Special"> <- </span>new-editor <span class="Constant">1</span>:address:array:character, screen:address, <span class="Constant">0/left</span>, <span class="Constant">10/right</span> - editor-render screen, <span class="Constant">2</span>:address:editor-data -<span class="Constant"> $clear-trace</span> - assume-console [ - left-click <span class="Constant">1</span>, <span class="Constant">1</span> <span class="Comment"># on the 'b'</span> - ] - run [ - editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data - <span class="Constant">3</span>:number<span class="Special"> <- </span>get *<span class="Constant">2</span>:address:editor-data, <span class="Constant">cursor-row:offset</span> - <span class="Constant">4</span>:number<span class="Special"> <- </span>get *<span class="Constant">2</span>:address:editor-data, <span class="Constant">cursor-column:offset</span> - ] - screen-should-contain [ - <span class="Constant"> . .</span> - <span class="Constant"> .abc .</span> -<span class="Constant"> .┈┈┈┈┈┈┈┈┈┈.</span> - <span class="Constant"> . .</span> - ] - memory-should-contain [ - <span class="Constant">3</span><span class="Special"> <- </span><span class="Constant">1</span> <span class="Comment"># cursor is at row 0..</span> - <span class="Constant">4</span><span class="Special"> <- </span><span class="Constant">1</span> <span class="Comment"># ..and column 1</span> - ] - check-trace-count-for-label <span class="Constant">0</span>, <span class="Constant">[print-character]</span> -] - -<span class="muScenario">scenario</span> editor-handles-mouse-clicks-outside-text [ - assume-screen <span class="Constant">10/width</span>, <span class="Constant">5/height</span> - <span class="Constant">1</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[abc]</span> - <span class="Constant">2</span>:address:editor-data<span class="Special"> <- </span>new-editor <span class="Constant">1</span>:address:array:character, screen:address, <span class="Constant">0/left</span>, <span class="Constant">10/right</span> -<span class="Constant"> $clear-trace</span> - assume-console [ - left-click <span class="Constant">1</span>, <span class="Constant">7</span> <span class="Comment"># last line, to the right of text</span> - ] - run [ - editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data - <span class="Constant">3</span>:number<span class="Special"> <- </span>get *<span class="Constant">2</span>:address:editor-data, <span class="Constant">cursor-row:offset</span> - <span class="Constant">4</span>:number<span class="Special"> <- </span>get *<span class="Constant">2</span>:address:editor-data, <span class="Constant">cursor-column:offset</span> - ] - memory-should-contain [ - <span class="Constant">3</span><span class="Special"> <- </span><span class="Constant">1</span> <span class="Comment"># cursor row</span> - <span class="Constant">4</span><span class="Special"> <- </span><span class="Constant">3</span> <span class="Comment"># cursor column</span> - ] - check-trace-count-for-label <span class="Constant">0</span>, <span class="Constant">[print-character]</span> -] - -<span class="muScenario">scenario</span> editor-handles-mouse-clicks-outside-text-2 [ - assume-screen <span class="Constant">10/width</span>, <span class="Constant">5/height</span> - <span class="Constant">1</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[abc</span> -<span class="Constant">def]</span> - <span class="Constant">2</span>:address:editor-data<span class="Special"> <- </span>new-editor <span class="Constant">1</span>:address:array:character, screen:address, <span class="Constant">0/left</span>, <span class="Constant">10/right</span> -<span class="Constant"> $clear-trace</span> - assume-console [ - left-click <span class="Constant">1</span>, <span class="Constant">7</span> <span class="Comment"># interior line, to the right of text</span> - ] - run [ - editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data - <span class="Constant">3</span>:number<span class="Special"> <- </span>get *<span class="Constant">2</span>:address:editor-data, <span class="Constant">cursor-row:offset</span> - <span class="Constant">4</span>:number<span class="Special"> <- </span>get *<span class="Constant">2</span>:address:editor-data, <span class="Constant">cursor-column:offset</span> - ] - memory-should-contain [ - <span class="Constant">3</span><span class="Special"> <- </span><span class="Constant">1</span> <span class="Comment"># cursor row</span> - <span class="Constant">4</span><span class="Special"> <- </span><span class="Constant">3</span> <span class="Comment"># cursor column</span> - ] - check-trace-count-for-label <span class="Constant">0</span>, <span class="Constant">[print-character]</span> -] - -<span class="muScenario">scenario</span> editor-handles-mouse-clicks-outside-text-3 [ - assume-screen <span class="Constant">10/width</span>, <span class="Constant">5/height</span> - <span class="Constant">1</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[abc</span> -<span class="Constant">def]</span> - <span class="Constant">2</span>:address:editor-data<span class="Special"> <- </span>new-editor <span class="Constant">1</span>:address:array:character, screen:address, <span class="Constant">0/left</span>, <span class="Constant">10/right</span> -<span class="Constant"> $clear-trace</span> - assume-console [ - left-click <span class="Constant">3</span>, <span class="Constant">7</span> <span class="Comment"># below text</span> - ] - run [ - editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data - <span class="Constant">3</span>:number<span class="Special"> <- </span>get *<span class="Constant">2</span>:address:editor-data, <span class="Constant">cursor-row:offset</span> - <span class="Constant">4</span>:number<span class="Special"> <- </span>get *<span class="Constant">2</span>:address:editor-data, <span class="Constant">cursor-column:offset</span> - ] - memory-should-contain [ - <span class="Constant">3</span><span class="Special"> <- </span><span class="Constant">2</span> <span class="Comment"># cursor row</span> - <span class="Constant">4</span><span class="Special"> <- </span><span class="Constant">3</span> <span class="Comment"># cursor column</span> - ] - check-trace-count-for-label <span class="Constant">0</span>, <span class="Constant">[print-character]</span> -] - -<span class="muScenario">scenario</span> editor-handles-mouse-clicks-outside-column [ - assume-screen <span class="Constant">10/width</span>, <span class="Constant">5/height</span> - <span class="Constant">1</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[abc]</span> - <span class="Comment"># editor occupies only left half of screen</span> - <span class="Constant">2</span>:address:editor-data<span class="Special"> <- </span>new-editor <span class="Constant">1</span>:address:array:character, screen:address, <span class="Constant">0/left</span>, <span class="Constant">5/right</span> - editor-render screen, <span class="Constant">2</span>:address:editor-data -<span class="Constant"> $clear-trace</span> - assume-console [ - <span class="Comment"># click on right half of screen</span> - left-click <span class="Constant">3</span>, <span class="Constant">8</span> - ] - run [ - editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data - <span class="Constant">3</span>:number<span class="Special"> <- </span>get *<span class="Constant">2</span>:address:editor-data, <span class="Constant">cursor-row:offset</span> - <span class="Constant">4</span>:number<span class="Special"> <- </span>get *<span class="Constant">2</span>:address:editor-data, <span class="Constant">cursor-column:offset</span> - ] - screen-should-contain [ - <span class="Constant"> . .</span> - <span class="Constant"> .abc .</span> - <span class="Constant"> .┈┈┈┈┈ .</span> - <span class="Constant"> . .</span> - ] - memory-should-contain [ - <span class="Constant">3</span><span class="Special"> <- </span><span class="Constant">1</span> <span class="Comment"># no change to cursor row</span> - <span class="Constant">4</span><span class="Special"> <- </span><span class="Constant">0</span> <span class="Comment"># ..or column</span> - ] - check-trace-count-for-label <span class="Constant">0</span>, <span class="Constant">[print-character]</span> -] - -<span class="muScenario">scenario</span> editor-inserts-characters-into-empty-editor [ - assume-screen <span class="Constant">10/width</span>, <span class="Constant">5/height</span> - <span class="Constant">1</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[]</span> - <span class="Constant">2</span>:address:editor-data<span class="Special"> <- </span>new-editor <span class="Constant">1</span>:address:array:character, screen:address, <span class="Constant">0/left</span>, <span class="Constant">5/right</span> - editor-render screen, <span class="Constant">2</span>:address:editor-data -<span class="Constant"> $clear-trace</span> - assume-console [ - type <span class="Constant">[abc]</span> - ] - run [ - editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data - ] - screen-should-contain [ - <span class="Constant"> . .</span> - <span class="Constant"> .abc .</span> - <span class="Constant"> .┈┈┈┈┈ .</span> - <span class="Constant"> . .</span> - ] - check-trace-count-for-label <span class="Constant">3</span>, <span class="Constant">[print-character]</span> -] - -<span class="muScenario">scenario</span> editor-inserts-characters-at-cursor [ - assume-screen <span class="Constant">10/width</span>, <span class="Constant">5/height</span> - <span class="Constant">1</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[abc]</span> - <span class="Constant">2</span>:address:editor-data<span class="Special"> <- </span>new-editor <span class="Constant">1</span>:address:array:character, screen:address, <span class="Constant">0/left</span>, <span class="Constant">10/right</span> - editor-render screen, <span class="Constant">2</span>:address:editor-data -<span class="Constant"> $clear-trace</span> - <span class="Comment"># type two letters at different places</span> - assume-console [ - type <span class="Constant">[0]</span> - left-click <span class="Constant">1</span>, <span class="Constant">2</span> - type <span class="Constant">[d]</span> - ] - run [ - editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data - ] - screen-should-contain [ - <span class="Constant"> . .</span> - <span class="Constant"> .0adbc .</span> -<span class="Constant"> .┈┈┈┈┈┈┈┈┈┈.</span> - <span class="Constant"> . .</span> - ] - check-trace-count-for-label <span class="Constant">7</span>, <span class="Constant">[print-character]</span> <span class="Comment"># 4 for first letter, 3 for second</span> -] - -<span class="muScenario">scenario</span> editor-inserts-characters-at-cursor-2 [ - assume-screen <span class="Constant">10/width</span>, <span class="Constant">5/height</span> - <span class="Constant">1</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[abc]</span> - <span class="Constant">2</span>:address:editor-data<span class="Special"> <- </span>new-editor <span class="Constant">1</span>:address:array:character, screen:address, <span class="Constant">0/left</span>, <span class="Constant">10/right</span> - editor-render screen, <span class="Constant">2</span>:address:editor-data -<span class="Constant"> $clear-trace</span> - assume-console [ - left-click <span class="Constant">1</span>, <span class="Constant">5</span> <span class="Comment"># right of last line</span> - type <span class="Constant">[d]</span> - ] - run [ - editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data - ] - screen-should-contain [ - <span class="Constant"> . .</span> - <span class="Constant"> .abcd .</span> -<span class="Constant"> .┈┈┈┈┈┈┈┈┈┈.</span> - <span class="Constant"> . .</span> - ] - check-trace-count-for-label <span class="Constant">1</span>, <span class="Constant">[print-character]</span> -] - -<span class="muScenario">scenario</span> editor-inserts-characters-at-cursor-5 [ - assume-screen <span class="Constant">10/width</span>, <span class="Constant">5/height</span> - <span class="Constant">1</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[abc</span> -<span class="Constant">d]</span> - <span class="Constant">2</span>:address:editor-data<span class="Special"> <- </span>new-editor <span class="Constant">1</span>:address:array:character, screen:address, <span class="Constant">0/left</span>, <span class="Constant">10/right</span> - editor-render screen, <span class="Constant">2</span>:address:editor-data -<span class="Constant"> $clear-trace</span> - assume-console [ - left-click <span class="Constant">1</span>, <span class="Constant">5</span> <span class="Comment"># right of non-last line</span> - type <span class="Constant">[e]</span> - ] - run [ - editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data - ] - screen-should-contain [ - <span class="Constant"> . .</span> - <span class="Constant"> .abce .</span> - <span class="Constant"> .d .</span> -<span class="Constant"> .┈┈┈┈┈┈┈┈┈┈.</span> - <span class="Constant"> . .</span> - ] - check-trace-count-for-label <span class="Constant">1</span>, <span class="Constant">[print-character]</span> -] - -<span class="muScenario">scenario</span> editor-inserts-characters-at-cursor-3 [ - assume-screen <span class="Constant">10/width</span>, <span class="Constant">5/height</span> - <span class="Constant">1</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[abc]</span> - <span class="Constant">2</span>:address:editor-data<span class="Special"> <- </span>new-editor <span class="Constant">1</span>:address:array:character, screen:address, <span class="Constant">0/left</span>, <span class="Constant">10/right</span> - editor-render screen, <span class="Constant">2</span>:address:editor-data -<span class="Constant"> $clear-trace</span> - assume-console [ - left-click <span class="Constant">3</span>, <span class="Constant">5</span> <span class="Comment"># below all text</span> - type <span class="Constant">[d]</span> - ] - run [ - editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data - ] - screen-should-contain [ - <span class="Constant"> . .</span> - <span class="Constant"> .abcd .</span> -<span class="Constant"> .┈┈┈┈┈┈┈┈┈┈.</span> - <span class="Constant"> . .</span> - ] - check-trace-count-for-label <span class="Constant">1</span>, <span class="Constant">[print-character]</span> -] - -<span class="muScenario">scenario</span> editor-inserts-characters-at-cursor-4 [ - assume-screen <span class="Constant">10/width</span>, <span class="Constant">5/height</span> - <span class="Constant">1</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[abc</span> -<span class="Constant">d]</span> - <span class="Constant">2</span>:address:editor-data<span class="Special"> <- </span>new-editor <span class="Constant">1</span>:address:array:character, screen:address, <span class="Constant">0/left</span>, <span class="Constant">10/right</span> - editor-render screen, <span class="Constant">2</span>:address:editor-data -<span class="Constant"> $clear-trace</span> - assume-console [ - left-click <span class="Constant">3</span>, <span class="Constant">5</span> <span class="Comment"># below all text</span> - type <span class="Constant">[e]</span> - ] - run [ - editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data - ] - screen-should-contain [ - <span class="Constant"> . .</span> - <span class="Constant"> .abc .</span> - <span class="Constant"> .de .</span> -<span class="Constant"> .┈┈┈┈┈┈┈┈┈┈.</span> - <span class="Constant"> . .</span> - ] - check-trace-count-for-label <span class="Constant">1</span>, <span class="Constant">[print-character]</span> -] - -<span class="muScenario">scenario</span> editor-inserts-characters-at-cursor-5 [ - assume-screen <span class="Constant">10/width</span>, <span class="Constant">5/height</span> - <span class="Constant">1</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[abc</span> -<span class="Constant">d]</span> - <span class="Constant">2</span>:address:editor-data<span class="Special"> <- </span>new-editor <span class="Constant">1</span>:address:array:character, screen:address, <span class="Constant">0/left</span>, <span class="Constant">10/right</span> - editor-render screen, <span class="Constant">2</span>:address:editor-data -<span class="Constant"> $clear-trace</span> - assume-console [ - left-click <span class="Constant">3</span>, <span class="Constant">5</span> <span class="Comment"># below all text</span> - type <span class="Constant">[ef]</span> - ] - run [ - editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data - ] - screen-should-contain [ - <span class="Constant"> . .</span> - <span class="Constant"> .abc .</span> - <span class="Constant"> .def .</span> -<span class="Constant"> .┈┈┈┈┈┈┈┈┈┈.</span> - <span class="Constant"> . .</span> - ] - check-trace-count-for-label <span class="Constant">2</span>, <span class="Constant">[print-character]</span> -] - -<span class="muScenario">scenario</span> editor-moves-cursor-after-inserting-characters [ - assume-screen <span class="Constant">10/width</span>, <span class="Constant">5/height</span> - <span class="Constant">1</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[ab]</span> - <span class="Constant">2</span>:address:editor-data<span class="Special"> <- </span>new-editor <span class="Constant">1</span>:address:array:character, screen:address, <span class="Constant">0/left</span>, <span class="Constant">5/right</span> - editor-render screen, <span class="Constant">2</span>:address:editor-data - assume-console [ - type <span class="Constant">[01]</span> - ] - run [ - editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data - ] - screen-should-contain [ - <span class="Constant"> . .</span> - <span class="Constant"> .01ab .</span> - <span class="Constant"> .┈┈┈┈┈ .</span> - <span class="Constant"> . .</span> - ] -] - -<span class="Comment"># if the cursor reaches the right margin, wrap the line</span> - -<span class="muScenario">scenario</span> editor-wraps-line-on-insert [ - assume-screen <span class="Constant">5/width</span>, <span class="Constant">5/height</span> - <span class="Constant">1</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[abc]</span> - <span class="Constant">2</span>:address:editor-data<span class="Special"> <- </span>new-editor <span class="Constant">1</span>:address:array:character, screen:address, <span class="Constant">0/left</span>, <span class="Constant">5/right</span> - editor-render screen, <span class="Constant">2</span>:address:editor-data - <span class="Comment"># type a letter</span> - assume-console [ - type <span class="Constant">[e]</span> - ] - run [ - editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data - ] - <span class="Comment"># no wrap yet</span> - screen-should-contain [ - <span class="Constant"> . .</span> - <span class="Constant"> .eabc .</span> -<span class="Constant"> .┈┈┈┈┈.</span> - <span class="Constant"> . .</span> - <span class="Constant"> . .</span> - ] - <span class="Comment"># type a second letter</span> - assume-console [ - type <span class="Constant">[f]</span> - ] - run [ - editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data - ] - <span class="Comment"># now wrap</span> - screen-should-contain [ - <span class="Constant"> . .</span> -<span class="Constant"> .efab↩.</span> - <span class="Constant"> .c .</span> -<span class="Constant"> .┈┈┈┈┈.</span> - <span class="Constant"> . .</span> - ] -] - -<span class="muRecipe">after</span> +insert-character-special-case [ - <span class="Comment"># if the line wraps at the cursor, move cursor to start of next row</span> - <span class="Delimiter">{</span> - <span class="Comment"># if we're at the column just before the wrap indicator</span> - wrap-column:number<span class="Special"> <- </span>subtract right, <span class="Constant">1</span> - at-wrap?:boolean<span class="Special"> <- </span>greater-or-equal *cursor-column, wrap-column - <span class="muControl">break-unless</span> at-wrap? - *cursor-column<span class="Special"> <- </span>subtract *cursor-column, wrap-column - *cursor-row<span class="Special"> <- </span>add *cursor-row, <span class="Constant">1</span> - <span class="Comment"># if we're out of the screen, scroll down</span> - <span class="Delimiter">{</span> - below-screen?:boolean<span class="Special"> <- </span>greater-or-equal *cursor-row, screen-height - <span class="muControl">break-unless</span> below-screen? -<span class="Constant"> +scroll-down</span> - <span class="Delimiter">}</span> - <span class="muControl">reply</span> editor/same-as-ingredient:<span class="Constant">0</span>, screen/same-as-ingredient:<span class="Constant">2</span>, <span class="Constant">1/go-render</span> - <span class="Delimiter">}</span> -] - -<span class="muScenario">scenario</span> editor-wraps-cursor-after-inserting-characters [ - assume-screen <span class="Constant">10/width</span>, <span class="Constant">5/height</span> - <span class="Constant">1</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[abcde]</span> - <span class="Constant">2</span>:address:editor-data<span class="Special"> <- </span>new-editor <span class="Constant">1</span>:address:array:character, screen:address, <span class="Constant">0/left</span>, <span class="Constant">5/right</span> - assume-console [ - left-click <span class="Constant">1</span>, <span class="Constant">4</span> <span class="Comment"># line is full; no wrap icon yet</span> - type <span class="Constant">[f]</span> - ] - run [ - editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data - <span class="Constant">3</span>:number<span class="Special"> <- </span>get *<span class="Constant">2</span>:address:editor-data, <span class="Constant">cursor-row:offset</span> - <span class="Constant">4</span>:number<span class="Special"> <- </span>get *<span class="Constant">2</span>:address:editor-data, <span class="Constant">cursor-column:offset</span> - ] - screen-should-contain [ - <span class="Constant"> . .</span> - <span class="Constant"> .abcd↩ .</span> - <span class="Constant"> .fe .</span> - <span class="Constant"> .┈┈┈┈┈ .</span> - <span class="Constant"> . .</span> - ] - memory-should-contain [ - <span class="Constant">3</span><span class="Special"> <- </span><span class="Constant">2</span> <span class="Comment"># cursor row</span> - <span class="Constant">4</span><span class="Special"> <- </span><span class="Constant">1</span> <span class="Comment"># cursor column</span> - ] -] - -<span class="muScenario">scenario</span> editor-wraps-cursor-after-inserting-characters-2 [ - assume-screen <span class="Constant">10/width</span>, <span class="Constant">5/height</span> - <span class="Constant">1</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[abcde]</span> - <span class="Constant">2</span>:address:editor-data<span class="Special"> <- </span>new-editor <span class="Constant">1</span>:address:array:character, screen:address, <span class="Constant">0/left</span>, <span class="Constant">5/right</span> - assume-console [ - left-click <span class="Constant">1</span>, <span class="Constant">3</span> <span class="Comment"># right before the wrap icon</span> - type <span class="Constant">[f]</span> - ] - run [ - editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data - <span class="Constant">3</span>:number<span class="Special"> <- </span>get *<span class="Constant">2</span>:address:editor-data, <span class="Constant">cursor-row:offset</span> - <span class="Constant">4</span>:number<span class="Special"> <- </span>get *<span class="Constant">2</span>:address:editor-data, <span class="Constant">cursor-column:offset</span> - ] - screen-should-contain [ - <span class="Constant"> . .</span> - <span class="Constant"> .abcf↩ .</span> - <span class="Constant"> .de .</span> - <span class="Constant"> .┈┈┈┈┈ .</span> - <span class="Constant"> . .</span> - ] - memory-should-contain [ - <span class="Constant">3</span><span class="Special"> <- </span><span class="Constant">2</span> <span class="Comment"># cursor row</span> - <span class="Constant">4</span><span class="Special"> <- </span><span class="Constant">0</span> <span class="Comment"># cursor column</span> - ] -] - -<span class="Comment"># if newline, move cursor to start of next line, and maybe align indent with previous line</span> - -container editor-data [ - indent:boolean -] - -<span class="muRecipe">after</span> +editor-initialization [ - indent:address:boolean<span class="Special"> <- </span>get-address *result, <span class="Constant">indent:offset</span> - *indent<span class="Special"> <- </span>copy <span class="Constant">1/true</span> -] - -<span class="muScenario">scenario</span> editor-moves-cursor-down-after-inserting-newline [ - assume-screen <span class="Constant">10/width</span>, <span class="Constant">5/height</span> - <span class="Constant">1</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[abc]</span> - <span class="Constant">2</span>:address:editor-data<span class="Special"> <- </span>new-editor <span class="Constant">1</span>:address:array:character, screen:address, <span class="Constant">0/left</span>, <span class="Constant">10/right</span> - assume-console [ - type <span class="Constant">[0</span> -<span class="Constant">1]</span> - ] - run [ - editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data - ] - screen-should-contain [ - <span class="Constant"> . .</span> - <span class="Constant"> .0 .</span> - <span class="Constant"> .1abc .</span> -<span class="Constant"> .┈┈┈┈┈┈┈┈┈┈.</span> - <span class="Constant"> . .</span> - ] -] - -<span class="muRecipe">after</span> +insert-character-special-case [ - <span class="Delimiter">{</span> - newline?:boolean<span class="Special"> <- </span>equal c, <span class="Constant">10/newline</span> - <span class="muControl">break-unless</span> newline? - *cursor-row<span class="Special"> <- </span>add *cursor-row, <span class="Constant">1</span> - *cursor-column<span class="Special"> <- </span>copy left - <span class="Delimiter">{</span> - below-screen?:boolean<span class="Special"> <- </span>greater-or-equal *cursor-row, screen-height <span class="Comment"># must be equal, never greater</span> - <span class="muControl">break-unless</span> below-screen? -<span class="Constant"> +scroll-down</span> - *cursor-row<span class="Special"> <- </span>subtract *cursor-row, <span class="Constant">1</span> <span class="Comment"># bring back into screen range</span> - <span class="Delimiter">}</span> - <span class="Comment"># indent if necessary</span> - indent?:boolean<span class="Special"> <- </span>get *editor, <span class="Constant">indent:offset</span> - <span class="muControl">reply-unless</span> indent?, editor/same-as-ingredient:<span class="Constant">0</span>, screen/same-as-ingredient:<span class="Constant">2</span>, <span class="Constant">1/go-render</span> - d:address:duplex-list<span class="Special"> <- </span>get *editor, <span class="Constant">data:offset</span> - end-of-previous-line:address:duplex-list<span class="Special"> <- </span>prev-duplex *before-cursor - indent:number<span class="Special"> <- </span>line-indent end-of-previous-line, d - i:number<span class="Special"> <- </span>copy <span class="Constant">0</span> - <span class="Delimiter">{</span> - indent-done?:boolean<span class="Special"> <- </span>greater-or-equal i, indent - <span class="muControl">break-if</span> indent-done? - insert-at-cursor editor, <span class="Constant">32/space</span>, screen - i<span class="Special"> <- </span>add i, <span class="Constant">1</span> - <span class="muControl">loop</span> - <span class="Delimiter">}</span> - <span class="muControl">reply</span> editor/same-as-ingredient:<span class="Constant">0</span>, screen/same-as-ingredient:<span class="Constant">2</span>, <span class="Constant">1/go-render</span> - <span class="Delimiter">}</span> -] - -<span class="Comment"># takes a pointer 'curr' into the doubly-linked list and its sentinel, counts</span> -<span class="Comment"># the number of spaces at the start of the line containing 'curr'.</span> -<span class="muRecipe">recipe</span> line-indent [ - <span class="Constant">local-scope</span> - curr:address:duplex-list<span class="Special"> <- </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</span> - <span class="muControl">reply-unless</span> curr, result - at-start?:boolean<span class="Special"> <- </span>equal curr, start - <span class="muControl">reply-if</span> at-start?, result - <span class="Delimiter">{</span> - curr<span class="Special"> <- </span>prev-duplex curr - <span class="muControl">break-unless</span> curr - at-start?:boolean<span class="Special"> <- </span>equal curr, start - <span class="muControl">break-if</span> at-start? - c:character<span class="Special"> <- </span>get *curr, <span class="Constant">value:offset</span> - at-newline?:boolean<span class="Special"> <- </span>equal c, <span class="Constant">10/newline</span> - <span class="muControl">break-if</span> at-newline? - <span class="Comment"># if c is a space, increment result</span> - is-space?:boolean<span class="Special"> <- </span>equal c, <span class="Constant">32/space</span> - <span class="Delimiter">{</span> - <span class="muControl">break-unless</span> is-space? - result<span class="Special"> <- </span>add result, <span class="Constant">1</span> - <span class="Delimiter">}</span> - <span class="Comment"># if c is not a space, reset result</span> - <span class="Delimiter">{</span> - <span class="muControl">break-if</span> is-space? - result<span class="Special"> <- </span>copy <span class="Constant">0</span> - <span class="Delimiter">}</span> - <span class="muControl">loop</span> - <span class="Delimiter">}</span> - <span class="muControl">reply</span> result -] - -<span class="muScenario">scenario</span> editor-moves-cursor-down-after-inserting-newline-2 [ - assume-screen <span class="Constant">10/width</span>, <span class="Constant">5/height</span> - <span class="Constant">1</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[abc]</span> - <span class="Constant">2</span>:address:editor-data<span class="Special"> <- </span>new-editor <span class="Constant">1</span>:address:array:character, screen:address, <span class="Constant">1/left</span>, <span class="Constant">10/right</span> - assume-console [ - type <span class="Constant">[0</span> -<span class="Constant">1]</span> - ] - run [ - editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data - ] - screen-should-contain [ - <span class="Constant"> . .</span> - <span class="Constant"> . 0 .</span> - <span class="Constant"> . 1abc .</span> - <span class="Constant"> . ┈┈┈┈┈┈┈┈┈.</span> - <span class="Constant"> . .</span> - ] -] - -<span class="muScenario">scenario</span> editor-clears-previous-line-completely-after-inserting-newline [ - assume-screen <span class="Constant">10/width</span>, <span class="Constant">5/height</span> - <span class="Constant">1</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[abcde]</span> - <span class="Constant">2</span>:address:editor-data<span class="Special"> <- </span>new-editor <span class="Constant">1</span>:address:array:character, screen:address, <span class="Constant">0/left</span>, <span class="Constant">5/right</span> - <span class="Comment"># press just a 'newline'</span> - assume-console [ - type [ -] - ] - screen-should-contain [ - <span class="Constant"> . .</span> - <span class="Constant"> .abcd↩ .</span> - <span class="Constant"> .e .</span> - <span class="Constant"> . .</span> - <span class="Constant"> . .</span> - ] - run [ - editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data - ] - <span class="Comment"># line should be fully cleared</span> - screen-should-contain [ - <span class="Constant"> . .</span> - <span class="Constant"> . .</span> - <span class="Constant"> .abcd↩ .</span> - <span class="Constant"> .e .</span> - <span class="Constant"> .┈┈┈┈┈ .</span> - ] -] - -<span class="muScenario">scenario</span> editor-inserts-indent-after-newline [ - assume-screen <span class="Constant">10/width</span>, <span class="Constant">10/height</span> - <span class="Constant">1</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[ab</span> -<span class="Constant"> cd</span> -<span class="Constant">ef]</span> - <span class="Constant">2</span>:address:editor-data<span class="Special"> <- </span>new-editor <span class="Constant">1</span>:address:array:character, screen:address, <span class="Constant">0/left</span>, <span class="Constant">10/right</span> - <span class="Comment"># position cursor after 'cd' and hit 'newline'</span> - assume-console [ - left-click <span class="Constant">2</span>, <span class="Constant">8</span> - type [ -] - ] - run [ - editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data - <span class="Constant">3</span>:number<span class="Special"> <- </span>get *<span class="Constant">2</span>:address:editor-data, <span class="Constant">cursor-row:offset</span> - <span class="Constant">4</span>:number<span class="Special"> <- </span>get *<span class="Constant">2</span>:address:editor-data, <span class="Constant">cursor-column:offset</span> - ] - <span class="Comment"># cursor should be below start of previous line</span> - memory-should-contain [ - <span class="Constant">3</span><span class="Special"> <- </span><span class="Constant">3</span> <span class="Comment"># cursor row</span> - <span class="Constant">4</span><span class="Special"> <- </span><span class="Constant">2</span> <span class="Comment"># cursor column (indented)</span> - ] -] - -<span class="muScenario">scenario</span> editor-skips-indent-around-paste [ - assume-screen <span class="Constant">10/width</span>, <span class="Constant">10/height</span> - <span class="Constant">1</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[ab</span> -<span class="Constant"> cd</span> -<span class="Constant">ef]</span> - <span class="Constant">2</span>:address:editor-data<span class="Special"> <- </span>new-editor <span class="Constant">1</span>:address:array:character, screen:address, <span class="Constant">0/left</span>, <span class="Constant">10/right</span> - <span class="Comment"># position cursor after 'cd' and hit 'newline' surrounded by paste markers</span> - assume-console [ - left-click <span class="Constant">2</span>, <span class="Constant">8</span> - press <span class="Constant">65507</span> <span class="Comment"># start paste</span> - type [ -] - press <span class="Constant">65506</span> <span class="Comment"># end paste</span> - ] - run [ - editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data - <span class="Constant">3</span>:number<span class="Special"> <- </span>get *<span class="Constant">2</span>:address:editor-data, <span class="Constant">cursor-row:offset</span> - <span class="Constant">4</span>:number<span class="Special"> <- </span>get *<span class="Constant">2</span>:address:editor-data, <span class="Constant">cursor-column:offset</span> - ] - <span class="Comment"># cursor should be below start of previous line</span> - memory-should-contain [ - <span class="Constant">3</span><span class="Special"> <- </span><span class="Constant">3</span> <span class="Comment"># cursor row</span> - <span class="Constant">4</span><span class="Special"> <- </span><span class="Constant">0</span> <span class="Comment"># cursor column (not indented)</span> - ] -] - -<span class="muRecipe">after</span> +handle-special-key [ - <span class="Delimiter">{</span> - paste-start?:boolean<span class="Special"> <- </span>equal *k, <span class="Constant">65507/paste-start</span> - <span class="muControl">break-unless</span> paste-start? - indent:address:boolean<span class="Special"> <- </span>get-address *editor, <span class="Constant">indent:offset</span> - *indent<span class="Special"> <- </span>copy <span class="Constant">0/false</span> - <span class="muControl">reply</span> screen/same-as-ingredient:<span class="Constant">0</span>, editor/same-as-ingredient:<span class="Constant">1</span>, <span class="Constant">1/go-render</span> - <span class="Delimiter">}</span> -] - -<span class="muRecipe">after</span> +handle-special-key [ - <span class="Delimiter">{</span> - paste-end?:boolean<span class="Special"> <- </span>equal *k, <span class="Constant">65506/paste-end</span> - <span class="muControl">break-unless</span> paste-end? - indent:address:boolean<span class="Special"> <- </span>get-address *editor, <span class="Constant">indent:offset</span> - *indent<span class="Special"> <- </span>copy <span class="Constant">1/true</span> - <span class="muControl">reply</span> screen/same-as-ingredient:<span class="Constant">0</span>, editor/same-as-ingredient:<span class="Constant">1</span>, <span class="Constant">1/go-render</span> - <span class="Delimiter">}</span> -] - -<span class="SalientComment">## special shortcuts for manipulating the editor</span> -<span class="Comment"># Some keys on the keyboard generate unicode characters, others generate</span> -<span class="Comment"># terminfo key codes. We need to modify different places in the two cases.</span> - -<span class="Comment"># tab - insert two spaces</span> - -<span class="muScenario">scenario</span> editor-inserts-two-spaces-on-tab [ - assume-screen <span class="Constant">10/width</span>, <span class="Constant">5/height</span> - <span class="Comment"># just one character in final line</span> - <span class="Constant">1</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[ab</span> -<span class="Constant">cd]</span> - <span class="Constant">2</span>:address:editor-data<span class="Special"> <- </span>new-editor <span class="Constant">1</span>:address:array:character, screen:address, <span class="Constant">0/left</span>, <span class="Constant">5/right</span> - assume-console [ - type <span class="Constant">[»]</span> - ] - <span class="Constant">3</span>:event/tab<span class="Special"> <- </span>merge <span class="Constant">0/text</span>, <span class="Constant">9/tab</span>, <span class="Constant">0/dummy</span>, <span class="Constant">0/dummy</span> - replace-in-console <span class="Constant">187/»</span>, <span class="Constant">3</span>:event/tab - run [ - editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data - ] - screen-should-contain [ - <span class="Constant"> . .</span> - <span class="Constant"> . ab .</span> - <span class="Constant"> .cd .</span> - ] -] - -<span class="muRecipe">after</span> +handle-special-character [ - <span class="Delimiter">{</span> - tab?:boolean<span class="Special"> <- </span>equal *c, <span class="Constant">9/tab</span> - <span class="muControl">break-unless</span> tab? - insert-at-cursor editor, <span class="Constant">32/space</span>, screen - insert-at-cursor editor, <span class="Constant">32/space</span>, screen - <span class="muControl">reply</span> screen/same-as-ingredient:<span class="Constant">0</span>, editor/same-as-ingredient:<span class="Constant">1</span>, <span class="Constant">1/go-render</span> - <span class="Delimiter">}</span> -] - -<span class="Comment"># backspace - delete character before cursor</span> - -<span class="muScenario">scenario</span> editor-handles-backspace-key [ - assume-screen <span class="Constant">10/width</span>, <span class="Constant">5/height</span> - <span class="Constant">1</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[abc]</span> - <span class="Constant">2</span>:address:editor-data<span class="Special"> <- </span>new-editor <span class="Constant">1</span>:address:array:character, screen:address, <span class="Constant">0/left</span>, <span class="Constant">10/right</span> - editor-render screen, <span class="Constant">2</span>:address:editor-data -<span class="Constant"> $clear-trace</span> - assume-console [ - left-click <span class="Constant">1</span>, <span class="Constant">1</span> - type <span class="Constant">[«]</span> - ] - <span class="Constant">3</span>:event/backspace<span class="Special"> <- </span>merge <span class="Constant">0/text</span>, <span class="Constant">8/backspace</span>, <span class="Constant">0/dummy</span>, <span class="Constant">0/dummy</span> - replace-in-console <span class="Constant">171/«</span>, <span class="Constant">3</span>:event/backspace - run [ - editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data - <span class="Constant">4</span>:number<span class="Special"> <- </span>get *<span class="Constant">2</span>:address:editor-data, <span class="Constant">cursor-row:offset</span> - <span class="Constant">5</span>:number<span class="Special"> <- </span>get *<span class="Constant">2</span>:address:editor-data, <span class="Constant">cursor-column:offset</span> - ] - screen-should-contain [ - <span class="Constant"> . .</span> - <span class="Constant"> .bc .</span> -<span class="Constant"> .┈┈┈┈┈┈┈┈┈┈.</span> - <span class="Constant"> . .</span> - ] - memory-should-contain [ - <span class="Constant">4</span><span class="Special"> <- </span><span class="Constant">1</span> - <span class="Constant">5</span><span class="Special"> <- </span><span class="Constant">0</span> - ] - check-trace-count-for-label <span class="Constant">3</span>, <span class="Constant">[print-character]</span> <span class="Comment"># length of original line to overwrite</span> -] - -<span class="muRecipe">after</span> +handle-special-character [ - <span class="Delimiter">{</span> - backspace?:boolean<span class="Special"> <- </span>equal *c, <span class="Constant">8/backspace</span> - <span class="muControl">break-unless</span> backspace? - editor, screen, go-render?:boolean<span class="Special"> <- </span>delete-before-cursor editor, screen - <span class="muControl">reply</span> screen/same-as-ingredient:<span class="Constant">0</span>, editor/same-as-ingredient:<span class="Constant">1</span>, go-render? - <span class="Delimiter">}</span> -] - -<span class="muRecipe">recipe</span> delete-before-cursor [ - <span class="Constant">local-scope</span> - editor:address:editor-data<span class="Special"> <- </span><span class="Constant">next-ingredient</span> - screen:address<span class="Special"> <- </span><span class="Constant">next-ingredient</span> - before-cursor:address:address:duplex-list<span class="Special"> <- </span>get-address *editor, <span class="Constant">before-cursor:offset</span> - <span class="Comment"># if at start of text (before-cursor at § sentinel), return</span> - prev:address:duplex-list<span class="Special"> <- </span>prev-duplex *before-cursor - <span class="muControl">reply-unless</span> prev, editor/same-as-ingredient:<span class="Constant">0</span>, screen/same-as-ingredient:<span class="Constant">1</span>, <span class="Constant">0/no-more-render</span> -<span class="CommentedCode">#? trace 10, [app], [delete-before-cursor] #? 1</span> - original-row:number<span class="Special"> <- </span>get *editor, <span class="Constant">cursor-row:offset</span> - editor, scroll?:boolean<span class="Special"> <- </span>move-cursor-coordinates-left editor - remove-duplex *before-cursor - *before-cursor<span class="Special"> <- </span>copy prev - <span class="muControl">reply-if</span> scroll?, editor/same-as-ingredient:<span class="Constant">0</span>, <span class="Constant">1/go-render</span> - screen-width:number<span class="Special"> <- </span>screen-width screen - cursor-row:number<span class="Special"> <- </span>get *editor, <span class="Constant">cursor-row:offset</span> - cursor-column:number<span class="Special"> <- </span>get *editor, <span class="Constant">cursor-column:offset</span> - <span class="Comment"># did we just backspace over a newline?</span> - same-row?:boolean<span class="Special"> <- </span>equal cursor-row, original-row - <span class="muControl">reply-unless</span> same-row?, editor/same-as-ingredient:<span class="Constant">0</span>, screen/same-as-ingredient:<span class="Constant">1</span>, <span class="Constant">1/go-render</span> - left:number<span class="Special"> <- </span>get *editor, <span class="Constant">left:offset</span> - right:number<span class="Special"> <- </span>get *editor, <span class="Constant">right:offset</span> - curr:address:duplex-list<span class="Special"> <- </span>next-duplex *before-cursor - screen<span class="Special"> <- </span>move-cursor screen, cursor-row, cursor-column - curr-column:number<span class="Special"> <- </span>copy cursor-column - <span class="Delimiter">{</span> - <span class="Comment"># hit right margin? give up and let caller render</span> - at-right?:boolean<span class="Special"> <- </span>greater-or-equal curr-column, screen-width - <span class="muControl">reply-if</span> at-right?, editor/same-as-ingredient:<span class="Constant">0</span>, screen/same-as-ingredient:<span class="Constant">1</span>, <span class="Constant">1/go-render</span> - <span class="muControl">break-unless</span> curr - <span class="Comment"># newline? done.</span> - currc:character<span class="Special"> <- </span>get *curr, <span class="Constant">value:offset</span> - at-newline?:boolean<span class="Special"> <- </span>equal currc, <span class="Constant">10/newline</span> - <span class="muControl">break-if</span> at-newline? - screen<span class="Special"> <- </span>print-character screen, currc - curr-column<span class="Special"> <- </span>add curr-column, <span class="Constant">1</span> - curr<span class="Special"> <- </span>next-duplex curr - <span class="muControl">loop</span> - <span class="Delimiter">}</span> - <span class="Comment"># we're guaranteed not to be at the right margin</span> - screen<span class="Special"> <- </span>print-character screen, <span class="Constant">32/space</span> - <span class="muControl">reply</span> editor/same-as-ingredient:<span class="Constant">0</span>, screen/same-as-ingredient:<span class="Constant">1</span>, <span class="Constant">0/no-more-render</span> -] - -<span class="muRecipe">recipe</span> move-cursor-coordinates-left [ - <span class="Constant">local-scope</span> - editor:address:editor-data<span class="Special"> <- </span><span class="Constant">next-ingredient</span> - before-cursor:address:duplex-list<span class="Special"> <- </span>get *editor, <span class="Constant">before-cursor:offset</span> - cursor-row:address:number<span class="Special"> <- </span>get-address *editor, <span class="Constant">cursor-row:offset</span> - cursor-column:address:number<span class="Special"> <- </span>get-address *editor, <span class="Constant">cursor-column:offset</span> - left:number<span class="Special"> <- </span>get *editor, <span class="Constant">left:offset</span> - <span class="Comment"># if not at left margin, move one character left</span> - <span class="Delimiter">{</span> - at-left-margin?:boolean<span class="Special"> <- </span>equal *cursor-column, left - <span class="muControl">break-if</span> at-left-margin? -<span class="CommentedCode">#? trace 10, [app], [decrementing cursor column] #? 1</span> - *cursor-column<span class="Special"> <- </span>subtract *cursor-column, <span class="Constant">1</span> - <span class="muControl">reply</span> editor/same-as-ingredient:<span class="Constant">0</span>, <span class="Constant">0/no-more-render</span> - <span class="Delimiter">}</span> - <span class="Comment"># if at left margin, we must move to previous row:</span> - top-of-screen?:boolean<span class="Special"> <- </span>equal *cursor-row, <span class="Constant">1</span> <span class="Comment"># exclude menu bar</span> - go-render?:boolean<span class="Special"> <- </span>copy <span class="Constant">0/false</span> - <span class="Delimiter">{</span> - <span class="muControl">break-if</span> top-of-screen? - *cursor-row<span class="Special"> <- </span>subtract *cursor-row, <span class="Constant">1</span> - <span class="Delimiter">}</span> - <span class="Delimiter">{</span> - <span class="muControl">break-unless</span> top-of-screen? -<span class="Constant"> +scroll-up</span> - go-render?<span class="Special"> <- </span>copy <span class="Constant">1/true</span> - <span class="Delimiter">}</span> - <span class="Delimiter">{</span> - <span class="Comment"># case 1: if previous character was newline, figure out how long the previous line is</span> - previous-character:character<span class="Special"> <- </span>get *before-cursor, <span class="Constant">value:offset</span> - previous-character-is-newline?:boolean<span class="Special"> <- </span>equal previous-character, <span class="Constant">10/newline</span> - <span class="muControl">break-unless</span> previous-character-is-newline? - <span class="Comment"># compute length of previous line</span> -<span class="CommentedCode">#? trace 10, [app], [switching to previous line] #? 1</span> - d:address:duplex-list<span class="Special"> <- </span>get *editor, <span class="Constant">data:offset</span> - end-of-line:number<span class="Special"> <- </span>previous-line-length before-cursor, d - *cursor-column<span class="Special"> <- </span>add left, end-of-line - <span class="muControl">reply</span> editor/same-as-ingredient:<span class="Constant">0</span>, go-render? - <span class="Delimiter">}</span> - <span class="Comment"># case 2: if previous-character was not newline, we're just at a wrapped line</span> -<span class="CommentedCode">#? trace 10, [app], [wrapping to previous line] #? 1</span> - right:number<span class="Special"> <- </span>get *editor, <span class="Constant">right:offset</span> - *cursor-column<span class="Special"> <- </span>subtract right, <span class="Constant">1</span> <span class="Comment"># leave room for wrap icon</span> - <span class="muControl">reply</span> editor/same-as-ingredient:<span class="Constant">0</span>, go-render? -] - -<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</span> - <span class="muControl">reply-unless</span> curr, result - at-start?:boolean<span class="Special"> <- </span>equal curr, start - <span class="muControl">reply-if</span> at-start?, result - <span class="Delimiter">{</span> - curr<span class="Special"> <- </span>prev-duplex curr - <span class="muControl">break-unless</span> curr - at-start?:boolean<span class="Special"> <- </span>equal curr, start - <span class="muControl">break-if</span> at-start? - c:character<span class="Special"> <- </span>get *curr, <span class="Constant">value:offset</span> - at-newline?:boolean<span class="Special"> <- </span>equal c, <span class="Constant">10/newline</span> - <span class="muControl">break-if</span> at-newline? - result<span class="Special"> <- </span>add result, <span class="Constant">1</span> - <span class="muControl">loop</span> - <span class="Delimiter">}</span> - <span class="muControl">reply</span> result -] - -<span class="muScenario">scenario</span> editor-clears-last-line-on-backspace [ - assume-screen <span class="Constant">10/width</span>, <span class="Constant">5/height</span> - <span class="Comment"># just one character in final line</span> - <span class="Constant">1</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[ab</span> -<span class="Constant">cd]</span> - <span class="Constant">2</span>:address:editor-data<span class="Special"> <- </span>new-editor <span class="Constant">1</span>:address:array:character, screen:address, <span class="Constant">0/left</span>, <span class="Constant">10/right</span> - assume-console [ - left-click <span class="Constant">2</span>, <span class="Constant">0</span> <span class="Comment"># cursor at only character in final line</span> - type <span class="Constant">[«]</span> - ] - <span class="Constant">3</span>:event/backspace<span class="Special"> <- </span>merge <span class="Constant">0/text</span>, <span class="Constant">8/backspace</span>, <span class="Constant">0/dummy</span>, <span class="Constant">0/dummy</span> - replace-in-console <span class="Constant">171/«</span>, <span class="Constant">3</span>:event/backspace - run [ - editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data - <span class="Constant">4</span>:number<span class="Special"> <- </span>get *<span class="Constant">2</span>:address:editor-data, <span class="Constant">cursor-row:offset</span> - <span class="Constant">5</span>:number<span class="Special"> <- </span>get *<span class="Constant">2</span>:address:editor-data, <span class="Constant">cursor-column:offset</span> - ] - screen-should-contain [ - <span class="Constant"> . .</span> - <span class="Constant"> .abcd .</span> -<span class="Constant"> .┈┈┈┈┈┈┈┈┈┈.</span> - <span class="Constant"> . .</span> - ] - memory-should-contain [ - <span class="Constant">4</span><span class="Special"> <- </span><span class="Constant">1</span> - <span class="Constant">5</span><span class="Special"> <- </span><span class="Constant">2</span> - ] -] - -<span class="Comment"># delete - delete character at cursor</span> - -<span class="muScenario">scenario</span> editor-handles-delete-key [ - assume-screen <span class="Constant">10/width</span>, <span class="Constant">5/height</span> - <span class="Constant">1</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[abc]</span> - <span class="Constant">2</span>:address:editor-data<span class="Special"> <- </span>new-editor <span class="Constant">1</span>:address:array:character, screen:address, <span class="Constant">0/left</span>, <span class="Constant">10/right</span> - editor-render screen, <span class="Constant">2</span>:address:editor-data -<span class="Constant"> $clear-trace</span> - assume-console [ - press <span class="Constant">65522</span> <span class="Comment"># delete</span> - ] - run [ - editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data - ] - screen-should-contain [ - <span class="Constant"> . .</span> - <span class="Constant"> .bc .</span> -<span class="Constant"> .┈┈┈┈┈┈┈┈┈┈.</span> - <span class="Constant"> . .</span> - ] - check-trace-count-for-label <span class="Constant">3</span>, <span class="Constant">[print-character]</span> <span class="Comment"># length of original line to overwrite</span> -<span class="Constant"> $clear-trace</span> - assume-console [ - press <span class="Constant">65522</span> <span class="Comment"># delete</span> - ] - run [ - editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data - ] - screen-should-contain [ - <span class="Constant"> . .</span> - <span class="Constant"> .c .</span> -<span class="Constant"> .┈┈┈┈┈┈┈┈┈┈.</span> - <span class="Constant"> . .</span> - ] - check-trace-count-for-label <span class="Constant">2</span>, <span class="Constant">[print-character]</span> <span class="Comment"># new length to overwrite</span> -] - -<span class="muRecipe">after</span> +handle-special-key [ - <span class="Delimiter">{</span> - delete?:boolean<span class="Special"> <- </span>equal *k, <span class="Constant">65522/delete</span> - <span class="muControl">break-unless</span> delete? - curr:address:duplex-list<span class="Special"> <- </span>next-duplex *before-cursor - <span class="muControl">reply-unless</span> curr, editor/same-as-ingredient:<span class="Constant">0</span>, screen/same-as-ingredient:<span class="Constant">1</span>, <span class="Constant">0/no-more-render</span> - currc:character<span class="Special"> <- </span>get *curr, <span class="Constant">value:offset</span> - remove-duplex curr - deleted-newline?:boolean<span class="Special"> <- </span>equal currc, <span class="Constant">10/newline</span> - <span class="muControl">reply-if</span> deleted-newline?, screen/same-as-ingredient:<span class="Constant">0</span>, editor/same-as-ingredient:<span class="Constant">1</span>, <span class="Constant">1/go-render</span> - <span class="Comment"># wasn't a newline? render rest of line</span> - curr:address:duplex-list<span class="Special"> <- </span>next-duplex *before-cursor <span class="Comment"># refresh after remove-duplex above</span> - screen<span class="Special"> <- </span>move-cursor screen, *cursor-row, *cursor-column - curr-column:number<span class="Special"> <- </span>copy *cursor-column - <span class="Delimiter">{</span> - <span class="Comment"># hit right margin? give up and let caller render</span> - at-right?:boolean<span class="Special"> <- </span>greater-or-equal curr-column, screen-width - <span class="muControl">reply-if</span> at-right?, editor/same-as-ingredient:<span class="Constant">0</span>, screen/same-as-ingredient:<span class="Constant">1</span>, <span class="Constant">1/go-render</span> - <span class="muControl">break-unless</span> curr - <span class="Comment"># newline? done.</span> - currc:character<span class="Special"> <- </span>get *curr, <span class="Constant">value:offset</span> - at-newline?:boolean<span class="Special"> <- </span>equal currc, <span class="Constant">10/newline</span> - <span class="muControl">break-if</span> at-newline? - screen<span class="Special"> <- </span>print-character screen, currc - curr-column<span class="Special"> <- </span>add curr-column, <span class="Constant">1</span> - curr<span class="Special"> <- </span>next-duplex curr - <span class="muControl">loop</span> - <span class="Delimiter">}</span> - <span class="Comment"># we're guaranteed not to be at the right margin</span> - screen<span class="Special"> <- </span>print-character screen, <span class="Constant">32/space</span> - <span class="muControl">reply</span> screen/same-as-ingredient:<span class="Constant">0</span>, editor/same-as-ingredient:<span class="Constant">1</span>, <span class="Constant">0/no-more-render</span> - <span class="Delimiter">}</span> -] - -<span class="Comment"># right arrow</span> - -<span class="muScenario">scenario</span> editor-moves-cursor-right-with-key [ - assume-screen <span class="Constant">10/width</span>, <span class="Constant">5/height</span> - <span class="Constant">1</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[abc]</span> - <span class="Constant">2</span>:address:editor-data<span class="Special"> <- </span>new-editor <span class="Constant">1</span>:address:array:character, screen:address, <span class="Constant">0/left</span>, <span class="Constant">10/right</span> - editor-render screen, <span class="Constant">2</span>:address:editor-data -<span class="Constant"> $clear-trace</span> - assume-console [ - press <span class="Constant">65514</span> <span class="Comment"># right arrow</span> - type <span class="Constant">[0]</span> - ] - run [ - editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data - ] - screen-should-contain [ - <span class="Constant"> . .</span> - <span class="Constant"> .a0bc .</span> -<span class="Constant"> .┈┈┈┈┈┈┈┈┈┈.</span> - <span class="Constant"> . .</span> - ] - check-trace-count-for-label <span class="Constant">3</span>, <span class="Constant">[print-character]</span> <span class="Comment"># 0 and following characters</span> -] - -<span class="muRecipe">after</span> +handle-special-key [ - <span class="Delimiter">{</span> - move-to-next-character?:boolean<span class="Special"> <- </span>equal *k, <span class="Constant">65514/right-arrow</span> - <span class="muControl">break-unless</span> move-to-next-character? - <span class="Comment"># if not at end of text</span> - old-cursor:address:duplex-list<span class="Special"> <- </span>next-duplex *before-cursor - <span class="muControl">break-unless</span> old-cursor - <span class="Comment"># scan to next character</span> - *before-cursor<span class="Special"> <- </span>copy old-cursor - <span class="Comment"># if crossed a newline, move cursor to start of next row</span> - <span class="Delimiter">{</span> - old-cursor-character:character<span class="Special"> <- </span>get **before-cursor, <span class="Constant">value:offset</span> - was-at-newline?:boolean<span class="Special"> <- </span>equal old-cursor-character, <span class="Constant">10/newline</span> - <span class="muControl">break-unless</span> was-at-newline? - *cursor-row<span class="Special"> <- </span>add *cursor-row, <span class="Constant">1</span> - *cursor-column<span class="Special"> <- </span>copy left - below-screen?:boolean<span class="Special"> <- </span>greater-or-equal *cursor-row, screen-height <span class="Comment"># must be equal</span> - screen<span class="Special"> <- </span>move-cursor screen, *cursor-row, *cursor-column - <span class="muControl">reply-unless</span> below-screen?, screen/same-as-ingredient:<span class="Constant">0</span>, editor/same-as-ingredient:<span class="Constant">1</span>, <span class="Constant">0/no-more-render</span> -<span class="Constant"> +scroll-down</span> - *cursor-row<span class="Special"> <- </span>subtract *cursor-row, <span class="Constant">1</span> <span class="Comment"># bring back into screen range</span> - <span class="muControl">reply</span> screen/same-as-ingredient:<span class="Constant">0</span>, editor/same-as-ingredient:<span class="Constant">1</span>, <span class="Constant">1/go-render</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, <span class="Constant">1</span> - at-wrap?:boolean<span class="Special"> <- </span>equal *cursor-column, wrap-column - <span class="muControl">break-unless</span> at-wrap? - <span class="Comment"># and if next character isn't newline</span> - new-cursor:address:duplex-list<span class="Special"> <- </span>next-duplex old-cursor - <span class="muControl">break-unless</span> new-cursor - next-character:character<span class="Special"> <- </span>get *new-cursor, <span class="Constant">value:offset</span> - newline?:boolean<span class="Special"> <- </span>equal next-character, <span class="Constant">10/newline</span> - <span class="muControl">break-if</span> newline? - *cursor-row<span class="Special"> <- </span>add *cursor-row, <span class="Constant">1</span> - *cursor-column<span class="Special"> <- </span>copy left - below-screen?:boolean<span class="Special"> <- </span>greater-or-equal *cursor-row, screen-height <span class="Comment"># must be equal</span> - screen<span class="Special"> <- </span>move-cursor screen, *cursor-row, *cursor-column - <span class="muControl">reply-unless</span> below-screen?, screen/same-as-ingredient:<span class="Constant">0</span>, editor/same-as-ingredient:<span class="Constant">1</span>, <span class="Constant">0/no-more-render</span> -<span class="Constant"> +scroll-down</span> - *cursor-row<span class="Special"> <- </span>subtract *cursor-row, <span class="Constant">1</span> <span class="Comment"># bring back into screen range</span> - <span class="muControl">reply</span> screen/same-as-ingredient:<span class="Constant">0</span>, editor/same-as-ingredient:<span class="Constant">1</span>, <span class="Constant">1/go-render</span> - <span class="Delimiter">}</span> - <span class="Comment"># otherwise move cursor one character right</span> - *cursor-column<span class="Special"> <- </span>add *cursor-column, <span class="Constant">1</span> - screen<span class="Special"> <- </span>move-cursor screen, *cursor-row, *cursor-column - <span class="muControl">reply</span> screen/same-as-ingredient:<span class="Constant">0</span>, editor/same-as-ingredient:<span class="Constant">1</span>, <span class="Constant">0/no-more-render</span> - <span class="Delimiter">}</span> -] - -<span class="muScenario">scenario</span> editor-moves-cursor-to-next-line-with-right-arrow [ - assume-screen <span class="Constant">10/width</span>, <span class="Constant">5/height</span> - <span class="Constant">1</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[abc</span> -<span class="Constant">d]</span> - <span class="Constant">2</span>:address:editor-data<span class="Special"> <- </span>new-editor <span class="Constant">1</span>:address:array:character, screen:address, <span class="Constant">0/left</span>, <span class="Constant">10/right</span> - editor-render screen, <span class="Constant">2</span>:address:editor-data -<span class="Constant"> $clear-trace</span> - <span class="Comment"># type right-arrow a few times to get to start of second line</span> - assume-console [ - press <span class="Constant">65514</span> <span class="Comment"># right arrow</span> - press <span class="Constant">65514</span> <span class="Comment"># right arrow</span> - press <span class="Constant">65514</span> <span class="Comment"># right arrow</span> - press <span class="Constant">65514</span> <span class="Comment"># right arrow - next line</span> - ] - run [ - editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data - ] - check-trace-count-for-label <span class="Constant">0</span>, <span class="Constant">[print-character]</span> - <span class="Comment"># type something and ensure it goes where it should</span> - assume-console [ - type <span class="Constant">[0]</span> - ] - run [ - editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data - ] - screen-should-contain [ - <span class="Constant"> . .</span> - <span class="Constant"> .abc .</span> - <span class="Constant"> .0d .</span> -<span class="Constant"> .┈┈┈┈┈┈┈┈┈┈.</span> - <span class="Constant"> . .</span> - ] - check-trace-count-for-label <span class="Constant">2</span>, <span class="Constant">[print-character]</span> <span class="Comment"># new length of second line</span> -] - -<span class="muScenario">scenario</span> editor-moves-cursor-to-next-line-with-right-arrow-2 [ - assume-screen <span class="Constant">10/width</span>, <span class="Constant">5/height</span> - <span class="Constant">1</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[abc</span> -<span class="Constant">d]</span> - <span class="Constant">2</span>:address:editor-data<span class="Special"> <- </span>new-editor <span class="Constant">1</span>:address:array:character, screen:address, <span class="Constant">1/left</span>, <span class="Constant">10/right</span> - editor-render screen, <span class="Constant">2</span>:address:editor-data - assume-console [ - press <span class="Constant">65514</span> <span class="Comment"># right arrow</span> - press <span class="Constant">65514</span> <span class="Comment"># right arrow</span> - press <span class="Constant">65514</span> <span class="Comment"># right arrow</span> - press <span class="Constant">65514</span> <span class="Comment"># right arrow - next line</span> - type <span class="Constant">[0]</span> - ] - run [ - editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data - ] - screen-should-contain [ - <span class="Constant"> . .</span> - <span class="Constant"> . abc .</span> - <span class="Constant"> . 0d .</span> - <span class="Constant"> . ┈┈┈┈┈┈┈┈┈.</span> - <span class="Constant"> . .</span> - ] -] - -<span class="muScenario">scenario</span> editor-moves-cursor-to-next-wrapped-line-with-right-arrow [ - assume-screen <span class="Constant">10/width</span>, <span class="Constant">5/height</span> - <span class="Constant">1</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[abcdef]</span> - <span class="Constant">2</span>:address:editor-data<span class="Special"> <- </span>new-editor <span class="Constant">1</span>:address:array:character, screen:address, <span class="Constant">0/left</span>, <span class="Constant">5/right</span> - editor-render screen, <span class="Constant">2</span>:address:editor-data -<span class="Constant"> $clear-trace</span> - assume-console [ - left-click <span class="Constant">1</span>, <span class="Constant">3</span> - press <span class="Constant">65514</span> <span class="Comment"># right arrow</span> - ] - run [ - editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data - <span class="Constant">3</span>:number<span class="Special"> <- </span>get *<span class="Constant">2</span>:address:editor-data, <span class="Constant">cursor-row:offset</span> - <span class="Constant">4</span>:number<span class="Special"> <- </span>get *<span class="Constant">2</span>:address:editor-data, <span class="Constant">cursor-column:offset</span> - ] - screen-should-contain [ - <span class="Constant"> . .</span> - <span class="Constant"> .abcd↩ .</span> - <span class="Constant"> .ef .</span> - <span class="Constant"> .┈┈┈┈┈ .</span> - <span class="Constant"> . .</span> - ] - memory-should-contain [ - <span class="Constant">3</span><span class="Special"> <- </span><span class="Constant">2</span> - <span class="Constant">4</span><span class="Special"> <- </span><span class="Constant">0</span> - ] - check-trace-count-for-label <span class="Constant">0</span>, <span class="Constant">[print-character]</span> -] - -<span class="muScenario">scenario</span> editor-moves-cursor-to-next-wrapped-line-with-right-arrow-2 [ - assume-screen <span class="Constant">10/width</span>, <span class="Constant">5/height</span> - <span class="Comment"># line just barely wrapping</span> - <span class="Constant">1</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[abcde]</span> - <span class="Constant">2</span>:address:editor-data<span class="Special"> <- </span>new-editor <span class="Constant">1</span>:address:array:character, screen:address, <span class="Constant">0/left</span>, <span class="Constant">5/right</span> - editor-render screen, <span class="Constant">2</span>:address:editor-data -<span class="Constant"> $clear-trace</span> - <span class="Comment"># position cursor at last character before wrap and hit right-arrow</span> - assume-console [ - left-click <span class="Constant">1</span>, <span class="Constant">3</span> - press <span class="Constant">65514</span> <span class="Comment"># right arrow</span> - ] - run [ - editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data - <span class="Constant">3</span>:number<span class="Special"> <- </span>get *<span class="Constant">2</span>:address:editor-data, <span class="Constant">cursor-row:offset</span> - <span class="Constant">4</span>:number<span class="Special"> <- </span>get *<span class="Constant">2</span>:address:editor-data, <span class="Constant">cursor-column:offset</span> - ] - memory-should-contain [ - <span class="Constant">3</span><span class="Special"> <- </span><span class="Constant">2</span> - <span class="Constant">4</span><span class="Special"> <- </span><span class="Constant">0</span> - ] - <span class="Comment"># now hit right arrow again</span> - assume-console [ - press <span class="Constant">65514</span> - ] - run [ - editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data - <span class="Constant">3</span>:number<span class="Special"> <- </span>get *<span class="Constant">2</span>:address:editor-data, <span class="Constant">cursor-row:offset</span> - <span class="Constant">4</span>:number<span class="Special"> <- </span>get *<span class="Constant">2</span>:address:editor-data, <span class="Constant">cursor-column:offset</span> - ] - memory-should-contain [ - <span class="Constant">3</span><span class="Special"> <- </span><span class="Constant">2</span> - <span class="Constant">4</span><span class="Special"> <- </span><span class="Constant">1</span> - ] - check-trace-count-for-label <span class="Constant">0</span>, <span class="Constant">[print-character]</span> -] - -<span class="muScenario">scenario</span> editor-moves-cursor-to-next-wrapped-line-with-right-arrow-3 [ - assume-screen <span class="Constant">10/width</span>, <span class="Constant">5/height</span> - <span class="Constant">1</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[abcdef]</span> - <span class="Constant">2</span>:address:editor-data<span class="Special"> <- </span>new-editor <span class="Constant">1</span>:address:array:character, screen:address, <span class="Constant">1/left</span>, <span class="Constant">6/right</span> - editor-render screen, <span class="Constant">2</span>:address:editor-data -<span class="Constant"> $clear-trace</span> - assume-console [ - left-click <span class="Constant">1</span>, <span class="Constant">4</span> - press <span class="Constant">65514</span> <span class="Comment"># right arrow</span> - ] - run [ - editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data - <span class="Constant">3</span>:number<span class="Special"> <- </span>get *<span class="Constant">2</span>:address:editor-data, <span class="Constant">cursor-row:offset</span> - <span class="Constant">4</span>:number<span class="Special"> <- </span>get *<span class="Constant">2</span>:address:editor-data, <span class="Constant">cursor-column:offset</span> - ] - screen-should-contain [ - <span class="Constant"> . .</span> - <span class="Constant"> . abcd↩ .</span> - <span class="Constant"> . ef .</span> - <span class="Constant"> . ┈┈┈┈┈ .</span> - <span class="Constant"> . .</span> - ] - memory-should-contain [ - <span class="Constant">3</span><span class="Special"> <- </span><span class="Constant">2</span> - <span class="Constant">4</span><span class="Special"> <- </span><span class="Constant">1</span> - ] - check-trace-count-for-label <span class="Constant">0</span>, <span class="Constant">[print-character]</span> -] - -<span class="muScenario">scenario</span> editor-moves-cursor-to-next-line-with-right-arrow-at-end-of-line [ - assume-screen <span class="Constant">10/width</span>, <span class="Constant">5/height</span> - <span class="Constant">1</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[abc</span> -<span class="Constant">d]</span> - <span class="Constant">2</span>:address:editor-data<span class="Special"> <- </span>new-editor <span class="Constant">1</span>:address:array:character, screen:address, <span class="Constant">0/left</span>, <span class="Constant">10/right</span> - editor-render screen, <span class="Constant">2</span>:address:editor-data -<span class="Constant"> $clear-trace</span> - assume-console [ - left-click <span class="Constant">1</span>, <span class="Constant">3</span> - press <span class="Constant">65514</span> <span class="Comment"># right arrow - next line</span> - type <span class="Constant">[0]</span> - ] - run [ - editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data - ] - screen-should-contain [ - <span class="Constant"> . .</span> - <span class="Constant"> .abc .</span> - <span class="Constant"> .0d .</span> -<span class="Constant"> .┈┈┈┈┈┈┈┈┈┈.</span> - <span class="Constant"> . .</span> - ] - check-trace-count-for-label <span class="Constant">2</span>, <span class="Constant">[print-character]</span> -] - -<span class="Comment"># left arrow</span> - -<span class="muScenario">scenario</span> editor-moves-cursor-left-with-key [ - assume-screen <span class="Constant">10/width</span>, <span class="Constant">5/height</span> - <span class="Constant">1</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[abc]</span> - <span class="Constant">2</span>:address:editor-data<span class="Special"> <- </span>new-editor <span class="Constant">1</span>:address:array:character, screen:address, <span class="Constant">0/left</span>, <span class="Constant">10/right</span> - editor-render screen, <span class="Constant">2</span>:address:editor-data -<span class="Constant"> $clear-trace</span> - assume-console [ - left-click <span class="Constant">1</span>, <span class="Constant">2</span> - press <span class="Constant">65515</span> <span class="Comment"># left arrow</span> - type <span class="Constant">[0]</span> - ] - run [ - editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data - ] - screen-should-contain [ - <span class="Constant"> . .</span> - <span class="Constant"> .a0bc .</span> -<span class="Constant"> .┈┈┈┈┈┈┈┈┈┈.</span> - <span class="Constant"> . .</span> - ] - check-trace-count-for-label <span class="Constant">3</span>, <span class="Constant">[print-character]</span> -] - -<span class="muRecipe">after</span> +handle-special-key [ - <span class="Delimiter">{</span> - move-to-previous-character?:boolean<span class="Special"> <- </span>equal *k, <span class="Constant">65515/left-arrow</span> - <span class="muControl">break-unless</span> move-to-previous-character? -<span class="CommentedCode">#? trace 10, [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 - <span class="muControl">reply-unless</span> prev, screen/same-as-ingredient:<span class="Constant">0</span>, editor/same-as-ingredient:<span class="Constant">1</span>, <span class="Constant">0/no-more-render</span> - editor, go-render?<span class="Special"> <- </span>move-cursor-coordinates-left editor - *before-cursor<span class="Special"> <- </span>copy prev - <span class="muControl">reply</span> screen/same-as-ingredient:<span class="Constant">0</span>, editor/same-as-ingredient:<span class="Constant">1</span>, go-render? - <span class="Delimiter">}</span> -] - -<span class="muScenario">scenario</span> editor-moves-cursor-to-previous-line-with-left-arrow-at-start-of-line [ - assume-screen <span class="Constant">10/width</span>, <span class="Constant">5/height</span> - <span class="Comment"># initialize editor with two lines</span> - <span class="Constant">1</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[abc</span> -<span class="Constant">d]</span> - <span class="Constant">2</span>:address:editor-data<span class="Special"> <- </span>new-editor <span class="Constant">1</span>:address:array:character, screen:address, <span class="Constant">0/left</span>, <span class="Constant">10/right</span> - editor-render screen, <span class="Constant">2</span>:address:editor-data -<span class="Constant"> $clear-trace</span> - <span class="Comment"># position cursor at start of second line (so there's no previous newline)</span> - assume-console [ - left-click <span class="Constant">2</span>, <span class="Constant">0</span> - press <span class="Constant">65515</span> <span class="Comment"># left arrow</span> - ] - run [ - editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data - <span class="Constant">3</span>:number<span class="Special"> <- </span>get *<span class="Constant">2</span>:address:editor-data, <span class="Constant">cursor-row:offset</span> - <span class="Constant">4</span>:number<span class="Special"> <- </span>get *<span class="Constant">2</span>:address:editor-data, <span class="Constant">cursor-column:offset</span> - ] - memory-should-contain [ - <span class="Constant">3</span><span class="Special"> <- </span><span class="Constant">1</span> - <span class="Constant">4</span><span class="Special"> <- </span><span class="Constant">3</span> - ] - check-trace-count-for-label <span class="Constant">0</span>, <span class="Constant">[print-character]</span> -] - -<span class="muScenario">scenario</span> editor-moves-cursor-to-previous-line-with-left-arrow-at-start-of-line-2 [ - assume-screen <span class="Constant">10/width</span>, <span class="Constant">5/height</span> - <span class="Comment"># initialize editor with three lines</span> - <span class="Constant">1</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[abc</span> -<span class="Constant">def</span> -<span class="Constant">g]</span> - <span class="Constant">2</span>:address:editor-data<span class="Special"> <- </span>new-editor <span class="Constant">1</span>:address:array:character, screen:address, <span class="Constant">0/left</span>, <span class="Constant">10/right</span> - editor-render screen, <span class="Constant">2</span>:address:editor-data -<span class="Constant"> $clear-trace</span> - <span class="Comment"># position cursor further down (so there's a newline before the character at</span> - <span class="Comment"># the cursor)</span> - assume-console [ - left-click <span class="Constant">3</span>, <span class="Constant">0</span> - press <span class="Constant">65515</span> <span class="Comment"># left arrow</span> - type <span class="Constant">[0]</span> - ] - run [ - editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data - ] - screen-should-contain [ - <span class="Constant"> . .</span> - <span class="Constant"> .abc .</span> - <span class="Constant"> .def0 .</span> - <span class="Constant"> .g .</span> -<span class="Constant"> .┈┈┈┈┈┈┈┈┈┈.</span> - ] - check-trace-count-for-label <span class="Constant">1</span>, <span class="Constant">[print-character]</span> <span class="Comment"># just the '0'</span> -] - -<span class="muScenario">scenario</span> editor-moves-cursor-to-previous-line-with-left-arrow-at-start-of-line-3 [ - assume-screen <span class="Constant">10/width</span>, <span class="Constant">5/height</span> - <span class="Constant">1</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[abc</span> -<span class="Constant">def</span> -<span class="Constant">g]</span> - <span class="Constant">2</span>:address:editor-data<span class="Special"> <- </span>new-editor <span class="Constant">1</span>:address:array:character, screen:address, <span class="Constant">0/left</span>, <span class="Constant">10/right</span> - editor-render screen, <span class="Constant">2</span>:address:editor-data -<span class="Constant"> $clear-trace</span> - <span class="Comment"># position cursor at start of text</span> - assume-console [ - left-click <span class="Constant">1</span>, <span class="Constant">0</span> - press <span class="Constant">65515</span> <span class="Comment"># left arrow should have no effect</span> - type <span class="Constant">[0]</span> - ] - run [ - editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data - ] - screen-should-contain [ - <span class="Constant"> . .</span> - <span class="Constant"> .0abc .</span> - <span class="Constant"> .def .</span> - <span class="Constant"> .g .</span> -<span class="Constant"> .┈┈┈┈┈┈┈┈┈┈.</span> - ] - check-trace-count-for-label <span class="Constant">4</span>, <span class="Constant">[print-character]</span> <span class="Comment"># length of first line</span> -] - -<span class="muScenario">scenario</span> editor-moves-cursor-to-previous-line-with-left-arrow-at-start-of-line-4 [ - assume-screen <span class="Constant">10/width</span>, <span class="Constant">5/height</span> - <span class="Comment"># initialize editor with text containing an empty line</span> - <span class="Constant">1</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[abc</span> - -d] - <span class="Constant">2</span>:address:editor-data<span class="Special"> <- </span>new-editor <span class="Constant">1</span>:address:array:character, screen:address, <span class="Constant">0/left</span>, <span class="Constant">10/right</span> - editor-render screen, <span class="Constant">2</span>:address:editor-data -<span class="Constant"> $clear-trace</span> - <span class="Comment"># position cursor right after empty line</span> - assume-console [ - left-click <span class="Constant">3</span>, <span class="Constant">0</span> - press <span class="Constant">65515</span> <span class="Comment"># left arrow</span> - type <span class="Constant">[0]</span> - ] - run [ - editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data - ] - screen-should-contain [ - <span class="Constant"> . .</span> - <span class="Constant"> .abc .</span> - <span class="Constant"> .0 .</span> - <span class="Constant"> .d .</span> -<span class="Constant"> .┈┈┈┈┈┈┈┈┈┈.</span> - ] - check-trace-count-for-label <span class="Constant">1</span>, <span class="Constant">[print-character]</span> <span class="Comment"># just the '0'</span> -] - -<span class="muScenario">scenario</span> editor-moves-across-screen-lines-across-wrap-with-left-arrow [ - assume-screen <span class="Constant">10/width</span>, <span class="Constant">5/height</span> - <span class="Comment"># initialize editor with text containing an empty line</span> - <span class="Constant">1</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[abcdef]</span> - <span class="Constant">2</span>:address:editor-data<span class="Special"> <- </span>new-editor <span class="Constant">1</span>:address:array:character, screen:address, <span class="Constant">0/left</span>, <span class="Constant">5/right</span> - editor-render screen, <span class="Constant">2</span>:address:editor-data -<span class="Constant"> $clear-trace</span> - screen-should-contain [ - <span class="Constant"> . .</span> - <span class="Constant"> .abcd↩ .</span> - <span class="Constant"> .ef .</span> - <span class="Constant"> .┈┈┈┈┈ .</span> - <span class="Constant"> . .</span> - ] - <span class="Comment"># position cursor right after empty line</span> - assume-console [ - left-click <span class="Constant">2</span>, <span class="Constant">0</span> - press <span class="Constant">65515</span> <span class="Comment"># left arrow</span> - ] - run [ - editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data - <span class="Constant">3</span>:number<span class="Special"> <- </span>get *<span class="Constant">2</span>:address:editor-data, <span class="Constant">cursor-row:offset</span> - <span class="Constant">4</span>:number<span class="Special"> <- </span>get *<span class="Constant">2</span>:address:editor-data, <span class="Constant">cursor-column:offset</span> - ] - memory-should-contain [ - <span class="Constant">3</span><span class="Special"> <- </span><span class="Constant">1</span> <span class="Comment"># previous row</span> - <span class="Constant">4</span><span class="Special"> <- </span><span class="Constant">3</span> <span class="Comment"># end of wrapped line</span> - ] - check-trace-count-for-label <span class="Constant">0</span>, <span class="Constant">[print-character]</span> -] - -<span class="Comment"># up arrow</span> - -<span class="muScenario">scenario</span> editor-moves-to-previous-line-with-up-arrow [ - assume-screen <span class="Constant">10/width</span>, <span class="Constant">5/height</span> - <span class="Constant">1</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[abc</span> -<span class="Constant">def]</span> - <span class="Constant">2</span>:address:editor-data<span class="Special"> <- </span>new-editor <span class="Constant">1</span>:address:array:character, screen:address, <span class="Constant">0/left</span>, <span class="Constant">10/right</span> - editor-render screen, <span class="Constant">2</span>:address:editor-data -<span class="Constant"> $clear-trace</span> - assume-console [ - left-click <span class="Constant">2</span>, <span class="Constant">1</span> - press <span class="Constant">65517</span> <span class="Comment"># up arrow</span> - ] - run [ - editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data - <span class="Constant">3</span>:number<span class="Special"> <- </span>get *<span class="Constant">2</span>:address:editor-data, <span class="Constant">cursor-row:offset</span> - <span class="Constant">4</span>:number<span class="Special"> <- </span>get *<span class="Constant">2</span>:address:editor-data, <span class="Constant">cursor-column:offset</span> - ] - memory-should-contain [ - <span class="Constant">3</span><span class="Special"> <- </span><span class="Constant">1</span> - <span class="Constant">4</span><span class="Special"> <- </span><span class="Constant">1</span> - ] - check-trace-count-for-label <span class="Constant">0</span>, <span class="Constant">[print-character]</span> - assume-console [ - type <span class="Constant">[0]</span> - ] - run [ - editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data - ] - screen-should-contain [ - <span class="Constant"> . .</span> - <span class="Constant"> .a0bc .</span> - <span class="Constant"> .def .</span> -<span class="Constant"> .┈┈┈┈┈┈┈┈┈┈.</span> - <span class="Constant"> . .</span> - ] -] - -<span class="muRecipe">after</span> +handle-special-key [ - <span class="Delimiter">{</span> - move-to-previous-line?:boolean<span class="Special"> <- </span>equal *k, <span class="Constant">65517/up-arrow</span> - <span class="muControl">break-unless</span> move-to-previous-line? - already-at-top?:boolean<span class="Special"> <- </span>lesser-or-equal *cursor-row, <span class="Constant">1/top</span> - <span class="Delimiter">{</span> - <span class="Comment"># if cursor not at top, move it</span> - <span class="muControl">break-if</span> already-at-top? - *cursor-row<span class="Special"> <- </span>subtract *cursor-row, <span class="Constant">1</span> - <span class="Comment"># scan back two newlines, then ahead to right column or until end of line</span> - prev:address:duplex-list<span class="Special"> <- </span>before-previous-line *before-cursor, editor - no-motion?:boolean<span class="Special"> <- </span>equal prev, *before-cursor - <span class="muControl">reply-if</span> no-motion?, screen/same-as-ingredient:<span class="Constant">0</span>, editor/same-as-ingredient:<span class="Constant">1</span>, <span class="Constant">0/no-more-render</span> - tmp:address:duplex-list<span class="Special"> <- </span>copy prev - prev:address:duplex-list<span class="Special"> <- </span>before-previous-line tmp, editor - no-motion?:boolean<span class="Special"> <- </span>equal prev, *before-cursor - <span class="muControl">reply-if</span> no-motion?, screen/same-as-ingredient:<span class="Constant">0</span>, editor/same-as-ingredient:<span class="Constant">1</span>, <span class="Constant">0/no-more-render</span> - *before-cursor<span class="Special"> <- </span>copy prev - target-column:number<span class="Special"> <- </span>copy *cursor-column - *cursor-column<span class="Special"> <- </span>copy left - <span class="Delimiter">{</span> - done?:boolean<span class="Special"> <- </span>greater-or-equal *cursor-column, target-column - <span class="muControl">break-if</span> done? - curr:address:duplex-list<span class="Special"> <- </span>next-duplex *before-cursor - <span class="muControl">break-unless</span> curr - currc:character<span class="Special"> <- </span>get *curr, <span class="Constant">value:offset</span> - at-newline?:boolean<span class="Special"> <- </span>equal currc, <span class="Constant">10/newline</span> - not-at-start?:boolean<span class="Special"> <- </span>greater-than *cursor-column, left - line-done?:boolean<span class="Special"> <- </span>and at-newline?, not-at-start? - <span class="muControl">break-if</span> line-done? - <span class="Comment">#</span> - *before-cursor<span class="Special"> <- </span>copy curr - *cursor-column<span class="Special"> <- </span>add *cursor-column, <span class="Constant">1</span> - <span class="muControl">loop</span> - <span class="Delimiter">}</span> - <span class="muControl">reply</span> screen/same-as-ingredient:<span class="Constant">0</span>, editor/same-as-ingredient:<span class="Constant">1</span>, <span class="Constant">0/no-more-render</span> - <span class="Delimiter">}</span> - <span class="Delimiter">{</span> - <span class="Comment"># if cursor already at top, scroll up</span> - <span class="muControl">break-unless</span> already-at-top? -<span class="Constant"> +scroll-up</span> - <span class="muControl">reply</span> screen/same-as-ingredient:<span class="Constant">0</span>, editor/same-as-ingredient:<span class="Constant">1</span>, <span class="Constant">1/go-render</span> - <span class="Delimiter">}</span> - <span class="Delimiter">}</span> -] - -<span class="muScenario">scenario</span> editor-adjusts-column-at-previous-line [ - assume-screen <span class="Constant">10/width</span>, <span class="Constant">5/height</span> - <span class="Constant">1</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[ab</span> -<span class="Constant">def]</span> - <span class="Constant">2</span>:address:editor-data<span class="Special"> <- </span>new-editor <span class="Constant">1</span>:address:array:character, screen:address, <span class="Constant">0/left</span>, <span class="Constant">10/right</span> - editor-render screen, <span class="Constant">2</span>:address:editor-data -<span class="Constant"> $clear-trace</span> - assume-console [ - left-click <span class="Constant">2</span>, <span class="Constant">3</span> - press <span class="Constant">65517</span> <span class="Comment"># up arrow</span> - ] - run [ - editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data - <span class="Constant">3</span>:number<span class="Special"> <- </span>get *<span class="Constant">2</span>:address:editor-data, <span class="Constant">cursor-row:offset</span> - <span class="Constant">4</span>:number<span class="Special"> <- </span>get *<span class="Constant">2</span>:address:editor-data, <span class="Constant">cursor-column:offset</span> - ] - memory-should-contain [ - <span class="Constant">3</span><span class="Special"> <- </span><span class="Constant">1</span> - <span class="Constant">4</span><span class="Special"> <- </span><span class="Constant">2</span> - ] - check-trace-count-for-label <span class="Constant">0</span>, <span class="Constant">[print-character]</span> - assume-console [ - type <span class="Constant">[0]</span> - ] - run [ - editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data - ] - screen-should-contain [ - <span class="Constant"> . .</span> - <span class="Constant"> .ab0 .</span> - <span class="Constant"> .def .</span> -<span class="Constant"> .┈┈┈┈┈┈┈┈┈┈.</span> - <span class="Constant"> . .</span> - ] -] - -<span class="Comment"># down arrow</span> - -<span class="muScenario">scenario</span> editor-moves-to-next-line-with-down-arrow [ - assume-screen <span class="Constant">10/width</span>, <span class="Constant">5/height</span> - <span class="Constant">1</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[abc</span> -<span class="Constant">def]</span> - <span class="Constant">2</span>:address:editor-data<span class="Special"> <- </span>new-editor <span class="Constant">1</span>:address:array:character, screen:address, <span class="Constant">0/left</span>, <span class="Constant">10/right</span> - editor-render screen, <span class="Constant">2</span>:address:editor-data -<span class="Constant"> $clear-trace</span> - <span class="Comment"># cursor starts out at (1, 0)</span> - assume-console [ - press <span class="Constant">65516</span> <span class="Comment"># down arrow</span> - ] - run [ - editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data - <span class="Constant">3</span>:number<span class="Special"> <- </span>get *<span class="Constant">2</span>:address:editor-data, <span class="Constant">cursor-row:offset</span> - <span class="Constant">4</span>:number<span class="Special"> <- </span>get *<span class="Constant">2</span>:address:editor-data, <span class="Constant">cursor-column:offset</span> - ] - <span class="Comment"># ..and ends at (2, 0)</span> - memory-should-contain [ - <span class="Constant">3</span><span class="Special"> <- </span><span class="Constant">2</span> - <span class="Constant">4</span><span class="Special"> <- </span><span class="Constant">0</span> - ] - check-trace-count-for-label <span class="Constant">0</span>, <span class="Constant">[print-character]</span> - assume-console [ - type <span class="Constant">[0]</span> - ] - run [ - editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data - ] - screen-should-contain [ - <span class="Constant"> . .</span> - <span class="Constant"> .abc .</span> - <span class="Constant"> .0def .</span> -<span class="Constant"> .┈┈┈┈┈┈┈┈┈┈.</span> - <span class="Constant"> . .</span> - ] -] - -<span class="muRecipe">after</span> +handle-special-key [ - <span class="Delimiter">{</span> - move-to-next-line?:boolean<span class="Special"> <- </span>equal *k, <span class="Constant">65516/down-arrow</span> - <span class="muControl">break-unless</span> move-to-next-line? - last-line:number<span class="Special"> <- </span>subtract screen-height, <span class="Constant">1</span> - already-at-bottom?:boolean<span class="Special"> <- </span>greater-or-equal *cursor-row, last-line - <span class="Delimiter">{</span> - <span class="Comment"># if cursor not at top, move it</span> - <span class="muControl">break-if</span> already-at-bottom? - *cursor-row<span class="Special"> <- </span>add *cursor-row, <span class="Constant">1</span> - <span class="Comment"># scan to start of next line, then to right column or until end of line</span> - max:number<span class="Special"> <- </span>subtract right, left - next-line:address:duplex-list<span class="Special"> <- </span>before-start-of-next-line *before-cursor, max - no-motion?:boolean<span class="Special"> <- </span>equal next-line, *before-cursor - <span class="muControl">reply-if</span> no-motion?, screen/same-as-ingredient:<span class="Constant">0</span>, editor/same-as-ingredient:<span class="Constant">1</span>, <span class="Constant">0/no-more-render</span> - *before-cursor<span class="Special"> <- </span>copy next-line - target-column:number<span class="Special"> <- </span>copy *cursor-column - *cursor-column<span class="Special"> <- </span>copy left - <span class="Delimiter">{</span> - done?:boolean<span class="Special"> <- </span>greater-or-equal *cursor-column, target-column - <span class="muControl">break-if</span> done? - curr:address:duplex-list<span class="Special"> <- </span>next-duplex *before-cursor - <span class="muControl">break-unless</span> curr - currc:character<span class="Special"> <- </span>get *curr, <span class="Constant">value:offset</span> - at-newline?:boolean<span class="Special"> <- </span>equal currc, <span class="Constant">10/newline</span> - not-at-start?:boolean<span class="Special"> <- </span>greater-than *cursor-column, left - line-done?:boolean<span class="Special"> <- </span>and at-newline?, not-at-start? - <span class="muControl">break-if</span> line-done? - <span class="Comment">#</span> - *before-cursor<span class="Special"> <- </span>copy curr - *cursor-column<span class="Special"> <- </span>add *cursor-column, <span class="Constant">1</span> - <span class="muControl">loop</span> - <span class="Delimiter">}</span> - <span class="muControl">reply</span> screen/same-as-ingredient:<span class="Constant">0</span>, editor/same-as-ingredient:<span class="Constant">1</span>, <span class="Constant">0/no-more-render</span> - <span class="Delimiter">}</span> - <span class="Delimiter">{</span> - <span class="Comment"># if cursor already at top, scroll up</span> - <span class="muControl">break-unless</span> already-at-bottom? -<span class="Constant"> +scroll-down</span> - <span class="muControl">reply</span> screen/same-as-ingredient:<span class="Constant">0</span>, editor/same-as-ingredient:<span class="Constant">1</span>, <span class="Constant">1/go-render</span> - <span class="Delimiter">}</span> - <span class="Delimiter">}</span> -] - -<span class="muScenario">scenario</span> editor-adjusts-column-at-next-line [ - assume-screen <span class="Constant">10/width</span>, <span class="Constant">5/height</span> - <span class="Constant">1</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[abc</span> -<span class="Constant">de]</span> - <span class="Constant">2</span>:address:editor-data<span class="Special"> <- </span>new-editor <span class="Constant">1</span>:address:array:character, screen:address, <span class="Constant">0/left</span>, <span class="Constant">10/right</span> - editor-render screen, <span class="Constant">2</span>:address:editor-data -<span class="Constant"> $clear-trace</span> - assume-console [ - left-click <span class="Constant">1</span>, <span class="Constant">3</span> - press <span class="Constant">65516</span> <span class="Comment"># down arrow</span> - ] - run [ - editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data - <span class="Constant">3</span>:number<span class="Special"> <- </span>get *<span class="Constant">2</span>:address:editor-data, <span class="Constant">cursor-row:offset</span> - <span class="Constant">4</span>:number<span class="Special"> <- </span>get *<span class="Constant">2</span>:address:editor-data, <span class="Constant">cursor-column:offset</span> - ] - memory-should-contain [ - <span class="Constant">3</span><span class="Special"> <- </span><span class="Constant">2</span> - <span class="Constant">4</span><span class="Special"> <- </span><span class="Constant">2</span> - ] - check-trace-count-for-label <span class="Constant">0</span>, <span class="Constant">[print-character]</span> - assume-console [ - type <span class="Constant">[0]</span> - ] - run [ - editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data - ] - screen-should-contain [ - <span class="Constant"> . .</span> - <span class="Constant"> .abc .</span> - <span class="Constant"> .de0 .</span> -<span class="Constant"> .┈┈┈┈┈┈┈┈┈┈.</span> - <span class="Constant"> . .</span> - ] -] - -<span class="Comment"># ctrl-a/home - move cursor to start of line</span> - -<span class="muScenario">scenario</span> editor-moves-to-start-of-line-with-ctrl-a [ - assume-screen <span class="Constant">10/width</span>, <span class="Constant">5/height</span> - <span class="Constant">1</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[123</span> -<span class="Constant">456]</span> - <span class="Constant">2</span>:address:editor-data<span class="Special"> <- </span>new-editor <span class="Constant">1</span>:address:array:character, screen:address, <span class="Constant">0/left</span>, <span class="Constant">10/right</span> - editor-render screen, <span class="Constant">2</span>:address:editor-data -<span class="Constant"> $clear-trace</span> - <span class="Comment"># start on second line, press ctrl-a</span> - assume-console [ - left-click <span class="Constant">2</span>, <span class="Constant">3</span> - type <span class="Constant">[a]</span> <span class="Comment"># ctrl-a</span> - ] - <span class="Constant">3</span>:event/ctrl-a<span class="Special"> <- </span>merge <span class="Constant">0/text</span>, <span class="Constant">1/ctrl-a</span>, <span class="Constant">0/dummy</span>, <span class="Constant">0/dummy</span> - replace-in-console <span class="Constant">97/a</span>, <span class="Constant">3</span>:event/ctrl-a - run [ - editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data - <span class="Constant">4</span>:number<span class="Special"> <- </span>get *<span class="Constant">2</span>:address:editor-data, <span class="Constant">cursor-row:offset</span> - <span class="Constant">5</span>:number<span class="Special"> <- </span>get *<span class="Constant">2</span>:address:editor-data, <span class="Constant">cursor-column:offset</span> - ] - <span class="Comment"># cursor moves to start of line</span> - memory-should-contain [ - <span class="Constant">4</span><span class="Special"> <- </span><span class="Constant">2</span> - <span class="Constant">5</span><span class="Special"> <- </span><span class="Constant">0</span> - ] - check-trace-count-for-label <span class="Constant">0</span>, <span class="Constant">[print-character]</span> -] - -<span class="muRecipe">after</span> +handle-special-character [ - <span class="Delimiter">{</span> - ctrl-a?:boolean<span class="Special"> <- </span>equal *c, <span class="Constant">1/ctrl-a</span> - <span class="muControl">break-unless</span> ctrl-a? - move-to-start-of-line editor - <span class="muControl">reply</span> screen/same-as-ingredient:<span class="Constant">0</span>, editor/same-as-ingredient:<span class="Constant">1</span>, <span class="Constant">0/no-more-render</span> - <span class="Delimiter">}</span> -] - -<span class="muRecipe">after</span> +handle-special-key [ - <span class="Delimiter">{</span> - home?:boolean<span class="Special"> <- </span>equal *k, <span class="Constant">65521/home</span> - <span class="muControl">break-unless</span> home? - move-to-start-of-line editor - <span class="muControl">reply</span> screen/same-as-ingredient:<span class="Constant">0</span>, editor/same-as-ingredient:<span class="Constant">1</span>, <span class="Constant">0/no-more-render</span> - <span class="Delimiter">}</span> -] - -<span class="muRecipe">recipe</span> move-to-start-of-line [ - <span class="Constant">local-scope</span> - editor:address:editor-data<span class="Special"> <- </span><span class="Constant">next-ingredient</span> - <span class="Comment"># update cursor column</span> - left:number<span class="Special"> <- </span>get *editor, <span class="Constant">left:offset</span> - cursor-column:address:number<span class="Special"> <- </span>get-address *editor, <span class="Constant">cursor-column:offset</span> - *cursor-column<span class="Special"> <- </span>copy left - <span class="Comment"># update before-cursor</span> - before-cursor:address:address:duplex-list<span class="Special"> <- </span>get-address *editor, <span class="Constant">before-cursor:offset</span> - init:address:duplex-list<span class="Special"> <- </span>get *editor, <span class="Constant">data:offset</span> - <span class="Comment"># while not at start of line, move </span> - <span class="Delimiter">{</span> - at-start-of-text?:boolean<span class="Special"> <- </span>equal *before-cursor, init - <span class="muControl">break-if</span> at-start-of-text? - prev:character<span class="Special"> <- </span>get **before-cursor, <span class="Constant">value:offset</span> - at-start-of-line?:boolean<span class="Special"> <- </span>equal prev, <span class="Constant">10/newline</span> - <span class="muControl">break-if</span> at-start-of-line? - *before-cursor<span class="Special"> <- </span>prev-duplex *before-cursor - assert *before-cursor, <span class="Constant">[move-to-start-of-line tried to move before start of text]</span> - <span class="muControl">loop</span> - <span class="Delimiter">}</span> -] - -<span class="muScenario">scenario</span> editor-moves-to-start-of-line-with-ctrl-a-2 [ - assume-screen <span class="Constant">10/width</span>, <span class="Constant">5/height</span> - <span class="Constant">1</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[123</span> -<span class="Constant">456]</span> - <span class="Constant">2</span>:address:editor-data<span class="Special"> <- </span>new-editor <span class="Constant">1</span>:address:array:character, screen:address, <span class="Constant">0/left</span>, <span class="Constant">10/right</span> - editor-render screen, <span class="Constant">2</span>:address:editor-data -<span class="Constant"> $clear-trace</span> - <span class="Comment"># start on first line (no newline before), press ctrl-a</span> - assume-console [ - left-click <span class="Constant">1</span>, <span class="Constant">3</span> - type <span class="Constant">[a]</span> <span class="Comment"># ctrl-a</span> - ] - <span class="Constant">3</span>:event/ctrl-a<span class="Special"> <- </span>merge <span class="Constant">0/text</span>, <span class="Constant">1/ctrl-a</span>, <span class="Constant">0/dummy</span>, <span class="Constant">0/dummy</span> - replace-in-console <span class="Constant">97/a</span>, <span class="Constant">3</span>:event/ctrl-a - run [ - editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data - <span class="Constant">4</span>:number<span class="Special"> <- </span>get *<span class="Constant">2</span>:address:editor-data, <span class="Constant">cursor-row:offset</span> - <span class="Constant">5</span>:number<span class="Special"> <- </span>get *<span class="Constant">2</span>:address:editor-data, <span class="Constant">cursor-column:offset</span> - ] - <span class="Comment"># cursor moves to start of line</span> - memory-should-contain [ - <span class="Constant">4</span><span class="Special"> <- </span><span class="Constant">1</span> - <span class="Constant">5</span><span class="Special"> <- </span><span class="Constant">0</span> - ] - check-trace-count-for-label <span class="Constant">0</span>, <span class="Constant">[print-character]</span> -] - -<span class="muScenario">scenario</span> editor-moves-to-start-of-line-with-home [ - assume-screen <span class="Constant">10/width</span>, <span class="Constant">5/height</span> - <span class="Constant">1</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[123</span> -<span class="Constant">456]</span> - <span class="Constant">2</span>:address:editor-data<span class="Special"> <- </span>new-editor <span class="Constant">1</span>:address:array:character, screen:address, <span class="Constant">0/left</span>, <span class="Constant">10/right</span> -<span class="Constant"> $clear-trace</span> - <span class="Comment"># start on second line, press 'home'</span> - assume-console [ - left-click <span class="Constant">2</span>, <span class="Constant">3</span> - press <span class="Constant">65521</span> <span class="Comment"># 'home'</span> - ] - run [ - editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data - <span class="Constant">3</span>:number<span class="Special"> <- </span>get *<span class="Constant">2</span>:address:editor-data, <span class="Constant">cursor-row:offset</span> - <span class="Constant">4</span>:number<span class="Special"> <- </span>get *<span class="Constant">2</span>:address:editor-data, <span class="Constant">cursor-column:offset</span> - ] - <span class="Comment"># cursor moves to start of line</span> - memory-should-contain [ - <span class="Constant">3</span><span class="Special"> <- </span><span class="Constant">2</span> - <span class="Constant">4</span><span class="Special"> <- </span><span class="Constant">0</span> - ] - check-trace-count-for-label <span class="Constant">0</span>, <span class="Constant">[print-character]</span> -] - -<span class="muScenario">scenario</span> editor-moves-to-start-of-line-with-home-2 [ - assume-screen <span class="Constant">10/width</span>, <span class="Constant">5/height</span> - <span class="Constant">1</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[123</span> -<span class="Constant">456]</span> - <span class="Constant">2</span>:address:editor-data<span class="Special"> <- </span>new-editor <span class="Constant">1</span>:address:array:character, screen:address, <span class="Constant">0/left</span>, <span class="Constant">10/right</span> - editor-render screen, <span class="Constant">2</span>:address:editor-data -<span class="Constant"> $clear-trace</span> - <span class="Comment"># start on first line (no newline before), press 'home'</span> - assume-console [ - left-click <span class="Constant">1</span>, <span class="Constant">3</span> - press <span class="Constant">65521</span> <span class="Comment"># 'home'</span> - ] - run [ - editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data - <span class="Constant">3</span>:number<span class="Special"> <- </span>get *<span class="Constant">2</span>:address:editor-data, <span class="Constant">cursor-row:offset</span> - <span class="Constant">4</span>:number<span class="Special"> <- </span>get *<span class="Constant">2</span>:address:editor-data, <span class="Constant">cursor-column:offset</span> - ] - <span class="Comment"># cursor moves to start of line</span> - memory-should-contain [ - <span class="Constant">3</span><span class="Special"> <- </span><span class="Constant">1</span> - <span class="Constant">4</span><span class="Special"> <- </span><span class="Constant">0</span> - ] - check-trace-count-for-label <span class="Constant">0</span>, <span class="Constant">[print-character]</span> -] - -<span class="Comment"># ctrl-e/end - move cursor to end of line</span> - -<span class="muScenario">scenario</span> editor-moves-to-end-of-line-with-ctrl-e [ - assume-screen <span class="Constant">10/width</span>, <span class="Constant">5/height</span> - <span class="Constant">1</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[123</span> -<span class="Constant">456]</span> - <span class="Constant">2</span>:address:editor-data<span class="Special"> <- </span>new-editor <span class="Constant">1</span>:address:array:character, screen:address, <span class="Constant">0/left</span>, <span class="Constant">10/right</span> - editor-render screen, <span class="Constant">2</span>:address:editor-data -<span class="Constant"> $clear-trace</span> - <span class="Comment"># start on first line, press ctrl-e</span> - assume-console [ - left-click <span class="Constant">1</span>, <span class="Constant">1</span> - type <span class="Constant">[e]</span> <span class="Comment"># ctrl-e</span> - ] - <span class="Constant">3</span>:event/ctrl-e<span class="Special"> <- </span>merge <span class="Constant">0/text</span>, <span class="Constant">5/ctrl-e</span>, <span class="Constant">0/dummy</span>, <span class="Constant">0/dummy</span> - replace-in-console <span class="Constant">101/e</span>, <span class="Constant">3</span>:event/ctrl-e - run [ - editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data - <span class="Constant">4</span>:number<span class="Special"> <- </span>get *<span class="Constant">2</span>:address:editor-data, <span class="Constant">cursor-row:offset</span> - <span class="Constant">5</span>:number<span class="Special"> <- </span>get *<span class="Constant">2</span>:address:editor-data, <span class="Constant">cursor-column:offset</span> - ] - <span class="Comment"># cursor moves to end of line</span> - memory-should-contain [ - <span class="Constant">4</span><span class="Special"> <- </span><span class="Constant">1</span> - <span class="Constant">5</span><span class="Special"> <- </span><span class="Constant">3</span> - ] - check-trace-count-for-label <span class="Constant">0</span>, <span class="Constant">[print-character]</span> - <span class="Comment"># editor inserts future characters at cursor</span> - assume-console [ - type <span class="Constant">[z]</span> - ] - run [ - editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data - <span class="Constant">4</span>:number<span class="Special"> <- </span>get *<span class="Constant">2</span>:address:editor-data, <span class="Constant">cursor-row:offset</span> - <span class="Constant">5</span>:number<span class="Special"> <- </span>get *<span class="Constant">2</span>:address:editor-data, <span class="Constant">cursor-column:offset</span> - ] - memory-should-contain [ - <span class="Constant">4</span><span class="Special"> <- </span><span class="Constant">1</span> - <span class="Constant">5</span><span class="Special"> <- </span><span class="Constant">4</span> - ] - screen-should-contain [ - <span class="Constant"> . .</span> - <span class="Constant"> .123z .</span> - <span class="Constant"> .456 .</span> -<span class="Constant"> .┈┈┈┈┈┈┈┈┈┈.</span> - <span class="Constant"> . .</span> - ] - check-trace-count-for-label <span class="Constant">1</span>, <span class="Constant">[print-character]</span> -] - -<span class="muRecipe">after</span> +handle-special-character [ - <span class="Delimiter">{</span> - ctrl-e?:boolean<span class="Special"> <- </span>equal *c, <span class="Constant">5/ctrl-e</span> - <span class="muControl">break-unless</span> ctrl-e? - move-to-end-of-line editor - <span class="muControl">reply</span> screen/same-as-ingredient:<span class="Constant">0</span>, editor/same-as-ingredient:<span class="Constant">1</span>, <span class="Constant">0/no-more-render</span> - <span class="Delimiter">}</span> -] - -<span class="muRecipe">after</span> +handle-special-key [ - <span class="Delimiter">{</span> - end?:boolean<span class="Special"> <- </span>equal *k, <span class="Constant">65520/end</span> - <span class="muControl">break-unless</span> end? - move-to-end-of-line editor - <span class="muControl">reply</span> screen/same-as-ingredient:<span class="Constant">0</span>, editor/same-as-ingredient:<span class="Constant">1</span>, <span class="Constant">0/no-more-render</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, <span class="Constant">before-cursor:offset</span> - cursor-column:address:number<span class="Special"> <- </span>get-address *editor, <span class="Constant">cursor-column:offset</span> - <span class="Comment"># while not at start of line, move </span> - <span class="Delimiter">{</span> - next:address:duplex-list<span class="Special"> <- </span>next-duplex *before-cursor - <span class="muControl">break-unless</span> next <span class="Comment"># end of text</span> - nextc:character<span class="Special"> <- </span>get *next, <span class="Constant">value:offset</span> - at-end-of-line?:boolean<span class="Special"> <- </span>equal nextc, <span class="Constant">10/newline</span> - <span class="muControl">break-if</span> at-end-of-line? - *before-cursor<span class="Special"> <- </span>copy next - *cursor-column<span class="Special"> <- </span>add *cursor-column, <span class="Constant">1</span> - <span class="muControl">loop</span> - <span class="Delimiter">}</span> -] - -<span class="muScenario">scenario</span> editor-moves-to-end-of-line-with-ctrl-e-2 [ - assume-screen <span class="Constant">10/width</span>, <span class="Constant">5/height</span> - <span class="Constant">1</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[123</span> -<span class="Constant">456]</span> - <span class="Constant">2</span>:address:editor-data<span class="Special"> <- </span>new-editor <span class="Constant">1</span>:address:array:character, screen:address, <span class="Constant">0/left</span>, <span class="Constant">10/right</span> - editor-render screen, <span class="Constant">2</span>:address:editor-data -<span class="Constant"> $clear-trace</span> - <span class="Comment"># start on second line (no newline after), press ctrl-e</span> - assume-console [ - left-click <span class="Constant">2</span>, <span class="Constant">1</span> - type <span class="Constant">[e]</span> <span class="Comment"># ctrl-e</span> - ] - <span class="Constant">3</span>:event/ctrl-e<span class="Special"> <- </span>merge <span class="Constant">0/text</span>, <span class="Constant">5/ctrl-e</span>, <span class="Constant">0/dummy</span>, <span class="Constant">0/dummy</span> - replace-in-console <span class="Constant">101/e</span>, <span class="Constant">3</span>:event/ctrl-e - run [ - editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data - <span class="Constant">4</span>:number<span class="Special"> <- </span>get *<span class="Constant">2</span>:address:editor-data, <span class="Constant">cursor-row:offset</span> - <span class="Constant">5</span>:number<span class="Special"> <- </span>get *<span class="Constant">2</span>:address:editor-data, <span class="Constant">cursor-column:offset</span> - ] - <span class="Comment"># cursor moves to end of line</span> - memory-should-contain [ - <span class="Constant">4</span><span class="Special"> <- </span><span class="Constant">2</span> - <span class="Constant">5</span><span class="Special"> <- </span><span class="Constant">3</span> - ] - check-trace-count-for-label <span class="Constant">0</span>, <span class="Constant">[print-character]</span> -] - -<span class="muScenario">scenario</span> editor-moves-to-end-of-line-with-end [ - assume-screen <span class="Constant">10/width</span>, <span class="Constant">5/height</span> - <span class="Constant">1</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[123</span> -<span class="Constant">456]</span> - <span class="Constant">2</span>:address:editor-data<span class="Special"> <- </span>new-editor <span class="Constant">1</span>:address:array:character, screen:address, <span class="Constant">0/left</span>, <span class="Constant">10/right</span> - editor-render screen, <span class="Constant">2</span>:address:editor-data -<span class="Constant"> $clear-trace</span> - <span class="Comment"># start on first line, press 'end'</span> - assume-console [ - left-click <span class="Constant">1</span>, <span class="Constant">1</span> - press <span class="Constant">65520</span> <span class="Comment"># 'end'</span> - ] - run [ - editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data - <span class="Constant">3</span>:number<span class="Special"> <- </span>get *<span class="Constant">2</span>:address:editor-data, <span class="Constant">cursor-row:offset</span> - <span class="Constant">4</span>:number<span class="Special"> <- </span>get *<span class="Constant">2</span>:address:editor-data, <span class="Constant">cursor-column:offset</span> - ] - <span class="Comment"># cursor moves to end of line</span> - memory-should-contain [ - <span class="Constant">3</span><span class="Special"> <- </span><span class="Constant">1</span> - <span class="Constant">4</span><span class="Special"> <- </span><span class="Constant">3</span> - ] - check-trace-count-for-label <span class="Constant">0</span>, <span class="Constant">[print-character]</span> -] - -<span class="muScenario">scenario</span> editor-moves-to-end-of-line-with-end-2 [ - assume-screen <span class="Constant">10/width</span>, <span class="Constant">5/height</span> - <span class="Constant">1</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[123</span> -<span class="Constant">456]</span> - <span class="Constant">2</span>:address:editor-data<span class="Special"> <- </span>new-editor <span class="Constant">1</span>:address:array:character, screen:address, <span class="Constant">0/left</span>, <span class="Constant">10/right</span> - editor-render screen, <span class="Constant">2</span>:address:editor-data -<span class="Constant"> $clear-trace</span> - <span class="Comment"># start on second line (no newline after), press 'end'</span> - assume-console [ - left-click <span class="Constant">2</span>, <span class="Constant">1</span> - press <span class="Constant">65520</span> <span class="Comment"># 'end'</span> - ] - run [ - editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data - <span class="Constant">3</span>:number<span class="Special"> <- </span>get *<span class="Constant">2</span>:address:editor-data, <span class="Constant">cursor-row:offset</span> - <span class="Constant">4</span>:number<span class="Special"> <- </span>get *<span class="Constant">2</span>:address:editor-data, <span class="Constant">cursor-column:offset</span> - ] - <span class="Comment"># cursor moves to end of line</span> - memory-should-contain [ - <span class="Constant">3</span><span class="Special"> <- </span><span class="Constant">2</span> - <span class="Constant">4</span><span class="Special"> <- </span><span class="Constant">3</span> - ] - check-trace-count-for-label <span class="Constant">0</span>, <span class="Constant">[print-character]</span> -] - -<span class="Comment"># ctrl-u - delete text from start of line until (but not at) cursor</span> - -<span class="muScenario">scenario</span> editor-deletes-to-start-of-line-with-ctrl-u [ - assume-screen <span class="Constant">10/width</span>, <span class="Constant">5/height</span> - <span class="Constant">1</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[123</span> -<span class="Constant">456]</span> - <span class="Constant">2</span>:address:editor-data<span class="Special"> <- </span>new-editor <span class="Constant">1</span>:address:array:character, screen:address, <span class="Constant">0/left</span>, <span class="Constant">10/right</span> - <span class="Comment"># start on second line, press ctrl-u</span> - assume-console [ - left-click <span class="Constant">2</span>, <span class="Constant">2</span> - type <span class="Constant">[u]</span> <span class="Comment"># ctrl-u</span> - ] - <span class="Constant">3</span>:event/ctrl-a<span class="Special"> <- </span>merge <span class="Constant">0/text</span>, <span class="Constant">21/ctrl-u</span>, <span class="Constant">0/dummy</span>, <span class="Constant">0/dummy</span> - replace-in-console <span class="Constant">117/u</span>, <span class="Constant">3</span>:event/ctrl-u - run [ - editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data - ] - <span class="Comment"># cursor deletes to start of line</span> - screen-should-contain [ - <span class="Constant"> . .</span> - <span class="Constant"> .123 .</span> - <span class="Constant"> .6 .</span> -<span class="Constant"> .┈┈┈┈┈┈┈┈┈┈.</span> - <span class="Constant"> . .</span> - ] -] - -<span class="muRecipe">after</span> +handle-special-character [ - <span class="Delimiter">{</span> - ctrl-u?:boolean<span class="Special"> <- </span>equal *c, <span class="Constant">21/ctrl-u</span> - <span class="muControl">break-unless</span> ctrl-u? - delete-to-start-of-line editor - <span class="muControl">reply</span> screen/same-as-ingredient:<span class="Constant">0</span>, editor/same-as-ingredient:<span class="Constant">1</span>, <span class="Constant">1/go-render</span> - <span class="Delimiter">}</span> -] - -<span class="muRecipe">recipe</span> delete-to-start-of-line [ - <span class="Constant">local-scope</span> - editor:address:editor-data<span class="Special"> <- </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, <span class="Constant">data:offset</span> - before-cursor:address:address:duplex-list<span class="Special"> <- </span>get-address *editor, <span class="Constant">before-cursor:offset</span> - start:address:duplex-list<span class="Special"> <- </span>copy *before-cursor - end:address:duplex-list<span class="Special"> <- </span>next-duplex *before-cursor - <span class="Delimiter">{</span> - at-start-of-text?:boolean<span class="Special"> <- </span>equal start, init - <span class="muControl">break-if</span> at-start-of-text? - curr:character<span class="Special"> <- </span>get *start, <span class="Constant">value:offset</span> - at-start-of-line?:boolean<span class="Special"> <- </span>equal curr, <span class="Constant">10/newline</span> - <span class="muControl">break-if</span> at-start-of-line? - start<span class="Special"> <- </span>prev-duplex start - assert start, <span class="Constant">[delete-to-start-of-line tried to move before start of text]</span> - <span class="muControl">loop</span> - <span class="Delimiter">}</span> - <span class="Comment"># snip it out</span> - start-next:address:address:duplex-list<span class="Special"> <- </span>get-address *start, <span class="Constant">next:offset</span> - *start-next<span class="Special"> <- </span>copy end - <span class="Delimiter">{</span> - <span class="muControl">break-unless</span> end - end-prev:address:address:duplex-list<span class="Special"> <- </span>get-address *end, <span class="Constant">prev:offset</span> - *end-prev<span class="Special"> <- </span>copy start - <span class="Delimiter">}</span> - <span class="Comment"># adjust cursor</span> - *before-cursor<span class="Special"> <- </span>prev-duplex end - left:number<span class="Special"> <- </span>get *editor, <span class="Constant">left:offset</span> - cursor-column:address:number<span class="Special"> <- </span>get-address *editor, <span class="Constant">cursor-column:offset</span> - *cursor-column<span class="Special"> <- </span>copy left -] - -<span class="muScenario">scenario</span> editor-deletes-to-start-of-line-with-ctrl-u-2 [ - assume-screen <span class="Constant">10/width</span>, <span class="Constant">5/height</span> - <span class="Constant">1</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[123</span> -<span class="Constant">456]</span> - <span class="Constant">2</span>:address:editor-data<span class="Special"> <- </span>new-editor <span class="Constant">1</span>:address:array:character, screen:address, <span class="Constant">0/left</span>, <span class="Constant">10/right</span> - <span class="Comment"># start on first line (no newline before), press ctrl-u</span> - assume-console [ - left-click <span class="Constant">1</span>, <span class="Constant">2</span> - type <span class="Constant">[u]</span> <span class="Comment"># ctrl-u</span> - ] - <span class="Constant">3</span>:event/ctrl-u<span class="Special"> <- </span>merge <span class="Constant">0/text</span>, <span class="Constant">21/ctrl-u</span>, <span class="Constant">0/dummy</span>, <span class="Constant">0/dummy</span> - replace-in-console <span class="Constant">117/u</span>, <span class="Constant">3</span>:event/ctrl-u - run [ - editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data - ] - <span class="Comment"># cursor deletes to start of line</span> - screen-should-contain [ - <span class="Constant"> . .</span> - <span class="Constant"> .3 .</span> - <span class="Constant"> .456 .</span> -<span class="Constant"> .┈┈┈┈┈┈┈┈┈┈.</span> - <span class="Constant"> . .</span> - ] -] - -<span class="muScenario">scenario</span> editor-deletes-to-start-of-line-with-ctrl-u-3 [ - assume-screen <span class="Constant">10/width</span>, <span class="Constant">5/height</span> - <span class="Constant">1</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[123</span> -<span class="Constant">456]</span> - <span class="Constant">2</span>:address:editor-data<span class="Special"> <- </span>new-editor <span class="Constant">1</span>:address:array:character, screen:address, <span class="Constant">0/left</span>, <span class="Constant">10/right</span> - <span class="Comment"># start past end of line, press ctrl-u</span> - assume-console [ - left-click <span class="Constant">1</span>, <span class="Constant">3</span> - type <span class="Constant">[u]</span> <span class="Comment"># ctrl-u</span> - ] - <span class="Constant">3</span>:event/ctrl-u<span class="Special"> <- </span>merge <span class="Constant">0/text</span>, <span class="Constant">21/ctrl-u</span>, <span class="Constant">0/dummy</span>, <span class="Constant">0/dummy</span> - replace-in-console <span class="Constant">117/u</span>, <span class="Constant">3</span>:event/ctrl-u - run [ - editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data - ] - <span class="Comment"># cursor deletes to start of line</span> - screen-should-contain [ - <span class="Constant"> . .</span> - <span class="Constant"> . .</span> - <span class="Constant"> .456 .</span> -<span class="Constant"> .┈┈┈┈┈┈┈┈┈┈.</span> - <span class="Constant"> . .</span> - ] -] - -<span class="muScenario">scenario</span> editor-deletes-to-start-of-final-line-with-ctrl-u [ - assume-screen <span class="Constant">10/width</span>, <span class="Constant">5/height</span> - <span class="Constant">1</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[123</span> -<span class="Constant">456]</span> - <span class="Constant">2</span>:address:editor-data<span class="Special"> <- </span>new-editor <span class="Constant">1</span>:address:array:character, screen:address, <span class="Constant">0/left</span>, <span class="Constant">10/right</span> - <span class="Comment"># start past end of final line, press ctrl-u</span> - assume-console [ - left-click <span class="Constant">2</span>, <span class="Constant">3</span> - type <span class="Constant">[u]</span> <span class="Comment"># ctrl-u</span> - ] - <span class="Constant">3</span>:event/ctrl-u<span class="Special"> <- </span>merge <span class="Constant">0/text</span>, <span class="Constant">21/ctrl-u</span>, <span class="Constant">0/dummy</span>, <span class="Constant">0/dummy</span> - replace-in-console <span class="Constant">117/u</span>, <span class="Constant">3</span>:event/ctrl-u - run [ - editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data - ] - <span class="Comment"># cursor deletes to start of line</span> - screen-should-contain [ - <span class="Constant"> . .</span> - <span class="Constant"> .123 .</span> - <span class="Constant"> . .</span> -<span class="Constant"> .┈┈┈┈┈┈┈┈┈┈.</span> - <span class="Constant"> . .</span> - ] -] - -<span class="Comment"># ctrl-k - delete text from cursor to end of line (but not the newline)</span> - -<span class="muScenario">scenario</span> editor-deletes-to-end-of-line-with-ctrl-k [ - assume-screen <span class="Constant">10/width</span>, <span class="Constant">5/height</span> - <span class="Constant">1</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[123</span> -<span class="Constant">456]</span> - <span class="Constant">2</span>:address:editor-data<span class="Special"> <- </span>new-editor <span class="Constant">1</span>:address:array:character, screen:address, <span class="Constant">0/left</span>, <span class="Constant">10/right</span> - <span class="Comment"># start on first line, press ctrl-k</span> - assume-console [ - left-click <span class="Constant">1</span>, <span class="Constant">1</span> - type <span class="Constant">[k]</span> <span class="Comment"># ctrl-k</span> - ] - <span class="Constant">3</span>:event/ctrl-k<span class="Special"> <- </span>merge <span class="Constant">0/text</span>, <span class="Constant">11/ctrl-k</span>, <span class="Constant">0/dummy</span>, <span class="Constant">0/dummy</span> - replace-in-console <span class="Constant">107/k</span>, <span class="Constant">3</span>:event/ctrl-k - run [ - editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data - ] - <span class="Comment"># cursor deletes to end of line</span> - screen-should-contain [ - <span class="Constant"> . .</span> - <span class="Constant"> .1 .</span> - <span class="Constant"> .456 .</span> -<span class="Constant"> .┈┈┈┈┈┈┈┈┈┈.</span> - <span class="Constant"> . .</span> - ] -] - -<span class="muRecipe">after</span> +handle-special-character [ - <span class="Delimiter">{</span> - ctrl-k?:boolean<span class="Special"> <- </span>equal *c, <span class="Constant">11/ctrl-k</span> - <span class="muControl">break-unless</span> ctrl-k? - delete-to-end-of-line editor - <span class="muControl">reply</span> screen/same-as-ingredient:<span class="Constant">0</span>, editor/same-as-ingredient:<span class="Constant">1</span>, <span class="Constant">1/go-render</span> - <span class="Delimiter">}</span> -] - -<span class="muRecipe">recipe</span> delete-to-end-of-line [ - <span class="Constant">local-scope</span> - editor:address:editor-data<span class="Special"> <- </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, <span class="Constant">before-cursor:offset</span> - end:address:duplex-list<span class="Special"> <- </span>next-duplex start - <span class="Delimiter">{</span> - at-end-of-text?:boolean<span class="Special"> <- </span>equal end, <span class="Constant">0/null</span> - <span class="muControl">break-if</span> at-end-of-text? - curr:character<span class="Special"> <- </span>get *end, <span class="Constant">value:offset</span> - at-end-of-line?:boolean<span class="Special"> <- </span>equal curr, <span class="Constant">10/newline</span> - <span class="muControl">break-if</span> at-end-of-line? - end<span class="Special"> <- </span>next-duplex end - <span class="muControl">loop</span> - <span class="Delimiter">}</span> - <span class="Comment"># snip it out</span> - start-next:address:address:duplex-list<span class="Special"> <- </span>get-address *start, <span class="Constant">next:offset</span> - *start-next<span class="Special"> <- </span>copy end - <span class="Delimiter">{</span> - <span class="muControl">break-unless</span> end - end-prev:address:address:duplex-list<span class="Special"> <- </span>get-address *end, <span class="Constant">prev:offset</span> - *end-prev<span class="Special"> <- </span>copy start - <span class="Delimiter">}</span> -] - -<span class="muScenario">scenario</span> editor-deletes-to-end-of-line-with-ctrl-k-2 [ - assume-screen <span class="Constant">10/width</span>, <span class="Constant">5/height</span> - <span class="Constant">1</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[123</span> -<span class="Constant">456]</span> - <span class="Constant">2</span>:address:editor-data<span class="Special"> <- </span>new-editor <span class="Constant">1</span>:address:array:character, screen:address, <span class="Constant">0/left</span>, <span class="Constant">10/right</span> - <span class="Comment"># start on second line (no newline after), press ctrl-k</span> - assume-console [ - left-click <span class="Constant">2</span>, <span class="Constant">1</span> - type <span class="Constant">[k]</span> <span class="Comment"># ctrl-k</span> - ] - <span class="Constant">3</span>:event/ctrl-k<span class="Special"> <- </span>merge <span class="Constant">0/text</span>, <span class="Constant">11/ctrl-k</span>, <span class="Constant">0/dummy</span>, <span class="Constant">0/dummy</span> - replace-in-console <span class="Constant">107/k</span>, <span class="Constant">3</span>:event/ctrl-k - run [ - editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data - ] - <span class="Comment"># cursor deletes to end of line</span> - screen-should-contain [ - <span class="Constant"> . .</span> - <span class="Constant"> .123 .</span> - <span class="Constant"> .4 .</span> -<span class="Constant"> .┈┈┈┈┈┈┈┈┈┈.</span> - <span class="Constant"> . .</span> - ] -] - -<span class="muScenario">scenario</span> editor-deletes-to-end-of-line-with-ctrl-k-3 [ - assume-screen <span class="Constant">10/width</span>, <span class="Constant">5/height</span> - <span class="Constant">1</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[123</span> -<span class="Constant">456]</span> - <span class="Constant">2</span>:address:editor-data<span class="Special"> <- </span>new-editor <span class="Constant">1</span>:address:array:character, screen:address, <span class="Constant">0/left</span>, <span class="Constant">10/right</span> - <span class="Comment"># start at end of line</span> - assume-console [ - left-click <span class="Constant">1</span>, <span class="Constant">2</span> - type <span class="Constant">[k]</span> <span class="Comment"># ctrl-k</span> - ] - <span class="Constant">3</span>:event/ctrl-k<span class="Special"> <- </span>merge <span class="Constant">0/text</span>, <span class="Constant">11/ctrl-k</span>, <span class="Constant">0/dummy</span>, <span class="Constant">0/dummy</span> - replace-in-console <span class="Constant">107/k</span>, <span class="Constant">3</span>:event/ctrl-k - run [ - editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data - ] - <span class="Comment"># cursor deletes to end of line</span> - screen-should-contain [ - <span class="Constant"> . .</span> - <span class="Constant"> .12 .</span> - <span class="Constant"> .456 .</span> -<span class="Constant"> .┈┈┈┈┈┈┈┈┈┈.</span> - <span class="Constant"> . .</span> - ] -] - -<span class="muScenario">scenario</span> editor-deletes-to-end-of-line-with-ctrl-k-4 [ - assume-screen <span class="Constant">10/width</span>, <span class="Constant">5/height</span> - <span class="Constant">1</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[123</span> -<span class="Constant">456]</span> - <span class="Constant">2</span>:address:editor-data<span class="Special"> <- </span>new-editor <span class="Constant">1</span>:address:array:character, screen:address, <span class="Constant">0/left</span>, <span class="Constant">10/right</span> - <span class="Comment"># start past end of line</span> - assume-console [ - left-click <span class="Constant">1</span>, <span class="Constant">3</span> - type <span class="Constant">[k]</span> <span class="Comment"># ctrl-k</span> - ] - <span class="Constant">3</span>:event/ctrl-k<span class="Special"> <- </span>merge <span class="Constant">0/text</span>, <span class="Constant">11/ctrl-k</span>, <span class="Constant">0/dummy</span>, <span class="Constant">0/dummy</span> - replace-in-console <span class="Constant">107/k</span>, <span class="Constant">3</span>:event/ctrl-k - run [ - editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data - ] - <span class="Comment"># cursor deletes to end of line</span> - screen-should-contain [ - <span class="Constant"> . .</span> - <span class="Constant"> .123 .</span> - <span class="Constant"> .456 .</span> -<span class="Constant"> .┈┈┈┈┈┈┈┈┈┈.</span> - <span class="Constant"> . .</span> - ] -] - -<span class="muScenario">scenario</span> editor-deletes-to-end-of-line-with-ctrl-k-5 [ - assume-screen <span class="Constant">10/width</span>, <span class="Constant">5/height</span> - <span class="Constant">1</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[123</span> -<span class="Constant">456]</span> - <span class="Constant">2</span>:address:editor-data<span class="Special"> <- </span>new-editor <span class="Constant">1</span>:address:array:character, screen:address, <span class="Constant">0/left</span>, <span class="Constant">10/right</span> - <span class="Comment"># start at end of text</span> - assume-console [ - left-click <span class="Constant">2</span>, <span class="Constant">2</span> - type <span class="Constant">[k]</span> <span class="Comment"># ctrl-k</span> - ] - <span class="Constant">3</span>:event/ctrl-k<span class="Special"> <- </span>merge <span class="Constant">0/text</span>, <span class="Constant">11/ctrl-k</span>, <span class="Constant">0/dummy</span>, <span class="Constant">0/dummy</span> - replace-in-console <span class="Constant">107/k</span>, <span class="Constant">3</span>:event/ctrl-k - run [ - editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data - ] - <span class="Comment"># cursor deletes to end of line</span> - screen-should-contain [ - <span class="Constant"> . .</span> - <span class="Constant"> .123 .</span> - <span class="Constant"> .45 .</span> -<span class="Constant"> .┈┈┈┈┈┈┈┈┈┈.</span> - <span class="Constant"> . .</span> - ] -] - -<span class="muScenario">scenario</span> editor-deletes-to-end-of-line-with-ctrl-k-6 [ - assume-screen <span class="Constant">10/width</span>, <span class="Constant">5/height</span> - <span class="Constant">1</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[123</span> -<span class="Constant">456]</span> - <span class="Constant">2</span>:address:editor-data<span class="Special"> <- </span>new-editor <span class="Constant">1</span>:address:array:character, screen:address, <span class="Constant">0/left</span>, <span class="Constant">10/right</span> - <span class="Comment"># start past end of text</span> - assume-console [ - left-click <span class="Constant">2</span>, <span class="Constant">3</span> - type <span class="Constant">[k]</span> <span class="Comment"># ctrl-k</span> - ] - <span class="Constant">3</span>:event/ctrl-k<span class="Special"> <- </span>merge <span class="Constant">0/text</span>, <span class="Constant">11/ctrl-k</span>, <span class="Constant">0/dummy</span>, <span class="Constant">0/dummy</span> - replace-in-console <span class="Constant">107/k</span>, <span class="Constant">3</span>:event/ctrl-k - run [ - editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data - ] - <span class="Comment"># cursor deletes to end of line</span> - screen-should-contain [ - <span class="Constant"> . .</span> - <span class="Constant"> .123 .</span> - <span class="Constant"> .456 .</span> -<span class="Constant"> .┈┈┈┈┈┈┈┈┈┈.</span> - <span class="Constant"> . .</span> - ] -] - -<span class="Comment"># cursor-down can scroll if necessary</span> - -<span class="muScenario">scenario</span> editor-can-scroll-down-using-arrow-keys [ - <span class="Comment"># screen has 1 line for menu + 3 lines</span> - assume-screen <span class="Constant">10/width</span>, <span class="Constant">4/height</span> - <span class="Comment"># initialize editor with >3 lines</span> - <span class="Constant">1</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[a</span> -<span class="Constant">b</span> -<span class="Constant">c</span> -<span class="Constant">d]</span> - <span class="Constant">2</span>:address:editor-data<span class="Special"> <- </span>new-editor <span class="Constant">1</span>:address:array:character, screen:address, <span class="Constant">0/left</span>, <span class="Constant">10/right</span> - screen-should-contain [ - <span class="Constant"> . .</span> - <span class="Constant"> .a .</span> - <span class="Constant"> .b .</span> - <span class="Constant"> .c .</span> - ] - <span class="Comment"># position cursor at last line, then try to move further down</span> - assume-console [ - left-click <span class="Constant">3</span>, <span class="Constant">0</span> - press <span class="Constant">65516</span> <span class="Comment"># down-arrow</span> - ] - run [ - editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data - ] - <span class="Comment"># screen slides by one line</span> - screen-should-contain [ - <span class="Constant"> . .</span> - <span class="Constant"> .b .</span> - <span class="Constant"> .c .</span> - <span class="Constant"> .d .</span> - ] -] - -<span class="muRecipe">after</span> +scroll-down [ -<span class="CommentedCode">#? $print [scroll down], 10/newline #? 2</span> - top-of-screen:address:address:duplex-list<span class="Special"> <- </span>get-address *editor, <span class="Constant">top-of-screen:offset</span> - left:number<span class="Special"> <- </span>get *editor, <span class="Constant">left:offset</span> - right:number<span class="Special"> <- </span>get *editor, <span class="Constant">right:offset</span> - max:number<span class="Special"> <- </span>subtract right, left - *top-of-screen<span class="Special"> <- </span>before-start-of-next-line *top-of-screen, max -] - -<span class="Comment"># takes a pointer into the doubly-linked list, scans ahead at most 'max'</span> -<span class="Comment"># positions until the next newline</span> -<span class="Comment"># beware: never return null pointer.</span> -<span class="muRecipe">recipe</span> before-start-of-next-line [ - <span class="Constant">local-scope</span> - original:address:duplex-list<span class="Special"> <- </span><span class="Constant">next-ingredient</span> - max:number<span class="Special"> <- </span><span class="Constant">next-ingredient</span> - count:number<span class="Special"> <- </span>copy <span class="Constant">0</span> - curr:address:duplex-list<span class="Special"> <- </span>copy original - <span class="Comment"># skip the initial newline if it exists</span> - <span class="Delimiter">{</span> - c:character<span class="Special"> <- </span>get *curr, <span class="Constant">value:offset</span> - at-newline?:boolean<span class="Special"> <- </span>equal c, <span class="Constant">10/newline</span> - <span class="muControl">break-unless</span> at-newline? - curr<span class="Special"> <- </span>next-duplex curr - count<span class="Special"> <- </span>add count, <span class="Constant">1</span> - <span class="Delimiter">}</span> - <span class="Delimiter">{</span> - <span class="muControl">reply-unless</span> curr, original - done?:boolean<span class="Special"> <- </span>greater-or-equal count, max - <span class="muControl">break-if</span> done? - c:character<span class="Special"> <- </span>get *curr, <span class="Constant">value:offset</span> - at-newline?:boolean<span class="Special"> <- </span>equal c, <span class="Constant">10/newline</span> - <span class="muControl">break-if</span> at-newline? - curr<span class="Special"> <- </span>next-duplex curr - count<span class="Special"> <- </span>add count, <span class="Constant">1</span> - <span class="muControl">loop</span> - <span class="Delimiter">}</span> - <span class="muControl">reply-unless</span> curr, original - <span class="muControl">reply</span> curr -] - -<span class="muScenario">scenario</span> editor-scrolls-down-past-wrapped-line-using-arrow-keys [ - <span class="Comment"># screen has 1 line for menu + 3 lines</span> - assume-screen <span class="Constant">10/width</span>, <span class="Constant">4/height</span> - <span class="Comment"># initialize editor with a long, wrapped line and more than a screen of</span> - <span class="Comment"># other lines</span> - <span class="Constant">1</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[abcdef</span> -<span class="Constant">g</span> -<span class="Constant">h</span> -<span class="Constant">i]</span> - <span class="Constant">2</span>:address:editor-data<span class="Special"> <- </span>new-editor <span class="Constant">1</span>:address:array:character, screen:address, <span class="Constant">0/left</span>, <span class="Constant">5/right</span> - screen-should-contain [ - <span class="Constant"> . .</span> - <span class="Constant"> .abcd↩ .</span> - <span class="Constant"> .ef .</span> - <span class="Constant"> .g .</span> - ] - <span class="Comment"># position cursor at last line, then try to move further down</span> - assume-console [ - left-click <span class="Constant">3</span>, <span class="Constant">0</span> - press <span class="Constant">65516</span> <span class="Comment"># down-arrow</span> - ] - run [ - editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data - ] - <span class="Comment"># screen shows partial wrapped line</span> - screen-should-contain [ - <span class="Constant"> . .</span> - <span class="Constant"> .ef .</span> - <span class="Constant"> .g .</span> - <span class="Constant"> .h .</span> - ] -] - -<span class="muScenario">scenario</span> editor-scrolls-down-past-wrapped-line-using-arrow-keys-2 [ - <span class="Comment"># screen has 1 line for menu + 3 lines</span> - assume-screen <span class="Constant">10/width</span>, <span class="Constant">4/height</span> - <span class="Comment"># editor starts with a long line wrapping twice</span> - <span class="Constant">1</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[abcdefghij</span> -<span class="Constant">k</span> -<span class="Constant">l</span> -<span class="Constant">m]</span> - <span class="Constant">2</span>:address:editor-data<span class="Special"> <- </span>new-editor <span class="Constant">1</span>:address:array:character, screen:address, <span class="Constant">0/left</span>, <span class="Constant">5/right</span> - <span class="Comment"># position cursor at last line, then try to move further down</span> - assume-console [ - left-click <span class="Constant">3</span>, <span class="Constant">0</span> - press <span class="Constant">65516</span> <span class="Comment"># down-arrow</span> - ] - run [ - editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data - ] - <span class="Comment"># screen shows partial wrapped line containing a wrap icon</span> - screen-should-contain [ - <span class="Constant"> . .</span> - <span class="Constant"> .efgh↩ .</span> - <span class="Constant"> .ij .</span> - <span class="Constant"> .k .</span> - ] - <span class="Comment"># scroll down again</span> - assume-console [ - press <span class="Constant">65516</span> <span class="Comment"># down-arrow</span> - ] - run [ - editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data - ] - <span class="Comment"># screen shows partial wrapped line</span> - screen-should-contain [ - <span class="Constant"> . .</span> - <span class="Constant"> .ij .</span> - <span class="Constant"> .k .</span> - <span class="Constant"> .l .</span> - ] -] - -<span class="muScenario">scenario</span> editor-scrolls-down-when-line-wraps [ - <span class="Comment"># screen has 1 line for menu + 3 lines</span> - assume-screen <span class="Constant">5/width</span>, <span class="Constant">4/height</span> - <span class="Comment"># editor contains a long line in the third line</span> - <span class="Constant">1</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[a</span> -<span class="Constant">b</span> -<span class="Constant">cdef]</span> - <span class="Constant">2</span>:address:editor-data<span class="Special"> <- </span>new-editor <span class="Constant">1</span>:address:array:character, screen:address, <span class="Constant">0/left</span>, <span class="Constant">5/right</span> - <span class="Comment"># position cursor at end, type a character</span> - assume-console [ - left-click <span class="Constant">3</span>, <span class="Constant">4</span> - type <span class="Constant">[g]</span> - ] - run [ - editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data - <span class="Constant">3</span>:number<span class="Special"> <- </span>get *<span class="Constant">2</span>:address:editor-data, <span class="Constant">cursor-row:offset</span> - <span class="Constant">4</span>:number<span class="Special"> <- </span>get *<span class="Constant">2</span>:address:editor-data, <span class="Constant">cursor-column:offset</span> - ] - <span class="Comment"># screen scrolls</span> - screen-should-contain [ - <span class="Constant"> . .</span> - <span class="Constant"> .b .</span> -<span class="Constant"> .cdef↩.</span> - <span class="Constant"> .g .</span> - ] - memory-should-contain [ - <span class="Constant">3</span><span class="Special"> <- </span><span class="Constant">3</span> - <span class="Constant">4</span><span class="Special"> <- </span><span class="Constant">1</span> - ] -] - -<span class="muScenario">scenario</span> editor-scrolls-down-on-newline [ - assume-screen <span class="Constant">5/width</span>, <span class="Constant">4/height</span> - <span class="Comment"># position cursor after last line and type newline</span> - <span class="Constant">1</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[a</span> -<span class="Constant">b</span> -<span class="Constant">c]</span> - <span class="Constant">2</span>:address:editor-data<span class="Special"> <- </span>new-editor <span class="Constant">1</span>:address:array:character, screen:address, <span class="Constant">0/left</span>, <span class="Constant">5/right</span> - assume-console [ - left-click <span class="Constant">3</span>, <span class="Constant">4</span> - type [ -] - ] - run [ - editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data - <span class="Constant">3</span>:number<span class="Special"> <- </span>get *<span class="Constant">2</span>:address:editor-data, <span class="Constant">cursor-row:offset</span> - <span class="Constant">4</span>:number<span class="Special"> <- </span>get *<span class="Constant">2</span>:address:editor-data, <span class="Constant">cursor-column:offset</span> - ] - <span class="Comment"># screen scrolls</span> - screen-should-contain [ - <span class="Constant"> . .</span> - <span class="Constant"> .b .</span> - <span class="Constant"> .c .</span> - <span class="Constant"> . .</span> - ] - memory-should-contain [ - <span class="Constant">3</span><span class="Special"> <- </span><span class="Constant">3</span> - <span class="Constant">4</span><span class="Special"> <- </span><span class="Constant">0</span> - ] -] - -<span class="muScenario">scenario</span> editor-scrolls-down-on-right-arrow [ - <span class="Comment"># screen has 1 line for menu + 3 lines</span> - assume-screen <span class="Constant">5/width</span>, <span class="Constant">4/height</span> - <span class="Comment"># editor contains a wrapped line</span> - <span class="Constant">1</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[a</span> -<span class="Constant">b</span> -<span class="Constant">cdefgh]</span> - <span class="Constant">2</span>:address:editor-data<span class="Special"> <- </span>new-editor <span class="Constant">1</span>:address:array:character, screen:address, <span class="Constant">0/left</span>, <span class="Constant">5/right</span> - <span class="Comment"># position cursor at end of screen and try to move right</span> - assume-console [ - left-click <span class="Constant">3</span>, <span class="Constant">3</span> - press <span class="Constant">65514</span> <span class="Comment"># right arrow</span> - ] - run [ - editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data - <span class="Constant">3</span>:number<span class="Special"> <- </span>get *<span class="Constant">2</span>:address:editor-data, <span class="Constant">cursor-row:offset</span> - <span class="Constant">4</span>:number<span class="Special"> <- </span>get *<span class="Constant">2</span>:address:editor-data, <span class="Constant">cursor-column:offset</span> - ] - <span class="Comment"># screen scrolls</span> - screen-should-contain [ - <span class="Constant"> . .</span> - <span class="Constant"> .b .</span> -<span class="Constant"> .cdef↩.</span> - <span class="Constant"> .gh .</span> - ] - memory-should-contain [ - <span class="Constant">3</span><span class="Special"> <- </span><span class="Constant">3</span> - <span class="Constant">4</span><span class="Special"> <- </span><span class="Constant">0</span> - ] -] - -<span class="muScenario">scenario</span> editor-scrolls-down-on-right-arrow-2 [ - <span class="Comment"># screen has 1 line for menu + 3 lines</span> - assume-screen <span class="Constant">5/width</span>, <span class="Constant">4/height</span> - <span class="Comment"># editor contains more lines than can fit on screen</span> - <span class="Constant">1</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[a</span> -<span class="Constant">b</span> -<span class="Constant">c</span> -<span class="Constant">d]</span> - <span class="Constant">2</span>:address:editor-data<span class="Special"> <- </span>new-editor <span class="Constant">1</span>:address:array:character, screen:address, <span class="Constant">0/left</span>, <span class="Constant">5/right</span> - <span class="Comment"># position cursor at end of screen and try to move right</span> - assume-console [ - left-click <span class="Constant">3</span>, <span class="Constant">3</span> - press <span class="Constant">65514</span> <span class="Comment"># right arrow</span> - ] - run [ - editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data - <span class="Constant">3</span>:number<span class="Special"> <- </span>get *<span class="Constant">2</span>:address:editor-data, <span class="Constant">cursor-row:offset</span> - <span class="Constant">4</span>:number<span class="Special"> <- </span>get *<span class="Constant">2</span>:address:editor-data, <span class="Constant">cursor-column:offset</span> - ] - <span class="Comment"># screen scrolls</span> - screen-should-contain [ - <span class="Constant"> . .</span> - <span class="Constant"> .b .</span> - <span class="Constant"> .c .</span> - <span class="Constant"> .d .</span> - ] - memory-should-contain [ - <span class="Constant">3</span><span class="Special"> <- </span><span class="Constant">3</span> - <span class="Constant">4</span><span class="Special"> <- </span><span class="Constant">0</span> - ] -] - -<span class="muScenario">scenario</span> editor-combines-page-and-line-scroll [ - <span class="Comment"># screen has 1 line for menu + 3 lines</span> - assume-screen <span class="Constant">10/width</span>, <span class="Constant">4/height</span> - <span class="Comment"># initialize editor with a few pages of lines</span> - <span class="Constant">1</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[a</span> -<span class="Constant">b</span> -<span class="Constant">c</span> -<span class="Constant">d</span> -<span class="Constant">e</span> -<span class="Constant">f</span> -<span class="Constant">g]</span> - <span class="Constant">2</span>:address:editor-data<span class="Special"> <- </span>new-editor <span class="Constant">1</span>:address:array:character, screen:address, <span class="Constant">0/left</span>, <span class="Constant">5/right</span> - <span class="Comment"># scroll down one page and one line</span> - assume-console [ - press <span class="Constant">65518</span> <span class="Comment"># page-down</span> - left-click <span class="Constant">3</span>, <span class="Constant">0</span> - press <span class="Constant">65516</span> <span class="Comment"># down-arrow</span> - ] - run [ - editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data - ] - <span class="Comment"># screen scrolls down 3 lines</span> - screen-should-contain [ - <span class="Constant"> . .</span> - <span class="Constant"> .d .</span> - <span class="Constant"> .e .</span> - <span class="Constant"> .f .</span> - ] -] - -<span class="Comment"># cursor-up can scroll if necessary</span> - -<span class="muScenario">scenario</span> editor-can-scroll-up-using-arrow-keys [ - <span class="Comment"># screen has 1 line for menu + 3 lines</span> - assume-screen <span class="Constant">10/width</span>, <span class="Constant">4/height</span> - <span class="Comment"># initialize editor with >3 lines</span> - <span class="Constant">1</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[a</span> -<span class="Constant">b</span> -<span class="Constant">c</span> -<span class="Constant">d]</span> - <span class="Constant">2</span>:address:editor-data<span class="Special"> <- </span>new-editor <span class="Constant">1</span>:address:array:character, screen:address, <span class="Constant">0/left</span>, <span class="Constant">10/right</span> - screen-should-contain [ - <span class="Constant"> . .</span> - <span class="Constant"> .a .</span> - <span class="Constant"> .b .</span> - <span class="Constant"> .c .</span> - ] - <span class="Comment"># position cursor at top of second page, then try to move up</span> - assume-console [ - press <span class="Constant">65518</span> <span class="Comment"># page-down</span> - press <span class="Constant">65517</span> <span class="Comment"># up-arrow</span> - ] - run [ - editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data - ] - <span class="Comment"># screen slides by one line</span> - screen-should-contain [ - <span class="Constant"> . .</span> - <span class="Constant"> .b .</span> - <span class="Constant"> .c .</span> - <span class="Constant"> .d .</span> - ] -] - -<span class="muRecipe">after</span> +scroll-up [ -<span class="CommentedCode">#? $print [scroll up], 10/newline #? 1</span> - top-of-screen:address:address:duplex-list<span class="Special"> <- </span>get-address *editor, <span class="Constant">top-of-screen:offset</span> - *top-of-screen<span class="Special"> <- </span>before-previous-line *top-of-screen, editor -] - -<span class="Comment"># takes a pointer into the doubly-linked list, scans back to before start of</span> -<span class="Comment"># previous *wrapped* line</span> -<span class="Comment"># beware: never return null pointer</span> -<span class="muRecipe">recipe</span> before-previous-line [ - <span class="Constant">local-scope</span> - curr:address:duplex-list<span class="Special"> <- </span><span class="Constant">next-ingredient</span> - c:character<span class="Special"> <- </span>get *curr, <span class="Constant">value:offset</span> -<span class="CommentedCode">#? $print [curr at ], c, 10/newline #? 1</span> - <span class="Comment"># compute max, number of characters to skip</span> - <span class="Comment"># 1 + len%(width-1)</span> - <span class="Comment"># except rotate second term to vary from 1 to width-1 rather than 0 to width-2</span> - editor:address:editor-data<span class="Special"> <- </span><span class="Constant">next-ingredient</span> - left:number<span class="Special"> <- </span>get *editor, <span class="Constant">left:offset</span> - right:number<span class="Special"> <- </span>get *editor, <span class="Constant">right:offset</span> - max-line-length:number<span class="Special"> <- </span>subtract right, left, <span class="Constant">-1/exclusive-right</span>, <span class="Constant">1/wrap-icon</span> - sentinel:address:duplex-list<span class="Special"> <- </span>get *editor, <span class="Constant">data:offset</span> - len:number<span class="Special"> <- </span>previous-line-length curr, sentinel -<span class="CommentedCode">#? $print [previous line: ], len, 10/newline #? 1</span> - <span class="Delimiter">{</span> - <span class="muControl">break-if</span> len - <span class="Comment"># empty line; just skip this newline</span> - prev:address:duplex-list<span class="Special"> <- </span>prev-duplex curr - <span class="muControl">reply-unless</span> prev, curr - <span class="muControl">reply</span> prev - <span class="Delimiter">}</span> - _, max:number<span class="Special"> <- </span>divide-with-remainder len, max-line-length - <span class="Comment"># remainder 0 => scan one width-worth</span> - <span class="Delimiter">{</span> - <span class="muControl">break-if</span> max -<span class="CommentedCode">#? $print [remainder 0; scan one width], 10/newline #? 1</span> - max<span class="Special"> <- </span>copy max-line-length - <span class="Delimiter">}</span> - max<span class="Special"> <- </span>add max, <span class="Constant">1</span> -<span class="CommentedCode">#? $print [skipping ], max, [ characters], 10/newline #? 1</span> - count:number<span class="Special"> <- </span>copy <span class="Constant">0</span> - <span class="Comment"># skip 'max' characters</span> - <span class="Delimiter">{</span> - done?:boolean<span class="Special"> <- </span>greater-or-equal count, max - <span class="muControl">break-if</span> done? - prev:address:duplex-list<span class="Special"> <- </span>prev-duplex curr - <span class="muControl">break-unless</span> prev - curr<span class="Special"> <- </span>copy prev - count<span class="Special"> <- </span>add count, <span class="Constant">1</span> - <span class="muControl">loop</span> - <span class="Delimiter">}</span> - <span class="muControl">reply</span> curr -] - -<span class="muScenario">scenario</span> editor-scrolls-up-past-wrapped-line-using-arrow-keys [ - <span class="Comment"># screen has 1 line for menu + 3 lines</span> - assume-screen <span class="Constant">10/width</span>, <span class="Constant">4/height</span> - <span class="Comment"># initialize editor with a long, wrapped line and more than a screen of</span> - <span class="Comment"># other lines</span> - <span class="Constant">1</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[abcdef</span> -<span class="Constant">g</span> -<span class="Constant">h</span> -<span class="Constant">i]</span> - <span class="Constant">2</span>:address:editor-data<span class="Special"> <- </span>new-editor <span class="Constant">1</span>:address:array:character, screen:address, <span class="Constant">0/left</span>, <span class="Constant">5/right</span> - screen-should-contain [ - <span class="Constant"> . .</span> - <span class="Constant"> .abcd↩ .</span> - <span class="Constant"> .ef .</span> - <span class="Constant"> .g .</span> - ] - <span class="Comment"># position cursor at top of second page, just below wrapped line</span> - assume-console [ - press <span class="Constant">65518</span> <span class="Comment"># page-down</span> - ] - run [ - editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data - ] - screen-should-contain [ - <span class="Constant"> . .</span> - <span class="Constant"> .g .</span> - <span class="Constant"> .h .</span> - <span class="Constant"> .i .</span> - ] - <span class="Comment"># now move up one line</span> - assume-console [ - press <span class="Constant">65517</span> <span class="Comment"># up-arrow</span> - ] - run [ - editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data - ] - <span class="Comment"># screen shows partial wrapped line</span> - screen-should-contain [ - <span class="Constant"> . .</span> - <span class="Constant"> .ef .</span> - <span class="Constant"> .g .</span> - <span class="Constant"> .h .</span> - ] -] - -<span class="muScenario">scenario</span> editor-scrolls-up-past-wrapped-line-using-arrow-keys-2 [ - <span class="Comment"># screen has 1 line for menu + 4 lines</span> - assume-screen <span class="Constant">10/width</span>, <span class="Constant">5/height</span> - <span class="Comment"># editor starts with a long line wrapping twice, occupying 3 of the 4 lines</span> - <span class="Constant">1</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[abcdefghij</span> -<span class="Constant">k</span> -<span class="Constant">l</span> -<span class="Constant">m]</span> - <span class="Constant">2</span>:address:editor-data<span class="Special"> <- </span>new-editor <span class="Constant">1</span>:address:array:character, screen:address, <span class="Constant">0/left</span>, <span class="Constant">5/right</span> - <span class="Comment"># position cursor at top of second page</span> - assume-console [ - press <span class="Constant">65518</span> <span class="Comment"># page-down</span> - ] - run [ - editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data - ] - screen-should-contain [ - <span class="Constant"> . .</span> - <span class="Constant"> .k .</span> - <span class="Constant"> .l .</span> - <span class="Constant"> .m .</span> - <span class="Constant"> .┈┈┈┈┈ .</span> - ] - <span class="Comment"># move up one line</span> - assume-console [ - press <span class="Constant">65517</span> <span class="Comment"># up-arrow</span> - ] - run [ - editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data - ] - <span class="Comment"># screen shows partial wrapped line</span> - screen-should-contain [ - <span class="Constant"> . .</span> - <span class="Constant"> .ij .</span> - <span class="Constant"> .k .</span> - <span class="Constant"> .l .</span> - <span class="Constant"> .m .</span> - ] - <span class="Comment"># move up a second line</span> - assume-console [ - press <span class="Constant">65517</span> <span class="Comment"># up-arrow</span> - ] - run [ - editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data - ] - <span class="Comment"># screen shows partial wrapped line</span> - screen-should-contain [ - <span class="Constant"> . .</span> - <span class="Constant"> .efgh↩ .</span> - <span class="Constant"> .ij .</span> - <span class="Constant"> .k .</span> - <span class="Constant"> .l .</span> - ] - <span class="Comment"># move up a third line</span> - assume-console [ - press <span class="Constant">65517</span> <span class="Comment"># up-arrow</span> - ] - run [ - editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data - ] - <span class="Comment"># screen shows partial wrapped line</span> - screen-should-contain [ - <span class="Constant"> . .</span> - <span class="Constant"> .abcd↩ .</span> - <span class="Constant"> .efgh↩ .</span> - <span class="Constant"> .ij .</span> - <span class="Constant"> .k .</span> - ] -] - -<span class="Comment"># same as editor-scrolls-up-past-wrapped-line-using-arrow-keys but length</span> -<span class="Comment"># slightly off, just to prevent over-training</span> -<span class="muScenario">scenario</span> editor-scrolls-up-past-wrapped-line-using-arrow-keys-3 [ - <span class="Comment"># screen has 1 line for menu + 3 lines</span> - assume-screen <span class="Constant">10/width</span>, <span class="Constant">4/height</span> - <span class="Comment"># initialize editor with a long, wrapped line and more than a screen of</span> - <span class="Comment"># other lines</span> - <span class="Constant">1</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[abcdef</span> -<span class="Constant">g</span> -<span class="Constant">h</span> -<span class="Constant">i]</span> - <span class="Constant">2</span>:address:editor-data<span class="Special"> <- </span>new-editor <span class="Constant">1</span>:address:array:character, screen:address, <span class="Constant">0/left</span>, <span class="Constant">6/right</span> - screen-should-contain [ - <span class="Constant"> . .</span> - <span class="Constant"> .abcde↩ .</span> - <span class="Constant"> .f .</span> - <span class="Constant"> .g .</span> - ] - <span class="Comment"># position cursor at top of second page, just below wrapped line</span> - assume-console [ - press <span class="Constant">65518</span> <span class="Comment"># page-down</span> - ] - run [ - editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data - ] - screen-should-contain [ - <span class="Constant"> . .</span> - <span class="Constant"> .g .</span> - <span class="Constant"> .h .</span> - <span class="Constant"> .i .</span> - ] - <span class="Comment"># now move up one line</span> - assume-console [ - press <span class="Constant">65517</span> <span class="Comment"># up-arrow</span> - ] - run [ - editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data - ] - <span class="Comment"># screen shows partial wrapped line</span> - screen-should-contain [ - <span class="Constant"> . .</span> - <span class="Constant"> .f .</span> - <span class="Constant"> .g .</span> - <span class="Constant"> .h .</span> - ] -] - -<span class="Comment"># check empty lines</span> -<span class="muScenario">scenario</span> editor-scrolls-up-past-wrapped-line-using-arrow-keys-4 [ - assume-screen <span class="Constant">10/width</span>, <span class="Constant">4/height</span> - <span class="Comment"># initialize editor with some lines around an empty line</span> - <span class="Constant">1</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[a</span> -<span class="Constant">b</span> - -c -d -e] - <span class="Constant">2</span>:address:editor-data<span class="Special"> <- </span>new-editor <span class="Constant">1</span>:address:array:character, screen:address, <span class="Constant">0/left</span>, <span class="Constant">6/right</span> - assume-console [ - press <span class="Constant">65518</span> <span class="Comment"># page-down</span> - ] - run [ - editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data - ] - screen-should-contain [ - <span class="Constant"> . .</span> - <span class="Constant"> . .</span> - <span class="Constant"> .c .</span> - <span class="Constant"> .d .</span> - ] - assume-console [ - press <span class="Constant">65518</span> <span class="Comment"># page-down</span> - ] - run [ - editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data - ] - screen-should-contain [ - <span class="Constant"> . .</span> - <span class="Constant"> .d .</span> - <span class="Constant"> .e .</span> - <span class="Constant"> .┈┈┈┈┈┈ .</span> - ] - assume-console [ - press <span class="Constant">65519</span> <span class="Comment"># page-up</span> - ] - run [ - editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data - ] - screen-should-contain [ - <span class="Constant"> . .</span> - <span class="Constant"> . .</span> - <span class="Constant"> .c .</span> - <span class="Constant"> .d .</span> - ] -] - -<span class="muScenario">scenario</span> editor-scrolls-up-on-left-arrow [ - <span class="Comment"># screen has 1 line for menu + 3 lines</span> - assume-screen <span class="Constant">5/width</span>, <span class="Constant">4/height</span> - <span class="Comment"># editor contains >3 lines</span> - <span class="Constant">1</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[a</span> -<span class="Constant">b</span> -<span class="Constant">c</span> -<span class="Constant">d</span> -<span class="Constant">e]</span> - <span class="Constant">2</span>:address:editor-data<span class="Special"> <- </span>new-editor <span class="Constant">1</span>:address:array:character, screen:address, <span class="Constant">0/left</span>, <span class="Constant">5/right</span> - <span class="Comment"># position cursor at top of second page</span> - assume-console [ - press <span class="Constant">65518</span> <span class="Comment"># page-down</span> - ] - run [ - editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data - ] - screen-should-contain [ - <span class="Constant"> . .</span> - <span class="Constant"> .c .</span> - <span class="Constant"> .d .</span> - <span class="Constant"> .e .</span> - ] - <span class="Comment"># now try to move left</span> - assume-console [ - press <span class="Constant">65515</span> <span class="Comment"># left arrow</span> - ] - run [ - editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data - <span class="Constant">3</span>:number<span class="Special"> <- </span>get *<span class="Constant">2</span>:address:editor-data, <span class="Constant">cursor-row:offset</span> - <span class="Constant">4</span>:number<span class="Special"> <- </span>get *<span class="Constant">2</span>:address:editor-data, <span class="Constant">cursor-column:offset</span> - ] - <span class="Comment"># screen scrolls</span> - screen-should-contain [ - <span class="Constant"> . .</span> - <span class="Constant"> .b .</span> - <span class="Constant"> .c .</span> - <span class="Constant"> .d .</span> - ] - memory-should-contain [ - <span class="Constant">3</span><span class="Special"> <- </span><span class="Constant">1</span> - <span class="Constant">4</span><span class="Special"> <- </span><span class="Constant">1</span> - ] -] - -<span class="muScenario">scenario</span> editor-can-scroll-up-to-start-of-file [ - <span class="Comment"># screen has 1 line for menu + 3 lines</span> - assume-screen <span class="Constant">10/width</span>, <span class="Constant">4/height</span> - <span class="Comment"># initialize editor with >3 lines</span> - <span class="Constant">1</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[a</span> -<span class="Constant">b</span> -<span class="Constant">c</span> -<span class="Constant">d]</span> - <span class="Constant">2</span>:address:editor-data<span class="Special"> <- </span>new-editor <span class="Constant">1</span>:address:array:character, screen:address, <span class="Constant">0/left</span>, <span class="Constant">10/right</span> - screen-should-contain [ - <span class="Constant"> . .</span> - <span class="Constant"> .a .</span> - <span class="Constant"> .b .</span> - <span class="Constant"> .c .</span> - ] - <span class="Comment"># position cursor at top of second page, then try to move up to start of</span> - <span class="Comment"># text</span> - assume-console [ - press <span class="Constant">65518</span> <span class="Comment"># page-down</span> - press <span class="Constant">65517</span> <span class="Comment"># up-arrow</span> - press <span class="Constant">65517</span> <span class="Comment"># up-arrow</span> - ] - run [ - editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data - ] - <span class="Comment"># screen slides by one line</span> - screen-should-contain [ - <span class="Constant"> . .</span> - <span class="Constant"> .a .</span> - <span class="Constant"> .b .</span> - <span class="Constant"> .c .</span> - ] - <span class="Comment"># try to move up again</span> - assume-console [ - press <span class="Constant">65517</span> <span class="Comment"># up-arrow</span> - ] - run [ - editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data - ] - <span class="Comment"># screen remains unchanged</span> - screen-should-contain [ - <span class="Constant"> . .</span> - <span class="Constant"> .a .</span> - <span class="Constant"> .b .</span> - <span class="Constant"> .c .</span> - ] -] - -<span class="Comment"># ctrl-f/page-down - render next page if it exists</span> - -<span class="muScenario">scenario</span> editor-can-scroll [ - assume-screen <span class="Constant">10/width</span>, <span class="Constant">4/height</span> - <span class="Constant">1</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[a</span> -<span class="Constant">b</span> -<span class="Constant">c</span> -<span class="Constant">d]</span> - <span class="Constant">2</span>:address:editor-data<span class="Special"> <- </span>new-editor <span class="Constant">1</span>:address:array:character, screen:address, <span class="Constant">0/left</span>, <span class="Constant">10/right</span> - screen-should-contain [ - <span class="Constant"> . .</span> - <span class="Constant"> .a .</span> - <span class="Constant"> .b .</span> - <span class="Constant"> .c .</span> - ] - <span class="Comment"># scroll down</span> - assume-console [ - press <span class="Constant">65518</span> <span class="Comment"># page-down</span> - ] - run [ - editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data - ] - <span class="Comment"># screen shows next page</span> - screen-should-contain [ - <span class="Constant"> . .</span> - <span class="Constant"> .c .</span> - <span class="Constant"> .d .</span> -<span class="Constant"> .┈┈┈┈┈┈┈┈┈┈.</span> - ] -] - -<span class="muRecipe">after</span> +handle-special-character [ - <span class="Delimiter">{</span> - ctrl-f?:boolean<span class="Special"> <- </span>equal *c, <span class="Constant">6/ctrl-f</span> - <span class="muControl">break-unless</span> ctrl-f? - page-down editor - <span class="muControl">reply</span> screen/same-as-ingredient:<span class="Constant">0</span>, editor/same-as-ingredient:<span class="Constant">1</span>, <span class="Constant">1/go-render</span> - <span class="Delimiter">}</span> -] - -<span class="muRecipe">after</span> +handle-special-key [ - <span class="Delimiter">{</span> - page-down?:boolean<span class="Special"> <- </span>equal *k, <span class="Constant">65518/page-down</span> - <span class="muControl">break-unless</span> page-down? - page-down editor - <span class="muControl">reply</span> screen/same-as-ingredient:<span class="Constant">0</span>, editor/same-as-ingredient:<span class="Constant">1</span>, <span class="Constant">1/go-render</span> - <span class="Delimiter">}</span> -] - -<span class="Comment"># page-down skips entire wrapped lines, so it can't scroll past lines</span> -<span class="Comment"># taking up the entire screen</span> -<span class="muRecipe">recipe</span> page-down [ - <span class="Constant">local-scope</span> - editor:address:editor-data<span class="Special"> <- </span><span class="Constant">next-ingredient</span> - <span class="Comment"># if editor contents don't overflow screen, do nothing</span> - bottom-of-screen:address:duplex-list<span class="Special"> <- </span>get *editor, <span class="Constant">bottom-of-screen:offset</span> - <span class="muControl">reply-unless</span> bottom-of-screen, editor/same-as-ingredient:<span class="Constant">0</span> - <span class="Comment"># if not, position cursor at final character</span> - before-cursor:address:address:duplex-list<span class="Special"> <- </span>get-address *editor, <span class="Constant">before-cursor:offset</span> - *before-cursor<span class="Special"> <- </span>prev-duplex bottom-of-screen - <span class="Comment"># keep one line in common with previous page</span> - <span class="Delimiter">{</span> - last:character<span class="Special"> <- </span>get **before-cursor, <span class="Constant">value:offset</span> - newline?:boolean<span class="Special"> <- </span>equal last, <span class="Constant">10/newline</span> - <span class="muControl">break-unless</span> newline?:boolean - *before-cursor<span class="Special"> <- </span>prev-duplex *before-cursor - <span class="Delimiter">}</span> - <span class="Comment"># move cursor and top-of-screen to start of that line</span> - move-to-start-of-line editor - top-of-screen:address:address:duplex-list<span class="Special"> <- </span>get-address *editor, <span class="Constant">top-of-screen:offset</span> - *top-of-screen<span class="Special"> <- </span>copy *before-cursor - <span class="muControl">reply</span> editor/same-as-ingredient:<span class="Constant">0</span> -] - -<span class="muScenario">scenario</span> editor-does-not-scroll-past-end [ - assume-screen <span class="Constant">10/width</span>, <span class="Constant">4/height</span> - <span class="Constant">1</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[a</span> -<span class="Constant">b]</span> - <span class="Constant">2</span>:address:editor-data<span class="Special"> <- </span>new-editor <span class="Constant">1</span>:address:array:character, screen:address, <span class="Constant">0/left</span>, <span class="Constant">10/right</span> - editor-render screen, <span class="Constant">2</span>:address:editor-data - screen-should-contain [ - <span class="Constant"> . .</span> - <span class="Constant"> .a .</span> - <span class="Constant"> .b .</span> -<span class="Constant"> .┈┈┈┈┈┈┈┈┈┈.</span> - ] - <span class="Comment"># scroll down</span> - assume-console [ - press <span class="Constant">65518</span> <span class="Comment"># page-down</span> - ] - run [ - editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data - ] - <span class="Comment"># screen remains unmodified</span> - screen-should-contain [ - <span class="Constant"> . .</span> - <span class="Constant"> .a .</span> - <span class="Constant"> .b .</span> -<span class="Constant"> .┈┈┈┈┈┈┈┈┈┈.</span> - ] -] - -<span class="muScenario">scenario</span> editor-starts-next-page-at-start-of-wrapped-line [ - <span class="Comment"># screen has 1 line for menu + 3 lines for text</span> - assume-screen <span class="Constant">10/width</span>, <span class="Constant">4/height</span> - <span class="Comment"># editor contains a long last line</span> - <span class="Constant">1</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[a</span> -<span class="Constant">b</span> -<span class="Constant">cdefgh]</span> - <span class="Comment"># editor screen triggers wrap of last line</span> - <span class="Constant">2</span>:address:editor-data<span class="Special"> <- </span>new-editor <span class="Constant">1</span>:address:array:character, screen:address, <span class="Constant">0/left</span>, <span class="Constant">4/right</span> - <span class="Comment"># some part of last line is not displayed</span> - screen-should-contain [ - <span class="Constant"> . .</span> - <span class="Constant"> .a .</span> - <span class="Constant"> .b .</span> - <span class="Constant"> .cde↩ .</span> - ] - <span class="Comment"># scroll down</span> - assume-console [ - press <span class="Constant">65518</span> <span class="Comment"># page-down</span> - ] - run [ - editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data - ] - <span class="Comment"># screen shows entire wrapped line</span> - screen-should-contain [ - <span class="Constant"> . .</span> - <span class="Constant"> .cde↩ .</span> - <span class="Constant"> .fgh .</span> - <span class="Constant"> .┈┈┈┈ .</span> - ] -] - -<span class="muScenario">scenario</span> editor-starts-next-page-at-start-of-wrapped-line-2 [ - <span class="Comment"># screen has 1 line for menu + 3 lines for text</span> - assume-screen <span class="Constant">10/width</span>, <span class="Constant">4/height</span> - <span class="Comment"># editor contains a very long line that occupies last two lines of screen</span> - <span class="Comment"># and still has something left over</span> - <span class="Constant">1</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[a</span> -<span class="Constant">bcdefgh]</span> - <span class="Constant">2</span>:address:editor-data<span class="Special"> <- </span>new-editor <span class="Constant">1</span>:address:array:character, screen:address, <span class="Constant">0/left</span>, <span class="Constant">4/right</span> - <span class="Comment"># some part of last line is not displayed</span> - screen-should-contain [ - <span class="Constant"> . .</span> - <span class="Constant"> .a .</span> - <span class="Constant"> .bcd↩ .</span> - <span class="Constant"> .efg↩ .</span> - ] - <span class="Comment"># scroll down</span> - assume-console [ - press <span class="Constant">65518</span> <span class="Comment"># page-down</span> - ] - run [ - editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data - ] - <span class="Comment"># screen shows entire wrapped line</span> - screen-should-contain [ - <span class="Constant"> . .</span> - <span class="Constant"> .bcd↩ .</span> - <span class="Constant"> .efg↩ .</span> - <span class="Constant"> .h .</span> - ] -] - -<span class="Comment"># ctrl-b/page-up - render previous page if it exists</span> - -<span class="muScenario">scenario</span> editor-can-scroll-up [ - assume-screen <span class="Constant">10/width</span>, <span class="Constant">4/height</span> - <span class="Constant">1</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[a</span> -<span class="Constant">b</span> -<span class="Constant">c</span> -<span class="Constant">d]</span> - <span class="Constant">2</span>:address:editor-data<span class="Special"> <- </span>new-editor <span class="Constant">1</span>:address:array:character, screen:address, <span class="Constant">0/left</span>, <span class="Constant">10/right</span> - screen-should-contain [ - <span class="Constant"> . .</span> - <span class="Constant"> .a .</span> - <span class="Constant"> .b .</span> - <span class="Constant"> .c .</span> - ] - <span class="Comment"># scroll down</span> - assume-console [ - press <span class="Constant">65518</span> <span class="Comment"># page-down</span> - ] - run [ - editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data - ] - <span class="Comment"># screen shows next page</span> - screen-should-contain [ - <span class="Constant"> . .</span> - <span class="Constant"> .c .</span> - <span class="Constant"> .d .</span> -<span class="Constant"> .┈┈┈┈┈┈┈┈┈┈.</span> - ] - <span class="Comment"># scroll back up</span> - assume-console [ - press <span class="Constant">65519</span> <span class="Comment"># page-up</span> - ] - run [ - editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data - ] - <span class="Comment"># screen shows original page again</span> - screen-should-contain [ - <span class="Constant"> . .</span> - <span class="Constant"> .a .</span> - <span class="Constant"> .b .</span> - <span class="Constant"> .c .</span> - ] -] - -<span class="muRecipe">after</span> +handle-special-character [ - <span class="Delimiter">{</span> - ctrl-b?:boolean<span class="Special"> <- </span>equal *c, <span class="Constant">2/ctrl-f</span> - <span class="muControl">break-unless</span> ctrl-b? - editor<span class="Special"> <- </span>page-up editor, screen-height - <span class="muControl">reply</span> screen/same-as-ingredient:<span class="Constant">0</span>, editor/same-as-ingredient:<span class="Constant">1</span>, <span class="Constant">1/go-render</span> - <span class="Delimiter">}</span> -] - -<span class="muRecipe">after</span> +handle-special-key [ - <span class="Delimiter">{</span> - page-up?:boolean<span class="Special"> <- </span>equal *k, <span class="Constant">65519/page-up</span> - <span class="muControl">break-unless</span> page-up? - editor<span class="Special"> <- </span>page-up editor, screen-height - <span class="muControl">reply</span> screen/same-as-ingredient:<span class="Constant">0</span>, editor/same-as-ingredient:<span class="Constant">1</span>, <span class="Constant">1/go-render</span> - <span class="Delimiter">}</span> -] - -<span class="muRecipe">recipe</span> page-up [ - <span class="Constant">local-scope</span> - editor:address:editor-data<span class="Special"> <- </span><span class="Constant">next-ingredient</span> - screen-height:number<span class="Special"> <- </span><span class="Constant">next-ingredient</span> - max:number<span class="Special"> <- </span>subtract screen-height, <span class="Constant">1/menu-bar</span>, <span class="Constant">1/overlapping-line</span> - count:number<span class="Special"> <- </span>copy <span class="Constant">0</span> - top-of-screen:address:address:duplex-list<span class="Special"> <- </span>get-address *editor, <span class="Constant">top-of-screen:offset</span> - <span class="Delimiter">{</span> -<span class="CommentedCode">#? $print [- ], count, [ vs ], max, 10/newline #? 1</span> - done?:boolean<span class="Special"> <- </span>greater-or-equal count, max - <span class="muControl">break-if</span> done? - prev:address:duplex-list<span class="Special"> <- </span>before-previous-line *top-of-screen, editor - <span class="muControl">break-unless</span> prev - *top-of-screen<span class="Special"> <- </span>copy prev - count<span class="Special"> <- </span>add count, <span class="Constant">1</span> - <span class="muControl">loop</span> - <span class="Delimiter">}</span> - <span class="muControl">reply</span> editor/same-as-ingredient:<span class="Constant">0</span> -] - -<span class="muScenario">scenario</span> editor-can-scroll-up-multiple-pages [ - <span class="Comment"># screen has 1 line for menu + 3 lines</span> - assume-screen <span class="Constant">10/width</span>, <span class="Constant">4/height</span> - <span class="Comment"># initialize editor with 8 lines</span> - <span class="Constant">1</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[a</span> -<span class="Constant">b</span> -<span class="Constant">c</span> -<span class="Constant">d</span> -<span class="Constant">e</span> -<span class="Constant">f</span> -<span class="Constant">g</span> -<span class="Constant">h]</span> - <span class="Constant">2</span>:address:editor-data<span class="Special"> <- </span>new-editor <span class="Constant">1</span>:address:array:character, screen:address, <span class="Constant">0/left</span>, <span class="Constant">10/right</span> - screen-should-contain [ - <span class="Constant"> . .</span> - <span class="Constant"> .a .</span> - <span class="Constant"> .b .</span> - <span class="Constant"> .c .</span> - ] - <span class="Comment"># scroll down two pages</span> - assume-console [ - press <span class="Constant">65518</span> <span class="Comment"># page-down</span> - press <span class="Constant">65518</span> <span class="Comment"># page-down</span> - ] - run [ - editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data - ] - <span class="Comment"># screen shows third page</span> - screen-should-contain [ - <span class="Constant"> . .</span> - <span class="Constant"> .e .</span> - <span class="Constant"> .f .</span> - <span class="Constant"> .g .</span> - ] - <span class="Comment"># scroll up</span> - assume-console [ - press <span class="Constant">65519</span> <span class="Comment"># page-up</span> - ] - run [ - editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data - ] - <span class="Comment"># screen shows second page</span> - screen-should-contain [ - <span class="Constant"> . .</span> - <span class="Constant"> .c .</span> - <span class="Constant"> .d .</span> - <span class="Constant"> .e .</span> - ] - <span class="Comment"># scroll up again</span> - assume-console [ - press <span class="Constant">65519</span> <span class="Comment"># page-up</span> - ] - run [ - editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data - ] - <span class="Comment"># screen shows original page again</span> - screen-should-contain [ - <span class="Constant"> . .</span> - <span class="Constant"> .a .</span> - <span class="Constant"> .b .</span> - <span class="Constant"> .c .</span> - ] -] - -<span class="muScenario">scenario</span> editor-can-scroll-up-wrapped-lines [ - <span class="Comment"># screen has 1 line for menu + 5 lines for text</span> - assume-screen <span class="Constant">10/width</span>, <span class="Constant">6/height</span> - <span class="Comment"># editor contains a long line in the first page</span> - <span class="Constant">1</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[a</span> -<span class="Constant">b</span> -<span class="Constant">cdefgh</span> -<span class="Constant">i</span> -<span class="Constant">j</span> -<span class="Constant">k</span> -<span class="Constant">l</span> -<span class="Constant">m</span> -<span class="Constant">n</span> -<span class="Constant">o]</span> - <span class="Comment"># editor screen triggers wrap of last line</span> - <span class="Constant">2</span>:address:editor-data<span class="Special"> <- </span>new-editor <span class="Constant">1</span>:address:array:character, screen:address, <span class="Constant">0/left</span>, <span class="Constant">4/right</span> - <span class="Comment"># some part of last line is not displayed</span> - screen-should-contain [ - <span class="Constant"> . .</span> - <span class="Constant"> .a .</span> - <span class="Constant"> .b .</span> - <span class="Constant"> .cde↩ .</span> - <span class="Constant"> .fgh .</span> - <span class="Constant"> .i .</span> - ] - <span class="Comment"># scroll down a page and a line</span> - assume-console [ - press <span class="Constant">65518</span> <span class="Comment"># page-down</span> - left-click <span class="Constant">5</span>, <span class="Constant">0</span> - press <span class="Constant">65516</span> <span class="Comment"># down-arrow</span> - ] - run [ - editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data - ] - <span class="Comment"># screen shows entire wrapped line</span> - screen-should-contain [ - <span class="Constant"> . .</span> - <span class="Constant"> .j .</span> - <span class="Constant"> .k .</span> - <span class="Constant"> .l .</span> - <span class="Constant"> .m .</span> - <span class="Constant"> .n .</span> - ] - <span class="Comment"># now scroll up one page</span> - assume-console [ - press <span class="Constant">65519</span> <span class="Comment"># page-up</span> - ] - run [ - editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data - ] - <span class="Comment"># screen resets</span> - screen-should-contain [ - <span class="Constant"> . .</span> - <span class="Constant"> .b .</span> - <span class="Constant"> .cde↩ .</span> - <span class="Constant"> .fgh .</span> - <span class="Constant"> .i .</span> - <span class="Constant"> .j .</span> - ] -] - -<span class="muScenario">scenario</span> editor-can-scroll-up-wrapped-lines-2 [ - <span class="Comment"># screen has 1 line for menu + 3 lines for text</span> - assume-screen <span class="Constant">10/width</span>, <span class="Constant">4/height</span> - <span class="Comment"># editor contains a very long line that occupies last two lines of screen</span> - <span class="Comment"># and still has something left over</span> - <span class="Constant">1</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[a</span> -<span class="Constant">bcdefgh]</span> - <span class="Constant">2</span>:address:editor-data<span class="Special"> <- </span>new-editor <span class="Constant">1</span>:address:array:character, screen:address, <span class="Constant">0/left</span>, <span class="Constant">4/right</span> - <span class="Comment"># some part of last line is not displayed</span> - screen-should-contain [ - <span class="Constant"> . .</span> - <span class="Constant"> .a .</span> - <span class="Constant"> .bcd↩ .</span> - <span class="Constant"> .efg↩ .</span> - ] - <span class="Comment"># scroll down</span> - assume-console [ - press <span class="Constant">65518</span> <span class="Comment"># page-down</span> - ] - run [ - editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data - ] - <span class="Comment"># screen shows entire wrapped line</span> - screen-should-contain [ - <span class="Constant"> . .</span> - <span class="Constant"> .bcd↩ .</span> - <span class="Constant"> .efg↩ .</span> - <span class="Constant"> .h .</span> - ] - <span class="Comment"># scroll back up</span> - assume-console [ - press <span class="Constant">65519</span> <span class="Comment"># page-up</span> - ] - run [ - editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data - ] - <span class="Comment"># screen resets</span> - screen-should-contain [ - <span class="Constant"> . .</span> - <span class="Constant"> .a .</span> - <span class="Constant"> .bcd↩ .</span> - <span class="Constant"> .efg↩ .</span> - ] -] - -<span class="muScenario">scenario</span> editor-can-scroll-up-past-nonempty-lines [ - assume-screen <span class="Constant">10/width</span>, <span class="Constant">4/height</span> - <span class="Comment"># text with empty line in second screen</span> - <span class="Constant">1</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[axx</span> -<span class="Constant">bxx</span> -<span class="Constant">cxx</span> -<span class="Constant">dxx</span> -<span class="Constant">exx</span> -<span class="Constant">fxx</span> -<span class="Constant">gxx</span> -<span class="Constant">hxx</span> -<span class="Constant">]</span> - <span class="Constant">2</span>:address:editor-data<span class="Special"> <- </span>new-editor <span class="Constant">1</span>:address:array:character, screen:address, <span class="Constant">0/left</span>, <span class="Constant">4/right</span> - screen-should-contain [ - <span class="Constant"> . .</span> - <span class="Constant"> .axx .</span> - <span class="Constant"> .bxx .</span> - <span class="Constant"> .cxx .</span> - ] - assume-console [ - press <span class="Constant">65518</span> <span class="Comment"># page-down</span> - ] - run [ - editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data - ] - screen-should-contain [ - <span class="Constant"> . .</span> - <span class="Constant"> .cxx .</span> - <span class="Constant"> .dxx .</span> - <span class="Constant"> .exx .</span> - ] - assume-console [ - press <span class="Constant">65518</span> <span class="Comment"># page-down</span> - ] - run [ - editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data - ] - screen-should-contain [ - <span class="Constant"> . .</span> - <span class="Constant"> .exx .</span> - <span class="Constant"> .fxx .</span> - <span class="Constant"> .gxx .</span> - ] - <span class="Comment"># scroll back up past empty line</span> - assume-console [ - press <span class="Constant">65519</span> <span class="Comment"># page-up</span> - ] - run [ - editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data - ] - screen-should-contain [ - <span class="Constant"> . .</span> - <span class="Constant"> .cxx .</span> - <span class="Constant"> .dxx .</span> - <span class="Constant"> .exx .</span> - ] -] - -<span class="muScenario">scenario</span> editor-can-scroll-up-past-empty-lines [ - assume-screen <span class="Constant">10/width</span>, <span class="Constant">4/height</span> - <span class="Comment"># text with empty line in second screen</span> - <span class="Constant">1</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[axy</span> -<span class="Constant">bxy</span> -<span class="Constant">cxy</span> - -dxy -exy -fxy -gxy -] - <span class="Constant">2</span>:address:editor-data<span class="Special"> <- </span>new-editor <span class="Constant">1</span>:address:array:character, screen:address, <span class="Constant">0/left</span>, <span class="Constant">4/right</span> - screen-should-contain [ - <span class="Constant"> . .</span> - <span class="Constant"> .axy .</span> - <span class="Constant"> .bxy .</span> - <span class="Constant"> .cxy .</span> - ] - assume-console [ - press <span class="Constant">65518</span> <span class="Comment"># page-down</span> - ] - run [ - editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data - ] - screen-should-contain [ - <span class="Constant"> . .</span> - <span class="Constant"> .cxy .</span> - <span class="Constant"> . .</span> - <span class="Constant"> .dxy .</span> - ] - assume-console [ - press <span class="Constant">65518</span> <span class="Comment"># page-down</span> - ] - run [ - editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data - ] - screen-should-contain [ - <span class="Constant"> . .</span> - <span class="Constant"> .dxy .</span> - <span class="Constant"> .exy .</span> - <span class="Constant"> .fxy .</span> - ] - <span class="Comment"># scroll back up past empty line</span> - assume-console [ - press <span class="Constant">65519</span> <span class="Comment"># page-up</span> - ] - run [ - editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data - ] - screen-should-contain [ - <span class="Constant"> . .</span> - <span class="Constant"> .cxy .</span> - <span class="Constant"> . .</span> - <span class="Constant"> .dxy .</span> - ] -] - -<span class="SalientComment">## putting the environment together out of editors</span> - -container programming-environment-data [ - recipes:address:editor-data - recipe-warnings:address:array:character - current-sandbox:address:editor-data - sandbox:address:sandbox-data <span class="Comment"># list of sandboxes, from top to bottom</span> - sandbox-in-focus?:boolean <span class="Comment"># false => cursor in recipes; true => cursor 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 - height:number<span class="Special"> <- </span>screen-height screen - <span class="Comment"># top menu</span> - result:address:programming-environment-data<span class="Special"> <- </span>new <span class="Constant">programming-environment-data:type</span> - draw-horizontal screen, <span class="Constant">0</span>, <span class="Constant">0/left</span>, width, <span class="Constant">32/space</span>, <span class="Constant">0/black</span>, <span class="Constant">238/grey</span> - button-start:number<span class="Special"> <- </span>subtract width, <span class="Constant">20</span> - button-on-screen?:boolean<span class="Special"> <- </span>greater-or-equal button-start, <span class="Constant">0</span> - assert button-on-screen?, <span class="Constant">[screen too narrow for menu]</span> - screen<span class="Special"> <- </span>move-cursor screen, <span class="Constant">0/row</span>, button-start - run-button:address:array:character<span class="Special"> <- </span>new <span class="Constant">[ run (F4) ]</span> - print-string screen, run-button, <span class="Constant">255/white</span>, <span class="Constant">161/reddish</span> - <span class="Comment"># dotted line down the middle</span> - divider:number, _<span class="Special"> <- </span>divide-with-remainder width, <span class="Constant">2</span> - draw-vertical screen, divider, <span class="Constant">1/top</span>, height, <span class="Constant">9482/vertical-dotted</span> - <span class="Comment"># recipe editor on the left</span> - recipes:address:address:editor-data<span class="Special"> <- </span>get-address *result, <span class="Constant">recipes:offset</span> - *recipes<span class="Special"> <- </span>new-editor initial-recipe-contents, screen, <span class="Constant">0/left</span>, divider/right - <span class="Comment"># sandbox editor on the right</span> - new-left:number<span class="Special"> <- </span>add divider, <span class="Constant">1</span> - current-sandbox:address:address:editor-data<span class="Special"> <- </span>get-address *result, <span class="Constant">current-sandbox:offset</span> - *current-sandbox<span class="Special"> <- </span>new-editor initial-sandbox-contents, screen, new-left, width/right -<span class="Constant"> +programming-environment-initialization</span> - <span class="muControl">reply</span> result -] - -<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, <span class="Constant">recipes:offset</span> - current-sandbox:address:editor-data<span class="Special"> <- </span>get *env, <span class="Constant">current-sandbox:offset</span> - sandbox-in-focus?:address:boolean<span class="Special"> <- </span>get-address *env, <span class="Constant">sandbox-in-focus?:offset</span> - <span class="Delimiter">{</span> - <span class="Comment"># looping over each (keyboard or touch) event as it occurs</span> -<span class="Constant"> +next-event</span> - e:event, console, found?:boolean, quit?:boolean<span class="Special"> <- </span>read-event console - <span class="muControl">loop-unless</span> found? - <span class="muControl">break-if</span> quit? <span class="Comment"># only in tests</span> - trace <span class="Constant">10</span>, <span class="Constant">[app]</span>, <span class="Constant">[next-event]</span> -<span class="Constant"> +handle-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, <span class="Constant">keycode:variant</span> - <span class="muControl">break-unless</span> k -<span class="Constant"> +global-keypress</span> - <span class="Delimiter">}</span> - <span class="Delimiter">{</span> - c:address:character<span class="Special"> <- </span>maybe-convert e:event, <span class="Constant">text:variant</span> - <span class="muControl">break-unless</span> c -<span class="Constant"> +global-type</span> - <span class="Delimiter">}</span> - <span class="Comment"># 'touch' event - send to both sides, see what picks it up</span> - <span class="Delimiter">{</span> - t:address:touch-event<span class="Special"> <- </span>maybe-convert e:event, <span class="Constant">touch:variant</span> - <span class="muControl">break-unless</span> t - <span class="Comment"># ignore all but 'left-click' events for now</span> - <span class="Comment"># todo: test this</span> - touch-type:number<span class="Special"> <- </span>get *t, <span class="Constant">type:offset</span> - is-left-click?:boolean<span class="Special"> <- </span>equal touch-type, <span class="Constant">65513/mouse-left</span> - <span class="muControl">loop-unless</span> is-left-click?, <span class="Constant">+next-event:label</span> - <span class="Comment"># later exceptions for non-editor touches will go here</span> -<span class="Constant"> +global-touch</span> - <span class="Comment"># send to both editors</span> - _<span class="Special"> <- </span>move-cursor-in-editor screen, recipes, *t - *sandbox-in-focus?<span class="Special"> <- </span>move-cursor-in-editor screen, current-sandbox, *t - screen<span class="Special"> <- </span>update-cursor screen, recipes, current-sandbox, *sandbox-in-focus? - <span class="muControl">loop</span> <span class="Constant">+next-event:label</span> - <span class="Delimiter">}</span> - <span class="Comment"># 'resize' event - redraw editor</span> - <span class="Comment"># todo: test this after supporting resize in assume-console</span> - <span class="Delimiter">{</span> - r:address:resize-event<span class="Special"> <- </span>maybe-convert e:event, <span class="Constant">resize:variant</span> - <span class="muControl">break-unless</span> r - <span class="Comment"># if more events, we're still resizing; wait until we stop</span> - more-events?:boolean<span class="Special"> <- </span>has-more-events? console - <span class="muControl">break-if</span> more-events? - env<span class="Special"> <- </span>resize screen, env - screen<span class="Special"> <- </span>render-all screen, env - <span class="muControl">loop</span> <span class="Constant">+next-event:label</span> - <span class="Delimiter">}</span> - <span class="Comment"># if it's not global and not a touch event, send to appropriate editor</span> - <span class="Delimiter">{</span> - hide-screen screen - <span class="Delimiter">{</span> - <span class="muControl">break-if</span> *sandbox-in-focus? - screen, recipes, render?:boolean<span class="Special"> <- </span>handle-keyboard-event screen, recipes, e:event - <span class="Delimiter">{</span> - <span class="muControl">break-unless</span> render? - screen<span class="Special"> <- </span>render-recipes screen, env - <span class="Delimiter">}</span> - <span class="Delimiter">}</span> - <span class="Delimiter">{</span> - <span class="muControl">break-unless</span> *sandbox-in-focus? - screen, current-sandbox, render?:boolean<span class="Special"> <- </span>handle-keyboard-event screen, current-sandbox, e:event - <span class="Delimiter">{</span> - <span class="muControl">break-unless</span> render?:boolean - screen<span class="Special"> <- </span>render-sandbox-side screen, env - <span class="Delimiter">}</span> - <span class="Delimiter">}</span> - screen<span class="Special"> <- </span>update-cursor screen, recipes, current-sandbox, *sandbox-in-focus? - show-screen screen - <span class="Delimiter">}</span> - <span class="muControl">loop</span> - <span class="Delimiter">}</span> -] - -<span class="muRecipe">recipe</span> resize [ - <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> - <span class="Comment"># hack: clear screen to update screen dimensions</span> - clear-screen screen - width:number<span class="Special"> <- </span>screen-width screen - height:number<span class="Special"> <- </span>screen-height screen - <span class="Comment"># top menu</span> - draw-horizontal screen, <span class="Constant">0</span>, <span class="Constant">0/left</span>, width, <span class="Constant">32/space</span>, <span class="Constant">0/black</span>, <span class="Constant">238/grey</span> - button-start:number<span class="Special"> <- </span>subtract width, <span class="Constant">20</span> - button-on-screen?:boolean<span class="Special"> <- </span>greater-or-equal button-start, <span class="Constant">0</span> - assert button-on-screen?, <span class="Constant">[screen too narrow for menu]</span> - screen<span class="Special"> <- </span>move-cursor screen, <span class="Constant">0/row</span>, button-start - run-button:address:array:character<span class="Special"> <- </span>new <span class="Constant">[ run (F4) ]</span> - print-string screen, run-button, <span class="Constant">255/white</span>, <span class="Constant">161/reddish</span> - <span class="Comment"># dotted line down the middle</span> - divider:number, _<span class="Special"> <- </span>divide-with-remainder width, <span class="Constant">2</span> - draw-vertical screen, divider, <span class="Constant">1/top</span>, height, <span class="Constant">9482/vertical-dotted</span> - <span class="Comment"># update recipe editor</span> - recipes:address:editor-data<span class="Special"> <- </span>get *env, <span class="Constant">recipes:offset</span> - right:address:number<span class="Special"> <- </span>get-address *recipes, <span class="Constant">right:offset</span> - *right<span class="Special"> <- </span>subtract divider, <span class="Constant">1</span> - <span class="Comment"># update sandbox editor</span> - current-sandbox:address:editor-data<span class="Special"> <- </span>get *env, <span class="Constant">current-sandbox:offset</span> - left:address:number<span class="Special"> <- </span>get-address *current-sandbox, <span class="Constant">left:offset</span> - right:address:number<span class="Special"> <- </span>get-address *current-sandbox, <span class="Constant">right:offset</span> - *left<span class="Special"> <- </span>add divider, <span class="Constant">1</span> - *right<span class="Special"> <- </span>subtract width, <span class="Constant">1</span> - <span class="muControl">reply</span> env/same-as-ingredient:<span class="Constant">1</span> -] - -<span class="muScenario">scenario</span> point-at-multiple-editors [ -<span class="Constant"> $close-trace</span> - assume-screen <span class="Constant">30/width</span>, <span class="Constant">5/height</span> - <span class="Comment"># initialize both halves of screen</span> - <span class="Constant">1</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[abc]</span> - <span class="Constant">2</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[def]</span> - <span class="Constant">3</span>:address:programming-environment-data<span class="Special"> <- </span>new-programming-environment screen:address, <span class="Constant">1</span>:address:array:character, <span class="Constant">2</span>:address:array:character - <span class="Comment"># focus on both sides</span> - assume-console [ - left-click <span class="Constant">1</span>, <span class="Constant">1</span> - left-click <span class="Constant">1</span>, <span class="Constant">17</span> - ] - <span class="Comment"># check cursor column in each</span> - run [ - event-loop screen:address, console:address, <span class="Constant">3</span>:address:programming-environment-data - <span class="Constant">4</span>:address:editor-data<span class="Special"> <- </span>get *<span class="Constant">3</span>:address:programming-environment-data, <span class="Constant">recipes:offset</span> - <span class="Constant">5</span>:number<span class="Special"> <- </span>get *<span class="Constant">4</span>:address:editor-data, <span class="Constant">cursor-column:offset</span> - <span class="Constant">6</span>:address:editor-data<span class="Special"> <- </span>get *<span class="Constant">3</span>:address:programming-environment-data, <span class="Constant">current-sandbox:offset</span> - <span class="Constant">7</span>:number<span class="Special"> <- </span>get *<span class="Constant">6</span>:address:editor-data, <span class="Constant">cursor-column:offset</span> - ] - memory-should-contain [ - <span class="Constant">5</span><span class="Special"> <- </span><span class="Constant">1</span> - <span class="Constant">7</span><span class="Special"> <- </span><span class="Constant">17</span> - ] -] - -<span class="muScenario">scenario</span> edit-multiple-editors [ -<span class="Constant"> $close-trace</span> - assume-screen <span class="Constant">30/width</span>, <span class="Constant">5/height</span> - <span class="Comment"># initialize both halves of screen</span> - <span class="Constant">1</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[abc]</span> - <span class="Constant">2</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[def]</span> - <span class="Constant">3</span>:address:programming-environment-data<span class="Special"> <- </span>new-programming-environment screen:address, <span class="Constant">1</span>:address:array:character, <span class="Constant">2</span>:address:array:character - render-all screen, <span class="Constant">3</span>:address:programming-environment-data - <span class="Comment"># type one letter in each of them</span> - assume-console [ - left-click <span class="Constant">1</span>, <span class="Constant">1</span> - type <span class="Constant">[0]</span> - left-click <span class="Constant">1</span>, <span class="Constant">17</span> - type <span class="Constant">[1]</span> - ] - run [ - event-loop screen:address, console:address, <span class="Constant">3</span>:address:programming-environment-data - <span class="Constant">4</span>:address:editor-data<span class="Special"> <- </span>get *<span class="Constant">3</span>:address:programming-environment-data, <span class="Constant">recipes:offset</span> - <span class="Constant">5</span>:number<span class="Special"> <- </span>get *<span class="Constant">4</span>:address:editor-data, <span class="Constant">cursor-column:offset</span> - <span class="Constant">6</span>:address:editor-data<span class="Special"> <- </span>get *<span class="Constant">3</span>:address:programming-environment-data, <span class="Constant">current-sandbox:offset</span> - <span class="Constant">7</span>:number<span class="Special"> <- </span>get *<span class="Constant">6</span>:address:editor-data, <span class="Constant">cursor-column:offset</span> - ] - screen-should-contain [ - <span class="Constant"> . run (F4) . # this line has a different background, but we don't test that yet</span> - <span class="Constant"> .a0bc ┊d1ef .</span> -<span class="Constant"> .┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┊━━━━━━━━━━━━━━.</span> - <span class="Constant"> . ┊ .</span> - ] - memory-should-contain [ - <span class="Constant">5</span><span class="Special"> <- </span><span class="Constant">2</span> <span class="Comment"># cursor column of recipe editor</span> - <span class="Constant">7</span><span class="Special"> <- </span><span class="Constant">18</span> <span class="Comment"># cursor column of sandbox editor</span> - ] - <span class="Comment"># show the cursor at the right window</span> - run [ - print-character screen:address, <span class="Constant">9251/␣/cursor</span> - ] - screen-should-contain [ - <span class="Constant"> . run (F4) .</span> - <span class="Constant"> .a0bc ┊d1␣f .</span> -<span class="Constant"> .┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┊━━━━━━━━━━━━━━.</span> - <span class="Constant"> . ┊ .</span> - ] -] - -<span class="muScenario">scenario</span> multiple-editors-cover-only-their-own-areas [ -<span class="Constant"> $close-trace</span> - assume-screen <span class="Constant">60/width</span>, <span class="Constant">10/height</span> - run [ - <span class="Constant">1</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[abc]</span> - <span class="Constant">2</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[def]</span> - <span class="Constant">3</span>:address:programming-environment-data<span class="Special"> <- </span>new-programming-environment screen:address, <span class="Constant">1</span>:address:array:character, <span class="Constant">2</span>:address:array:character - render-all screen, <span class="Constant">3</span>:address:programming-environment-data - ] - <span class="Comment"># divider isn't messed up</span> - screen-should-contain [ - <span class="Constant"> . run (F4) .</span> - <span class="Constant"> .abc ┊def .</span> -<span class="Constant"> .┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┊━━━━━━━━━━━━━━━━━━━━━━━━━━━━━.</span> - <span class="Constant"> . ┊ .</span> - <span class="Constant"> . ┊ .</span> - ] -] - -<span class="muScenario">scenario</span> editor-in-focus-keeps-cursor [ -<span class="Constant"> $close-trace</span> - assume-screen <span class="Constant">30/width</span>, <span class="Constant">5/height</span> - <span class="Constant">1</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[abc]</span> - <span class="Constant">2</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[def]</span> - <span class="Constant">3</span>:address:programming-environment-data<span class="Special"> <- </span>new-programming-environment screen:address, <span class="Constant">1</span>:address:array:character, <span class="Constant">2</span>:address:array:character - render-all screen, <span class="Constant">3</span>:address:programming-environment-data - <span class="Comment"># initialize programming environment and highlight cursor</span> - assume-console <span class="Constant">[]</span> - run [ - event-loop screen:address, console:address, <span class="Constant">3</span>:address:programming-environment-data - print-character screen:address, <span class="Constant">9251/␣</span> - ] - <span class="Comment"># is cursor at the right place?</span> - screen-should-contain [ - <span class="Constant"> . run (F4) .</span> - <span class="Constant"> .␣bc ┊def .</span> -<span class="Constant"> .┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┊━━━━━━━━━━━━━━.</span> - <span class="Constant"> . ┊ .</span> - ] - <span class="Comment"># now try typing a letter</span> - assume-console [ - type <span class="Constant">[z]</span> - ] - run [ - event-loop screen:address, console:address, <span class="Constant">3</span>:address:programming-environment-data - print-character screen:address, <span class="Constant">9251/␣</span> - ] - <span class="Comment"># cursor should still be right</span> - screen-should-contain [ - <span class="Constant"> . run (F4) .</span> - <span class="Constant"> .z␣bc ┊def .</span> -<span class="Constant"> .┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┊━━━━━━━━━━━━━━.</span> - <span class="Constant"> . ┊ .</span> - ] -] - -<span class="muScenario">scenario</span> backspace-in-sandbox-editor-joins-lines [ -<span class="Constant"> $close-trace</span> - assume-screen <span class="Constant">30/width</span>, <span class="Constant">5/height</span> - <span class="Comment"># initialize sandbox side with two lines</span> - <span class="Constant">1</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[]</span> - <span class="Constant">2</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[abc</span> -<span class="Constant">def]</span> - <span class="Constant">3</span>:address:programming-environment-data<span class="Special"> <- </span>new-programming-environment screen:address, <span class="Constant">1</span>:address:array:character, <span class="Constant">2</span>:address:array:character - render-all screen, <span class="Constant">3</span>:address:programming-environment-data - screen-should-contain [ - <span class="Constant"> . run (F4) .</span> - <span class="Constant"> . ┊abc .</span> - <span class="Constant"> .┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┊def .</span> - <span class="Constant"> . ┊━━━━━━━━━━━━━━.</span> - <span class="Constant"> . ┊ .</span> - ] - <span class="Comment"># position cursor at start of second line and hit backspace</span> - assume-console [ - left-click <span class="Constant">2</span>, <span class="Constant">16</span> - type <span class="Constant">[«]</span> - ] - <span class="Constant">4</span>:event/backspace<span class="Special"> <- </span>merge <span class="Constant">0/text</span>, <span class="Constant">8/backspace</span>, <span class="Constant">0/dummy</span>, <span class="Constant">0/dummy</span> - replace-in-console <span class="Constant">171/«</span>, <span class="Constant">4</span>:event/backspace - run [ - event-loop screen:address, console:address, <span class="Constant">3</span>:address:programming-environment-data - print-character screen:address, <span class="Constant">9251/␣</span> - ] - <span class="Comment"># cursor moves to end of old line</span> - screen-should-contain [ - <span class="Constant"> . run (F4) .</span> - <span class="Constant"> . ┊abc␣ef .</span> -<span class="Constant"> .┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┊━━━━━━━━━━━━━━.</span> - <span class="Constant"> . ┊ .</span> - ] -] - -<span class="muRecipe">recipe</span> render-all [ - <span class="Constant">local-scope</span> - screen:address<span class="Special"> <- </span><span class="Constant">next-ingredient</span> - env:address:programming-environment-data<span class="Special"> <- </span><span class="Constant">next-ingredient</span> - hide-screen screen - <span class="Comment"># top menu</span> - width:number<span class="Special"> <- </span>screen-width screen - draw-horizontal screen, <span class="Constant">0</span>, <span class="Constant">0/left</span>, width, <span class="Constant">32/space</span>, <span class="Constant">0/black</span>, <span class="Constant">238/grey</span> - button-start:number<span class="Special"> <- </span>subtract width, <span class="Constant">20</span> - button-on-screen?:boolean<span class="Special"> <- </span>greater-or-equal button-start, <span class="Constant">0</span> - assert button-on-screen?, <span class="Constant">[screen too narrow for menu]</span> - screen<span class="Special"> <- </span>move-cursor screen, <span class="Constant">0/row</span>, button-start - run-button:address:array:character<span class="Special"> <- </span>new <span class="Constant">[ run (F4) ]</span> - print-string screen, run-button, <span class="Constant">255/white</span>, <span class="Constant">161/reddish</span> - <span class="Comment"># error message</span> - recipe-warnings:address:array:character<span class="Special"> <- </span>get *env, <span class="Constant">recipe-warnings:offset</span> - <span class="Delimiter">{</span> - <span class="muControl">break-unless</span> recipe-warnings - status:address:array:character<span class="Special"> <- </span>new <span class="Constant">[errors found]</span> - update-status screen, status, <span class="Constant">1/red</span> - <span class="Delimiter">}</span> - <span class="Comment"># dotted line down the middle</span> - divider:number, _<span class="Special"> <- </span>divide-with-remainder width, <span class="Constant">2</span> - height:number<span class="Special"> <- </span>screen-height screen - draw-vertical screen, divider, <span class="Constant">1/top</span>, height, <span class="Constant">9482/vertical-dotted</span> - <span class="Comment">#</span> - screen<span class="Special"> <- </span>render-recipes screen, env - screen<span class="Special"> <- </span>render-sandbox-side screen, env - <span class="Comment">#</span> - recipes:address:editor-data<span class="Special"> <- </span>get *env, <span class="Constant">recipes:offset</span> - current-sandbox:address:editor-data<span class="Special"> <- </span>get *env, <span class="Constant">current-sandbox:offset</span> - sandbox-in-focus?:boolean<span class="Special"> <- </span>get *env, <span class="Constant">sandbox-in-focus?:offset</span> - screen<span class="Special"> <- </span>update-cursor screen, recipes, current-sandbox, sandbox-in-focus? - <span class="Comment">#</span> - show-screen screen - <span class="muControl">reply</span> screen/same-as-ingredient:<span class="Constant">0</span> -] - -<span class="muRecipe">recipe</span> render-minimal [ - <span class="Constant">local-scope</span> - screen:address<span class="Special"> <- </span><span class="Constant">next-ingredient</span> - env:address:programming-environment-data<span class="Special"> <- </span><span class="Constant">next-ingredient</span> - hide-screen screen - recipes:address:editor-data<span class="Special"> <- </span>get *env, <span class="Constant">recipes:offset</span> - current-sandbox:address:editor-data<span class="Special"> <- </span>get *env, <span class="Constant">current-sandbox:offset</span> - sandbox-in-focus?:boolean<span class="Special"> <- </span>get *env, <span class="Constant">sandbox-in-focus?:offset</span> - <span class="Delimiter">{</span> - <span class="muControl">break-if</span> sandbox-in-focus? - screen<span class="Special"> <- </span>render-recipes screen, env - cursor-row:number<span class="Special"> <- </span>get *recipes, <span class="Constant">cursor-row:offset</span> - cursor-column:number<span class="Special"> <- </span>get *recipes, <span class="Constant">cursor-column:offset</span> - <span class="Delimiter">}</span> - <span class="Delimiter">{</span> - <span class="muControl">break-unless</span> sandbox-in-focus? - screen<span class="Special"> <- </span>render-sandbox-side screen, env - cursor-row:number<span class="Special"> <- </span>get *current-sandbox, <span class="Constant">cursor-row:offset</span> - cursor-column:number<span class="Special"> <- </span>get *current-sandbox, <span class="Constant">cursor-column:offset</span> - <span class="Delimiter">}</span> - screen<span class="Special"> <- </span>move-cursor screen, cursor-row, cursor-column - show-screen screen - <span class="muControl">reply</span> screen/same-as-ingredient:<span class="Constant">0</span> -] - -<span class="muRecipe">recipe</span> render-recipes [ - <span class="Constant">local-scope</span> - screen:address<span class="Special"> <- </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, <span class="Constant">recipes:offset</span> - <span class="Comment"># render recipes</span> - left:number<span class="Special"> <- </span>get *recipes, <span class="Constant">left:offset</span> - right:number<span class="Special"> <- </span>get *recipes, <span class="Constant">right:offset</span> - row:number, column:number, screen<span class="Special"> <- </span>render screen, recipes - clear-line-delimited screen, column, right - recipe-warnings:address:array:character<span class="Special"> <- </span>get *env, <span class="Constant">recipe-warnings:offset</span> - <span class="Delimiter">{</span> - <span class="Comment"># print any warnings</span> - <span class="muControl">break-unless</span> recipe-warnings - row, screen<span class="Special"> <- </span>render-string screen, recipe-warnings, left, right, <span class="Constant">1/red</span>, row - <span class="Delimiter">}</span> - <span class="Delimiter">{</span> - <span class="Comment"># no warnings? move to next line</span> - <span class="muControl">break-if</span> recipe-warnings - row<span class="Special"> <- </span>add row, <span class="Constant">1</span> - <span class="Delimiter">}</span> - <span class="Comment"># draw dotted line after recipes</span> - draw-horizontal screen, row, left, right, <span class="Constant">9480/horizontal-dotted</span> - row<span class="Special"> <- </span>add row, <span class="Constant">1</span> - clear-screen-from screen, row, left, left, right - <span class="muControl">reply</span> screen/same-as-ingredient:<span class="Constant">0</span> -] - -<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? -<span class="CommentedCode">#? $print [recipes in focus</span> -<span class="CommentedCode">#? ] #? 1</span> - cursor-row:number<span class="Special"> <- </span>get *recipes, <span class="Constant">cursor-row:offset</span> - cursor-column:number<span class="Special"> <- </span>get *recipes, <span class="Constant">cursor-column:offset</span> - <span class="Delimiter">}</span> - <span class="Delimiter">{</span> - <span class="muControl">break-unless</span> sandbox-in-focus? -<span class="CommentedCode">#? $print [sandboxes in focus</span> -<span class="CommentedCode">#? ] #? 1</span> - cursor-row:number<span class="Special"> <- </span>get *current-sandbox, <span class="Constant">cursor-row:offset</span> - cursor-column:number<span class="Special"> <- </span>get *current-sandbox, <span class="Constant">cursor-column:offset</span> - <span class="Delimiter">}</span> - screen<span class="Special"> <- </span>move-cursor screen, cursor-row, cursor-column - <span class="muControl">reply</span> screen/same-as-ingredient:<span class="Constant">0</span> -] - -<span class="Comment"># ctrl-l - redraw screen (just in case it printed junk somehow)</span> - -<span class="muRecipe">after</span> +global-type [ - <span class="Delimiter">{</span> - ctrl-l?:boolean<span class="Special"> <- </span>equal *c, <span class="Constant">12/ctrl-l</span> - <span class="muControl">break-unless</span> ctrl-l? - screen<span class="Special"> <- </span>render-all screen, env:address:programming-environment-data - <span class="muControl">loop</span> <span class="Constant">+next-event:label</span> - <span class="Delimiter">}</span> -] - -<span class="Comment"># ctrl-n - switch focus</span> -<span class="Comment"># todo: test this</span> - -<span class="muRecipe">after</span> +global-type [ - <span class="Delimiter">{</span> - ctrl-n?:boolean<span class="Special"> <- </span>equal *c, <span class="Constant">14/ctrl-n</span> - <span class="muControl">break-unless</span> ctrl-n? - *sandbox-in-focus?<span class="Special"> <- </span>not *sandbox-in-focus? - screen<span class="Special"> <- </span>update-cursor screen, recipes, current-sandbox, *sandbox-in-focus? - <span class="muControl">loop</span> <span class="Constant">+next-event:label</span> - <span class="Delimiter">}</span> -] - -<span class="Comment"># ctrl-x - maximize/unmaximize the side with focus</span> - -<span class="muScenario">scenario</span> maximize-side [ -<span class="Constant"> $close-trace</span> - assume-screen <span class="Constant">30/width</span>, <span class="Constant">5/height</span> - <span class="Comment"># initialize both halves of screen</span> - <span class="Constant">1</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[abc]</span> - <span class="Constant">2</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[def]</span> - <span class="Constant">3</span>:address:programming-environment-data<span class="Special"> <- </span>new-programming-environment screen:address, <span class="Constant">1</span>:address:array:character, <span class="Constant">2</span>:address:array:character - screen<span class="Special"> <- </span>render-all screen, <span class="Constant">3</span>:address:programming-environment-data - screen-should-contain [ - <span class="Constant"> . run (F4) .</span> - <span class="Constant"> .abc ┊def .</span> -<span class="Constant"> .┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┊━━━━━━━━━━━━━━.</span> - <span class="Constant"> . ┊ .</span> - ] - <span class="Comment"># hit ctrl-x</span> - assume-console [ - type <span class="Constant">[x]</span> - ] - <span class="Constant">4</span>:event/ctrl-x<span class="Special"> <- </span>merge <span class="Constant">0/text</span>, <span class="Constant">24/ctrl-x</span>, <span class="Constant">0/dummy</span>, <span class="Constant">0/dummy</span> - replace-in-console <span class="Constant">120/x</span>, <span class="Constant">4</span>:event/ctrl-x - run [ - event-loop screen:address, console:address, <span class="Constant">3</span>:address:programming-environment-data - ] - <span class="Comment"># only left side visible</span> - screen-should-contain [ - <span class="Constant"> . run (F4) .</span> - <span class="Constant"> .abc .</span> -<span class="Constant"> .┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈.</span> - <span class="Constant"> . .</span> - ] - <span class="Comment"># hit any key to toggle back</span> - assume-console [ - press <span class="Constant">24</span> <span class="Comment"># ctrl-x</span> - ] - run [ - event-loop screen:address, console:address, <span class="Constant">3</span>:address:programming-environment-data - ] - screen-should-contain [ - <span class="Constant"> . run (F4) .</span> - <span class="Constant"> .abc ┊def .</span> -<span class="Constant"> .┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┊━━━━━━━━━━━━━━.</span> - <span class="Constant"> . ┊ .</span> - ] -] - -container programming-environment-data [ - maximized?:boolean -] - -<span class="muRecipe">after</span> +global-type [ - <span class="Delimiter">{</span> - ctrl-x?:boolean<span class="Special"> <- </span>equal *c, <span class="Constant">24/ctrl-x</span> - <span class="muControl">break-unless</span> ctrl-x? - screen, console<span class="Special"> <- </span>maximize screen, console, env:address:programming-environment-data - <span class="muControl">loop</span> <span class="Constant">+next-event:label</span> - <span class="Delimiter">}</span> -] - -<span class="muRecipe">recipe</span> maximize [ - <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> - hide-screen screen - <span class="Comment"># maximize one of the sides</span> - maximized?:address:boolean<span class="Special"> <- </span>get-address *env, <span class="Constant">maximized?:offset</span> - *maximized?<span class="Special"> <- </span>copy <span class="Constant">1/true</span> - <span class="Comment">#</span> - sandbox-in-focus?:boolean<span class="Special"> <- </span>get *env, <span class="Constant">sandbox-in-focus?:offset</span> - <span class="Delimiter">{</span> - <span class="muControl">break-if</span> sandbox-in-focus? - editor:address:editor-data<span class="Special"> <- </span>get *env, <span class="Constant">recipes:offset</span> - right:address:number<span class="Special"> <- </span>get-address *editor, <span class="Constant">right:offset</span> - *right<span class="Special"> <- </span>screen-width screen - *right<span class="Special"> <- </span>subtract *right, <span class="Constant">1</span> - screen<span class="Special"> <- </span>render-recipes screen, env - <span class="Delimiter">}</span> - <span class="Delimiter">{</span> - <span class="muControl">break-unless</span> sandbox-in-focus? - editor:address:editor-data<span class="Special"> <- </span>get *env, <span class="Constant">current-sandbox:offset</span> - left:address:number<span class="Special"> <- </span>get-address *editor, <span class="Constant">left:offset</span> - *left<span class="Special"> <- </span>copy <span class="Constant">0</span> - screen<span class="Special"> <- </span>render-sandbox-side screen, env - <span class="Delimiter">}</span> - show-screen screen - <span class="muControl">reply</span> screen/same-as-ingredient:<span class="Constant">0</span>, console/same-as-ingredient:<span class="Constant">1</span> -] - -<span class="Comment"># when maximized, wait for any event and simply unmaximize</span> -<span class="muRecipe">after</span> +handle-event [ - <span class="Delimiter">{</span> - maximized?:address:boolean<span class="Special"> <- </span>get-address *env, <span class="Constant">maximized?:offset</span> - <span class="muControl">break-unless</span> *maximized? - *maximized?<span class="Special"> <- </span>copy <span class="Constant">0/false</span> - <span class="Comment"># undo maximize</span> - <span class="Delimiter">{</span> - <span class="muControl">break-if</span> *sandbox-in-focus? - editor:address:editor-data<span class="Special"> <- </span>get *env, <span class="Constant">recipes:offset</span> - right:address:number<span class="Special"> <- </span>get-address *editor, <span class="Constant">right:offset</span> - *right<span class="Special"> <- </span>screen-width screen - *right<span class="Special"> <- </span>divide *right, <span class="Constant">2</span> - *right<span class="Special"> <- </span>subtract *right, <span class="Constant">1</span> - <span class="Delimiter">}</span> - <span class="Delimiter">{</span> - <span class="muControl">break-unless</span> *sandbox-in-focus? - editor:address:editor-data<span class="Special"> <- </span>get *env, <span class="Constant">current-sandbox:offset</span> - left:address:number<span class="Special"> <- </span>get-address *editor, <span class="Constant">left:offset</span> - *left<span class="Special"> <- </span>screen-width screen - *left<span class="Special"> <- </span>divide *left, <span class="Constant">2</span> - *left<span class="Special"> <- </span>add *left, <span class="Constant">1</span> - <span class="Delimiter">}</span> - render-all screen, env - show-screen screen - <span class="muControl">loop</span> <span class="Constant">+next-event:label</span> - <span class="Delimiter">}</span> -] - -<span class="SalientComment">## running code from the editor and creating sandboxes</span> - -container sandbox-data [ - data:address:array:character - response:address:array:character - warnings:address:array:character - trace:address:array:character - expected-response:address:array:character - <span class="Comment"># coordinates to track clicks</span> - starting-row-on-screen:number - code-ending-row-on-screen:number - response-starting-row-on-screen:number - display-trace?:boolean - screen:address:screen <span class="Comment"># prints in the sandbox go here</span> - next-sandbox:address:sandbox-data -] - -<span class="muScenario">scenario</span> run-and-show-results [ - $close-trace <span class="Comment"># trace too long for github</span> - assume-screen <span class="Constant">100/width</span>, <span class="Constant">15/height</span> - <span class="Comment"># recipe editor is empty</span> - <span class="Constant">1</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[]</span> - <span class="Comment"># sandbox editor contains an instruction without storing outputs</span> - <span class="Constant">2</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[divide-with-remainder 11, 3]</span> - <span class="Constant">3</span>:address:programming-environment-data<span class="Special"> <- </span>new-programming-environment screen:address, <span class="Constant">1</span>:address:array:character, <span class="Constant">2</span>:address:array:character - <span class="Comment"># run the code in the editors</span> - assume-console [ - press <span class="Constant">65532</span> <span class="Comment"># F4</span> - ] - run [ - event-loop screen:address, console:address, <span class="Constant">3</span>:address:programming-environment-data - ] - <span class="Comment"># check that screen prints the results</span> - screen-should-contain [ - <span class="Constant"> . run (F4) .</span> - <span class="Constant"> . ┊ .</span> -<span class="Constant"> .┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┊━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━.</span> - <span class="Constant"> . ┊ x.</span> - <span class="Constant"> . ┊divide-with-remainder 11, 3 .</span> - <span class="Constant"> . ┊3 .</span> - <span class="Constant"> . ┊2 .</span> - <span class="Constant"> . ┊━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━.</span> - <span class="Constant"> . ┊ .</span> - ] - screen-should-contain-in-color <span class="Constant">7/white</span>, [ - <span class="Constant"> . .</span> - <span class="Constant"> . .</span> - <span class="Constant"> . .</span> - <span class="Constant"> . .</span> - <span class="Constant"> . divide-with-remainder 11, 3 .</span> - <span class="Constant"> . .</span> - <span class="Constant"> . .</span> - <span class="Constant"> . .</span> - <span class="Constant"> . .</span> - ] - screen-should-contain-in-color <span class="Constant">245/grey</span>, [ - <span class="Constant"> . .</span> - <span class="Constant"> . ┊ .</span> -<span class="Constant"> .┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┊━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━.</span> - <span class="Constant"> . ┊ x.</span> - <span class="Constant"> . ┊ .</span> - <span class="Constant"> . ┊3 .</span> - <span class="Constant"> . ┊2 .</span> - <span class="Constant"> . ┊━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━.</span> - <span class="Constant"> . ┊ .</span> - ] - <span class="Comment"># run another command</span> - assume-console [ - left-click <span class="Constant">1</span>, <span class="Constant">80</span> - type <span class="Constant">[add 2, 2]</span> - press <span class="Constant">65532</span> <span class="Comment"># F4</span> - ] - run [ - event-loop screen:address, console:address, <span class="Constant">3</span>:address:programming-environment-data - ] - <span class="Comment"># check that screen prints the results</span> - screen-should-contain [ - <span class="Constant"> . run (F4) .</span> - <span class="Constant"> . ┊ .</span> -<span class="Constant"> .┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┊━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━.</span> - <span class="Constant"> . ┊ x.</span> - <span class="Constant"> . ┊add 2, 2 .</span> - <span class="Constant"> . ┊4 .</span> - <span class="Constant"> . ┊━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━.</span> - <span class="Constant"> . ┊ x.</span> - <span class="Constant"> . ┊divide-with-remainder 11, 3 .</span> - <span class="Constant"> . ┊3 .</span> - <span class="Constant"> . ┊2 .</span> - <span class="Constant"> . ┊━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━.</span> - <span class="Constant"> . ┊ .</span> - ] -] - -<span class="Comment"># hook into event-loop recipe: read non-unicode keypress from k, process it if</span> -<span class="Comment"># necessary, then go to next level</span> -<span class="muRecipe">after</span> +global-keypress [ - <span class="Comment"># F4? load all code and run all sandboxes.</span> - <span class="Delimiter">{</span> - do-run?:boolean<span class="Special"> <- </span>equal *k, <span class="Constant">65532/F4</span> - <span class="muControl">break-unless</span> do-run? - status:address:array:character<span class="Special"> <- </span>new <span class="Constant">[running... ]</span> - screen<span class="Special"> <- </span>update-status screen, status, <span class="Constant">245/grey</span> - screen, error?:boolean<span class="Special"> <- </span>run-sandboxes env, screen - <span class="Comment"># F4 might update warnings and results on both sides</span> - screen<span class="Special"> <- </span>render-all screen, env - <span class="Delimiter">{</span> - <span class="muControl">break-if</span> error? - status:address:array:character<span class="Special"> <- </span>new <span class="Constant">[ ]</span> - screen<span class="Special"> <- </span>update-status screen, status, <span class="Constant">245/grey</span> - <span class="Delimiter">}</span> - screen<span class="Special"> <- </span>update-cursor screen, recipes, current-sandbox, *sandbox-in-focus? - <span class="muControl">loop</span> <span class="Constant">+next-event:label</span> - <span class="Delimiter">}</span> -] - -<span class="muRecipe">recipe</span> run-sandboxes [ - <span class="Constant">local-scope</span> - env:address:programming-environment-data<span class="Special"> <- </span><span class="Constant">next-ingredient</span> - screen:address<span class="Special"> <- </span><span class="Constant">next-ingredient</span> - recipes:address:editor-data<span class="Special"> <- </span>get *env, <span class="Constant">recipes:offset</span> - <span class="Comment"># copy code from recipe editor, persist, load into mu, save any warnings</span> - in:address:array:character<span class="Special"> <- </span>editor-contents recipes - save <span class="Constant">[recipes.mu]</span>, in - recipe-warnings:address:address:array:character<span class="Special"> <- </span>get-address *env, <span class="Constant">recipe-warnings:offset</span> - *recipe-warnings<span class="Special"> <- </span>reload in - <span class="Comment"># if recipe editor has errors, stop</span> - <span class="Delimiter">{</span> - <span class="muControl">break-unless</span> *recipe-warnings - status:address:array:character<span class="Special"> <- </span>new <span class="Constant">[errors found]</span> - update-status screen, status, <span class="Constant">1/red</span> - <span class="muControl">reply</span> screen/same-as-ingredient:<span class="Constant">1</span>, <span class="Constant">1/errors-found</span> - <span class="Delimiter">}</span> - <span class="Comment"># check contents of right editor (sandbox)</span> - current-sandbox:address:editor-data<span class="Special"> <- </span>get *env, <span class="Constant">current-sandbox:offset</span> - <span class="Delimiter">{</span> - sandbox-contents:address:array:character<span class="Special"> <- </span>editor-contents current-sandbox - <span class="muControl">break-unless</span> sandbox-contents - <span class="Comment"># if contents exist, first save them</span> - <span class="Comment"># run them and turn them into a new sandbox-data</span> - new-sandbox:address:sandbox-data<span class="Special"> <- </span>new <span class="Constant">sandbox-data:type</span> - data:address:address:array:character<span class="Special"> <- </span>get-address *new-sandbox, <span class="Constant">data:offset</span> - *data<span class="Special"> <- </span>copy sandbox-contents - <span class="Comment"># push to head of sandbox list</span> - dest:address:address:sandbox-data<span class="Special"> <- </span>get-address *env, <span class="Constant">sandbox:offset</span> - next:address:address:sandbox-data<span class="Special"> <- </span>get-address *new-sandbox, <span class="Constant">next-sandbox:offset</span> - *next<span class="Special"> <- </span>copy *dest - *dest<span class="Special"> <- </span>copy new-sandbox - <span class="Comment"># clear sandbox editor</span> - init:address:address:duplex-list<span class="Special"> <- </span>get-address *current-sandbox, <span class="Constant">data:offset</span> - *init<span class="Special"> <- </span>push-duplex <span class="Constant">167/§</span>, <span class="Constant">0/tail</span> - top-of-screen:address:address:duplex-list<span class="Special"> <- </span>get-address *current-sandbox, <span class="Constant">top-of-screen:offset</span> - *top-of-screen<span class="Special"> <- </span>copy *init - <span class="Delimiter">}</span> - <span class="Comment"># save all sandboxes before running, just in case we die when running</span> - save-sandboxes env - <span class="Comment"># run all sandboxes</span> - curr:address:sandbox-data<span class="Special"> <- </span>get *env, <span class="Constant">sandbox:offset</span> - <span class="Delimiter">{</span> - <span class="muControl">break-unless</span> curr - data<span class="Special"> <- </span>get-address *curr, <span class="Constant">data:offset</span> - response:address:address:array:character<span class="Special"> <- </span>get-address *curr, <span class="Constant">response:offset</span> - warnings:address:address:array:character<span class="Special"> <- </span>get-address *curr, <span class="Constant">warnings:offset</span> - trace:address:address:array:character<span class="Special"> <- </span>get-address *curr, <span class="Constant">trace:offset</span> - fake-screen:address:address:screen<span class="Special"> <- </span>get-address *curr, <span class="Constant">screen:offset</span> - *response, *warnings, *fake-screen, *trace, completed?:boolean<span class="Special"> <- </span>run-interactive *data - <span class="Delimiter">{</span> - <span class="muControl">break-if</span> *warnings - <span class="muControl">break-if</span> completed?:boolean - *warnings<span class="Special"> <- </span>new <span class="Constant">[took too long!</span> -<span class="Constant">]</span> - <span class="Delimiter">}</span> - curr<span class="Special"> <- </span>get *curr, <span class="Constant">next-sandbox:offset</span> - <span class="muControl">loop</span> - <span class="Delimiter">}</span> - <span class="muControl">reply</span> screen/same-as-ingredient:<span class="Constant">1</span>, <span class="Constant">0/no-errors-found</span> -] - -<span class="muRecipe">recipe</span> update-status [ - <span class="Constant">local-scope</span> - screen:address<span class="Special"> <- </span><span class="Constant">next-ingredient</span> - msg: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> - screen<span class="Special"> <- </span>move-cursor screen, <span class="Constant">0</span>, <span class="Constant">2</span> - screen<span class="Special"> <- </span>print-string screen, msg, color, <span class="Constant">238/grey/background</span> - <span class="muControl">reply</span> screen/same-as-ingredient:<span class="Constant">0</span> -] - -<span class="muRecipe">recipe</span> save-sandboxes [ - <span class="Constant">local-scope</span> - env:address:programming-environment-data<span class="Special"> <- </span><span class="Constant">next-ingredient</span> - current-sandbox:address:editor-data<span class="Special"> <- </span>get *env, <span class="Constant">current-sandbox:offset</span> - <span class="Comment"># first clear previous versions, in case we deleted some sandbox</span> - $system <span class="Constant">[rm lesson/[0-9]</span>* >/dev/null <span class="Constant">2</span>>/dev/null] <span class="Comment"># some shells can't handle '>&'</span> - curr:address:sandbox-data<span class="Special"> <- </span>get *env, <span class="Constant">sandbox:offset</span> - suffix:address:array:character<span class="Special"> <- </span>new <span class="Constant">[.out]</span> - idx:number<span class="Special"> <- </span>copy <span class="Constant">0</span> - <span class="Delimiter">{</span> - <span class="muControl">break-unless</span> curr - data:address:array:character<span class="Special"> <- </span>get *curr, <span class="Constant">data:offset</span> - filename:address:array:character<span class="Special"> <- </span>integer-to-decimal-string idx - save filename, data - <span class="Delimiter">{</span> - expected-response:address:array:character<span class="Special"> <- </span>get *curr, <span class="Constant">expected-response:offset</span> - <span class="muControl">break-unless</span> expected-response - filename<span class="Special"> <- </span>string-append filename, suffix - save filename, expected-response - <span class="Delimiter">}</span> - idx<span class="Special"> <- </span>add idx, <span class="Constant">1</span> - curr<span class="Special"> <- </span>get *curr, <span class="Constant">next-sandbox:offset</span> - <span class="muControl">loop</span> - <span class="Delimiter">}</span> -] - -<span class="muRecipe">recipe</span> render-sandbox-side [ - <span class="Constant">local-scope</span> - screen:address<span class="Special"> <- </span><span class="Constant">next-ingredient</span> - env:address:programming-environment-data<span class="Special"> <- </span><span class="Constant">next-ingredient</span> -<span class="CommentedCode">#? trace 10, [app], [render sandbox side] #? 1</span> - current-sandbox:address:editor-data<span class="Special"> <- </span>get *env, <span class="Constant">current-sandbox:offset</span> - left:number<span class="Special"> <- </span>get *current-sandbox, <span class="Constant">left:offset</span> - right:number<span class="Special"> <- </span>get *current-sandbox, <span class="Constant">right:offset</span> - row:number, column:number, screen, current-sandbox<span class="Special"> <- </span>render screen, current-sandbox - clear-screen-from screen, row, column, left, right - row<span class="Special"> <- </span>add row, <span class="Constant">1</span> - draw-horizontal screen, row, left, right, <span class="Constant">9473/horizontal-double</span> - sandbox:address:sandbox-data<span class="Special"> <- </span>get *env, <span class="Constant">sandbox:offset</span> - row, screen<span class="Special"> <- </span>render-sandboxes screen, sandbox, left, right, row - clear-rest-of-screen screen, row, left, left, right - <span class="muControl">reply</span> screen/same-as-ingredient:<span class="Constant">0</span> -] - -<span class="muRecipe">recipe</span> render-sandboxes [ - <span class="Constant">local-scope</span> - screen:address<span class="Special"> <- </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, row/same-as-ingredient:<span class="Constant">4</span>, screen/same-as-ingredient:<span class="Constant">0</span> - screen-height:number<span class="Special"> <- </span>screen-height screen - at-bottom?:boolean<span class="Special"> <- </span>greater-or-equal row, screen-height - <span class="muControl">reply-if</span> at-bottom?:boolean, row/same-as-ingredient:<span class="Constant">4</span>, screen/same-as-ingredient:<span class="Constant">0</span> - <span class="Comment"># render sandbox menu</span> - row<span class="Special"> <- </span>add row, <span class="Constant">1</span> - screen<span class="Special"> <- </span>move-cursor screen, row, left - clear-line-delimited screen, left, right - print-character screen, <span class="Constant">120/x</span>, <span class="Constant">245/grey</span> - <span class="Comment"># save menu row so we can detect clicks to it later</span> - starting-row:address:number<span class="Special"> <- </span>get-address *sandbox, <span class="Constant">starting-row-on-screen:offset</span> - *starting-row<span class="Special"> <- </span>copy row - <span class="Comment"># render sandbox contents</span> - sandbox-data:address:array:character<span class="Special"> <- </span>get *sandbox, <span class="Constant">data:offset</span> - row, screen<span class="Special"> <- </span>render-string screen, sandbox-data, left, right, <span class="Constant">7/white</span>, row - code-ending-row:address:number<span class="Special"> <- </span>get-address *sandbox, <span class="Constant">code-ending-row-on-screen:offset</span> - *code-ending-row<span class="Special"> <- </span>copy row - <span class="Comment"># render sandbox warnings, screen or response, in that order</span> - response-starting-row:address:number<span class="Special"> <- </span>get-address *sandbox, <span class="Constant">response-starting-row-on-screen:offset</span> - sandbox-response:address:array:character<span class="Special"> <- </span>get *sandbox, <span class="Constant">response:offset</span> - sandbox-warnings:address:array:character<span class="Special"> <- </span>get *sandbox, <span class="Constant">warnings:offset</span> - sandbox-screen:address<span class="Special"> <- </span>get *sandbox, <span class="Constant">screen:offset</span> -<span class="Constant"> +render-sandbox-results</span> - <span class="Delimiter">{</span> - <span class="muControl">break-unless</span> sandbox-warnings - *response-starting-row<span class="Special"> <- </span>copy <span class="Constant">0</span> <span class="Comment"># no response</span> - row, screen<span class="Special"> <- </span>render-string screen, sandbox-warnings, left, right, <span class="Constant">1/red</span>, row - <span class="Delimiter">}</span> - <span class="Delimiter">{</span> - <span class="muControl">break-if</span> sandbox-warnings - empty-screen?:boolean<span class="Special"> <- </span>fake-screen-is-empty? sandbox-screen - <span class="muControl">break-if</span> empty-screen? - row, screen<span class="Special"> <- </span>render-screen screen, sandbox-screen, left, right, row - <span class="Delimiter">}</span> - <span class="Delimiter">{</span> - <span class="muControl">break-if</span> sandbox-warnings - <span class="muControl">break-unless</span> empty-screen? -<span class="CommentedCode">#? $print [display response from ], row, 10/newline #? 1</span> - *response-starting-row<span class="Special"> <- </span>add row, <span class="Constant">1</span> -<span class="Constant"> +render-sandbox-response</span> - row, screen<span class="Special"> <- </span>render-string screen, sandbox-response, left, right, <span class="Constant">245/grey</span>, row - <span class="Delimiter">}</span> -<span class="Constant"> +render-sandbox-end</span> - at-bottom?:boolean<span class="Special"> <- </span>greater-or-equal row, screen-height - <span class="muControl">reply-if</span> at-bottom?, row/same-as-ingredient:<span class="Constant">4</span>, screen/same-as-ingredient:<span class="Constant">0</span> - <span class="Comment"># draw solid line after sandbox</span> - draw-horizontal screen, row, left, right, <span class="Constant">9473/horizontal-double</span> - <span class="Comment"># draw next sandbox</span> - next-sandbox:address:sandbox-data<span class="Special"> <- </span>get *sandbox, <span class="Constant">next-sandbox:offset</span> - row, screen<span class="Special"> <- </span>render-sandboxes screen, next-sandbox, left, right, row - <span class="muControl">reply</span> row/same-as-ingredient:<span class="Constant">4</span>, screen/same-as-ingredient:<span class="Constant">0</span> -] - -<span class="Comment"># assumes programming environment has no sandboxes; restores them from previous session</span> -<span class="muRecipe">recipe</span> restore-sandboxes [ - <span class="Constant">local-scope</span> - env:address:programming-environment-data<span class="Special"> <- </span><span class="Constant">next-ingredient</span> - <span class="Comment"># read all scenarios, pushing them to end of a list of scenarios</span> - suffix:address:array:character<span class="Special"> <- </span>new <span class="Constant">[.out]</span> - idx:number<span class="Special"> <- </span>copy <span class="Constant">0</span> - curr:address:address:sandbox-data<span class="Special"> <- </span>get-address *env, <span class="Constant">sandbox:offset</span> - <span class="Delimiter">{</span> - filename:address:array:character<span class="Special"> <- </span>integer-to-decimal-string idx - contents:address:array:character<span class="Special"> <- </span>restore filename - <span class="muControl">break-unless</span> contents <span class="Comment"># stop at first error; assuming file didn't exist</span> - <span class="Comment"># create new sandbox for file</span> - *curr<span class="Special"> <- </span>new <span class="Constant">sandbox-data:type</span> - data:address:address:array:character<span class="Special"> <- </span>get-address **curr, <span class="Constant">data:offset</span> - *data<span class="Special"> <- </span>copy contents - <span class="Comment"># restore expected output for sandbox if it exists</span> - <span class="Delimiter">{</span> - filename<span class="Special"> <- </span>string-append filename, suffix - contents<span class="Special"> <- </span>restore filename - <span class="muControl">break-unless</span> contents - expected-response:address:address:array:character<span class="Special"> <- </span>get-address **curr, <span class="Constant">expected-response:offset</span> - *expected-response<span class="Special"> <- </span>copy contents - <span class="Delimiter">}</span> -<span class="Constant"> +continue</span> - idx<span class="Special"> <- </span>add idx, <span class="Constant">1</span> - curr<span class="Special"> <- </span>get-address **curr, <span class="Constant">next-sandbox:offset</span> - <span class="muControl">loop</span> - <span class="Delimiter">}</span> - <span class="muControl">reply</span> env/same-as-ingredient:<span class="Constant">0</span> -] - -<span class="Comment"># row, screen <- 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<span class="Special"> <- </span>add row, <span class="Constant">1</span> - <span class="muControl">reply-unless</span> s, row/same-as-ingredient:<span class="Constant">4</span>, screen/same-as-ingredient:<span class="Constant">0</span> - <span class="Comment"># print 'screen:'</span> - header:address:array:character<span class="Special"> <- </span>new <span class="Constant">[screen:]</span> - row<span class="Special"> <- </span>subtract row, <span class="Constant">1</span> <span class="Comment"># compensate for render-string below</span> - row<span class="Special"> <- </span>render-string screen, header, left, right, <span class="Constant">245/grey</span>, row - <span class="Comment"># newline</span> - row<span class="Special"> <- </span>add row, <span class="Constant">1</span> - screen<span class="Special"> <- </span>move-cursor screen, row, left - <span class="Comment"># start printing s</span> - column:number<span class="Special"> <- </span>copy left - s-width:number<span class="Special"> <- </span>screen-width s - s-height:number<span class="Special"> <- </span>screen-height s - buf:address:array:screen-cell<span class="Special"> <- </span>get *s, <span class="Constant">data:offset</span> - stop-printing:number<span class="Special"> <- </span>add left, s-width, <span class="Constant">3</span> - max-column:number<span class="Special"> <- </span>min stop-printing, right - i:number<span class="Special"> <- </span>copy <span class="Constant">0</span> - len:number<span class="Special"> <- </span>length *buf - screen-height:number<span class="Special"> <- </span>screen-height screen - <span class="Delimiter">{</span> - done?:boolean<span class="Special"> <- </span>greater-or-equal i, len - <span class="muControl">break-if</span> done? - done?<span class="Special"> <- </span>greater-or-equal row, screen-height - <span class="muControl">break-if</span> done? - column<span class="Special"> <- </span>copy left - screen<span class="Special"> <- </span>move-cursor screen, row, column - <span class="Comment"># initial leader for each row: two spaces and a '.'</span> - print-character screen, <span class="Constant">32/space</span>, <span class="Constant">245/grey</span> - print-character screen, <span class="Constant">32/space</span>, <span class="Constant">245/grey</span> - print-character screen, <span class="Constant">46/full-stop</span>, <span class="Constant">245/grey</span> - column<span class="Special"> <- </span>add left, <span class="Constant">3</span> - <span class="Delimiter">{</span> - <span class="Comment"># print row</span> - row-done?:boolean<span class="Special"> <- </span>greater-or-equal column, max-column - <span class="muControl">break-if</span> row-done? - curr:screen-cell<span class="Special"> <- </span>index *buf, i - c:character<span class="Special"> <- </span>get curr, <span class="Constant">contents:offset</span> - print-character screen, c, <span class="Constant">245/grey</span> - column<span class="Special"> <- </span>add column, <span class="Constant">1</span> - i<span class="Special"> <- </span>add i, <span class="Constant">1</span> - <span class="muControl">loop</span> - <span class="Delimiter">}</span> - <span class="Comment"># print final '.'</span> - print-character screen, <span class="Constant">46/full-stop</span>, <span class="Constant">245/grey</span> - column<span class="Special"> <- </span>add column, <span class="Constant">1</span> - <span class="Delimiter">{</span> - <span class="Comment"># clear rest of current line</span> - line-done?:boolean<span class="Special"> <- </span>greater-than column, right - <span class="muControl">break-if</span> line-done? - print-character screen, <span class="Constant">32/space</span> - column<span class="Special"> <- </span>add column, <span class="Constant">1</span> - <span class="muControl">loop</span> - <span class="Delimiter">}</span> - row<span class="Special"> <- </span>add row, <span class="Constant">1</span> - <span class="muControl">loop</span> - <span class="Delimiter">}</span> - <span class="muControl">reply</span> row/same-as-ingredient:<span class="Constant">4</span>, screen/same-as-ingredient:<span class="Constant">0</span> -] - -<span class="muScenario">scenario</span> run-updates-results [ - $close-trace <span class="Comment"># trace too long for github</span> - assume-screen <span class="Constant">100/width</span>, <span class="Constant">12/height</span> - <span class="Comment"># define a recipe (no indent for the 'add' line below so column numbers are more obvious)</span> - <span class="Constant">1</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[ </span> -<span class="Constant">recipe foo [</span> -<span class="Constant">z:number <- add 2, 2</span> -<span class="Constant">]</span>] - <span class="Comment"># sandbox editor contains an instruction without storing outputs</span> - <span class="Constant">2</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[foo]</span> - <span class="Constant">3</span>:address:programming-environment-data<span class="Special"> <- </span>new-programming-environment screen:address, <span class="Constant">1</span>:address:array:character, <span class="Constant">2</span>:address:array:character - <span class="Comment"># run the code in the editors</span> - assume-console [ - press <span class="Constant">65532</span> <span class="Comment"># F4</span> - ] - run [ - event-loop screen:address, console:address, <span class="Constant">3</span>:address:programming-environment-data - ] - <span class="Comment"># check that screen prints the results</span> - screen-should-contain [ - <span class="Constant"> . run (F4) .</span> - <span class="Constant"> . ┊ .</span> - <span class="Constant"> .recipe foo [ ┊━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━.</span> - <span class="Constant"> .z:number <- add 2, 2 ┊ x.</span> - <span class="Constant"> .] ┊foo .</span> - <span class="Constant"> .┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┊4 .</span> - <span class="Constant"> . ┊━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━.</span> - <span class="Constant"> . ┊ .</span> - ] - <span class="Comment"># make a change (incrementing one of the args to 'add'), then rerun</span> - assume-console [ - left-click <span class="Constant">3</span>, <span class="Constant">28</span> <span class="Comment"># one past the value of the second arg</span> - type <span class="Constant">[«3]</span> <span class="Comment"># replace</span> - press <span class="Constant">65532</span> <span class="Comment"># F4</span> - ] - <span class="Constant">4</span>:event/backspace<span class="Special"> <- </span>merge <span class="Constant">0/text</span>, <span class="Constant">8/backspace</span>, <span class="Constant">0/dummy</span>, <span class="Constant">0/dummy</span> - replace-in-console <span class="Constant">171/«</span>, <span class="Constant">4</span>:event/backspace - run [ - event-loop screen:address, console:address, <span class="Constant">3</span>:address:programming-environment-data - ] - <span class="Comment"># check that screen updates the result on the right</span> - screen-should-contain [ - <span class="Constant"> . run (F4) .</span> - <span class="Constant"> . ┊ .</span> - <span class="Constant"> .recipe foo [ ┊━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━.</span> - <span class="Constant"> .z:number <- add 2, 3 ┊ x.</span> - <span class="Constant"> .] ┊foo .</span> - <span class="Constant"> .┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┊5 .</span> - <span class="Constant"> . ┊━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━.</span> - <span class="Constant"> . ┊ .</span> - ] -] - -<span class="muScenario">scenario</span> run-instruction-and-print-warnings [ - $close-trace <span class="Comment"># trace too long for github</span> - assume-screen <span class="Constant">100/width</span>, <span class="Constant">10/height</span> - <span class="Comment"># left editor is empty</span> - <span class="Constant">1</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[]</span> - <span class="Comment"># right editor contains an illegal instruction</span> - <span class="Constant">2</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[get 1234:number, foo:offset]</span> - <span class="Constant">3</span>:address:programming-environment-data<span class="Special"> <- </span>new-programming-environment screen:address, <span class="Constant">1</span>:address:array:character, <span class="Constant">2</span>:address:array:character - <span class="Comment"># run the code in the editors</span> - assume-console [ - press <span class="Constant">65532</span> <span class="Comment"># F4</span> - ] - run [ - event-loop screen:address, console:address, <span class="Constant">3</span>:address:programming-environment-data - ] - <span class="Comment"># check that screen prints error message in red</span> - screen-should-contain [ - <span class="Constant"> . run (F4) .</span> - <span class="Constant"> . ┊ .</span> -<span class="Constant"> .┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┊━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━.</span> - <span class="Constant"> . ┊ x.</span> - <span class="Constant"> . ┊get 1234:number, foo:offset .</span> - <span class="Constant"> . ┊unknown element foo in container number .</span> - <span class="Constant"> . ┊━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━.</span> - <span class="Constant"> . ┊ .</span> - ] - screen-should-contain-in-color <span class="Constant">7/white</span>, [ - <span class="Constant"> . .</span> - <span class="Constant"> . .</span> - <span class="Constant"> . .</span> - <span class="Constant"> . .</span> - <span class="Constant"> . get 1234:number, foo:offset .</span> - <span class="Constant"> . .</span> - <span class="Constant"> . .</span> - <span class="Constant"> . .</span> - ] - screen-should-contain-in-color <span class="Constant">1/red</span>, [ - <span class="Constant"> . .</span> - <span class="Constant"> . .</span> - <span class="Constant"> . .</span> - <span class="Constant"> . .</span> - <span class="Constant"> . .</span> - <span class="Constant"> . unknown element foo in container number .</span> - <span class="Constant"> . .</span> - ] - screen-should-contain-in-color <span class="Constant">245/grey</span>, [ - <span class="Constant"> . .</span> - <span class="Constant"> . ┊ .</span> -<span class="Constant"> .┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┊━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━.</span> - <span class="Constant"> . ┊ x.</span> - <span class="Constant"> . ┊ .</span> - <span class="Constant"> . ┊ .</span> - <span class="Constant"> . ┊━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━.</span> - <span class="Constant"> . ┊ .</span> - ] -] - -<span class="muScenario">scenario</span> run-instruction-and-print-warnings-only-once [ - $close-trace <span class="Comment"># trace too long for github</span> - assume-screen <span class="Constant">100/width</span>, <span class="Constant">10/height</span> - <span class="Comment"># left editor is empty</span> - <span class="Constant">1</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[]</span> - <span class="Comment"># right editor contains an illegal instruction</span> - <span class="Constant">2</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[get 1234:number, foo:offset]</span> - <span class="Constant">3</span>:address:programming-environment-data<span class="Special"> <- </span>new-programming-environment screen:address, <span class="Constant">1</span>:address:array:character, <span class="Constant">2</span>:address:array:character - <span class="Comment"># run the code in the editors multiple times</span> - assume-console [ - press <span class="Constant">65532</span> <span class="Comment"># F4</span> - press <span class="Constant">65532</span> <span class="Comment"># F4</span> - ] - run [ - event-loop screen:address, console:address, <span class="Constant">3</span>:address:programming-environment-data - ] - <span class="Comment"># check that screen prints error message just once</span> - screen-should-contain [ - <span class="Constant"> . run (F4) .</span> - <span class="Constant"> . ┊ .</span> -<span class="Constant"> .┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┊━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━.</span> - <span class="Constant"> . ┊ x.</span> - <span class="Constant"> . ┊get 1234:number, foo:offset .</span> - <span class="Constant"> . ┊unknown element foo in container number .</span> - <span class="Constant"> . ┊━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━.</span> - <span class="Constant"> . ┊ .</span> - ] -] - -<span class="muScenario">scenario</span> run-instruction-manages-screen-per-sandbox [ - $close-trace <span class="Comment"># trace too long for github</span> - assume-screen <span class="Constant">100/width</span>, <span class="Constant">20/height</span> - <span class="Comment"># left editor is empty</span> - <span class="Constant">1</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[]</span> - <span class="Comment"># right editor contains an instruction</span> - <span class="Constant">2</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[print-integer screen:address, 4]</span> - <span class="Constant">3</span>:address:programming-environment-data<span class="Special"> <- </span>new-programming-environment screen:address, <span class="Constant">1</span>:address:array:character, <span class="Constant">2</span>:address:array:character - <span class="Comment"># run the code in the editor</span> - assume-console [ - press <span class="Constant">65532</span> <span class="Comment"># F4</span> - ] - run [ - event-loop screen:address, console:address, <span class="Constant">3</span>:address:programming-environment-data - ] - <span class="Comment"># check that it prints a little toy screen</span> - screen-should-contain [ - <span class="Constant"> . run (F4) .</span> - <span class="Constant"> . ┊ .</span> -<span class="Constant"> .┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┊━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━.</span> - <span class="Constant"> . ┊ x.</span> - <span class="Constant"> . ┊print-integer screen:address, 4 .</span> - <span class="Constant"> . ┊screen: .</span> - <span class="Constant"> . ┊ .4 . .</span> - <span class="Constant"> . ┊ . . .</span> - <span class="Constant"> . ┊ . . .</span> - <span class="Constant"> . ┊ . . .</span> - <span class="Constant"> . ┊ . . .</span> - <span class="Constant"> . ┊━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━.</span> - <span class="Constant"> . ┊ .</span> - ] -] - -<span class="muScenario">scenario</span> sandbox-with-print-can-be-edited [ -<span class="Constant"> $close-trace</span> - assume-screen <span class="Constant">100/width</span>, <span class="Constant">20/height</span> - <span class="Comment"># left editor is empty</span> - <span class="Constant">1</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[]</span> - <span class="Comment"># right editor contains an instruction</span> - <span class="Constant">2</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[print-integer screen:address, 4]</span> - <span class="Constant">3</span>:address:programming-environment-data<span class="Special"> <- </span>new-programming-environment screen:address, <span class="Constant">1</span>:address:array:character, <span class="Constant">2</span>:address:array:character - <span class="Comment"># run the sandbox</span> - assume-console [ - press <span class="Constant">65532</span> <span class="Comment"># F4</span> - ] - run [ - event-loop screen:address, console:address, <span class="Constant">3</span>:address:programming-environment-data - ] - screen-should-contain [ - <span class="Constant"> . run (F4) .</span> - <span class="Constant"> . ┊ .</span> -<span class="Constant"> .┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┊━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━.</span> - <span class="Constant"> . ┊ x.</span> - <span class="Constant"> . ┊print-integer screen:address, 4 .</span> - <span class="Constant"> . ┊screen: .</span> - <span class="Constant"> . ┊ .4 . .</span> - <span class="Constant"> . ┊ . . .</span> - <span class="Constant"> . ┊ . . .</span> - <span class="Constant"> . ┊ . . .</span> - <span class="Constant"> . ┊ . . .</span> - <span class="Constant"> . ┊━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━.</span> - <span class="Constant"> . ┊ .</span> - ] - <span class="Comment"># edit the sandbox</span> - assume-console [ - left-click <span class="Constant">3</span>, <span class="Constant">70</span> - ] - run [ - event-loop screen:address, console:address, <span class="Constant">3</span>:address:programming-environment-data - ] - screen-should-contain [ - <span class="Constant"> . run (F4) .</span> - <span class="Constant"> . ┊print-integer screen:address, 4 .</span> -<span class="Constant"> .┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┊━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━.</span> - <span class="Constant"> . ┊ .</span> - <span class="Constant"> . ┊ .</span> - ] -] - -<span class="muScenario">scenario</span> sandbox-can-handle-infinite-loop [ -<span class="Constant"> $close-trace</span> - assume-screen <span class="Constant">100/width</span>, <span class="Constant">20/height</span> - <span class="Comment"># left editor is empty</span> - <span class="Constant">1</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[recipe foo [</span> -<span class="Constant"> {</span> -<span class="Constant"> loop</span> -<span class="Constant"> }</span> -<span class="Constant">]</span>] - <span class="Comment"># right editor contains an instruction</span> - <span class="Constant">2</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[foo]</span> - <span class="Constant">3</span>:address:programming-environment-data<span class="Special"> <- </span>new-programming-environment screen:address, <span class="Constant">1</span>:address:array:character, <span class="Constant">2</span>:address:array:character - <span class="Comment"># run the sandbox</span> - assume-console [ - press <span class="Constant">65532</span> <span class="Comment"># F4</span> - ] - run [ - event-loop screen:address, console:address, <span class="Constant">3</span>:address:programming-environment-data - ] - screen-should-contain [ - <span class="Constant"> . run (F4) .</span> - <span class="Constant"> .recipe foo [ ┊ .</span> - <span class="Constant"> . { ┊━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━.</span> - <span class="Constant"> . loop ┊ x.</span> - <span class="Constant"> . } ┊foo .</span> - <span class="Constant"> .] ┊took too long! .</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</span> - curr:address:duplex-list<span class="Special"> <- </span>get *editor, <span class="Constant">data:offset</span> - <span class="Comment"># skip § sentinel</span> - assert curr, <span class="Constant">[editor without data is illegal; must have at least a sentinel]</span> - curr<span class="Special"> <- </span>next-duplex curr - <span class="muControl">reply-unless</span> curr, <span class="Constant">0</span> - <span class="Delimiter">{</span> - <span class="muControl">break-unless</span> curr - c:character<span class="Special"> <- </span>get *curr, <span class="Constant">value:offset</span> - buffer-append buf, c - curr<span class="Special"> <- </span>next-duplex curr - <span class="muControl">loop</span> - <span class="Delimiter">}</span> - result:address:array:character<span class="Special"> <- </span>buffer-to-array buf - <span class="muControl">reply</span> result -] - -<span class="muScenario">scenario</span> editor-provides-edited-contents [ - assume-screen <span class="Constant">10/width</span>, <span class="Constant">5/height</span> - <span class="Constant">1</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[abc]</span> - <span class="Constant">2</span>:address:editor-data<span class="Special"> <- </span>new-editor <span class="Constant">1</span>:address:array:character, screen:address, <span class="Constant">0/left</span>, <span class="Constant">10/right</span> - assume-console [ - left-click <span class="Constant">1</span>, <span class="Constant">2</span> - type <span class="Constant">[def]</span> - ] - run [ - editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data - <span class="Constant">3</span>:address:array:character<span class="Special"> <- </span>editor-contents <span class="Constant">2</span>:address:editor-data - <span class="Constant">4</span>:array:character<span class="Special"> <- </span>copy *<span class="Constant">3</span>:address:array:character - ] - memory-should-contain [ - <span class="Constant">4</span>:string<span class="Special"> <- </span><span class="Constant">[abdefc]</span> - ] -] - -<span class="SalientComment">## editing sandboxes after they've been created</span> - -<span class="muScenario">scenario</span> clicking-on-a-sandbox-moves-it-to-editor [ -<span class="Constant"> $close-trace</span> - assume-screen <span class="Constant">40/width</span>, <span class="Constant">10/height</span> - <span class="Comment"># basic recipe</span> - <span class="Constant">1</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[ </span> -<span class="Constant">recipe foo [</span> -<span class="Constant"> add 2, 2</span> -<span class="Constant">]</span>] - <span class="Comment"># run it</span> - <span class="Constant">2</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[foo]</span> - assume-console [ - press <span class="Constant">65532</span> <span class="Comment"># F4</span> - ] - <span class="Constant">3</span>:address:programming-environment-data<span class="Special"> <- </span>new-programming-environment screen:address, <span class="Constant">1</span>:address:array:character, <span class="Constant">2</span>:address:array:character - event-loop screen:address, console:address, <span class="Constant">3</span>:address:programming-environment-data - screen-should-contain [ - <span class="Constant"> . run (F4) .</span> - <span class="Constant"> . ┊ .</span> - <span class="Constant"> .recipe foo [ ┊━━━━━━━━━━━━━━━━━━━.</span> - <span class="Constant"> . add 2, 2 ┊ x.</span> - <span class="Constant"> .] ┊foo .</span> - <span class="Constant"> .┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┊4 .</span> - <span class="Constant"> . ┊━━━━━━━━━━━━━━━━━━━.</span> - <span class="Constant"> . ┊ .</span> - ] - <span class="Comment"># click somewhere on the sandbox</span> - assume-console [ - left-click <span class="Constant">3</span>, <span class="Constant">30</span> - ] - run [ - event-loop screen:address, console:address, <span class="Constant">3</span>:address:programming-environment-data - ] - <span class="Comment"># it pops back into editor</span> - screen-should-contain [ - <span class="Constant"> . run (F4) .</span> - <span class="Constant"> . ┊foo .</span> - <span class="Constant"> .recipe foo [ ┊━━━━━━━━━━━━━━━━━━━.</span> - <span class="Constant"> . add 2, 2 ┊ .</span> - <span class="Constant"> .] ┊ .</span> - <span class="Constant"> .┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┊ .</span> - <span class="Constant"> . ┊ .</span> - <span class="Constant"> . ┊ .</span> - ] -] - -<span class="muRecipe">after</span> +global-touch [ - <span class="Comment"># right side of screen and below sandbox editor? pop appropriate sandbox</span> - <span class="Comment"># contents back into sandbox editor provided it's empty</span> - <span class="Delimiter">{</span> - sandbox-left-margin:number<span class="Special"> <- </span>get *current-sandbox, <span class="Constant">left:offset</span> - click-column:number<span class="Special"> <- </span>get *t, <span class="Constant">column:offset</span> - on-sandbox-side?:boolean<span class="Special"> <- </span>greater-or-equal click-column, sandbox-left-margin - <span class="muControl">break-unless</span> on-sandbox-side? - first-sandbox:address:sandbox-data<span class="Special"> <- </span>get *env, <span class="Constant">sandbox:offset</span> - <span class="muControl">break-unless</span> first-sandbox - first-sandbox-begins:number<span class="Special"> <- </span>get *first-sandbox, <span class="Constant">starting-row-on-screen:offset</span> - click-row:number<span class="Special"> <- </span>get *t, <span class="Constant">row:offset</span> - below-sandbox-editor?:boolean<span class="Special"> <- </span>greater-or-equal click-row, first-sandbox-begins - <span class="muControl">break-unless</span> below-sandbox-editor? - empty-sandbox-editor?:boolean<span class="Special"> <- </span>empty-editor? current-sandbox - <span class="muControl">break-unless</span> empty-sandbox-editor? <span class="Comment"># make the user hit F4 before editing a new sandbox</span> - <span class="Comment"># identify the sandbox to edit and remove it from the sandbox list</span> - sandbox:address:sandbox-data<span class="Special"> <- </span>extract-sandbox env, click-row - text:address:array:character<span class="Special"> <- </span>get *sandbox, <span class="Constant">data:offset</span> - current-sandbox<span class="Special"> <- </span>insert-text current-sandbox, text - hide-screen screen - screen<span class="Special"> <- </span>render-sandbox-side screen, env - screen<span class="Special"> <- </span>update-cursor screen, recipes, current-sandbox, *sandbox-in-focus? - show-screen screen - <span class="muControl">loop</span> <span class="Constant">+next-event:label</span> - <span class="Delimiter">}</span> -] - -<span class="muRecipe">recipe</span> empty-editor? [ - <span class="Constant">local-scope</span> - editor:address:editor-data<span class="Special"> <- </span><span class="Constant">next-ingredient</span> - head:address:duplex-list<span class="Special"> <- </span>get *editor, <span class="Constant">data:offset</span> - first:address:duplex-list<span class="Special"> <- </span>next-duplex head - result:boolean<span class="Special"> <- </span>not first - <span class="muControl">reply</span> result -] - -<span class="muRecipe">recipe</span> extract-sandbox [ - <span class="Constant">local-scope</span> - env:address:programming-environment-data<span class="Special"> <- </span><span class="Constant">next-ingredient</span> - click-row:number<span class="Special"> <- </span><span class="Constant">next-ingredient</span> - <span class="Comment"># assert click-row >= sandbox.starting-row-on-screen</span> - sandbox:address:address:sandbox-data<span class="Special"> <- </span>get-address *env, <span class="Constant">sandbox:offset</span> - start:number<span class="Special"> <- </span>get **sandbox, <span class="Constant">starting-row-on-screen:offset</span> - clicked-on-sandboxes?:boolean<span class="Special"> <- </span>greater-or-equal click-row, start - assert clicked-on-sandboxes?, <span class="Constant">[extract-sandbox called on click to sandbox editor]</span> - <span class="Delimiter">{</span> - next-sandbox:address:sandbox-data<span class="Special"> <- </span>get **sandbox, <span class="Constant">next-sandbox:offset</span> - <span class="muControl">break-unless</span> next-sandbox - <span class="Comment"># if click-row < sandbox.next-sandbox.starting-row-on-screen, break</span> - next-start:number<span class="Special"> <- </span>get *next-sandbox, <span class="Constant">starting-row-on-screen:offset</span> - found?:boolean<span class="Special"> <- </span>lesser-than click-row, next-start - <span class="muControl">break-if</span> found? - sandbox<span class="Special"> <- </span>get-address **sandbox, <span class="Constant">next-sandbox:offset</span> - <span class="muControl">loop</span> - <span class="Delimiter">}</span> - <span class="Comment"># snip sandbox out of its list</span> - result:address:sandbox-data<span class="Special"> <- </span>copy *sandbox - *sandbox<span class="Special"> <- </span>copy next-sandbox - <span class="muControl">reply</span> result -] - -<span class="SalientComment">## deleting sandboxes</span> - -<span class="muScenario">scenario</span> deleting-sandboxes [ - $close-trace <span class="Comment"># trace too long for github</span> - assume-screen <span class="Constant">100/width</span>, <span class="Constant">15/height</span> - <span class="Constant">1</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[]</span> - <span class="Constant">2</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[]</span> - <span class="Constant">3</span>:address:programming-environment-data<span class="Special"> <- </span>new-programming-environment screen:address, <span class="Constant">1</span>:address:array:character, <span class="Constant">2</span>:address:array:character - <span class="Comment"># run a few commands</span> - assume-console [ - left-click <span class="Constant">1</span>, <span class="Constant">80</span> - type <span class="Constant">[divide-with-remainder 11, 3]</span> - press <span class="Constant">65532</span> <span class="Comment"># F4</span> - type <span class="Constant">[add 2, 2]</span> - press <span class="Constant">65532</span> <span class="Comment"># F4</span> - ] - run [ - event-loop screen:address, console:address, <span class="Constant">3</span>:address:programming-environment-data - ] - screen-should-contain [ - <span class="Constant"> . run (F4) .</span> - <span class="Constant"> . ┊ .</span> -<span class="Constant"> .┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┊━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━.</span> - <span class="Constant"> . ┊ x.</span> - <span class="Constant"> . ┊add 2, 2 .</span> - <span class="Constant"> . ┊4 .</span> - <span class="Constant"> . ┊━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━.</span> - <span class="Constant"> . ┊ x.</span> - <span class="Constant"> . ┊divide-with-remainder 11, 3 .</span> - <span class="Constant"> . ┊3 .</span> - <span class="Constant"> . ┊2 .</span> - <span class="Constant"> . ┊━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━.</span> - <span class="Constant"> . ┊ .</span> - ] - <span class="Comment"># delete second sandbox</span> - assume-console [ - left-click <span class="Constant">7</span>, <span class="Constant">99</span> - ] - run [ - event-loop screen:address, console:address, <span class="Constant">3</span>:address:programming-environment-data - ] - screen-should-contain [ - <span class="Constant"> . run (F4) .</span> - <span class="Constant"> . ┊ .</span> -<span class="Constant"> .┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┊━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━.</span> - <span class="Constant"> . ┊ x.</span> - <span class="Constant"> . ┊add 2, 2 .</span> - <span class="Constant"> . ┊4 .</span> - <span class="Constant"> . ┊━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━.</span> - <span class="Constant"> . ┊ .</span> - <span class="Constant"> . ┊ .</span> - ] - <span class="Comment"># delete first sandbox</span> - assume-console [ - left-click <span class="Constant">3</span>, <span class="Constant">99</span> - ] - run [ - event-loop screen:address, console:address, <span class="Constant">3</span>:address:programming-environment-data - ] - screen-should-contain [ - <span class="Constant"> . run (F4) .</span> - <span class="Constant"> . ┊ .</span> -<span class="Constant"> .┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┊━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━.</span> - <span class="Constant"> . ┊ .</span> - <span class="Constant"> . ┊ .</span> - ] -] - -<span class="muRecipe">after</span> +global-touch [ - <span class="Comment"># on a sandbox delete icon? process delete</span> - <span class="Delimiter">{</span> - was-delete?:boolean<span class="Special"> <- </span>delete-sandbox *t, env - <span class="muControl">break-unless</span> was-delete? -<span class="CommentedCode">#? trace 10, [app], [delete clicked] #? 1</span> - hide-screen screen - screen<span class="Special"> <- </span>render-sandbox-side screen, env - screen<span class="Special"> <- </span>update-cursor screen, recipes, current-sandbox, *sandbox-in-focus? - show-screen screen - <span class="muControl">loop</span> <span class="Constant">+next-event:label</span> - <span class="Delimiter">}</span> -] - -<span class="Comment"># was-deleted?:boolean <- 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, <span class="Constant">column:offset</span> - current-sandbox:address:editor-data<span class="Special"> <- </span>get *env, <span class="Constant">current-sandbox:offset</span> - right:number<span class="Special"> <- </span>get *current-sandbox, <span class="Constant">right:offset</span> - at-right?:boolean<span class="Special"> <- </span>equal click-column, right - <span class="muControl">reply-unless</span> at-right?, <span class="Constant">0/false</span> - click-row:number<span class="Special"> <- </span>get t, <span class="Constant">row:offset</span> - prev:address:address:sandbox-data<span class="Special"> <- </span>get-address *env, <span class="Constant">sandbox:offset</span> - curr:address:sandbox-data<span class="Special"> <- </span>get *env, <span class="Constant">sandbox:offset</span> - <span class="Delimiter">{</span> - <span class="muControl">break-unless</span> curr - <span class="Comment"># more sandboxes to check</span> - <span class="Delimiter">{</span> - target-row:number<span class="Special"> <- </span>get *curr, <span class="Constant">starting-row-on-screen:offset</span> - delete-curr?:boolean<span class="Special"> <- </span>equal target-row, click-row - <span class="muControl">break-unless</span> delete-curr? - <span class="Comment"># delete this sandbox, rerender and stop</span> - *prev<span class="Special"> <- </span>get *curr, <span class="Constant">next-sandbox:offset</span> - <span class="muControl">reply</span> <span class="Constant">1/true</span> - <span class="Delimiter">}</span> - prev<span class="Special"> <- </span>get-address *curr, <span class="Constant">next-sandbox:offset</span> - curr<span class="Special"> <- </span>get *curr, <span class="Constant">next-sandbox:offset</span> - <span class="muControl">loop</span> - <span class="Delimiter">}</span> - <span class="muControl">reply</span> <span class="Constant">0/false</span> -] - -<span class="SalientComment">## clicking on sandbox results to 'fix' them and turn sandboxes into tests</span> - -<span class="muScenario">scenario</span> sandbox-click-on-result-toggles-color-to-green [ -<span class="Constant"> $close-trace</span> - assume-screen <span class="Constant">40/width</span>, <span class="Constant">10/height</span> - <span class="Comment"># basic recipe</span> - <span class="Constant">1</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[ </span> -<span class="Constant">recipe foo [</span> -<span class="Constant"> add 2, 2</span> -<span class="Constant">]</span>] - <span class="Comment"># run it</span> - <span class="Constant">2</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[foo]</span> - assume-console [ - press <span class="Constant">65532</span> <span class="Comment"># F4</span> - ] - <span class="Constant">3</span>:address:programming-environment-data<span class="Special"> <- </span>new-programming-environment screen:address, <span class="Constant">1</span>:address:array:character, <span class="Constant">2</span>:address:array:character - event-loop screen:address, console:address, <span class="Constant">3</span>:address:programming-environment-data - screen-should-contain [ - <span class="Constant"> . run (F4) .</span> - <span class="Constant"> . ┊ .</span> - <span class="Constant"> .recipe foo [ ┊━━━━━━━━━━━━━━━━━━━.</span> - <span class="Constant"> . add 2, 2 ┊ x.</span> - <span class="Constant"> .] ┊foo .</span> - <span class="Constant"> .┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┊4 .</span> - <span class="Constant"> . ┊━━━━━━━━━━━━━━━━━━━.</span> - <span class="Constant"> . ┊ .</span> - ] - <span class="Comment"># click on the '4' in the result</span> - assume-console [ - left-click <span class="Constant">5</span>, <span class="Constant">21</span> - ] - run [ - event-loop screen:address, console:address, <span class="Constant">3</span>:address:programming-environment-data - ] - <span class="Comment"># color toggles to green</span> - screen-should-contain-in-color <span class="Constant">2/green</span>, [ - <span class="Constant"> . .</span> - <span class="Constant"> . .</span> - <span class="Constant"> . .</span> - <span class="Constant"> . .</span> - <span class="Constant"> . .</span> - <span class="Constant"> . 4 .</span> - <span class="Constant"> . .</span> - <span class="Constant"> . .</span> - ] - <span class="Comment"># now change the second arg of the 'add'</span> - <span class="Comment"># then rerun</span> - assume-console [ - left-click <span class="Constant">3</span>, <span class="Constant">11</span> <span class="Comment"># cursor to end of line</span> - type <span class="Constant">[«3]</span> <span class="Comment"># turn '2' into '3'</span> - press <span class="Constant">65532</span> <span class="Comment"># F4</span> - ] - <span class="Constant">4</span>:event/backspace<span class="Special"> <- </span>merge <span class="Constant">0/text</span>, <span class="Constant">8/backspace</span>, <span class="Constant">0/dummy</span>, <span class="Constant">0/dummy</span> - replace-in-console <span class="Constant">171/«</span>, <span class="Constant">4</span>:event/backspace - run [ - event-loop screen:address, console:address, <span class="Constant">3</span>:address:programming-environment-data - ] - <span class="Comment"># result turns red</span> - screen-should-contain-in-color <span class="Constant">1/red</span>, [ - <span class="Constant"> . .</span> - <span class="Constant"> . .</span> - <span class="Constant"> . .</span> - <span class="Constant"> . .</span> - <span class="Constant"> . .</span> - <span class="Constant"> . 5 .</span> - <span class="Constant"> . .</span> - <span class="Constant"> . .</span> - ] -] - -<span class="Comment"># clicks on sandbox responses save it as 'expected'</span> -<span class="muRecipe">after</span> +global-touch [ - <span class="Comment"># right side of screen? check if it's inside the output of any sandbox</span> - <span class="Delimiter">{</span> - sandbox-left-margin:number<span class="Special"> <- </span>get *current-sandbox, <span class="Constant">left:offset</span> - click-column:number<span class="Special"> <- </span>get *t, <span class="Constant">column:offset</span> - on-sandbox-side?:boolean<span class="Special"> <- </span>greater-or-equal click-column, sandbox-left-margin - <span class="muControl">break-unless</span> on-sandbox-side? - first-sandbox:address:sandbox-data<span class="Special"> <- </span>get *env, <span class="Constant">sandbox:offset</span> - <span class="muControl">break-unless</span> first-sandbox - first-sandbox-begins:number<span class="Special"> <- </span>get *first-sandbox, <span class="Constant">starting-row-on-screen:offset</span> - click-row:number<span class="Special"> <- </span>get *t, <span class="Constant">row:offset</span> - below-sandbox-editor?:boolean<span class="Special"> <- </span>greater-or-equal click-row, first-sandbox-begins - <span class="muControl">break-unless</span> below-sandbox-editor? - <span class="Comment"># identify the sandbox whose output is being clicked on</span> - sandbox:address:sandbox-data<span class="Special"> <- </span>find-click-in-sandbox-output env, click-row - <span class="muControl">break-unless</span> sandbox - <span class="Comment"># toggle its expected-response, and save session</span> - sandbox<span class="Special"> <- </span>toggle-expected-response sandbox - save-sandboxes env - hide-screen screen - screen<span class="Special"> <- </span>render-sandbox-side screen, env, <span class="Constant">1/clear</span> - <span class="Comment"># no change in cursor</span> - show-screen screen - <span class="muControl">loop</span> <span class="Constant">+next-event:label</span> - <span class="Delimiter">}</span> -] - -<span class="muRecipe">recipe</span> find-click-in-sandbox-output [ - <span class="Constant">local-scope</span> - env:address:programming-environment-data<span class="Special"> <- </span><span class="Constant">next-ingredient</span> - click-row:number<span class="Special"> <- </span><span class="Constant">next-ingredient</span> - <span class="Comment"># assert click-row >= sandbox.starting-row-on-screen</span> - sandbox:address:sandbox-data<span class="Special"> <- </span>get *env, <span class="Constant">sandbox:offset</span> - start:number<span class="Special"> <- </span>get *sandbox, <span class="Constant">starting-row-on-screen:offset</span> - clicked-on-sandboxes?:boolean<span class="Special"> <- </span>greater-or-equal click-row, start - assert clicked-on-sandboxes?, <span class="Constant">[extract-sandbox called on click to sandbox editor]</span> - <span class="Comment"># while click-row < sandbox.next-sandbox.starting-row-on-screen</span> - <span class="Delimiter">{</span> - next-sandbox:address:sandbox-data<span class="Special"> <- </span>get *sandbox, <span class="Constant">next-sandbox:offset</span> - <span class="muControl">break-unless</span> next-sandbox - next-start:number<span class="Special"> <- </span>get *next-sandbox, <span class="Constant">starting-row-on-screen:offset</span> - found?:boolean<span class="Special"> <- </span>lesser-than click-row, next-start - <span class="muControl">break-if</span> found? - sandbox<span class="Special"> <- </span>copy next-sandbox - <span class="muControl">loop</span> - <span class="Delimiter">}</span> - <span class="Comment"># return sandbox if click is in its output region</span> - response-starting-row:number<span class="Special"> <- </span>get *sandbox, <span class="Constant">response-starting-row-on-screen:offset</span> - <span class="muControl">reply-unless</span> response-starting-row, <span class="Constant">0/no-click-in-sandbox-output</span> - click-in-response?:boolean<span class="Special"> <- </span>greater-or-equal click-row, response-starting-row - <span class="muControl">reply-unless</span> click-in-response?, <span class="Constant">0/no-click-in-sandbox-output</span> - <span class="muControl">reply</span> sandbox -] - -<span class="muRecipe">recipe</span> toggle-expected-response [ - <span class="Constant">local-scope</span> - sandbox:address:sandbox-data<span class="Special"> <- </span><span class="Constant">next-ingredient</span> - expected-response:address:address:array:character<span class="Special"> <- </span>get-address *sandbox, <span class="Constant">expected-response:offset</span> - <span class="Delimiter">{</span> - <span class="Comment"># if expected-response is set, reset</span> - <span class="muControl">break-unless</span> *expected-response - *expected-response<span class="Special"> <- </span>copy <span class="Constant">0</span> - <span class="muControl">reply</span> sandbox/same-as-ingredient:<span class="Constant">0</span> - <span class="Delimiter">}</span> - <span class="Comment"># if not, current response is the expected response</span> - response:address:array:character<span class="Special"> <- </span>get *sandbox, <span class="Constant">response:offset</span> - *expected-response<span class="Special"> <- </span>copy response - <span class="muControl">reply</span> sandbox/same-as-ingredient:<span class="Constant">0</span> -] - -<span class="Comment"># when rendering a sandbox, color it in red/green if expected response exists</span> -<span class="muRecipe">after</span> +render-sandbox-response [ - <span class="Delimiter">{</span> - <span class="muControl">break-unless</span> sandbox-response - expected-response:address:array:character<span class="Special"> <- </span>get *sandbox, <span class="Constant">expected-response:offset</span> - <span class="muControl">break-unless</span> expected-response <span class="Comment"># fall-through to print in grey</span> - response-is-expected?:boolean<span class="Special"> <- </span>string-equal expected-response, sandbox-response - <span class="Delimiter">{</span> - <span class="muControl">break-if</span> response-is-expected?:boolean - row, screen<span class="Special"> <- </span>render-string screen, sandbox-response, left, right, <span class="Constant">1/red</span>, row - <span class="Delimiter">}</span> - <span class="Delimiter">{</span> - <span class="muControl">break-unless</span> response-is-expected?:boolean - row, screen<span class="Special"> <- </span>render-string screen, sandbox-response, left, right, <span class="Constant">2/green</span>, row - <span class="Delimiter">}</span> - <span class="muControl">jump</span> <span class="Constant">+render-sandbox-end:label</span> - <span class="Delimiter">}</span> -] - -<span class="SalientComment">## clicking on the code typed into a sandbox toggles its trace</span> - -<span class="muScenario">scenario</span> sandbox-click-on-code-toggles-app-trace [ -<span class="Constant"> $close-trace</span> - assume-screen <span class="Constant">40/width</span>, <span class="Constant">10/height</span> - <span class="Comment"># basic recipe</span> - <span class="Constant">1</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[ </span> -<span class="Constant">recipe foo [</span> -<span class="Constant"> stash [abc]</span> -]] - <span class="Comment"># run it</span> - <span class="Constant">2</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[foo]</span> - assume-console [ - press <span class="Constant">65532</span> <span class="Comment"># F4</span> - ] - <span class="Constant">3</span>:address:programming-environment-data<span class="Special"> <- </span>new-programming-environment screen:address, <span class="Constant">1</span>:address:array:character, <span class="Constant">2</span>:address:array:character - event-loop screen:address, console:address, <span class="Constant">3</span>:address:programming-environment-data - screen-should-contain [ - <span class="Constant"> . run (F4) .</span> - <span class="Constant"> . ┊ .</span> - <span class="Constant"> .recipe foo [ ┊━━━━━━━━━━━━━━━━━━━.</span> - <span class="Constant"> . stash [abc] ┊ x.</span> - <span class="Constant"> .] ┊foo .</span> -<span class="Constant"> .┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┊━━━━━━━━━━━━━━━━━━━.</span> - <span class="Constant"> . ┊ .</span> - ] - <span class="Comment"># click on the 'foo' line in the sandbox</span> - assume-console [ - left-click <span class="Constant">4</span>, <span class="Constant">21</span> - ] - run [ - event-loop screen:address, console:address, <span class="Constant">3</span>:address:programming-environment-data - ] - <span class="Comment"># trace now printed</span> - screen-should-contain [ - <span class="Constant"> . run (F4) .</span> - <span class="Constant"> . ┊ .</span> - <span class="Constant"> .recipe foo [ ┊━━━━━━━━━━━━━━━━━━━.</span> - <span class="Constant"> . stash [abc] ┊ x.</span> - <span class="Constant"> .] ┊foo .</span> - <span class="Constant"> .┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┊abc .</span> - <span class="Constant"> . ┊━━━━━━━━━━━━━━━━━━━.</span> - <span class="Constant"> . ┊ .</span> - ] - screen-should-contain-in-color <span class="Constant">245/grey</span>, [ - <span class="Constant"> . .</span> - <span class="Constant"> . ┊ .</span> - <span class="Constant"> . ┊━━━━━━━━━━━━━━━━━━━.</span> - <span class="Constant"> . ┊ x.</span> - <span class="Constant"> . ┊ .</span> - <span class="Constant"> .┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┊abc .</span> - <span class="Constant"> . ┊━━━━━━━━━━━━━━━━━━━.</span> - <span class="Constant"> . ┊ .</span> - ] - <span class="Comment"># click again on the same region</span> - assume-console [ - left-click <span class="Constant">4</span>, <span class="Constant">25</span> - ] - run [ - event-loop screen:address, console:address, <span class="Constant">3</span>:address:programming-environment-data - ] - <span class="Comment"># trace hidden again</span> - screen-should-contain [ - <span class="Constant"> . run (F4) .</span> - <span class="Constant"> . ┊ .</span> - <span class="Constant"> .recipe foo [ ┊━━━━━━━━━━━━━━━━━━━.</span> - <span class="Constant"> . stash [abc] ┊ x.</span> - <span class="Constant"> .] ┊foo .</span> -<span class="Constant"> .┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┊━━━━━━━━━━━━━━━━━━━.</span> - <span class="Constant"> . ┊ .</span> - ] -] - -<span class="muScenario">scenario</span> sandbox-shows-app-trace-and-result [ -<span class="Constant"> $close-trace</span> - assume-screen <span class="Constant">40/width</span>, <span class="Constant">10/height</span> - <span class="Comment"># basic recipe</span> - <span class="Constant">1</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[ </span> -<span class="Constant">recipe foo [</span> -<span class="Constant"> stash [abc]</span> - add <span class="Constant">2</span>, <span class="Constant">2</span> -]] - <span class="Comment"># run it</span> - <span class="Constant">2</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[foo]</span> - assume-console [ - press <span class="Constant">65532</span> <span class="Comment"># F4</span> - ] - <span class="Constant">3</span>:address:programming-environment-data<span class="Special"> <- </span>new-programming-environment screen:address, <span class="Constant">1</span>:address:array:character, <span class="Constant">2</span>:address:array:character - event-loop screen:address, console:address, <span class="Constant">3</span>:address:programming-environment-data - screen-should-contain [ - <span class="Constant"> . run (F4) .</span> - <span class="Constant"> . ┊ .</span> - <span class="Constant"> .recipe foo [ ┊━━━━━━━━━━━━━━━━━━━.</span> - <span class="Constant"> . stash [abc] ┊ x.</span> - <span class="Constant"> . add 2, 2 ┊foo .</span> - <span class="Constant"> .] ┊4 .</span> -<span class="Constant"> .┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┊━━━━━━━━━━━━━━━━━━━.</span> - <span class="Constant"> . ┊ .</span> - ] - <span class="Comment"># click on the 'foo' line in the sandbox</span> - assume-console [ - left-click <span class="Constant">4</span>, <span class="Constant">21</span> - ] - run [ - event-loop screen:address, console:address, <span class="Constant">3</span>:address:programming-environment-data - ] - <span class="Comment"># trace now printed</span> - screen-should-contain [ - <span class="Constant"> . run (F4) .</span> - <span class="Constant"> . ┊ .</span> - <span class="Constant"> .recipe foo [ ┊━━━━━━━━━━━━━━━━━━━.</span> - <span class="Constant"> . stash [abc] ┊ x.</span> - <span class="Constant"> . add 2, 2 ┊foo .</span> - <span class="Constant"> .] ┊abc .</span> - <span class="Constant"> .┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┊4 .</span> - <span class="Constant"> . ┊━━━━━━━━━━━━━━━━━━━.</span> - <span class="Constant"> . ┊ .</span> - ] -] - -<span class="Comment"># clicks on sandbox code toggle its display-trace? flag</span> -<span class="muRecipe">after</span> +global-touch [ - <span class="Comment"># right side of screen? check if it's inside the code of any sandbox</span> - <span class="Delimiter">{</span> - sandbox-left-margin:number<span class="Special"> <- </span>get *current-sandbox, <span class="Constant">left:offset</span> - click-column:number<span class="Special"> <- </span>get *t, <span class="Constant">column:offset</span> - on-sandbox-side?:boolean<span class="Special"> <- </span>greater-or-equal click-column, sandbox-left-margin - <span class="muControl">break-unless</span> on-sandbox-side? - first-sandbox:address:sandbox-data<span class="Special"> <- </span>get *env, <span class="Constant">sandbox:offset</span> - <span class="muControl">break-unless</span> first-sandbox - first-sandbox-begins:number<span class="Special"> <- </span>get *first-sandbox, <span class="Constant">starting-row-on-screen:offset</span> - click-row:number<span class="Special"> <- </span>get *t, <span class="Constant">row:offset</span> - below-sandbox-editor?:boolean<span class="Special"> <- </span>greater-or-equal click-row, first-sandbox-begins - <span class="muControl">break-unless</span> below-sandbox-editor? - <span class="Comment"># identify the sandbox whose code is being clicked on</span> - sandbox:address:sandbox-data<span class="Special"> <- </span>find-click-in-sandbox-code env, click-row - <span class="muControl">break-unless</span> sandbox - <span class="Comment"># toggle its display-trace? property</span> - x:address:boolean<span class="Special"> <- </span>get-address *sandbox, <span class="Constant">display-trace?:offset</span> - *x<span class="Special"> <- </span>not *x - hide-screen screen - screen<span class="Special"> <- </span>render-sandbox-side screen, env, <span class="Constant">1/clear</span> - <span class="Comment"># no change in cursor</span> - show-screen screen - <span class="muControl">loop</span> <span class="Constant">+next-event:label</span> - <span class="Delimiter">}</span> -] - -<span class="muRecipe">recipe</span> find-click-in-sandbox-code [ - <span class="Constant">local-scope</span> - env:address:programming-environment-data<span class="Special"> <- </span><span class="Constant">next-ingredient</span> - click-row:number<span class="Special"> <- </span><span class="Constant">next-ingredient</span> - <span class="Comment"># assert click-row >= sandbox.starting-row-on-screen</span> - sandbox:address:sandbox-data<span class="Special"> <- </span>get *env, <span class="Constant">sandbox:offset</span> - start:number<span class="Special"> <- </span>get *sandbox, <span class="Constant">starting-row-on-screen:offset</span> - clicked-on-sandboxes?:boolean<span class="Special"> <- </span>greater-or-equal click-row, start - assert clicked-on-sandboxes?, <span class="Constant">[extract-sandbox called on click to sandbox editor]</span> - <span class="Comment"># while click-row < sandbox.next-sandbox.starting-row-on-screen</span> - <span class="Delimiter">{</span> - next-sandbox:address:sandbox-data<span class="Special"> <- </span>get *sandbox, <span class="Constant">next-sandbox:offset</span> - <span class="muControl">break-unless</span> next-sandbox - next-start:number<span class="Special"> <- </span>get *next-sandbox, <span class="Constant">starting-row-on-screen:offset</span> - found?:boolean<span class="Special"> <- </span>lesser-than click-row, next-start - <span class="muControl">break-if</span> found? - sandbox<span class="Special"> <- </span>copy next-sandbox - <span class="muControl">loop</span> - <span class="Delimiter">}</span> - <span class="Comment"># return sandbox if click is in its code region</span> - code-ending-row:number<span class="Special"> <- </span>get *sandbox, <span class="Constant">code-ending-row-on-screen:offset</span> - click-above-response?:boolean<span class="Special"> <- </span>lesser-or-equal click-row, code-ending-row - start:number<span class="Special"> <- </span>get *sandbox, <span class="Constant">starting-row-on-screen:offset</span> - click-below-menu?:boolean<span class="Special"> <- </span>greater-than click-row, start - click-on-sandbox-code?:boolean<span class="Special"> <- </span>and click-above-response?, click-below-menu? - <span class="Delimiter">{</span> - <span class="muControl">break-if</span> click-on-sandbox-code? - <span class="muControl">reply</span> <span class="Constant">0/no-click-in-sandbox-output</span> - <span class="Delimiter">}</span> - <span class="muControl">reply</span> sandbox -] - -<span class="Comment"># when rendering a sandbox, dump its trace before response/warning if display-trace? property is set</span> -<span class="muRecipe">after</span> +render-sandbox-results [ - <span class="Delimiter">{</span> - display-trace?:boolean<span class="Special"> <- </span>get *sandbox, <span class="Constant">display-trace?:offset</span> - <span class="muControl">break-unless</span> display-trace? - sandbox-trace:address:array:character<span class="Special"> <- </span>get *sandbox, <span class="Constant">trace:offset</span> - <span class="muControl">break-unless</span> sandbox-trace <span class="Comment"># nothing to print; move on</span> -<span class="CommentedCode">#? $print [display trace from ], row, 10/newline #? 1</span> - row, screen<span class="Special"> <- </span>render-string, screen, sandbox-trace, left, right, <span class="Constant">245/grey</span>, row - row<span class="Special"> <- </span>subtract row, <span class="Constant">1</span> <span class="Comment"># trim the trailing newline that's always present</span> - <span class="Delimiter">}</span> -] - -<span class="SalientComment">## handling malformed programs</span> - -<span class="muScenario">scenario</span> run-shows-warnings-in-get [ -<span class="Constant"> $close-trace</span> - assume-screen <span class="Constant">100/width</span>, <span class="Constant">15/height</span> - <span class="Constant">1</span>: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>] - <span class="Constant">2</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[foo]</span> - <span class="Constant">3</span>:address:programming-environment-data<span class="Special"> <- </span>new-programming-environment screen:address, <span class="Constant">1</span>:address:array:character, <span class="Constant">2</span>:address:array:character - assume-console [ - press <span class="Constant">65532</span> <span class="Comment"># F4</span> - ] - run [ - event-loop screen:address, console:address, <span class="Constant">3</span>:address:programming-environment-data - ] - screen-should-contain [ - <span class="Constant"> . errors found run (F4) .</span> - <span class="Constant"> . ┊foo .</span> - <span class="Constant"> .recipe foo [ ┊━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━.</span> - <span class="Constant"> . get 123:number, foo:offset ┊ .</span> - <span class="Constant"> .] ┊ .</span> - <span class="Constant"> .unknown element foo in container number ┊ .</span> - <span class="Constant"> .┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┊ .</span> - <span class="Constant"> . ┊ .</span> - ] - screen-should-contain-in-color <span class="Constant">1/red</span>, [ - <span class="Constant"> . errors found .</span> - <span class="Constant"> . .</span> - <span class="Constant"> . .</span> - <span class="Constant"> . .</span> - <span class="Constant"> . .</span> - <span class="Constant"> .unknown element foo in container number .</span> - <span class="Constant"> . .</span> - ] -] - -<span class="muScenario">scenario</span> run-shows-missing-type-warnings [ -<span class="Constant"> $close-trace</span> - assume-screen <span class="Constant">100/width</span>, <span class="Constant">15/height</span> - <span class="Constant">1</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[ </span> -<span class="Constant">recipe foo [</span> -<span class="Constant"> x <- copy 0</span> -<span class="Constant">]</span>] - <span class="Constant">2</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[foo]</span> - <span class="Constant">3</span>:address:programming-environment-data<span class="Special"> <- </span>new-programming-environment screen:address, <span class="Constant">1</span>:address:array:character, <span class="Constant">2</span>:address:array:character - assume-console [ - press <span class="Constant">65532</span> <span class="Comment"># F4</span> - ] - run [ - event-loop screen:address, console:address, <span class="Constant">3</span>:address:programming-environment-data - ] - screen-should-contain [ - <span class="Constant"> . errors found run (F4) .</span> - <span class="Constant"> . ┊foo .</span> - <span class="Constant"> .recipe foo [ ┊━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━.</span> - <span class="Constant"> . x <- copy 0 ┊ .</span> - <span class="Constant"> .] ┊ .</span> - <span class="Constant"> .missing type in 'x <- copy 0' ┊ .</span> - <span class="Constant"> .┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┊ .</span> - <span class="Constant"> . ┊ .</span> - ] -] - -<span class="muScenario">scenario</span> run-shows-unbalanced-bracket-warnings [ -<span class="Constant"> $close-trace</span> - assume-screen <span class="Constant">100/width</span>, <span class="Constant">15/height</span> - <span class="Comment"># recipe is incomplete (unbalanced '[')</span> - <span class="Constant">1</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[ </span> -<span class="Constant">recipe foo «</span> -<span class="Constant"> x <- copy 0</span> -<span class="Constant">]</span> - string-replace <span class="Constant">1</span>:address:array:character, <span class="Constant">171/«</span>, <span class="Constant">91</span> <span class="Comment"># '['</span> - <span class="Constant">2</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[foo]</span> - <span class="Constant">3</span>:address:programming-environment-data<span class="Special"> <- </span>new-programming-environment screen:address, <span class="Constant">1</span>:address:array:character, <span class="Constant">2</span>:address:array:character - assume-console [ - press <span class="Constant">65532</span> <span class="Comment"># F4</span> - ] - run [ - event-loop screen:address, console:address, <span class="Constant">3</span>:address:programming-environment-data - ] - screen-should-contain [ - <span class="Constant"> . errors found run (F4) .</span> - <span class="Constant"> . ┊foo .</span> - <span class="Constant"> .recipe foo \\\[ ┊━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━.</span> - <span class="Constant"> . x <- copy 0 ┊ .</span> - <span class="Constant"> . ┊ .</span> - <span class="Constant"> .9: unbalanced '\\\[' for recipe ┊ .</span> - <span class="Constant"> .┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┊ .</span> - <span class="Constant"> . ┊ .</span> - ] -] - -<span class="muScenario">scenario</span> run-shows-get-on-non-container-warnings [ -<span class="Constant"> $close-trace</span> - assume-screen <span class="Constant">100/width</span>, <span class="Constant">15/height</span> - <span class="Constant">1</span>: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>] - <span class="Constant">2</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[foo]</span> - <span class="Constant">3</span>:address:programming-environment-data<span class="Special"> <- </span>new-programming-environment screen:address, <span class="Constant">1</span>:address:array:character, <span class="Constant">2</span>:address:array:character - assume-console [ - press <span class="Constant">65532</span> <span class="Comment"># F4</span> - ] - run [ - event-loop screen:address, console:address, <span class="Constant">3</span>:address:programming-environment-data - ] - screen-should-contain [ - <span class="Constant"> . run (F4) .</span> - <span class="Constant"> . ┊ .</span> - <span class="Constant"> .recipe foo [ ┊━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━.</span> - <span class="Constant"> . x:address:point <- new point:type ┊ x.</span> - <span class="Constant"> . get x:address:point, 1:offset ┊foo .</span> - <span class="Constant"> .] ┊foo: first ingredient of 'get' should be a conta↩.</span> - <span class="Constant"> .┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┊iner, but got x:address:point .</span> - <span class="Constant"> . ┊━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━.</span> - <span class="Constant"> . ┊ .</span> - ] -] - -<span class="muScenario">scenario</span> run-shows-non-literal-get-argument-warnings [ -<span class="Constant"> $close-trace</span> - assume-screen <span class="Constant">100/width</span>, <span class="Constant">15/height</span> - <span class="Constant">1</span>: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, x:number</span> -<span class="Constant">]</span>] - <span class="Constant">2</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[foo]</span> - <span class="Constant">3</span>:address:programming-environment-data<span class="Special"> <- </span>new-programming-environment screen:address, <span class="Constant">1</span>:address:array:character, <span class="Constant">2</span>:address:array:character - assume-console [ - press <span class="Constant">65532</span> <span class="Comment"># F4</span> - ] - run [ - event-loop screen:address, console:address, <span class="Constant">3</span>:address:programming-environment-data - ] - screen-should-contain [ - <span class="Constant"> . errors found run (F4) .</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, 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="muScenario">scenario</span> run-shows-warnings-everytime [ -<span class="Constant"> $close-trace</span> - <span class="Comment"># try to run a file with an error</span> - assume-screen <span class="Constant">100/width</span>, <span class="Constant">15/height</span> - <span class="Constant">1</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[ </span> -<span class="Constant">recipe foo [</span> -<span class="Constant"> x:number <- copy y:number</span> -<span class="Constant">]</span>] - <span class="Constant">2</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[foo]</span> - <span class="Constant">3</span>:address:programming-environment-data<span class="Special"> <- </span>new-programming-environment screen:address, <span class="Constant">1</span>:address:array:character, <span class="Constant">2</span>:address:array:character - assume-console [ - press <span class="Constant">65532</span> <span class="Comment"># F4</span> - ] - run [ - event-loop screen:address, console:address, <span class="Constant">3</span>:address:programming-environment-data - ] - screen-should-contain [ - <span class="Constant"> . errors found run (F4) .</span> - <span class="Constant"> . ┊foo .</span> - <span class="Constant"> .recipe foo [ ┊━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━.</span> - <span class="Constant"> . x:number <- copy y:number ┊ .</span> - <span class="Constant"> .] ┊ .</span> - <span class="Constant"> .use before set: y in foo ┊ .</span> - <span class="Constant"> .┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┊ .</span> - <span class="Constant"> . ┊ .</span> - ] - <span class="Comment"># rerun the file, check for the same error</span> - assume-console [ - press <span class="Constant">65532</span> <span class="Comment"># F4</span> - ] - run [ - event-loop screen:address, console:address, <span class="Constant">3</span>:address:programming-environment-data - ] - screen-should-contain [ - <span class="Constant"> . errors found run (F4) .</span> - <span class="Constant"> . ┊foo .</span> - <span class="Constant"> .recipe foo [ ┊━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━.</span> - <span class="Constant"> . x:number <- copy y:number ┊ .</span> - <span class="Constant"> .] ┊ .</span> - <span class="Constant"> .use before set: y in foo ┊ .</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? - color<span class="Special"> <- </span>copy <span class="Constant">245/grey</span> - <span class="Delimiter">}</span> - <span class="Comment"># top border</span> - draw-horizontal screen, top, left, right, color - draw-horizontal screen, bottom, left, right, color - draw-vertical screen, left, top, bottom, color - draw-vertical screen, right, top, bottom, color - draw-top-left screen, top, left, color - draw-top-right screen, top, right, color - draw-bottom-left screen, bottom, left, color - draw-bottom-right screen, bottom, right, color - <span class="Comment"># position cursor inside box</span> - screen<span class="Special"> <- </span>move-cursor screen, top, left - cursor-down screen - cursor-right screen -] - -<span class="muRecipe">recipe</span> draw-horizontal [ - <span class="Constant">local-scope</span> - screen:address<span class="Special"> <- </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? - style<span class="Special"> <- </span>copy <span class="Constant">9472/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? - color<span class="Special"> <- </span>copy <span class="Constant">245/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? - bg-color<span class="Special"> <- </span>copy <span class="Constant">0/black</span> - <span class="Delimiter">}</span> - screen<span class="Special"> <- </span>move-cursor screen, row, x - <span class="Delimiter">{</span> - continue?:boolean<span class="Special"> <- </span>lesser-or-equal x, right <span class="Comment"># right is inclusive, to match editor-data semantics</span> - <span class="muControl">break-unless</span> continue? - print-character screen, style, color, bg-color - x<span class="Special"> <- </span>add x, <span class="Constant">1</span> - <span class="muControl">loop</span> - <span class="Delimiter">}</span> -] - -<span class="muRecipe">recipe</span> draw-vertical [ - <span class="Constant">local-scope</span> - screen:address<span class="Special"> <- </span><span class="Constant">next-ingredient</span> - col:number<span class="Special"> <- </span><span class="Constant">next-ingredient</span> - y: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? - style<span class="Special"> <- </span>copy <span class="Constant">9474/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? - color<span class="Special"> <- </span>copy <span class="Constant">245/grey</span> - <span class="Delimiter">}</span> - <span class="Delimiter">{</span> - continue?:boolean<span class="Special"> <- </span>lesser-than y, bottom - <span class="muControl">break-unless</span> continue? - screen<span class="Special"> <- </span>move-cursor screen, y, col - print-character screen, style, color - y<span class="Special"> <- </span>add y, <span class="Constant">1</span> - <span class="muControl">loop</span> - <span class="Delimiter">}</span> -] - -<span class="muRecipe">recipe</span> draw-top-left [ - <span class="Constant">local-scope</span> - screen:address<span class="Special"> <- </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? - color<span class="Special"> <- </span>copy <span class="Constant">245/grey</span> - <span class="Delimiter">}</span> - screen<span class="Special"> <- </span>move-cursor screen, top, left - print-character screen, <span class="Constant">9484/down-right</span>, color -] - -<span class="muRecipe">recipe</span> draw-top-right [ - <span class="Constant">local-scope</span> - screen:address<span class="Special"> <- </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? - color<span class="Special"> <- </span>copy <span class="Constant">245/grey</span> - <span class="Delimiter">}</span> - screen<span class="Special"> <- </span>move-cursor screen, top, right - print-character screen, <span class="Constant">9488/down-left</span>, color -] - -<span class="muRecipe">recipe</span> draw-bottom-left [ - <span class="Constant">local-scope</span> - screen:address<span class="Special"> <- </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? - color<span class="Special"> <- </span>copy <span class="Constant">245/grey</span> - <span class="Delimiter">}</span> - screen<span class="Special"> <- </span>move-cursor screen, bottom, left - print-character screen, <span class="Constant">9492/up-right</span>, color -] - -<span class="muRecipe">recipe</span> draw-bottom-right [ - <span class="Constant">local-scope</span> - screen:address<span class="Special"> <- </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? - color<span class="Special"> <- </span>copy <span class="Constant">245/grey</span> - <span class="Delimiter">}</span> - screen<span class="Special"> <- </span>move-cursor screen, bottom, right - print-character screen, <span class="Constant">9496/up-left</span>, color -] - -<span class="muRecipe">recipe</span> print-string-with-gradient-background [ - <span class="Constant">local-scope</span> - screen:address<span class="Special"> <- </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 - color-range:number<span class="Special"> <- </span>subtract bg-color2, bg-color1 - color-quantum:number<span class="Special"> <- </span>divide color-range, len - bg-color:number<span class="Special"> <- </span>copy bg-color1 - i:number<span class="Special"> <- </span>copy <span class="Constant">0</span> - <span class="Delimiter">{</span> - done?:boolean<span class="Special"> <- </span>greater-or-equal i, len - <span class="muControl">break-if</span> done? - c:character<span class="Special"> <- </span>index *s, i - print-character screen, c, color, bg-color - i<span class="Special"> <- </span>add i, <span class="Constant">1</span> - bg-color<span class="Special"> <- </span>add bg-color, color-quantum - <span class="muControl">loop</span> - <span class="Delimiter">}</span> - <span class="muControl">reply</span> screen/same-as-ingredient:<span class="Constant">0</span> -] -</pre> -</body> -</html> -<!-- vim: set foldmethod=manual : --> diff --git a/html/edit/001-editor.mu.html b/html/edit/001-editor.mu.html new file mode 100644 index 00000000..be568c9d --- /dev/null +++ b/html/edit/001-editor.mu.html @@ -0,0 +1,539 @@ +<!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/001-editor.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; } +.muRecipe { color: #ff8700; } +.muData { color: #ffff00; } +.Special { color: #ff6060; } +.muScenario { color: #00af00; } +.Comment { color: #9090ff; } +.Constant { color: #00a0a0; } +.SalientComment { color: #00ffff; } +.Delimiter { color: #a04060; } +.muControl { color: #c0a020; } +--> +</style> + +<script type='text/javascript'> +<!-- + +--> +</script> +</head> +<body> +<pre id='vimCodeElement'> +<span class="SalientComment">## the basic editor data structure, and how it displays text to the screen</span> + +<span class="Comment"># temporary main for this layer: just render the given string at the given</span> +<span class="Comment"># screen dimensions, then stop</span> +<span class="muRecipe">recipe!</span> main [ + <span class="Constant">local-scope</span> + text:address:array:character<span class="Special"> <- </span><span class="Constant">next-ingredient</span> + open-console + hide-screen <span class="Constant">0/screen</span> + new-editor text, <span class="Constant">0/screen</span>, <span class="Constant">0/left</span>, <span class="Constant">5/right</span> + show-screen <span class="Constant">0/screen</span> + wait-for-event <span class="Constant">0/console</span> + close-console +] + +<span class="muScenario">scenario</span> editor-initially-prints-string-to-screen [ + assume-screen <span class="Constant">10/width</span>, <span class="Constant">5/height</span> + run [ + <span class="Constant">1</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[abc]</span> + new-editor <span class="Constant">1</span>:address:array:character, screen:address, <span class="Constant">0/left</span>, <span class="Constant">10/right</span> + ] + screen-should-contain [ + <span class="Comment"># top line of screen reserved for menu</span> + <span class="Constant"> . .</span> + <span class="Constant"> .abc .</span> + <span class="Constant"> . .</span> + ] +] + +<span class="muData">container</span> editor-data [ + <span class="Comment"># editable text: doubly linked list of characters (head contains a special sentinel)</span> + data:address:duplex-list:character + top-of-screen:address:duplex-list:character + bottom-of-screen:address:duplex-list:character + <span class="Comment"># location before cursor inside data</span> + before-cursor:address:duplex-list:character + + <span class="Comment"># raw bounds of display area on screen</span> + <span class="Comment"># always displays from row 1 (leaving row 0 for a menu) and at most until bottom of screen</span> + left:number + right:number + <span class="Comment"># raw screen coordinates of cursor</span> + cursor-row:number + cursor-column:number +] + +<span class="Comment"># editor:address, screen <- 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<span class="Special"> <- </span>subtract right, <span class="Constant">1</span> + result:address:editor-data<span class="Special"> <- </span>new <span class="Constant">editor-data:type</span> + <span class="Comment"># initialize screen-related fields</span> + x:address:number<span class="Special"> <- </span>get-address *result, <span class="Constant">left:offset</span> + *x<span class="Special"> <- </span>copy left + x<span class="Special"> <- </span>get-address *result, <span class="Constant">right:offset</span> + *x<span class="Special"> <- </span>copy right + <span class="Comment"># initialize cursor</span> + x<span class="Special"> <- </span>get-address *result, <span class="Constant">cursor-row:offset</span> + *x<span class="Special"> <- </span>copy <span class="Constant">1/top</span> + x<span class="Special"> <- </span>get-address *result, <span class="Constant">cursor-column:offset</span> + *x<span class="Special"> <- </span>copy left + init:address:address:duplex-list<span class="Special"> <- </span>get-address *result, <span class="Constant">data:offset</span> + *init<span class="Special"> <- </span>push-duplex <span class="Constant">167/§</span>, <span class="Constant">0/tail</span> + top-of-screen:address:address:duplex-list<span class="Special"> <- </span>get-address *result, <span class="Constant">top-of-screen:offset</span> + *top-of-screen<span class="Special"> <- </span>copy *init + y:address:address:duplex-list<span class="Special"> <- </span>get-address *result, <span class="Constant">before-cursor:offset</span> + *y<span class="Special"> <- </span>copy *init + result<span class="Special"> <- </span>insert-text result, s + <span class="Comment"># initialize cursor to top of screen</span> + y<span class="Special"> <- </span>get-address *result, <span class="Constant">before-cursor:offset</span> + *y<span class="Special"> <- </span>copy *init + <span class="Comment"># initial render to screen, just for some old tests</span> + _, _, screen, result<span class="Special"> <- </span>render screen, result +<span class="Constant"> <editor-initialization></span> + <span class="muControl">reply</span> result +] + +<span class="muRecipe">recipe</span> insert-text [ + <span class="Constant">local-scope</span> + editor:address:editor-data<span class="Special"> <- </span><span class="Constant">next-ingredient</span> + text:address:array:character<span class="Special"> <- </span><span class="Constant">next-ingredient</span> + <span class="Comment"># early exit if text is empty</span> + <span class="muControl">reply-unless</span> text, editor/same-as-ingredient:<span class="Constant">0</span> + len:number<span class="Special"> <- </span>length *text + <span class="muControl">reply-unless</span> len, editor/same-as-ingredient:<span class="Constant">0</span> + idx:number<span class="Special"> <- </span>copy <span class="Constant">0</span> + <span class="Comment"># now we can start appending the rest, character by character</span> + curr:address:duplex-list<span class="Special"> <- </span>get *editor, <span class="Constant">data:offset</span> + <span class="Delimiter">{</span> + done?:boolean<span class="Special"> <- </span>greater-or-equal idx, len + <span class="muControl">break-if</span> done? + c:character<span class="Special"> <- </span>index *text, idx + insert-duplex c, curr + <span class="Comment"># next iter</span> + curr<span class="Special"> <- </span>next-duplex curr + idx<span class="Special"> <- </span>add idx, <span class="Constant">1</span> + <span class="muControl">loop</span> + <span class="Delimiter">}</span> + <span class="muControl">reply</span> editor/same-as-ingredient:<span class="Constant">0</span> +] + +<span class="muScenario">scenario</span> editor-initializes-without-data [ + assume-screen <span class="Constant">5/width</span>, <span class="Constant">3/height</span> + run [ + <span class="Constant">1</span>:address:editor-data<span class="Special"> <- </span>new-editor <span class="Constant">0/data</span>, screen:address, <span class="Constant">2/left</span>, <span class="Constant">5/right</span> + <span class="Constant">2</span>:editor-data<span class="Special"> <- </span>copy *<span class="Constant">1</span>:address:editor-data + ] + memory-should-contain [ + <span class="Comment"># 2 (data) <- just the § sentinel</span> + <span class="Comment"># 3 (top of screen) <- the § sentinel</span> + <span class="Constant">4</span><span class="Special"> <- </span><span class="Constant">0</span> <span class="Comment"># bottom-of-screen; null since text fits on screen</span> + <span class="Comment"># 5 (before cursor) <- the § sentinel</span> + <span class="Constant">6</span><span class="Special"> <- </span><span class="Constant">2</span> <span class="Comment"># left</span> + <span class="Constant">7</span><span class="Special"> <- </span><span class="Constant">4</span> <span class="Comment"># right (inclusive)</span> + <span class="Constant">8</span><span class="Special"> <- </span><span class="Constant">1</span> <span class="Comment"># cursor row</span> + <span class="Constant">9</span><span class="Special"> <- </span><span class="Constant">2</span> <span class="Comment"># cursor column</span> + ] + screen-should-contain [ + <span class="Constant"> . .</span> + <span class="Constant"> . .</span> + <span class="Constant"> . .</span> + ] +] + +<span class="Comment"># last-row:number, last-column:number, screen, editor <- render screen:address, editor:address:editor-data</span> +<span class="Comment">#</span> +<span class="Comment"># Assumes cursor should be at coordinates (cursor-row, cursor-column) and</span> +<span class="Comment"># updates before-cursor to match. Might also move coordinates if they're</span> +<span class="Comment"># outside text.</span> +<span class="muRecipe">recipe</span> render [ + <span class="Constant">local-scope</span> + screen:address<span class="Special"> <- </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, <span class="Constant">1/top</span>, <span class="Constant">0/left</span>, screen/same-as-ingredient:<span class="Constant">0</span>, editor/same-as-ingredient:<span class="Constant">1</span> + left:number<span class="Special"> <- </span>get *editor, <span class="Constant">left:offset</span> + screen-height:number<span class="Special"> <- </span>screen-height screen + right:number<span class="Special"> <- </span>get *editor, <span class="Constant">right:offset</span> + <span class="Comment"># traversing editor</span> + curr:address:duplex-list<span class="Special"> <- </span>get *editor, <span class="Constant">top-of-screen:offset</span> + prev:address:duplex-list<span class="Special"> <- </span>copy curr <span class="Comment"># just in case curr becomes null and we can't compute prev-duplex</span> + curr<span class="Special"> <- </span>next-duplex curr + <span class="Comment"># traversing screen</span> +<span class="Constant"> +render-loop-initialization</span> + color:number<span class="Special"> <- </span>copy <span class="Constant">7/white</span> + row:number<span class="Special"> <- </span>copy <span class="Constant">1/top</span> + column:number<span class="Special"> <- </span>copy left + cursor-row:address:number<span class="Special"> <- </span>get-address *editor, <span class="Constant">cursor-row:offset</span> + cursor-column:address:number<span class="Special"> <- </span>get-address *editor, <span class="Constant">cursor-column:offset</span> + before-cursor:address:address:duplex-list<span class="Special"> <- </span>get-address *editor, <span class="Constant">before-cursor:offset</span> + screen<span class="Special"> <- </span>move-cursor screen, row, column + <span class="Delimiter">{</span> +<span class="Constant"> +next-character</span> + <span class="muControl">break-unless</span> curr + off-screen?:boolean<span class="Special"> <- </span>greater-or-equal row, screen-height + <span class="muControl">break-if</span> off-screen? + <span class="Comment"># update editor-data.before-cursor</span> + <span class="Comment"># Doing so at the start of each iteration ensures it stays one step behind</span> + <span class="Comment"># the current character.</span> + <span class="Delimiter">{</span> + at-cursor-row?:boolean<span class="Special"> <- </span>equal row, *cursor-row + <span class="muControl">break-unless</span> at-cursor-row? + at-cursor?:boolean<span class="Special"> <- </span>equal column, *cursor-column + <span class="muControl">break-unless</span> at-cursor? + *before-cursor<span class="Special"> <- </span>copy prev + <span class="Delimiter">}</span> + c:character<span class="Special"> <- </span>get *curr, <span class="Constant">value:offset</span> +<span class="Constant"> <character-c-received></span> + <span class="Delimiter">{</span> + <span class="Comment"># newline? move to left rather than 0</span> + newline?:boolean<span class="Special"> <- </span>equal c, <span class="Constant">10/newline</span> + <span class="muControl">break-unless</span> newline? + <span class="Comment"># adjust cursor if necessary</span> + <span class="Delimiter">{</span> + at-cursor-row?:boolean<span class="Special"> <- </span>equal row, *cursor-row + <span class="muControl">break-unless</span> at-cursor-row? + left-of-cursor?:boolean<span class="Special"> <- </span>lesser-than column, *cursor-column + <span class="muControl">break-unless</span> left-of-cursor? + *cursor-column<span class="Special"> <- </span>copy column + *before-cursor<span class="Special"> <- </span>prev-duplex curr + <span class="Delimiter">}</span> + <span class="Comment"># clear rest of line in this window</span> + clear-line-delimited screen, column, right + <span class="Comment"># skip to next line</span> + row<span class="Special"> <- </span>add row, <span class="Constant">1</span> + column<span class="Special"> <- </span>copy left + screen<span class="Special"> <- </span>move-cursor screen, row, column + curr<span class="Special"> <- </span>next-duplex curr + prev<span class="Special"> <- </span>next-duplex prev + <span class="muControl">loop</span> <span class="Constant">+next-character:label</span> + <span class="Delimiter">}</span> + <span class="Delimiter">{</span> + <span class="Comment"># at right? wrap. even if there's only one more letter left; we need</span> + <span class="Comment"># room for clicking on the cursor after it.</span> + at-right?:boolean<span class="Special"> <- </span>equal column, right + <span class="muControl">break-unless</span> at-right? + <span class="Comment"># print wrap icon</span> + print-character screen, <span class="Constant">8617/loop-back-to-left</span>, <span class="Constant">245/grey</span> + column<span class="Special"> <- </span>copy left + row<span class="Special"> <- </span>add row, <span class="Constant">1</span> + screen<span class="Special"> <- </span>move-cursor screen, row, column + <span class="Comment"># don't increment curr</span> + <span class="muControl">loop</span> <span class="Constant">+next-character:label</span> + <span class="Delimiter">}</span> + print-character screen, c, color + curr<span class="Special"> <- </span>next-duplex curr + prev<span class="Special"> <- </span>next-duplex prev + column<span class="Special"> <- </span>add column, <span class="Constant">1</span> + <span class="muControl">loop</span> + <span class="Delimiter">}</span> + <span class="Comment"># save first character off-screen</span> + bottom-of-screen:address:address:duplex-list<span class="Special"> <- </span>get-address *editor, <span class="Constant">bottom-of-screen:offset</span> + *bottom-of-screen<span class="Special"> <- </span>copy curr + <span class="Comment"># is cursor to the right of the last line? move to end</span> + <span class="Delimiter">{</span> + at-cursor-row?:boolean<span class="Special"> <- </span>equal row, *cursor-row + cursor-outside-line?:boolean<span class="Special"> <- </span>lesser-or-equal column, *cursor-column + before-cursor-on-same-line?:boolean<span class="Special"> <- </span>and at-cursor-row?, cursor-outside-line? + above-cursor-row?:boolean<span class="Special"> <- </span>lesser-than row, *cursor-row + before-cursor?:boolean<span class="Special"> <- </span>or before-cursor-on-same-line?, above-cursor-row? + <span class="muControl">break-unless</span> before-cursor? + *cursor-row<span class="Special"> <- </span>copy row + *cursor-column<span class="Special"> <- </span>copy column + *before-cursor<span class="Special"> <- </span>copy prev + <span class="Delimiter">}</span> + <span class="muControl">reply</span> row, column, screen/same-as-ingredient:<span class="Constant">0</span>, editor/same-as-ingredient:<span class="Constant">1</span> +] + +<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> + column:number<span class="Special"> <- </span><span class="Constant">next-ingredient</span> + right:number<span class="Special"> <- </span><span class="Constant">next-ingredient</span> + <span class="Delimiter">{</span> + done?:boolean<span class="Special"> <- </span>greater-than column, right + <span class="muControl">break-if</span> done? + print-character screen, <span class="Constant">32/space</span> + column<span class="Special"> <- </span>add column, <span class="Constant">1</span> + <span class="muControl">loop</span> + <span class="Delimiter">}</span> +] + +<span class="muRecipe">recipe</span> clear-screen-from [ + <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> + column:number<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> + <span class="Comment"># if it's the real screen, use the optimized primitive</span> + <span class="Delimiter">{</span> + <span class="muControl">break-if</span> screen + clear-display-from row, column, left, right + <span class="muControl">reply</span> screen/same-as-ingredient:<span class="Constant">0</span> + <span class="Delimiter">}</span> + <span class="Comment"># if not, go the slower route</span> + screen<span class="Special"> <- </span>move-cursor screen, row, column + clear-line-delimited screen, column, right + clear-rest-of-screen screen, row, left, right + <span class="muControl">reply</span> screen/same-as-ingredient:<span class="Constant">0</span> +] + +<span class="muRecipe">recipe</span> clear-rest-of-screen [ + <span class="Constant">local-scope</span> + screen:address<span class="Special"> <- </span><span class="Constant">next-ingredient</span> + row:number<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<span class="Special"> <- </span>add row, <span class="Constant">1</span> + screen<span class="Special"> <- </span>move-cursor screen, row, left + screen-height:number<span class="Special"> <- </span>screen-height screen + <span class="Delimiter">{</span> + at-bottom-of-screen?:boolean<span class="Special"> <- </span>greater-or-equal row, screen-height + <span class="muControl">break-if</span> at-bottom-of-screen? + screen<span class="Special"> <- </span>move-cursor screen, row, left + clear-line-delimited screen, left, right + row<span class="Special"> <- </span>add row, <span class="Constant">1</span> + <span class="muControl">loop</span> + <span class="Delimiter">}</span> +] + +<span class="muScenario">scenario</span> editor-initially-prints-multiple-lines [ + assume-screen <span class="Constant">5/width</span>, <span class="Constant">5/height</span> + run [ + s:address:array:character<span class="Special"> <- </span>new <span class="Constant">[abc</span> +<span class="Constant">def]</span> + new-editor s:address:array:character, screen:address, <span class="Constant">0/left</span>, <span class="Constant">5/right</span> + ] + screen-should-contain [ + <span class="Constant"> . .</span> + <span class="Constant"> .abc .</span> + <span class="Constant"> .def .</span> + <span class="Constant"> . .</span> + ] +] + +<span class="muScenario">scenario</span> editor-initially-handles-offsets [ + assume-screen <span class="Constant">5/width</span>, <span class="Constant">5/height</span> + run [ + s:address:array:character<span class="Special"> <- </span>new <span class="Constant">[abc]</span> + new-editor s:address:array:character, screen:address, <span class="Constant">1/left</span>, <span class="Constant">5/right</span> + ] + screen-should-contain [ + <span class="Constant"> . .</span> + <span class="Constant"> . abc .</span> + <span class="Constant"> . .</span> + ] +] + +<span class="muScenario">scenario</span> editor-initially-prints-multiple-lines-at-offset [ + assume-screen <span class="Constant">5/width</span>, <span class="Constant">5/height</span> + run [ + s:address:array:character<span class="Special"> <- </span>new <span class="Constant">[abc</span> +<span class="Constant">def]</span> + new-editor s:address:array:character, screen:address, <span class="Constant">1/left</span>, <span class="Constant">5/right</span> + ] + screen-should-contain [ + <span class="Constant"> . .</span> + <span class="Constant"> . abc .</span> + <span class="Constant"> . def .</span> + <span class="Constant"> . .</span> + ] +] + +<span class="muScenario">scenario</span> editor-initially-wraps-long-lines [ + assume-screen <span class="Constant">5/width</span>, <span class="Constant">5/height</span> + run [ + s:address:array:character<span class="Special"> <- </span>new <span class="Constant">[abc def]</span> + new-editor s:address:array:character, screen:address, <span class="Constant">0/left</span>, <span class="Constant">5/right</span> + ] + screen-should-contain [ + <span class="Constant"> . .</span> + <span class="Constant"> .abc ↩.</span> + <span class="Constant"> .def .</span> + <span class="Constant"> . .</span> + ] + screen-should-contain-in-color <span class="Constant">245/grey</span> [ + <span class="Constant"> . .</span> + <span class="Constant"> . ↩.</span> + <span class="Constant"> . .</span> + <span class="Constant"> . .</span> + ] +] + +<span class="muScenario">scenario</span> editor-initially-wraps-barely-long-lines [ + assume-screen <span class="Constant">5/width</span>, <span class="Constant">5/height</span> + run [ + s:address:array:character<span class="Special"> <- </span>new <span class="Constant">[abcde]</span> + new-editor s:address:array:character, screen:address, <span class="Constant">0/left</span>, <span class="Constant">5/right</span> + ] + <span class="Comment"># still wrap, even though the line would fit. We need room to click on the</span> + <span class="Comment"># end of the line</span> + screen-should-contain [ + <span class="Constant"> . .</span> +<span class="Constant"> .abcd↩.</span> + <span class="Constant"> .e .</span> + <span class="Constant"> . .</span> + ] + screen-should-contain-in-color <span class="Constant">245/grey</span> [ + <span class="Constant"> . .</span> + <span class="Constant"> . ↩.</span> + <span class="Constant"> . .</span> + <span class="Constant"> . .</span> + ] +] + +<span class="muScenario">scenario</span> editor-initializes-empty-text [ + assume-screen <span class="Constant">5/width</span>, <span class="Constant">5/height</span> + run [ + <span class="Constant">1</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[]</span> + <span class="Constant">2</span>:address:editor-data<span class="Special"> <- </span>new-editor <span class="Constant">1</span>:address:array:character, screen:address, <span class="Constant">0/left</span>, <span class="Constant">5/right</span> + <span class="Constant">3</span>:number<span class="Special"> <- </span>get *<span class="Constant">2</span>:address:editor-data, <span class="Constant">cursor-row:offset</span> + <span class="Constant">4</span>:number<span class="Special"> <- </span>get *<span class="Constant">2</span>:address:editor-data, <span class="Constant">cursor-column:offset</span> + ] + screen-should-contain [ + <span class="Constant"> . .</span> + <span class="Constant"> . .</span> + <span class="Constant"> . .</span> + ] + memory-should-contain [ + <span class="Constant">3</span><span class="Special"> <- </span><span class="Constant">1</span> <span class="Comment"># cursor row</span> + <span class="Constant">4</span><span class="Special"> <- </span><span class="Constant">0</span> <span class="Comment"># cursor column</span> + ] +] + +<span class="Comment"># just a little color for mu code</span> + +<span class="muScenario">scenario</span> render-colors-comments [ + assume-screen <span class="Constant">5/width</span>, <span class="Constant">5/height</span> + run [ + s:address:array:character<span class="Special"> <- </span>new <span class="Constant">[abc</span> +<span class="Constant"># de</span> +<span class="Constant">f]</span> + new-editor s:address:array:character, screen:address, <span class="Constant">0/left</span>, <span class="Constant">5/right</span> + ] + screen-should-contain [ + <span class="Constant"> . .</span> + <span class="Constant"> .abc .</span> + <span class="Constant"> .# de .</span> + <span class="Constant"> .f .</span> + <span class="Constant"> . .</span> + ] + screen-should-contain-in-color <span class="Constant">12/lightblue</span>, [ + <span class="Constant"> . .</span> + <span class="Constant"> . .</span> + <span class="Constant"> .# de .</span> + <span class="Constant"> . .</span> + <span class="Constant"> . .</span> + ] + screen-should-contain-in-color <span class="Constant">7/white</span>, [ + <span class="Constant"> . .</span> + <span class="Constant"> .abc .</span> + <span class="Constant"> . .</span> + <span class="Constant"> .f .</span> + <span class="Constant"> . .</span> + ] +] + +<span class="muRecipe">after</span> <span class="Constant"><character-c-received></span> [ + color<span class="Special"> <- </span>get-color color, c +] + +<span class="Comment"># color <- get-color color:number, c:character</span> +<span class="Comment"># so far the previous color is all the information we need; that may change</span> +<span class="muRecipe">recipe</span> get-color [ + <span class="Constant">local-scope</span> + color:number<span class="Special"> <- </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, <span class="Constant">7/white</span> + <span class="Comment"># if color is white and next character is '#', switch color to blue</span> + <span class="Delimiter">{</span> + <span class="muControl">break-unless</span> color-is-white? + starting-comment?:boolean<span class="Special"> <- </span>equal c, <span class="Constant">35/#</span> + <span class="muControl">break-unless</span> starting-comment? + trace <span class="Constant">90</span>, <span class="Constant">[app]</span>, <span class="Constant">[switch color back to blue]</span> + color<span class="Special"> <- </span>copy <span class="Constant">12/lightblue</span> + <span class="muControl">jump</span> <span class="Constant">+exit:label</span> + <span class="Delimiter">}</span> + <span class="Comment"># if color is blue and next character is newline, switch color to white</span> + <span class="Delimiter">{</span> + color-is-blue?:boolean<span class="Special"> <- </span>equal color, <span class="Constant">12/lightblue</span> + <span class="muControl">break-unless</span> color-is-blue? + ending-comment?:boolean<span class="Special"> <- </span>equal c, <span class="Constant">10/newline</span> + <span class="muControl">break-unless</span> ending-comment? + trace <span class="Constant">90</span>, <span class="Constant">[app]</span>, <span class="Constant">[switch color back to white]</span> + color<span class="Special"> <- </span>copy <span class="Constant">7/white</span> + <span class="muControl">jump</span> <span class="Constant">+exit:label</span> + <span class="Delimiter">}</span> + <span class="Comment"># if color is white (no comments) and next character is '<', switch color to red</span> + <span class="Delimiter">{</span> + <span class="muControl">break-unless</span> color-is-white? + starting-assignment?:boolean<span class="Special"> <- </span>equal c, <span class="Constant">60/<</span> + <span class="muControl">break-unless</span> starting-assignment? + color<span class="Special"> <- </span>copy <span class="Constant">1/red</span> + <span class="muControl">jump</span> <span class="Constant">+exit:label</span> + <span class="Delimiter">}</span> + <span class="Comment"># if color is red and next character is space, switch color to white</span> + <span class="Delimiter">{</span> + color-is-red?:boolean<span class="Special"> <- </span>equal color, <span class="Constant">1/red</span> + <span class="muControl">break-unless</span> color-is-red? + ending-assignment?:boolean<span class="Special"> <- </span>equal c, <span class="Constant">32/space</span> + <span class="muControl">break-unless</span> ending-assignment? + color<span class="Special"> <- </span>copy <span class="Constant">7/white</span> + <span class="muControl">jump</span> <span class="Constant">+exit:label</span> + <span class="Delimiter">}</span> + <span class="Comment"># otherwise no change</span> +<span class="Constant"> +exit</span> + <span class="muControl">reply</span> color +] + +<span class="muScenario">scenario</span> render-colors-assignment [ + assume-screen <span class="Constant">8/width</span>, <span class="Constant">5/height</span> + run [ + s:address:array:character<span class="Special"> <- </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/left</span>, <span class="Constant">8/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/red</span>, [ + <span class="Constant"> . .</span> + <span class="Constant"> . .</span> + <span class="Constant"> . <- .</span> + <span class="Constant"> . .</span> + <span class="Constant"> . .</span> + ] +] +</pre> +</body> +</html> +<!-- vim: set foldmethod=manual : --> diff --git a/html/edit/002-typing.mu.html b/html/edit/002-typing.mu.html new file mode 100644 index 00000000..787e3a4e --- /dev/null +++ b/html/edit/002-typing.mu.html @@ -0,0 +1,1092 @@ +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd"> +<html> +<head> +<meta http-equiv="content-type" content="text/html; charset=UTF-8"> +<title>Mu - edit/002-typing.mu</title> +<meta name="Generator" content="Vim/7.4"> +<meta name="plugin-version" content="vim7.4_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; } +.muRecipe { color: #ff8700; } +.muData { color: #ffff00; } +.Special { color: #ff6060; } +.muScenario { color: #00af00; } +.Comment { color: #9090ff; } +.Constant { color: #00a0a0; } +.SalientComment { color: #00ffff; } +.Delimiter { color: #a04060; } +.muControl { color: #c0a020; } +--> +</style> + +<script type='text/javascript'> +<!-- + +--> +</script> +</head> +<body> +<pre id='vimCodeElement'> +<span class="SalientComment">## handling events from the keyboard, mouse, touch screen, ...</span> + +<span class="Comment"># temporary main: interactive editor</span> +<span class="Comment"># hit ctrl-c to exit</span> +<span class="muRecipe">recipe!</span> main [ + <span class="Constant">local-scope</span> + text:address:array:character<span class="Special"> <- </span><span class="Constant">next-ingredient</span> + open-console + editor:address:editor-data<span class="Special"> <- </span>new-editor text, <span class="Constant">0/screen</span>, <span class="Constant">5/left</span>, <span class="Constant">45/right</span> + editor-event-loop <span class="Constant">0/screen</span>, <span class="Constant">0/console</span>, editor + close-console +] + +<span class="muRecipe">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> + cursor-row:number<span class="Special"> <- </span>get *editor, <span class="Constant">cursor-row:offset</span> + cursor-column:number<span class="Special"> <- </span>get *editor, <span class="Constant">cursor-column:offset</span> + screen<span class="Special"> <- </span>move-cursor screen, cursor-row, cursor-column + e:event, console:address, found?:boolean, quit?:boolean<span class="Special"> <- </span>read-event console + <span class="muControl">loop-unless</span> found? + <span class="muControl">break-if</span> quit? <span class="Comment"># only in tests</span> + trace <span class="Constant">10</span>, <span class="Constant">[app]</span>, <span class="Constant">[next-event]</span> + <span class="Comment"># 'touch' event</span> + t:address:touch-event<span class="Special"> <- </span>maybe-convert e, <span class="Constant">touch:variant</span> + <span class="Delimiter">{</span> + <span class="muControl">break-unless</span> t + move-cursor-in-editor screen, editor, *t + <span class="muControl">loop</span> <span class="Constant">+next-event:label</span> + <span class="Delimiter">}</span> + <span class="Comment"># keyboard events</span> + <span class="Delimiter">{</span> + <span class="muControl">break-if</span> t + screen, editor, go-render?:boolean<span class="Special"> <- </span>handle-keyboard-event screen, editor, e + <span class="Delimiter">{</span> + <span class="muControl">break-unless</span> go-render? + screen<span class="Special"> <- </span>editor-render screen, editor + <span class="Delimiter">}</span> + <span class="Delimiter">}</span> + <span class="muControl">loop</span> + <span class="Delimiter">}</span> +] + +<span class="Comment"># process click, return if it was on current editor</span> +<span class="muRecipe">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, <span class="Constant">0/false</span> + click-row:number<span class="Special"> <- </span>get t, <span class="Constant">row:offset</span> + <span class="muControl">reply-unless</span> click-row, <span class="Constant">0/false</span> <span class="Comment"># ignore clicks on 'menu'</span> + click-column:number<span class="Special"> <- </span>get t, <span class="Constant">column:offset</span> + left:number<span class="Special"> <- </span>get *editor, <span class="Constant">left:offset</span> + too-far-left?:boolean<span class="Special"> <- </span>lesser-than click-column, left + <span class="muControl">reply-if</span> too-far-left?, <span class="Constant">0/false</span> + right:number<span class="Special"> <- </span>get *editor, <span class="Constant">right:offset</span> + too-far-right?:boolean<span class="Special"> <- </span>greater-than click-column, right + <span class="muControl">reply-if</span> too-far-right?, <span class="Constant">0/false</span> + <span class="Comment"># position cursor</span> +<span class="Constant"> <move-cursor-begin></span> + editor<span class="Special"> <- </span>snap-cursor screen, editor, click-row, click-column + undo-coalesce-tag:number<span class="Special"> <- </span>copy <span class="Constant">0/never</span> +<span class="Constant"> <move-cursor-end></span> + <span class="Comment"># gain focus</span> + <span class="muControl">reply</span> <span class="Constant">1/true</span> +] + +<span class="Comment"># editor <- snap-cursor screen:address, editor:address:editor-data, target-row:number, target-column:number</span> +<span class="Comment">#</span> +<span class="Comment"># Variant of 'render' that only moves the cursor (coordinates and</span> +<span class="Comment"># before-cursor). If it's past the end of a line, it 'slides' it left. If it's</span> +<span class="Comment"># past the last line it positions at end of last line.</span> +<span class="muRecipe">recipe</span> snap-cursor [ + <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> + target-row:number<span class="Special"> <- </span><span class="Constant">next-ingredient</span> + target-column:number<span class="Special"> <- </span><span class="Constant">next-ingredient</span> + <span class="muControl">reply-unless</span> editor, <span class="Constant">1/top</span>, editor/same-as-ingredient:<span class="Constant">1</span> + left:number<span class="Special"> <- </span>get *editor, <span class="Constant">left:offset</span> + right:number<span class="Special"> <- </span>get *editor, <span class="Constant">right:offset</span> + screen-height:number<span class="Special"> <- </span>screen-height screen + <span class="Comment"># count newlines until screen row</span> + curr:address:duplex-list<span class="Special"> <- </span>get *editor, <span class="Constant">top-of-screen:offset</span> + prev:address:duplex-list<span class="Special"> <- </span>copy curr <span class="Comment"># just in case curr becomes null and we can't compute prev-duplex</span> + curr<span class="Special"> <- </span>next-duplex curr + row:number<span class="Special"> <- </span>copy <span class="Constant">1/top</span> + column:number<span class="Special"> <- </span>copy left + cursor-row:address:number<span class="Special"> <- </span>get-address *editor, <span class="Constant">cursor-row:offset</span> + *cursor-row<span class="Special"> <- </span>copy target-row + cursor-column:address:number<span class="Special"> <- </span>get-address *editor, <span class="Constant">cursor-column:offset</span> + *cursor-column<span class="Special"> <- </span>copy target-column + before-cursor:address:address:duplex-list<span class="Special"> <- </span>get-address *editor, <span class="Constant">before-cursor:offset</span> + <span class="Delimiter">{</span> +<span class="Constant"> +next-character</span> + <span class="muControl">break-unless</span> curr + off-screen?:boolean<span class="Special"> <- </span>greater-or-equal row, screen-height + <span class="muControl">break-if</span> off-screen? + <span class="Comment"># update editor-data.before-cursor</span> + <span class="Comment"># Doing so at the start of each iteration ensures it stays one step behind</span> + <span class="Comment"># the current character.</span> + <span class="Delimiter">{</span> + at-cursor-row?:boolean<span class="Special"> <- </span>equal row, *cursor-row + <span class="muControl">break-unless</span> at-cursor-row? + at-cursor?:boolean<span class="Special"> <- </span>equal column, *cursor-column + <span class="muControl">break-unless</span> at-cursor? + *before-cursor<span class="Special"> <- </span>copy prev + <span class="Delimiter">}</span> + c:character<span class="Special"> <- </span>get *curr, <span class="Constant">value:offset</span> + <span class="Delimiter">{</span> + <span class="Comment"># newline? move to left rather than 0</span> + newline?:boolean<span class="Special"> <- </span>equal c, <span class="Constant">10/newline</span> + <span class="muControl">break-unless</span> newline? + <span class="Comment"># adjust cursor if necessary</span> + <span class="Delimiter">{</span> + at-cursor-row?:boolean<span class="Special"> <- </span>equal row, *cursor-row + <span class="muControl">break-unless</span> at-cursor-row? + left-of-cursor?:boolean<span class="Special"> <- </span>lesser-than column, *cursor-column + <span class="muControl">break-unless</span> left-of-cursor? + *cursor-column<span class="Special"> <- </span>copy column + *before-cursor<span class="Special"> <- </span>copy prev + <span class="Delimiter">}</span> + <span class="Comment"># skip to next line</span> + row<span class="Special"> <- </span>add row, <span class="Constant">1</span> + column<span class="Special"> <- </span>copy left + curr<span class="Special"> <- </span>next-duplex curr + prev<span class="Special"> <- </span>next-duplex prev + <span class="muControl">loop</span> <span class="Constant">+next-character:label</span> + <span class="Delimiter">}</span> + <span class="Delimiter">{</span> + <span class="Comment"># at right? wrap. even if there's only one more letter left; we need</span> + <span class="Comment"># room for clicking on the cursor after it.</span> + at-right?:boolean<span class="Special"> <- </span>equal column, right + <span class="muControl">break-unless</span> at-right? + column<span class="Special"> <- </span>copy left + row<span class="Special"> <- </span>add row, <span class="Constant">1</span> + <span class="Comment"># don't increment curr/prev</span> + <span class="muControl">loop</span> <span class="Constant">+next-character:label</span> + <span class="Delimiter">}</span> + curr<span class="Special"> <- </span>next-duplex curr + prev<span class="Special"> <- </span>next-duplex prev + column<span class="Special"> <- </span>add column, <span class="Constant">1</span> + <span class="muControl">loop</span> + <span class="Delimiter">}</span> + <span class="Comment"># is cursor to the right of the last line? move to end</span> + <span class="Delimiter">{</span> + at-cursor-row?:boolean<span class="Special"> <- </span>equal row, *cursor-row + cursor-outside-line?:boolean<span class="Special"> <- </span>lesser-or-equal column, *cursor-column + before-cursor-on-same-line?:boolean<span class="Special"> <- </span>and at-cursor-row?, cursor-outside-line? + above-cursor-row?:boolean<span class="Special"> <- </span>lesser-than row, *cursor-row + before-cursor?:boolean<span class="Special"> <- </span>or before-cursor-on-same-line?, above-cursor-row? + <span class="muControl">break-unless</span> before-cursor? + *cursor-row<span class="Special"> <- </span>copy row + *cursor-column<span class="Special"> <- </span>copy column + *before-cursor<span class="Special"> <- </span>copy prev + <span class="Delimiter">}</span> + <span class="muControl">reply</span> editor/same-as-ingredient:<span class="Constant">1</span> +] + +<span class="Comment"># screen, editor, go-render?:boolean <- handle-keyboard-event screen:address, editor:address:editor-data, e:event</span> +<span class="Comment"># Process an event 'e' and try to minimally update the screen.</span> +<span class="Comment"># Set 'go-render?' to true to indicate the caller must perform a non-minimal update.</span> +<span class="muRecipe">recipe</span> handle-keyboard-event [ + <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> + e:event<span class="Special"> <- </span><span class="Constant">next-ingredient</span> + <span class="muControl">reply-unless</span> editor, screen/same-as-ingredient:<span class="Constant">0</span>, editor/same-as-ingredient:<span class="Constant">1</span>, <span class="Constant">0/no-more-render</span> + screen-width:number<span class="Special"> <- </span>screen-width screen + screen-height:number<span class="Special"> <- </span>screen-height screen + left:number<span class="Special"> <- </span>get *editor, <span class="Constant">left:offset</span> + right:number<span class="Special"> <- </span>get *editor, <span class="Constant">right:offset</span> + before-cursor:address:address:duplex-list<span class="Special"> <- </span>get-address *editor, <span class="Constant">before-cursor:offset</span> + cursor-row:address:number<span class="Special"> <- </span>get-address *editor, <span class="Constant">cursor-row:offset</span> + cursor-column:address:number<span class="Special"> <- </span>get-address *editor, <span class="Constant">cursor-column:offset</span> + save-row:number<span class="Special"> <- </span>copy *cursor-row + save-column:number<span class="Special"> <- </span>copy *cursor-column + <span class="Comment"># character</span> + <span class="Delimiter">{</span> + c:address:character<span class="Special"> <- </span>maybe-convert e, <span class="Constant">text:variant</span> + <span class="muControl">break-unless</span> c + trace <span class="Constant">10</span>, <span class="Constant">[app]</span>, <span class="Constant">[handle-keyboard-event: special character]</span> + <span class="Comment"># exceptions for special characters go here</span> +<span class="Constant"> <handle-special-character></span> + <span class="Comment"># ignore any other special characters</span> + regular-character?:boolean<span class="Special"> <- </span>greater-or-equal *c, <span class="Constant">32/space</span> + <span class="muControl">reply-unless</span> regular-character?, screen/same-as-ingredient:<span class="Constant">0</span>, editor/same-as-ingredient:<span class="Constant">1</span>, <span class="Constant">0/no-more-render</span> + <span class="Comment"># otherwise type it in</span> +<span class="Constant"> <insert-character-begin></span> + editor, screen, go-render?:boolean<span class="Special"> <- </span>insert-at-cursor editor, *c, screen +<span class="Constant"> <insert-character-end></span> + <span class="muControl">reply</span> screen/same-as-ingredient:<span class="Constant">0</span>, editor/same-as-ingredient:<span class="Constant">1</span>, go-render? + <span class="Delimiter">}</span> + <span class="Comment"># special key to modify the text or move the cursor</span> + k:address:number<span class="Special"> <- </span>maybe-convert e:event, <span class="Constant">keycode:variant</span> + assert k, <span class="Constant">[event was of unknown type; neither keyboard nor mouse]</span> + <span class="Comment"># handlers for each special key will go here</span> +<span class="Constant"> <handle-special-key></span> + <span class="muControl">reply</span> screen/same-as-ingredient:<span class="Constant">0</span>, editor/same-as-ingredient:<span class="Constant">1</span>, <span class="Constant">1/go-render</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> + before-cursor:address:address:duplex-list<span class="Special"> <- </span>get-address *editor, <span class="Constant">before-cursor:offset</span> + insert-duplex c, *before-cursor + *before-cursor<span class="Special"> <- </span>next-duplex *before-cursor + cursor-row:address:number<span class="Special"> <- </span>get-address *editor, <span class="Constant">cursor-row:offset</span> + cursor-column:address:number<span class="Special"> <- </span>get-address *editor, <span class="Constant">cursor-column:offset</span> + left:number<span class="Special"> <- </span>get *editor, <span class="Constant">left:offset</span> + right:number<span class="Special"> <- </span>get *editor, <span class="Constant">right:offset</span> + save-row:number<span class="Special"> <- </span>copy *cursor-row + save-column:number<span class="Special"> <- </span>copy *cursor-column + screen-width:number<span class="Special"> <- </span>screen-width screen + screen-height:number<span class="Special"> <- </span>screen-height screen + <span class="Comment"># occasionally we'll need to mess with the cursor</span> +<span class="Constant"> <insert-character-special-case></span> + <span class="Comment"># but mostly we'll just move the cursor right</span> + *cursor-column<span class="Special"> <- </span>add *cursor-column, <span class="Constant">1</span> + next:address:duplex-list<span class="Special"> <- </span>next-duplex *before-cursor + <span class="Delimiter">{</span> + <span class="Comment"># at end of all text? no need to scroll? just print the character and leave</span> + at-end?:boolean<span class="Special"> <- </span>equal next, <span class="Constant">0/null</span> + <span class="muControl">break-unless</span> at-end? + bottom:number<span class="Special"> <- </span>subtract screen-height, <span class="Constant">1</span> + at-bottom?:boolean<span class="Special"> <- </span>equal save-row, bottom + at-right?:boolean<span class="Special"> <- </span>equal save-column, right + overflow?:boolean<span class="Special"> <- </span>and at-bottom?, at-right? + <span class="muControl">break-if</span> overflow? + move-cursor screen, save-row, save-column + print-character screen, c + <span class="muControl">reply</span> editor/same-as-ingredient:<span class="Constant">0</span>, screen/same-as-ingredient:<span class="Constant">2</span>, <span class="Constant">0/no-more-render</span> + <span class="Delimiter">}</span> + <span class="Delimiter">{</span> + <span class="Comment"># not at right margin? print the character and rest of line</span> + <span class="muControl">break-unless</span> next + at-right?:boolean<span class="Special"> <- </span>greater-or-equal *cursor-column, screen-width + <span class="muControl">break-if</span> at-right? + curr:address:duplex-list<span class="Special"> <- </span>copy *before-cursor + move-cursor screen, save-row, save-column + curr-column:number<span class="Special"> <- </span>copy save-column + <span class="Delimiter">{</span> + <span class="Comment"># hit right margin? give up and let caller render</span> + at-right?:boolean<span class="Special"> <- </span>greater-than curr-column, right + <span class="muControl">reply-if</span> at-right?, editor/same-as-ingredient:<span class="Constant">0</span>, screen/same-as-ingredient:<span class="Constant">2</span>, <span class="Constant">1/go-render</span> + <span class="muControl">break-unless</span> curr + <span class="Comment"># newline? done.</span> + currc:character<span class="Special"> <- </span>get *curr, <span class="Constant">value:offset</span> + at-newline?:boolean<span class="Special"> <- </span>equal currc, <span class="Constant">10/newline</span> + <span class="muControl">break-if</span> at-newline? + print-character screen, currc + curr-column<span class="Special"> <- </span>add curr-column, <span class="Constant">1</span> + curr<span class="Special"> <- </span>next-duplex curr + <span class="muControl">loop</span> + <span class="Delimiter">}</span> + <span class="muControl">reply</span> editor/same-as-ingredient:<span class="Constant">0</span>, screen/same-as-ingredient:<span class="Constant">2</span>, <span class="Constant">0/no-more-render</span> + <span class="Delimiter">}</span> + <span class="muControl">reply</span> editor/same-as-ingredient:<span class="Constant">0</span>, screen/same-as-ingredient:<span class="Constant">2</span>, <span class="Constant">1/go-render</span> +] + +<span class="Comment"># helper for tests</span> +<span class="muRecipe">recipe</span> editor-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> + left:number<span class="Special"> <- </span>get *editor, <span class="Constant">left:offset</span> + right:number<span class="Special"> <- </span>get *editor, <span class="Constant">right:offset</span> + row:number, column:number<span class="Special"> <- </span>render screen, editor + clear-line-delimited screen, column, right + row<span class="Special"> <- </span>add row, <span class="Constant">1</span> + draw-horizontal screen, row, left, right, <span class="Constant">9480/horizontal-dotted</span> + row<span class="Special"> <- </span>add row, <span class="Constant">1</span> + clear-screen-from screen, row, left, left, right +] + +<span class="muScenario">scenario</span> editor-handles-empty-event-queue [ + assume-screen <span class="Constant">10/width</span>, <span class="Constant">5/height</span> + <span class="Constant">1</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[abc]</span> + <span class="Constant">2</span>:address:editor-data<span class="Special"> <- </span>new-editor <span class="Constant">1</span>:address:array:character, screen:address, <span class="Constant">0/left</span>, <span class="Constant">10/right</span> + editor-render screen, <span class="Constant">2</span>:address:editor-data + assume-console <span class="Constant">[]</span> + run [ + editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data + ] + screen-should-contain [ + <span class="Constant"> . .</span> + <span class="Constant"> .abc .</span> +<span class="Constant"> .┈┈┈┈┈┈┈┈┈┈.</span> + <span class="Constant"> . .</span> + ] +] + +<span class="muScenario">scenario</span> editor-handles-mouse-clicks [ + assume-screen <span class="Constant">10/width</span>, <span class="Constant">5/height</span> + <span class="Constant">1</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[abc]</span> + <span class="Constant">2</span>:address:editor-data<span class="Special"> <- </span>new-editor <span class="Constant">1</span>:address:array:character, screen:address, <span class="Constant">0/left</span>, <span class="Constant">10/right</span> + editor-render screen, <span class="Constant">2</span>:address:editor-data +<span class="Constant"> $clear-trace</span> + assume-console [ + left-click <span class="Constant">1</span>, <span class="Constant">1</span> <span class="Comment"># on the 'b'</span> + ] + run [ + editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data + <span class="Constant">3</span>:number<span class="Special"> <- </span>get *<span class="Constant">2</span>:address:editor-data, <span class="Constant">cursor-row:offset</span> + <span class="Constant">4</span>:number<span class="Special"> <- </span>get *<span class="Constant">2</span>:address:editor-data, <span class="Constant">cursor-column:offset</span> + ] + screen-should-contain [ + <span class="Constant"> . .</span> + <span class="Constant"> .abc .</span> +<span class="Constant"> .┈┈┈┈┈┈┈┈┈┈.</span> + <span class="Constant"> . .</span> + ] + memory-should-contain [ + <span class="Constant">3</span><span class="Special"> <- </span><span class="Constant">1</span> <span class="Comment"># cursor is at row 0..</span> + <span class="Constant">4</span><span class="Special"> <- </span><span class="Constant">1</span> <span class="Comment"># ..and column 1</span> + ] + check-trace-count-for-label <span class="Constant">0</span>, <span class="Constant">[print-character]</span> +] + +<span class="muScenario">scenario</span> editor-handles-mouse-clicks-outside-text [ + assume-screen <span class="Constant">10/width</span>, <span class="Constant">5/height</span> + <span class="Constant">1</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[abc]</span> + <span class="Constant">2</span>:address:editor-data<span class="Special"> <- </span>new-editor <span class="Constant">1</span>:address:array:character, screen:address, <span class="Constant">0/left</span>, <span class="Constant">10/right</span> +<span class="Constant"> $clear-trace</span> + assume-console [ + left-click <span class="Constant">1</span>, <span class="Constant">7</span> <span class="Comment"># last line, to the right of text</span> + ] + run [ + editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data + <span class="Constant">3</span>:number<span class="Special"> <- </span>get *<span class="Constant">2</span>:address:editor-data, <span class="Constant">cursor-row:offset</span> + <span class="Constant">4</span>:number<span class="Special"> <- </span>get *<span class="Constant">2</span>:address:editor-data, <span class="Constant">cursor-column:offset</span> + ] + memory-should-contain [ + <span class="Constant">3</span><span class="Special"> <- </span><span class="Constant">1</span> <span class="Comment"># cursor row</span> + <span class="Constant">4</span><span class="Special"> <- </span><span class="Constant">3</span> <span class="Comment"># cursor column</span> + ] + check-trace-count-for-label <span class="Constant">0</span>, <span class="Constant">[print-character]</span> +] + +<span class="muScenario">scenario</span> editor-handles-mouse-clicks-outside-text-2 [ + assume-screen <span class="Constant">10/width</span>, <span class="Constant">5/height</span> + <span class="Constant">1</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[abc</span> +<span class="Constant">def]</span> + <span class="Constant">2</span>:address:editor-data<span class="Special"> <- </span>new-editor <span class="Constant">1</span>:address:array:character, screen:address, <span class="Constant">0/left</span>, <span class="Constant">10/right</span> +<span class="Constant"> $clear-trace</span> + assume-console [ + left-click <span class="Constant">1</span>, <span class="Constant">7</span> <span class="Comment"># interior line, to the right of text</span> + ] + run [ + editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data + <span class="Constant">3</span>:number<span class="Special"> <- </span>get *<span class="Constant">2</span>:address:editor-data, <span class="Constant">cursor-row:offset</span> + <span class="Constant">4</span>:number<span class="Special"> <- </span>get *<span class="Constant">2</span>:address:editor-data, <span class="Constant">cursor-column:offset</span> + ] + memory-should-contain [ + <span class="Constant">3</span><span class="Special"> <- </span><span class="Constant">1</span> <span class="Comment"># cursor row</span> + <span class="Constant">4</span><span class="Special"> <- </span><span class="Constant">3</span> <span class="Comment"># cursor column</span> + ] + check-trace-count-for-label <span class="Constant">0</span>, <span class="Constant">[print-character]</span> +] + +<span class="muScenario">scenario</span> editor-handles-mouse-clicks-outside-text-3 [ + assume-screen <span class="Constant">10/width</span>, <span class="Constant">5/height</span> + <span class="Constant">1</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[abc</span> +<span class="Constant">def]</span> + <span class="Constant">2</span>:address:editor-data<span class="Special"> <- </span>new-editor <span class="Constant">1</span>:address:array:character, screen:address, <span class="Constant">0/left</span>, <span class="Constant">10/right</span> +<span class="Constant"> $clear-trace</span> + assume-console [ + left-click <span class="Constant">3</span>, <span class="Constant">7</span> <span class="Comment"># below text</span> + ] + run [ + editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data + <span class="Constant">3</span>:number<span class="Special"> <- </span>get *<span class="Constant">2</span>:address:editor-data, <span class="Constant">cursor-row:offset</span> + <span class="Constant">4</span>:number<span class="Special"> <- </span>get *<span class="Constant">2</span>:address:editor-data, <span class="Constant">cursor-column:offset</span> + ] + memory-should-contain [ + <span class="Constant">3</span><span class="Special"> <- </span><span class="Constant">2</span> <span class="Comment"># cursor row</span> + <span class="Constant">4</span><span class="Special"> <- </span><span class="Constant">3</span> <span class="Comment"># cursor column</span> + ] + check-trace-count-for-label <span class="Constant">0</span>, <span class="Constant">[print-character]</span> +] + +<span class="muScenario">scenario</span> editor-handles-mouse-clicks-outside-column [ + assume-screen <span class="Constant">10/width</span>, <span class="Constant">5/height</span> + <span class="Constant">1</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[abc]</span> + <span class="Comment"># editor occupies only left half of screen</span> + <span class="Constant">2</span>:address:editor-data<span class="Special"> <- </span>new-editor <span class="Constant">1</span>:address:array:character, screen:address, <span class="Constant">0/left</span>, <span class="Constant">5/right</span> + editor-render screen, <span class="Constant">2</span>:address:editor-data +<span class="Constant"> $clear-trace</span> + assume-console [ + <span class="Comment"># click on right half of screen</span> + left-click <span class="Constant">3</span>, <span class="Constant">8</span> + ] + run [ + editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data + <span class="Constant">3</span>:number<span class="Special"> <- </span>get *<span class="Constant">2</span>:address:editor-data, <span class="Constant">cursor-row:offset</span> + <span class="Constant">4</span>:number<span class="Special"> <- </span>get *<span class="Constant">2</span>:address:editor-data, <span class="Constant">cursor-column:offset</span> + ] + screen-should-contain [ + <span class="Constant"> . .</span> + <span class="Constant"> .abc .</span> + <span class="Constant"> .┈┈┈┈┈ .</span> + <span class="Constant"> . .</span> + ] + memory-should-contain [ + <span class="Constant">3</span><span class="Special"> <- </span><span class="Constant">1</span> <span class="Comment"># no change to cursor row</span> + <span class="Constant">4</span><span class="Special"> <- </span><span class="Constant">0</span> <span class="Comment"># ..or column</span> + ] + check-trace-count-for-label <span class="Constant">0</span>, <span class="Constant">[print-character]</span> +] + +<span class="muScenario">scenario</span> editor-handles-mouse-clicks-in-menu-area [ + assume-screen <span class="Constant">10/width</span>, <span class="Constant">5/height</span> + <span class="Constant">1</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[abc]</span> + <span class="Constant">2</span>:address:editor-data<span class="Special"> <- </span>new-editor <span class="Constant">1</span>:address:array:character, screen:address, <span class="Constant">0/left</span>, <span class="Constant">5/right</span> + editor-render screen, <span class="Constant">2</span>:address:editor-data +<span class="Constant"> $clear-trace</span> + assume-console [ + <span class="Comment"># click on first, 'menu' row</span> + left-click <span class="Constant">0</span>, <span class="Constant">3</span> + ] + run [ + editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data + <span class="Constant">3</span>:number<span class="Special"> <- </span>get *<span class="Constant">2</span>:address:editor-data, <span class="Constant">cursor-row:offset</span> + <span class="Constant">4</span>:number<span class="Special"> <- </span>get *<span class="Constant">2</span>:address:editor-data, <span class="Constant">cursor-column:offset</span> + ] + <span class="Comment"># no change to cursor</span> + memory-should-contain [ + <span class="Constant">3</span><span class="Special"> <- </span><span class="Constant">1</span> + <span class="Constant">4</span><span class="Special"> <- </span><span class="Constant">0</span> + ] +] + +<span class="muScenario">scenario</span> editor-inserts-characters-into-empty-editor [ + assume-screen <span class="Constant">10/width</span>, <span class="Constant">5/height</span> + <span class="Constant">1</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[]</span> + <span class="Constant">2</span>:address:editor-data<span class="Special"> <- </span>new-editor <span class="Constant">1</span>:address:array:character, screen:address, <span class="Constant">0/left</span>, <span class="Constant">5/right</span> + editor-render screen, <span class="Constant">2</span>:address:editor-data +<span class="Constant"> $clear-trace</span> + assume-console [ + type <span class="Constant">[abc]</span> + ] + run [ + editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data + ] + screen-should-contain [ + <span class="Constant"> . .</span> + <span class="Constant"> .abc .</span> + <span class="Constant"> .┈┈┈┈┈ .</span> + <span class="Constant"> . .</span> + ] + check-trace-count-for-label <span class="Constant">3</span>, <span class="Constant">[print-character]</span> +] + +<span class="muScenario">scenario</span> editor-inserts-characters-at-cursor [ + assume-screen <span class="Constant">10/width</span>, <span class="Constant">5/height</span> + <span class="Constant">1</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[abc]</span> + <span class="Constant">2</span>:address:editor-data<span class="Special"> <- </span>new-editor <span class="Constant">1</span>:address:array:character, screen:address, <span class="Constant">0/left</span>, <span class="Constant">10/right</span> + editor-render screen, <span class="Constant">2</span>:address:editor-data +<span class="Constant"> $clear-trace</span> + <span class="Comment"># type two letters at different places</span> + assume-console [ + type <span class="Constant">[0]</span> + left-click <span class="Constant">1</span>, <span class="Constant">2</span> + type <span class="Constant">[d]</span> + ] + run [ + editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data + ] + screen-should-contain [ + <span class="Constant"> . .</span> + <span class="Constant"> .0adbc .</span> +<span class="Constant"> .┈┈┈┈┈┈┈┈┈┈.</span> + <span class="Constant"> . .</span> + ] + check-trace-count-for-label <span class="Constant">7</span>, <span class="Constant">[print-character]</span> <span class="Comment"># 4 for first letter, 3 for second</span> +] + +<span class="muScenario">scenario</span> editor-inserts-characters-at-cursor-2 [ + assume-screen <span class="Constant">10/width</span>, <span class="Constant">5/height</span> + <span class="Constant">1</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[abc]</span> + <span class="Constant">2</span>:address:editor-data<span class="Special"> <- </span>new-editor <span class="Constant">1</span>:address:array:character, screen:address, <span class="Constant">0/left</span>, <span class="Constant">10/right</span> + editor-render screen, <span class="Constant">2</span>:address:editor-data +<span class="Constant"> $clear-trace</span> + assume-console [ + left-click <span class="Constant">1</span>, <span class="Constant">5</span> <span class="Comment"># right of last line</span> + type <span class="Constant">[d]</span> + ] + run [ + editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data + ] + screen-should-contain [ + <span class="Constant"> . .</span> + <span class="Constant"> .abcd .</span> +<span class="Constant"> .┈┈┈┈┈┈┈┈┈┈.</span> + <span class="Constant"> . .</span> + ] + check-trace-count-for-label <span class="Constant">1</span>, <span class="Constant">[print-character]</span> +] + +<span class="muScenario">scenario</span> editor-inserts-characters-at-cursor-5 [ + assume-screen <span class="Constant">10/width</span>, <span class="Constant">5/height</span> + <span class="Constant">1</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[abc</span> +<span class="Constant">d]</span> + <span class="Constant">2</span>:address:editor-data<span class="Special"> <- </span>new-editor <span class="Constant">1</span>:address:array:character, screen:address, <span class="Constant">0/left</span>, <span class="Constant">10/right</span> + editor-render screen, <span class="Constant">2</span>:address:editor-data +<span class="Constant"> $clear-trace</span> + assume-console [ + left-click <span class="Constant">1</span>, <span class="Constant">5</span> <span class="Comment"># right of non-last line</span> + type <span class="Constant">[e]</span> + ] + run [ + editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data + ] + screen-should-contain [ + <span class="Constant"> . .</span> + <span class="Constant"> .abce .</span> + <span class="Constant"> .d .</span> +<span class="Constant"> .┈┈┈┈┈┈┈┈┈┈.</span> + <span class="Constant"> . .</span> + ] + check-trace-count-for-label <span class="Constant">1</span>, <span class="Constant">[print-character]</span> +] + +<span class="muScenario">scenario</span> editor-inserts-characters-at-cursor-3 [ + assume-screen <span class="Constant">10/width</span>, <span class="Constant">5/height</span> + <span class="Constant">1</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[abc]</span> + <span class="Constant">2</span>:address:editor-data<span class="Special"> <- </span>new-editor <span class="Constant">1</span>:address:array:character, screen:address, <span class="Constant">0/left</span>, <span class="Constant">10/right</span> + editor-render screen, <span class="Constant">2</span>:address:editor-data +<span class="Constant"> $clear-trace</span> + assume-console [ + left-click <span class="Constant">3</span>, <span class="Constant">5</span> <span class="Comment"># below all text</span> + type <span class="Constant">[d]</span> + ] + run [ + editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data + ] + screen-should-contain [ + <span class="Constant"> . .</span> + <span class="Constant"> .abcd .</span> +<span class="Constant"> .┈┈┈┈┈┈┈┈┈┈.</span> + <span class="Constant"> . .</span> + ] + check-trace-count-for-label <span class="Constant">1</span>, <span class="Constant">[print-character]</span> +] + +<span class="muScenario">scenario</span> editor-inserts-characters-at-cursor-4 [ + assume-screen <span class="Constant">10/width</span>, <span class="Constant">5/height</span> + <span class="Constant">1</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[abc</span> +<span class="Constant">d]</span> + <span class="Constant">2</span>:address:editor-data<span class="Special"> <- </span>new-editor <span class="Constant">1</span>:address:array:character, screen:address, <span class="Constant">0/left</span>, <span class="Constant">10/right</span> + editor-render screen, <span class="Constant">2</span>:address:editor-data +<span class="Constant"> $clear-trace</span> + assume-console [ + left-click <span class="Constant">3</span>, <span class="Constant">5</span> <span class="Comment"># below all text</span> + type <span class="Constant">[e]</span> + ] + run [ + editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data + ] + screen-should-contain [ + <span class="Constant"> . .</span> + <span class="Constant"> .abc .</span> + <span class="Constant"> .de .</span> +<span class="Constant"> .┈┈┈┈┈┈┈┈┈┈.</span> + <span class="Constant"> . .</span> + ] + check-trace-count-for-label <span class="Constant">1</span>, <span class="Constant">[print-character]</span> +] + +<span class="muScenario">scenario</span> editor-inserts-characters-at-cursor-6 [ + assume-screen <span class="Constant">10/width</span>, <span class="Constant">5/height</span> + <span class="Constant">1</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[abc</span> +<span class="Constant">d]</span> + <span class="Constant">2</span>:address:editor-data<span class="Special"> <- </span>new-editor <span class="Constant">1</span>:address:array:character, screen:address, <span class="Constant">0/left</span>, <span class="Constant">10/right</span> + editor-render screen, <span class="Constant">2</span>:address:editor-data +<span class="Constant"> $clear-trace</span> + assume-console [ + left-click <span class="Constant">3</span>, <span class="Constant">5</span> <span class="Comment"># below all text</span> + type <span class="Constant">[ef]</span> + ] + run [ + editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data + ] + screen-should-contain [ + <span class="Constant"> . .</span> + <span class="Constant"> .abc .</span> + <span class="Constant"> .def .</span> +<span class="Constant"> .┈┈┈┈┈┈┈┈┈┈.</span> + <span class="Constant"> . .</span> + ] + check-trace-count-for-label <span class="Constant">2</span>, <span class="Constant">[print-character]</span> +] + +<span class="muScenario">scenario</span> editor-moves-cursor-after-inserting-characters [ + assume-screen <span class="Constant">10/width</span>, <span class="Constant">5/height</span> + <span class="Constant">1</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[ab]</span> + <span class="Constant">2</span>:address:editor-data<span class="Special"> <- </span>new-editor <span class="Constant">1</span>:address:array:character, screen:address, <span class="Constant">0/left</span>, <span class="Constant">5/right</span> + editor-render screen, <span class="Constant">2</span>:address:editor-data + assume-console [ + type <span class="Constant">[01]</span> + ] + run [ + editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data + ] + screen-should-contain [ + <span class="Constant"> . .</span> + <span class="Constant"> .01ab .</span> + <span class="Constant"> .┈┈┈┈┈ .</span> + <span class="Constant"> . .</span> + ] +] + +<span class="Comment"># if the cursor reaches the right margin, wrap the line</span> + +<span class="muScenario">scenario</span> editor-wraps-line-on-insert [ + assume-screen <span class="Constant">5/width</span>, <span class="Constant">5/height</span> + <span class="Constant">1</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[abc]</span> + <span class="Constant">2</span>:address:editor-data<span class="Special"> <- </span>new-editor <span class="Constant">1</span>:address:array:character, screen:address, <span class="Constant">0/left</span>, <span class="Constant">5/right</span> + editor-render screen, <span class="Constant">2</span>:address:editor-data + <span class="Comment"># type a letter</span> + assume-console [ + type <span class="Constant">[e]</span> + ] + run [ + editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data + ] + <span class="Comment"># no wrap yet</span> + screen-should-contain [ + <span class="Constant"> . .</span> + <span class="Constant"> .eabc .</span> +<span class="Constant"> .┈┈┈┈┈.</span> + <span class="Constant"> . .</span> + <span class="Constant"> . .</span> + ] + <span class="Comment"># type a second letter</span> + assume-console [ + type <span class="Constant">[f]</span> + ] + run [ + editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data + ] + <span class="Comment"># now wrap</span> + screen-should-contain [ + <span class="Constant"> . .</span> +<span class="Constant"> .efab↩.</span> + <span class="Constant"> .c .</span> +<span class="Constant"> .┈┈┈┈┈.</span> + <span class="Constant"> . .</span> + ] +] + +<span class="muScenario">scenario</span> editor-wraps-line-on-insert-2 [ + <span class="Comment"># create an editor with some text</span> + assume-screen <span class="Constant">10/width</span>, <span class="Constant">5/height</span> + <span class="Constant">1</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[abcdefg</span> +<span class="Constant">defg]</span> + <span class="Constant">2</span>:address:editor-data<span class="Special"> <- </span>new-editor <span class="Constant">1</span>:address:array:character, screen:address, <span class="Constant">0/left</span>, <span class="Constant">5/right</span> + editor-render screen, <span class="Constant">2</span>:address:editor-data + <span class="Comment"># type more text at the start</span> + assume-console [ + left-click <span class="Constant">3</span>, <span class="Constant">0</span> + type <span class="Constant">[abc]</span> + ] + run [ + editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data + <span class="Constant">3</span>:number<span class="Special"> <- </span>get *<span class="Constant">2</span>:address:editor-data, <span class="Constant">cursor-row:offset</span> + <span class="Constant">4</span>:number<span class="Special"> <- </span>get *<span class="Constant">2</span>:address:editor-data, <span class="Constant">cursor-column:offset</span> + ] + <span class="Comment"># cursor is not wrapped</span> + memory-should-contain [ + <span class="Constant">3</span><span class="Special"> <- </span><span class="Constant">3</span> + <span class="Constant">4</span><span class="Special"> <- </span><span class="Constant">3</span> + ] + <span class="Comment"># but line is wrapped</span> + screen-should-contain [ + <span class="Constant"> . .</span> + <span class="Constant"> .abcd↩ .</span> + <span class="Constant"> .efg .</span> + <span class="Constant"> .abcd↩ .</span> + <span class="Constant"> .efg .</span> + ] +] + +<span class="muRecipe">after</span> <span class="Constant"><insert-character-special-case></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, <span class="Constant">1</span> + at-wrap?:boolean<span class="Special"> <- </span>greater-or-equal *cursor-column, wrap-column + <span class="muControl">break-unless</span> at-wrap? + *cursor-column<span class="Special"> <- </span>subtract *cursor-column, wrap-column + *cursor-column<span class="Special"> <- </span>add *cursor-column, left + *cursor-row<span class="Special"> <- </span>add *cursor-row, <span class="Constant">1</span> + <span class="Comment"># if we're out of the screen, scroll down</span> + <span class="Delimiter">{</span> + below-screen?:boolean<span class="Special"> <- </span>greater-or-equal *cursor-row, screen-height + <span class="muControl">break-unless</span> below-screen? +<span class="Constant"> <scroll-down></span> + <span class="Delimiter">}</span> + <span class="muControl">reply</span> editor/same-as-ingredient:<span class="Constant">0</span>, screen/same-as-ingredient:<span class="Constant">2</span>, <span class="Constant">1/go-render</span> + <span class="Delimiter">}</span> +] + +<span class="muScenario">scenario</span> editor-wraps-cursor-after-inserting-characters [ + assume-screen <span class="Constant">10/width</span>, <span class="Constant">5/height</span> + <span class="Constant">1</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[abcde]</span> + <span class="Constant">2</span>:address:editor-data<span class="Special"> <- </span>new-editor <span class="Constant">1</span>:address:array:character, screen:address, <span class="Constant">0/left</span>, <span class="Constant">5/right</span> + assume-console [ + left-click <span class="Constant">1</span>, <span class="Constant">4</span> <span class="Comment"># line is full; no wrap icon yet</span> + type <span class="Constant">[f]</span> + ] + run [ + editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data + <span class="Constant">3</span>:number<span class="Special"> <- </span>get *<span class="Constant">2</span>:address:editor-data, <span class="Constant">cursor-row:offset</span> + <span class="Constant">4</span>:number<span class="Special"> <- </span>get *<span class="Constant">2</span>:address:editor-data, <span class="Constant">cursor-column:offset</span> + ] + screen-should-contain [ + <span class="Constant"> . .</span> + <span class="Constant"> .abcd↩ .</span> + <span class="Constant"> .fe .</span> + <span class="Constant"> .┈┈┈┈┈ .</span> + <span class="Constant"> . .</span> + ] + memory-should-contain [ + <span class="Constant">3</span><span class="Special"> <- </span><span class="Constant">2</span> <span class="Comment"># cursor row</span> + <span class="Constant">4</span><span class="Special"> <- </span><span class="Constant">1</span> <span class="Comment"># cursor column</span> + ] +] + +<span class="muScenario">scenario</span> editor-wraps-cursor-after-inserting-characters-2 [ + assume-screen <span class="Constant">10/width</span>, <span class="Constant">5/height</span> + <span class="Constant">1</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[abcde]</span> + <span class="Constant">2</span>:address:editor-data<span class="Special"> <- </span>new-editor <span class="Constant">1</span>:address:array:character, screen:address, <span class="Constant">0/left</span>, <span class="Constant">5/right</span> + assume-console [ + left-click <span class="Constant">1</span>, <span class="Constant">3</span> <span class="Comment"># right before the wrap icon</span> + type <span class="Constant">[f]</span> + ] + run [ + editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data + <span class="Constant">3</span>:number<span class="Special"> <- </span>get *<span class="Constant">2</span>:address:editor-data, <span class="Constant">cursor-row:offset</span> + <span class="Constant">4</span>:number<span class="Special"> <- </span>get *<span class="Constant">2</span>:address:editor-data, <span class="Constant">cursor-column:offset</span> + ] + screen-should-contain [ + <span class="Constant"> . .</span> + <span class="Constant"> .abcf↩ .</span> + <span class="Constant"> .de .</span> + <span class="Constant"> .┈┈┈┈┈ .</span> + <span class="Constant"> . .</span> + ] + memory-should-contain [ + <span class="Constant">3</span><span class="Special"> <- </span><span class="Constant">2</span> <span class="Comment"># cursor row</span> + <span class="Constant">4</span><span class="Special"> <- </span><span class="Constant">0</span> <span class="Comment"># cursor column</span> + ] +] + +<span class="muScenario">scenario</span> editor-wraps-cursor-to-left-margin [ + assume-screen <span class="Constant">10/width</span>, <span class="Constant">5/height</span> + <span class="Constant">1</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[abcde]</span> + <span class="Constant">2</span>:address:editor-data<span class="Special"> <- </span>new-editor <span class="Constant">1</span>:address:array:character, screen:address, <span class="Constant">2/left</span>, <span class="Constant">7/right</span> + assume-console [ + left-click <span class="Constant">1</span>, <span class="Constant">5</span> <span class="Comment"># line is full; no wrap icon yet</span> + type <span class="Constant">[01]</span> + ] + run [ + editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data + <span class="Constant">3</span>:number<span class="Special"> <- </span>get *<span class="Constant">2</span>:address:editor-data, <span class="Constant">cursor-row:offset</span> + <span class="Constant">4</span>:number<span class="Special"> <- </span>get *<span class="Constant">2</span>:address:editor-data, <span class="Constant">cursor-column:offset</span> + ] + screen-should-contain [ + <span class="Constant"> . .</span> + <span class="Constant"> . abc0↩ .</span> + <span class="Constant"> . 1de .</span> + <span class="Constant"> . ┈┈┈┈┈ .</span> + <span class="Constant"> . .</span> + ] + memory-should-contain [ + <span class="Constant">3</span><span class="Special"> <- </span><span class="Constant">2</span> <span class="Comment"># cursor row</span> + <span class="Constant">4</span><span class="Special"> <- </span><span class="Constant">3</span> <span class="Comment"># cursor column</span> + ] +] + +<span class="Comment"># if newline, move cursor to start of next line, and maybe align indent with previous line</span> + +<span class="muData">container</span> editor-data [ + indent?:boolean +] + +<span class="muRecipe">after</span> <span class="Constant"><editor-initialization></span> [ + indent?:address:boolean<span class="Special"> <- </span>get-address *result, <span class="Constant">indent?:offset</span> + *indent?<span class="Special"> <- </span>copy <span class="Constant">1/true</span> +] + +<span class="muScenario">scenario</span> editor-moves-cursor-down-after-inserting-newline [ + assume-screen <span class="Constant">10/width</span>, <span class="Constant">5/height</span> + <span class="Constant">1</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[abc]</span> + <span class="Constant">2</span>:address:editor-data<span class="Special"> <- </span>new-editor <span class="Constant">1</span>:address:array:character, screen:address, <span class="Constant">0/left</span>, <span class="Constant">10/right</span> + assume-console [ + type <span class="Constant">[0</span> +<span class="Constant">1]</span> + ] + run [ + editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data + ] + screen-should-contain [ + <span class="Constant"> . .</span> + <span class="Constant"> .0 .</span> + <span class="Constant"> .1abc .</span> +<span class="Constant"> .┈┈┈┈┈┈┈┈┈┈.</span> + <span class="Constant"> . .</span> + ] +] + +<span class="muRecipe">after</span> <span class="Constant"><handle-special-character></span> [ + <span class="Delimiter">{</span> + newline?:boolean<span class="Special"> <- </span>equal *c, <span class="Constant">10/newline</span> + <span class="muControl">break-unless</span> newline? +<span class="Constant"> <insert-enter-begin></span> + editor<span class="Special"> <- </span>insert-new-line-and-indent editor, screen +<span class="Constant"> <insert-enter-end></span> + <span class="muControl">reply</span> screen/same-as-ingredient:<span class="Constant">0</span>, editor/same-as-ingredient:<span class="Constant">1</span>, <span class="Constant">1/go-render</span> + <span class="Delimiter">}</span> +] + +<span class="muRecipe">recipe</span> insert-new-line-and-indent [ + <span class="Constant">local-scope</span> + editor:address:editor-data<span class="Special"> <- </span><span class="Constant">next-ingredient</span> + screen:address<span class="Special"> <- </span><span class="Constant">next-ingredient</span> + cursor-row:address:number<span class="Special"> <- </span>get-address *editor, <span class="Constant">cursor-row:offset</span> + cursor-column:address:number<span class="Special"> <- </span>get-address *editor, <span class="Constant">cursor-column:offset</span> + before-cursor:address:address:duplex-list<span class="Special"> <- </span>get-address *editor, <span class="Constant">before-cursor:offset</span> + left:number<span class="Special"> <- </span>get *editor, <span class="Constant">left:offset</span> + right:number<span class="Special"> <- </span>get *editor, <span class="Constant">right:offset</span> + screen-height:number<span class="Special"> <- </span>screen-height screen + <span class="Comment"># insert newline</span> + insert-duplex <span class="Constant">10/newline</span>, *before-cursor + *before-cursor<span class="Special"> <- </span>next-duplex *before-cursor + *cursor-row<span class="Special"> <- </span>add *cursor-row, <span class="Constant">1</span> + *cursor-column<span class="Special"> <- </span>copy left + <span class="Comment"># maybe scroll</span> + <span class="Delimiter">{</span> + below-screen?:boolean<span class="Special"> <- </span>greater-or-equal *cursor-row, screen-height <span class="Comment"># must be equal, never greater</span> + <span class="muControl">break-unless</span> below-screen? +<span class="Constant"> <scroll-down></span> + *cursor-row<span class="Special"> <- </span>subtract *cursor-row, <span class="Constant">1</span> <span class="Comment"># bring back into screen range</span> + <span class="Delimiter">}</span> + <span class="Comment"># indent if necessary</span> + indent?:boolean<span class="Special"> <- </span>get *editor, <span class="Constant">indent?:offset</span> + <span class="muControl">reply-unless</span> indent?, editor/same-as-ingredient:<span class="Constant">0</span>, screen/same-as-ingredient:<span class="Constant">1</span> + d:address:duplex-list<span class="Special"> <- </span>get *editor, <span class="Constant">data:offset</span> + end-of-previous-line:address:duplex-list<span class="Special"> <- </span>prev-duplex *before-cursor + indent:number<span class="Special"> <- </span>line-indent end-of-previous-line, d + i:number<span class="Special"> <- </span>copy <span class="Constant">0</span> + <span class="Delimiter">{</span> + indent-done?:boolean<span class="Special"> <- </span>greater-or-equal i, indent + <span class="muControl">break-if</span> indent-done? + editor, screen, go-render?:boolean<span class="Special"> <- </span>insert-at-cursor editor, <span class="Constant">32/space</span>, screen + i<span class="Special"> <- </span>add i, <span class="Constant">1</span> + <span class="muControl">loop</span> + <span class="Delimiter">}</span> + <span class="muControl">reply</span> editor/same-as-ingredient:<span class="Constant">0</span>, screen/same-as-ingredient:<span class="Constant">1</span> +] + +<span class="Comment"># takes a pointer 'curr' into the doubly-linked list and its sentinel, counts</span> +<span class="Comment"># the number of spaces at the start of the line containing 'curr'.</span> +<span class="muRecipe">recipe</span> line-indent [ + <span class="Constant">local-scope</span> + curr:address:duplex-list<span class="Special"> <- </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</span> + <span class="muControl">reply-unless</span> curr, result + at-start?:boolean<span class="Special"> <- </span>equal curr, start + <span class="muControl">reply-if</span> at-start?, result + <span class="Delimiter">{</span> + curr<span class="Special"> <- </span>prev-duplex curr + <span class="muControl">break-unless</span> curr + at-start?:boolean<span class="Special"> <- </span>equal curr, start + <span class="muControl">break-if</span> at-start? + c:character<span class="Special"> <- </span>get *curr, <span class="Constant">value:offset</span> + at-newline?:boolean<span class="Special"> <- </span>equal c, <span class="Constant">10/newline</span> + <span class="muControl">break-if</span> at-newline? + <span class="Comment"># if c is a space, increment result</span> + is-space?:boolean<span class="Special"> <- </span>equal c, <span class="Constant">32/space</span> + <span class="Delimiter">{</span> + <span class="muControl">break-unless</span> is-space? + result<span class="Special"> <- </span>add result, <span class="Constant">1</span> + <span class="Delimiter">}</span> + <span class="Comment"># if c is not a space, reset result</span> + <span class="Delimiter">{</span> + <span class="muControl">break-if</span> is-space? + result<span class="Special"> <- </span>copy <span class="Constant">0</span> + <span class="Delimiter">}</span> + <span class="muControl">loop</span> + <span class="Delimiter">}</span> + <span class="muControl">reply</span> result +] + +<span class="muScenario">scenario</span> editor-moves-cursor-down-after-inserting-newline-2 [ + assume-screen <span class="Constant">10/width</span>, <span class="Constant">5/height</span> + <span class="Constant">1</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[abc]</span> + <span class="Constant">2</span>:address:editor-data<span class="Special"> <- </span>new-editor <span class="Constant">1</span>:address:array:character, screen:address, <span class="Constant">1/left</span>, <span class="Constant">10/right</span> + assume-console [ + type <span class="Constant">[0</span> +<span class="Constant">1]</span> + ] + run [ + editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data + ] + screen-should-contain [ + <span class="Constant"> . .</span> + <span class="Constant"> . 0 .</span> + <span class="Constant"> . 1abc .</span> + <span class="Constant"> . ┈┈┈┈┈┈┈┈┈.</span> + <span class="Constant"> . .</span> + ] +] + +<span class="muScenario">scenario</span> editor-clears-previous-line-completely-after-inserting-newline [ + assume-screen <span class="Constant">10/width</span>, <span class="Constant">5/height</span> + <span class="Constant">1</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[abcde]</span> + <span class="Constant">2</span>:address:editor-data<span class="Special"> <- </span>new-editor <span class="Constant">1</span>:address:array:character, screen:address, <span class="Constant">0/left</span>, <span class="Constant">5/right</span> + assume-console [ + press enter + ] + screen-should-contain [ + <span class="Constant"> . .</span> + <span class="Constant"> .abcd↩ .</span> + <span class="Constant"> .e .</span> + <span class="Constant"> . .</span> + <span class="Constant"> . .</span> + ] + run [ + editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data + ] + <span class="Comment"># line should be fully cleared</span> + screen-should-contain [ + <span class="Constant"> . .</span> + <span class="Constant"> . .</span> + <span class="Constant"> .abcd↩ .</span> + <span class="Constant"> .e .</span> + <span class="Constant"> .┈┈┈┈┈ .</span> + ] +] + +<span class="muScenario">scenario</span> editor-inserts-indent-after-newline [ + assume-screen <span class="Constant">10/width</span>, <span class="Constant">10/height</span> + <span class="Constant">1</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[ab</span> +<span class="Constant"> cd</span> +<span class="Constant">ef]</span> + <span class="Constant">2</span>:address:editor-data<span class="Special"> <- </span>new-editor <span class="Constant">1</span>:address:array:character, screen:address, <span class="Constant">0/left</span>, <span class="Constant">10/right</span> + <span class="Comment"># position cursor after 'cd' and hit 'newline'</span> + assume-console [ + left-click <span class="Constant">2</span>, <span class="Constant">8</span> + type [ +] + ] + run [ + editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data + <span class="Constant">3</span>:number<span class="Special"> <- </span>get *<span class="Constant">2</span>:address:editor-data, <span class="Constant">cursor-row:offset</span> + <span class="Constant">4</span>:number<span class="Special"> <- </span>get *<span class="Constant">2</span>:address:editor-data, <span class="Constant">cursor-column:offset</span> + ] + <span class="Comment"># cursor should be below start of previous line</span> + memory-should-contain [ + <span class="Constant">3</span><span class="Special"> <- </span><span class="Constant">3</span> <span class="Comment"># cursor row</span> + <span class="Constant">4</span><span class="Special"> <- </span><span class="Constant">2</span> <span class="Comment"># cursor column (indented)</span> + ] +] + +<span class="muScenario">scenario</span> editor-skips-indent-around-paste [ + assume-screen <span class="Constant">10/width</span>, <span class="Constant">10/height</span> + <span class="Constant">1</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[ab</span> +<span class="Constant"> cd</span> +<span class="Constant">ef]</span> + <span class="Constant">2</span>:address:editor-data<span class="Special"> <- </span>new-editor <span class="Constant">1</span>:address:array:character, screen:address, <span class="Constant">0/left</span>, <span class="Constant">10/right</span> + <span class="Comment"># position cursor after 'cd' and hit 'newline' surrounded by paste markers</span> + assume-console [ + left-click <span class="Constant">2</span>, <span class="Constant">8</span> + press <span class="Constant">65507</span> <span class="Comment"># start paste</span> + press enter + press <span class="Constant">65506</span> <span class="Comment"># end paste</span> + ] + run [ + editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data + <span class="Constant">3</span>:number<span class="Special"> <- </span>get *<span class="Constant">2</span>:address:editor-data, <span class="Constant">cursor-row:offset</span> + <span class="Constant">4</span>:number<span class="Special"> <- </span>get *<span class="Constant">2</span>:address:editor-data, <span class="Constant">cursor-column:offset</span> + ] + <span class="Comment"># cursor should be below start of previous line</span> + memory-should-contain [ + <span class="Constant">3</span><span class="Special"> <- </span><span class="Constant">3</span> <span class="Comment"># cursor row</span> + <span class="Constant">4</span><span class="Special"> <- </span><span class="Constant">0</span> <span class="Comment"># cursor column (not indented)</span> + ] +] + +<span class="muRecipe">after</span> <span class="Constant"><handle-special-key></span> [ + <span class="Delimiter">{</span> + paste-start?:boolean<span class="Special"> <- </span>equal *k, <span class="Constant">65507/paste-start</span> + <span class="muControl">break-unless</span> paste-start? + indent?:address:boolean<span class="Special"> <- </span>get-address *editor, <span class="Constant">indent?:offset</span> + *indent?<span class="Special"> <- </span>copy <span class="Constant">0/false</span> + <span class="muControl">reply</span> screen/same-as-ingredient:<span class="Constant">0</span>, editor/same-as-ingredient:<span class="Constant">1</span>, <span class="Constant">1/go-render</span> + <span class="Delimiter">}</span> +] + +<span class="muRecipe">after</span> <span class="Constant"><handle-special-key></span> [ + <span class="Delimiter">{</span> + paste-end?:boolean<span class="Special"> <- </span>equal *k, <span class="Constant">65506/paste-end</span> + <span class="muControl">break-unless</span> paste-end? + indent?:address:boolean<span class="Special"> <- </span>get-address *editor, <span class="Constant">indent?:offset</span> + *indent?<span class="Special"> <- </span>copy <span class="Constant">1/true</span> + <span class="muControl">reply</span> screen/same-as-ingredient:<span class="Constant">0</span>, editor/same-as-ingredient:<span class="Constant">1</span>, <span class="Constant">1/go-render</span> + <span class="Delimiter">}</span> +] + +<span class="SalientComment">## helpers</span> + +<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? + style<span class="Special"> <- </span>copy <span class="Constant">9472/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? + color<span class="Special"> <- </span>copy <span class="Constant">245/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? + bg-color<span class="Special"> <- </span>copy <span class="Constant">0/black</span> + <span class="Delimiter">}</span> + screen<span class="Special"> <- </span>move-cursor screen, row, x + <span class="Delimiter">{</span> + continue?:boolean<span class="Special"> <- </span>lesser-or-equal x, right <span class="Comment"># right is inclusive, to match editor-data semantics</span> + <span class="muControl">break-unless</span> continue? + print-character screen, style, color, bg-color + x<span class="Special"> <- </span>add x, <span class="Constant">1</span> + <span class="muControl">loop</span> + <span class="Delimiter">}</span> +] +</pre> +</body> +</html> +<!-- vim: set foldmethod=manual : --> diff --git a/html/edit/003-shortcuts.mu.html b/html/edit/003-shortcuts.mu.html new file mode 100644 index 00000000..82273ba7 --- /dev/null +++ b/html/edit/003-shortcuts.mu.html @@ -0,0 +1,3107 @@ +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd"> +<html> +<head> +<meta http-equiv="content-type" content="text/html; charset=UTF-8"> +<title>Mu - edit/003-shortcuts.mu</title> +<meta name="Generator" content="Vim/7.4"> +<meta name="plugin-version" content="vim7.4_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; } +.Special { color: #ff6060; } +.muRecipe { color: #ff8700; } +.Comment { color: #9090ff; } +.Constant { color: #00a0a0; } +.SalientComment { color: #00ffff; } +.Delimiter { color: #a04060; } +.muControl { color: #c0a020; } +--> +</style> + +<script type='text/javascript'> +<!-- + +--> +</script> +</head> +<body> +<pre id='vimCodeElement'> +<span class="SalientComment">## special shortcuts for manipulating the editor</span> +<span class="Comment"># Some keys on the keyboard generate unicode characters, others generate</span> +<span class="Comment"># terminfo key codes. We need to modify different places in the two cases.</span> + +<span class="Comment"># tab - insert two spaces</span> + +<span class="muScenario">scenario</span> editor-inserts-two-spaces-on-tab [ + assume-screen <span class="Constant">10/width</span>, <span class="Constant">5/height</span> + <span class="Comment"># just one character in final line</span> + <span class="Constant">1</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[ab</span> +<span class="Constant">cd]</span> + <span class="Constant">2</span>:address:editor-data<span class="Special"> <- </span>new-editor <span class="Constant">1</span>:address:array:character, screen:address, <span class="Constant">0/left</span>, <span class="Constant">5/right</span> + assume-console [ + press tab + ] + run [ + editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data + ] + screen-should-contain [ + <span class="Constant"> . .</span> + <span class="Constant"> . ab .</span> + <span class="Constant"> .cd .</span> + ] +] + +<span class="muRecipe">after</span> <span class="Constant"><handle-special-character></span> [ + <span class="Delimiter">{</span> + tab?:boolean<span class="Special"> <- </span>equal *c, <span class="Constant">9/tab</span> + <span class="muControl">break-unless</span> tab? +<span class="Constant"> <insert-character-begin></span> + editor, screen, go-render?:boolean<span class="Special"> <- </span>insert-at-cursor editor, <span class="Constant">32/space</span>, screen + editor, screen, go-render?:boolean<span class="Special"> <- </span>insert-at-cursor editor, <span class="Constant">32/space</span>, screen +<span class="Constant"> <insert-character-end></span> + <span class="muControl">reply</span> screen/same-as-ingredient:<span class="Constant">0</span>, editor/same-as-ingredient:<span class="Constant">1</span>, <span class="Constant">1/go-render</span> + <span class="Delimiter">}</span> +] + +<span class="Comment"># backspace - delete character before cursor</span> + +<span class="muScenario">scenario</span> editor-handles-backspace-key [ + assume-screen <span class="Constant">10/width</span>, <span class="Constant">5/height</span> + <span class="Constant">1</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[abc]</span> + <span class="Constant">2</span>:address:editor-data<span class="Special"> <- </span>new-editor <span class="Constant">1</span>:address:array:character, screen:address, <span class="Constant">0/left</span>, <span class="Constant">10/right</span> + editor-render screen, <span class="Constant">2</span>:address:editor-data +<span class="Constant"> $clear-trace</span> + assume-console [ + left-click <span class="Constant">1</span>, <span class="Constant">1</span> + press backspace + ] + run [ + editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data + <span class="Constant">4</span>:number<span class="Special"> <- </span>get *<span class="Constant">2</span>:address:editor-data, <span class="Constant">cursor-row:offset</span> + <span class="Constant">5</span>:number<span class="Special"> <- </span>get *<span class="Constant">2</span>:address:editor-data, <span class="Constant">cursor-column:offset</span> + ] + screen-should-contain [ + <span class="Constant"> . .</span> + <span class="Constant"> .bc .</span> +<span class="Constant"> .┈┈┈┈┈┈┈┈┈┈.</span> + <span class="Constant"> . .</span> + ] + memory-should-contain [ + <span class="Constant">4</span><span class="Special"> <- </span><span class="Constant">1</span> + <span class="Constant">5</span><span class="Special"> <- </span><span class="Constant">0</span> + ] + check-trace-count-for-label <span class="Constant">3</span>, <span class="Constant">[print-character]</span> <span class="Comment"># length of original line to overwrite</span> +] + +<span class="muRecipe">after</span> <span class="Constant"><handle-special-character></span> [ + <span class="Delimiter">{</span> + delete-previous-character?:boolean<span class="Special"> <- </span>equal *c, <span class="Constant">8/backspace</span> + <span class="muControl">break-unless</span> delete-previous-character? +<span class="Constant"> <backspace-character-begin></span> + editor, screen, go-render?:boolean, backspaced-cell:address:duplex-list<span class="Special"> <- </span>delete-before-cursor editor, screen +<span class="Constant"> <backspace-character-end></span> + <span class="muControl">reply</span> screen/same-as-ingredient:<span class="Constant">0</span>, editor/same-as-ingredient:<span class="Constant">1</span>, go-render? + <span class="Delimiter">}</span> +] + +<span class="Comment"># editor, screen, go-render?:boolean, backspaced-cell:address:duplex-list <- delete-before-cursor editor:address:editor-data, screen</span> +<span class="Comment"># return values:</span> +<span class="Comment"># go-render? - whether caller needs to update the screen</span> +<span class="Comment"># backspaced-cell - value deleted (or 0 if nothing was deleted) so we can save it for undo, etc.</span> +<span class="muRecipe">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> + screen:address<span class="Special"> <- </span><span class="Constant">next-ingredient</span> + before-cursor:address:address:duplex-list<span class="Special"> <- </span>get-address *editor, <span class="Constant">before-cursor:offset</span> + <span class="Comment"># if at start of text (before-cursor at § sentinel), return</span> + prev:address:duplex-list<span class="Special"> <- </span>prev-duplex *before-cursor + <span class="muControl">reply-unless</span> prev, editor/same-as-ingredient:<span class="Constant">0</span>, screen/same-as-ingredient:<span class="Constant">1</span>, <span class="Constant">0/no-more-render</span>, <span class="Constant">0/nothing-deleted</span> + trace <span class="Constant">10</span>, <span class="Constant">[app]</span>, <span class="Constant">[delete-before-cursor]</span> + original-row:number<span class="Special"> <- </span>get *editor, <span class="Constant">cursor-row:offset</span> + editor, scroll?:boolean<span class="Special"> <- </span>move-cursor-coordinates-left editor + backspaced-cell:address:duplex-list<span class="Special"> <- </span>copy *before-cursor + remove-duplex *before-cursor <span class="Comment"># will also neatly trim next/prev pointers in backspaced-cell/*before-cursor</span> + *before-cursor<span class="Special"> <- </span>copy prev + <span class="muControl">reply-if</span> scroll?, editor/same-as-ingredient:<span class="Constant">0</span>, <span class="Constant">1/go-render</span>, backspaced-cell + screen-width:number<span class="Special"> <- </span>screen-width screen + cursor-row:number<span class="Special"> <- </span>get *editor, <span class="Constant">cursor-row:offset</span> + cursor-column:number<span class="Special"> <- </span>get *editor, <span class="Constant">cursor-column:offset</span> + <span class="Comment"># did we just backspace over a newline?</span> + same-row?:boolean<span class="Special"> <- </span>equal cursor-row, original-row + <span class="muControl">reply-unless</span> same-row?, editor/same-as-ingredient:<span class="Constant">0</span>, screen/same-as-ingredient:<span class="Constant">1</span>, <span class="Constant">1/go-render</span>, backspaced-cell + left:number<span class="Special"> <- </span>get *editor, <span class="Constant">left:offset</span> + right:number<span class="Special"> <- </span>get *editor, <span class="Constant">right:offset</span> + curr:address:duplex-list<span class="Special"> <- </span>next-duplex *before-cursor + screen<span class="Special"> <- </span>move-cursor screen, cursor-row, cursor-column + curr-column:number<span class="Special"> <- </span>copy cursor-column + <span class="Delimiter">{</span> + <span class="Comment"># hit right margin? give up and let caller render</span> + at-right?:boolean<span class="Special"> <- </span>greater-or-equal curr-column, screen-width + <span class="muControl">reply-if</span> at-right?, editor/same-as-ingredient:<span class="Constant">0</span>, screen/same-as-ingredient:<span class="Constant">1</span>, <span class="Constant">1/go-render</span>, backspaced-cell + <span class="muControl">break-unless</span> curr + <span class="Comment"># newline? done.</span> + currc:character<span class="Special"> <- </span>get *curr, <span class="Constant">value:offset</span> + at-newline?:boolean<span class="Special"> <- </span>equal currc, <span class="Constant">10/newline</span> + <span class="muControl">break-if</span> at-newline? + screen<span class="Special"> <- </span>print-character screen, currc + curr-column<span class="Special"> <- </span>add curr-column, <span class="Constant">1</span> + curr<span class="Special"> <- </span>next-duplex curr + <span class="muControl">loop</span> + <span class="Delimiter">}</span> + <span class="Comment"># we're guaranteed not to be at the right margin</span> + screen<span class="Special"> <- </span>print-character screen, <span class="Constant">32/space</span> + <span class="muControl">reply</span> editor/same-as-ingredient:<span class="Constant">0</span>, screen/same-as-ingredient:<span class="Constant">1</span>, <span class="Constant">0/no-more-render</span>, backspaced-cell +] + +<span class="muRecipe">recipe</span> move-cursor-coordinates-left [ + <span class="Constant">local-scope</span> + editor:address:editor-data<span class="Special"> <- </span><span class="Constant">next-ingredient</span> + before-cursor:address:duplex-list<span class="Special"> <- </span>get *editor, <span class="Constant">before-cursor:offset</span> + cursor-row:address:number<span class="Special"> <- </span>get-address *editor, <span class="Constant">cursor-row:offset</span> + cursor-column:address:number<span class="Special"> <- </span>get-address *editor, <span class="Constant">cursor-column:offset</span> + left:number<span class="Special"> <- </span>get *editor, <span class="Constant">left:offset</span> + <span class="Comment"># if not at left margin, move one character left</span> + <span class="Delimiter">{</span> + at-left-margin?:boolean<span class="Special"> <- </span>equal *cursor-column, left + <span class="muControl">break-if</span> at-left-margin? + trace <span class="Constant">10</span>, <span class="Constant">[app]</span>, <span class="Constant">[decrementing cursor column]</span> + *cursor-column<span class="Special"> <- </span>subtract *cursor-column, <span class="Constant">1</span> + <span class="muControl">reply</span> editor/same-as-ingredient:<span class="Constant">0</span>, <span class="Constant">0/no-more-render</span> + <span class="Delimiter">}</span> + <span class="Comment"># if at left margin, we must move to previous row:</span> + top-of-screen?:boolean<span class="Special"> <- </span>equal *cursor-row, <span class="Constant">1</span> <span class="Comment"># exclude menu bar</span> + go-render?:boolean<span class="Special"> <- </span>copy <span class="Constant">0/false</span> + <span class="Delimiter">{</span> + <span class="muControl">break-if</span> top-of-screen? + *cursor-row<span class="Special"> <- </span>subtract *cursor-row, <span class="Constant">1</span> + <span class="Delimiter">}</span> + <span class="Delimiter">{</span> + <span class="muControl">break-unless</span> top-of-screen? +<span class="Constant"> <scroll-up></span> + go-render?<span class="Special"> <- </span>copy <span class="Constant">1/true</span> + <span class="Delimiter">}</span> + <span class="Delimiter">{</span> + <span class="Comment"># case 1: if previous character was newline, figure out how long the previous line is</span> + previous-character:character<span class="Special"> <- </span>get *before-cursor, <span class="Constant">value:offset</span> + previous-character-is-newline?:boolean<span class="Special"> <- </span>equal previous-character, <span class="Constant">10/newline</span> + <span class="muControl">break-unless</span> previous-character-is-newline? + <span class="Comment"># compute length of previous line</span> + trace <span class="Constant">10</span>, <span class="Constant">[app]</span>, <span class="Constant">[switching to previous line]</span> + d:address:duplex-list<span class="Special"> <- </span>get *editor, <span class="Constant">data:offset</span> + end-of-line:number<span class="Special"> <- </span>previous-line-length before-cursor, d + *cursor-column<span class="Special"> <- </span>add left, end-of-line + <span class="muControl">reply</span> editor/same-as-ingredient:<span class="Constant">0</span>, go-render? + <span class="Delimiter">}</span> + <span class="Comment"># case 2: if previous-character was not newline, we're just at a wrapped line</span> + trace <span class="Constant">10</span>, <span class="Constant">[app]</span>, <span class="Constant">[wrapping to previous line]</span> + right:number<span class="Special"> <- </span>get *editor, <span class="Constant">right:offset</span> + *cursor-column<span class="Special"> <- </span>subtract right, <span class="Constant">1</span> <span class="Comment"># leave room for wrap icon</span> + <span class="muControl">reply</span> editor/same-as-ingredient:<span class="Constant">0</span>, go-render? +] + +<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</span> + <span class="muControl">reply-unless</span> curr, result + at-start?:boolean<span class="Special"> <- </span>equal curr, start + <span class="muControl">reply-if</span> at-start?, result + <span class="Delimiter">{</span> + curr<span class="Special"> <- </span>prev-duplex curr + <span class="muControl">break-unless</span> curr + at-start?:boolean<span class="Special"> <- </span>equal curr, start + <span class="muControl">break-if</span> at-start? + c:character<span class="Special"> <- </span>get *curr, <span class="Constant">value:offset</span> + at-newline?:boolean<span class="Special"> <- </span>equal c, <span class="Constant">10/newline</span> + <span class="muControl">break-if</span> at-newline? + result<span class="Special"> <- </span>add result, <span class="Constant">1</span> + <span class="muControl">loop</span> + <span class="Delimiter">}</span> + <span class="muControl">reply</span> result +] + +<span class="muScenario">scenario</span> editor-clears-last-line-on-backspace [ + assume-screen <span class="Constant">10/width</span>, <span class="Constant">5/height</span> + <span class="Comment"># just one character in final line</span> + <span class="Constant">1</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[ab</span> +<span class="Constant">cd]</span> + <span class="Constant">2</span>:address:editor-data<span class="Special"> <- </span>new-editor <span class="Constant">1</span>:address:array:character, screen:address, <span class="Constant">0/left</span>, <span class="Constant">10/right</span> + assume-console [ + left-click <span class="Constant">2</span>, <span class="Constant">0</span> <span class="Comment"># cursor at only character in final line</span> + press backspace + ] + run [ + editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data + <span class="Constant">4</span>:number<span class="Special"> <- </span>get *<span class="Constant">2</span>:address:editor-data, <span class="Constant">cursor-row:offset</span> + <span class="Constant">5</span>:number<span class="Special"> <- </span>get *<span class="Constant">2</span>:address:editor-data, <span class="Constant">cursor-column:offset</span> + ] + screen-should-contain [ + <span class="Constant"> . .</span> + <span class="Constant"> .abcd .</span> +<span class="Constant"> .┈┈┈┈┈┈┈┈┈┈.</span> + <span class="Constant"> . .</span> + ] + memory-should-contain [ + <span class="Constant">4</span><span class="Special"> <- </span><span class="Constant">1</span> + <span class="Constant">5</span><span class="Special"> <- </span><span class="Constant">2</span> + ] +] + +<span class="Comment"># delete - delete character at cursor</span> + +<span class="muScenario">scenario</span> editor-handles-delete-key [ + assume-screen <span class="Constant">10/width</span>, <span class="Constant">5/height</span> + <span class="Constant">1</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[abc]</span> + <span class="Constant">2</span>:address:editor-data<span class="Special"> <- </span>new-editor <span class="Constant">1</span>:address:array:character, screen:address, <span class="Constant">0/left</span>, <span class="Constant">10/right</span> + editor-render screen, <span class="Constant">2</span>:address:editor-data +<span class="Constant"> $clear-trace</span> + assume-console [ + press delete + ] + run [ + editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data + ] + screen-should-contain [ + <span class="Constant"> . .</span> + <span class="Constant"> .bc .</span> +<span class="Constant"> .┈┈┈┈┈┈┈┈┈┈.</span> + <span class="Constant"> . .</span> + ] + check-trace-count-for-label <span class="Constant">3</span>, <span class="Constant">[print-character]</span> <span class="Comment"># length of original line to overwrite</span> +<span class="Constant"> $clear-trace</span> + assume-console [ + press delete + ] + run [ + editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data + ] + screen-should-contain [ + <span class="Constant"> . .</span> + <span class="Constant"> .c .</span> +<span class="Constant"> .┈┈┈┈┈┈┈┈┈┈.</span> + <span class="Constant"> . .</span> + ] + check-trace-count-for-label <span class="Constant">2</span>, <span class="Constant">[print-character]</span> <span class="Comment"># new length to overwrite</span> +] + +<span class="muRecipe">after</span> <span class="Constant"><handle-special-key></span> [ + <span class="Delimiter">{</span> + delete-next-character?:boolean<span class="Special"> <- </span>equal *k, <span class="Constant">65522/delete</span> + <span class="muControl">break-unless</span> delete-next-character? +<span class="Constant"> <delete-character-begin></span> + editor, screen, go-render?:boolean, deleted-cell:address:duplex-list<span class="Special"> <- </span>delete-at-cursor editor, screen +<span class="Constant"> <delete-character-end></span> + <span class="muControl">reply</span> screen/same-as-ingredient:<span class="Constant">0</span>, editor/same-as-ingredient:<span class="Constant">1</span>, go-render? + <span class="Delimiter">}</span> +] + +<span class="muRecipe">recipe</span> delete-at-cursor [ + <span class="Constant">local-scope</span> + editor:address:editor-data<span class="Special"> <- </span><span class="Constant">next-ingredient</span> + screen:address<span class="Special"> <- </span><span class="Constant">next-ingredient</span> + before-cursor:address:address:duplex-list<span class="Special"> <- </span>get-address *editor, <span class="Constant">before-cursor:offset</span> + candidate:address:duplex-list<span class="Special"> <- </span>next-duplex *before-cursor + <span class="muControl">reply-unless</span> candidate, editor/same-as-ingredient:<span class="Constant">0</span>, screen/same-as-ingredient:<span class="Constant">1</span>, <span class="Constant">0/no-more-render</span>, <span class="Constant">0/nothing-deleted</span> + currc:character<span class="Special"> <- </span>get *candidate, <span class="Constant">value:offset</span> + remove-duplex candidate + deleted-newline?:boolean<span class="Special"> <- </span>equal currc, <span class="Constant">10/newline</span> + <span class="muControl">reply-if</span> deleted-newline?, editor/same-as-ingredient:<span class="Constant">0</span>, screen/same-as-ingredient:<span class="Constant">1</span>, <span class="Constant">1/go-render</span>, candidate/deleted-cell + <span class="Comment"># wasn't a newline? render rest of line</span> + curr:address:duplex-list<span class="Special"> <- </span>next-duplex *before-cursor <span class="Comment"># refresh after remove-duplex above</span> + cursor-row:address:number<span class="Special"> <- </span>get-address *editor, <span class="Constant">cursor-row:offset</span> + cursor-column:address:number<span class="Special"> <- </span>get-address *editor, <span class="Constant">cursor-column:offset</span> + screen<span class="Special"> <- </span>move-cursor screen, *cursor-row, *cursor-column + curr-column:number<span class="Special"> <- </span>copy *cursor-column + screen-width:number<span class="Special"> <- </span>screen-width screen + <span class="Delimiter">{</span> + <span class="Comment"># hit right margin? give up and let caller render</span> + at-right?:boolean<span class="Special"> <- </span>greater-or-equal curr-column, screen-width + <span class="muControl">reply-if</span> at-right?, editor/same-as-ingredient:<span class="Constant">0</span>, screen/same-as-ingredient:<span class="Constant">1</span>, <span class="Constant">1/go-render</span>, candidate/deleted-cell + <span class="muControl">break-unless</span> curr + <span class="Comment"># newline? done.</span> + currc:character<span class="Special"> <- </span>get *curr, <span class="Constant">value:offset</span> + at-newline?:boolean<span class="Special"> <- </span>equal currc, <span class="Constant">10/newline</span> + <span class="muControl">break-if</span> at-newline? + screen<span class="Special"> <- </span>print-character screen, currc + curr-column<span class="Special"> <- </span>add curr-column, <span class="Constant">1</span> + curr<span class="Special"> <- </span>next-duplex curr + <span class="muControl">loop</span> + <span class="Delimiter">}</span> + <span class="Comment"># we're guaranteed not to be at the right margin</span> + screen<span class="Special"> <- </span>print-character screen, <span class="Constant">32/space</span> + <span class="muControl">reply</span> editor/same-as-ingredient:<span class="Constant">0</span>, screen/same-as-ingredient:<span class="Constant">1</span>, <span class="Constant">0/no-more-render</span>, candidate/deleted-cell +] + +<span class="Comment"># right arrow</span> + +<span class="muScenario">scenario</span> editor-moves-cursor-right-with-key [ + assume-screen <span class="Constant">10/width</span>, <span class="Constant">5/height</span> + <span class="Constant">1</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[abc]</span> + <span class="Constant">2</span>:address:editor-data<span class="Special"> <- </span>new-editor <span class="Constant">1</span>:address:array:character, screen:address, <span class="Constant">0/left</span>, <span class="Constant">10/right</span> + editor-render screen, <span class="Constant">2</span>:address:editor-data +<span class="Constant"> $clear-trace</span> + assume-console [ + press right-arrow + type <span class="Constant">[0]</span> + ] + run [ + editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data + ] + screen-should-contain [ + <span class="Constant"> . .</span> + <span class="Constant"> .a0bc .</span> +<span class="Constant"> .┈┈┈┈┈┈┈┈┈┈.</span> + <span class="Constant"> . .</span> + ] + check-trace-count-for-label <span class="Constant">3</span>, <span class="Constant">[print-character]</span> <span class="Comment"># 0 and following characters</span> +] + +<span class="muRecipe">after</span> <span class="Constant"><handle-special-key></span> [ + <span class="Delimiter">{</span> + move-to-next-character?:boolean<span class="Special"> <- </span>equal *k, <span class="Constant">65514/right-arrow</span> + <span class="muControl">break-unless</span> move-to-next-character? + <span class="Comment"># if not at end of text</span> + next-cursor:address:duplex-list<span class="Special"> <- </span>next-duplex *before-cursor + <span class="muControl">break-unless</span> next-cursor + <span class="Comment"># scan to next character</span> +<span class="Constant"> <move-cursor-begin></span> + *before-cursor<span class="Special"> <- </span>copy next-cursor + editor, go-render?:boolean<span class="Special"> <- </span>move-cursor-coordinates-right editor, screen-height + screen<span class="Special"> <- </span>move-cursor screen, *cursor-row, *cursor-column + undo-coalesce-tag:number<span class="Special"> <- </span>copy <span class="Constant">2/right-arrow</span> +<span class="Constant"> <move-cursor-end></span> + <span class="muControl">reply</span> screen/same-as-ingredient:<span class="Constant">0</span>, editor/same-as-ingredient:<span class="Constant">1</span>, go-render? + <span class="Delimiter">}</span> +] + +<span class="muRecipe">recipe</span> move-cursor-coordinates-right [ + <span class="Constant">local-scope</span> + editor:address:editor-data<span class="Special"> <- </span><span class="Constant">next-ingredient</span> + screen-height:number<span class="Special"> <- </span><span class="Constant">next-ingredient</span> + before-cursor:address:duplex-list<span class="Special"> <- </span>get *editor <span class="Constant">before-cursor:offset</span> + cursor-row:address:number<span class="Special"> <- </span>get-address *editor, <span class="Constant">cursor-row:offset</span> + cursor-column:address:number<span class="Special"> <- </span>get-address *editor, <span class="Constant">cursor-column:offset</span> + left:number<span class="Special"> <- </span>get *editor, <span class="Constant">left:offset</span> + right:number<span class="Special"> <- </span>get *editor, <span class="Constant">right:offset</span> + <span class="Comment"># if crossed a newline, move cursor to start of next row</span> + <span class="Delimiter">{</span> + old-cursor-character:character<span class="Special"> <- </span>get *before-cursor, <span class="Constant">value:offset</span> + was-at-newline?:boolean<span class="Special"> <- </span>equal old-cursor-character, <span class="Constant">10/newline</span> + <span class="muControl">break-unless</span> was-at-newline? + *cursor-row<span class="Special"> <- </span>add *cursor-row, <span class="Constant">1</span> + *cursor-column<span class="Special"> <- </span>copy left + below-screen?:boolean<span class="Special"> <- </span>greater-or-equal *cursor-row, screen-height <span class="Comment"># must be equal</span> + <span class="muControl">reply-unless</span> below-screen?, editor/same-as-ingredient:<span class="Constant">0</span>, <span class="Constant">0/no-more-render</span> +<span class="Constant"> <scroll-down></span> + *cursor-row<span class="Special"> <- </span>subtract *cursor-row, <span class="Constant">1</span> <span class="Comment"># bring back into screen range</span> + <span class="muControl">reply</span> editor/same-as-ingredient:<span class="Constant">0</span>, <span class="Constant">1/go-render</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, <span class="Constant">1</span> + at-wrap?:boolean<span class="Special"> <- </span>equal *cursor-column, wrap-column + <span class="muControl">break-unless</span> at-wrap? + <span class="Comment"># and if next character isn't newline</span> + next:address:duplex-list<span class="Special"> <- </span>next-duplex before-cursor + <span class="muControl">break-unless</span> next + next-character:character<span class="Special"> <- </span>get *next, <span class="Constant">value:offset</span> + newline?:boolean<span class="Special"> <- </span>equal next-character, <span class="Constant">10/newline</span> + <span class="muControl">break-if</span> newline? + *cursor-row<span class="Special"> <- </span>add *cursor-row, <span class="Constant">1</span> + *cursor-column<span class="Special"> <- </span>copy left + below-screen?:boolean<span class="Special"> <- </span>greater-or-equal *cursor-row, screen-height <span class="Comment"># must be equal</span> + <span class="muControl">reply-unless</span> below-screen?, editor/same-as-ingredient:<span class="Constant">0</span>, <span class="Constant">0/no-more-render</span> +<span class="Constant"> <scroll-down></span> + *cursor-row<span class="Special"> <- </span>subtract *cursor-row, <span class="Constant">1</span> <span class="Comment"># bring back into screen range</span> + <span class="muControl">reply</span> editor/same-as-ingredient:<span class="Constant">0</span>, <span class="Constant">1/go-render</span> + <span class="Delimiter">}</span> + <span class="Comment"># otherwise move cursor one character right</span> + *cursor-column<span class="Special"> <- </span>add *cursor-column, <span class="Constant">1</span> + <span class="muControl">reply</span> editor/same-as-ingredient:<span class="Constant">0</span>, <span class="Constant">0/no-more-render</span> +] + +<span class="muScenario">scenario</span> editor-moves-cursor-to-next-line-with-right-arrow [ + assume-screen <span class="Constant">10/width</span>, <span class="Constant">5/height</span> + <span class="Constant">1</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[abc</span> +<span class="Constant">d]</span> + <span class="Constant">2</span>:address:editor-data<span class="Special"> <- </span>new-editor <span class="Constant">1</span>:address:array:character, screen:address, <span class="Constant">0/left</span>, <span class="Constant">10/right</span> + editor-render screen, <span class="Constant">2</span>:address:editor-data +<span class="Constant"> $clear-trace</span> + <span class="Comment"># type right-arrow a few times to get to start of second line</span> + assume-console [ + press right-arrow + press right-arrow + press right-arrow + press right-arrow <span class="Comment"># next line</span> + ] + run [ + editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data + ] + check-trace-count-for-label <span class="Constant">0</span>, <span class="Constant">[print-character]</span> + <span class="Comment"># type something and ensure it goes where it should</span> + assume-console [ + type <span class="Constant">[0]</span> + ] + run [ + editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data + ] + screen-should-contain [ + <span class="Constant"> . .</span> + <span class="Constant"> .abc .</span> + <span class="Constant"> .0d .</span> +<span class="Constant"> .┈┈┈┈┈┈┈┈┈┈.</span> + <span class="Constant"> . .</span> + ] + check-trace-count-for-label <span class="Constant">2</span>, <span class="Constant">[print-character]</span> <span class="Comment"># new length of second line</span> +] + +<span class="muScenario">scenario</span> editor-moves-cursor-to-next-line-with-right-arrow-2 [ + assume-screen <span class="Constant">10/width</span>, <span class="Constant">5/height</span> + <span class="Constant">1</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[abc</span> +<span class="Constant">d]</span> + <span class="Constant">2</span>:address:editor-data<span class="Special"> <- </span>new-editor <span class="Constant">1</span>:address:array:character, screen:address, <span class="Constant">1/left</span>, <span class="Constant">10/right</span> + editor-render screen, <span class="Constant">2</span>:address:editor-data + assume-console [ + press right-arrow + press right-arrow + press right-arrow + press right-arrow <span class="Comment"># next line</span> + type <span class="Constant">[0]</span> + ] + run [ + editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data + ] + screen-should-contain [ + <span class="Constant"> . .</span> + <span class="Constant"> . abc .</span> + <span class="Constant"> . 0d .</span> + <span class="Constant"> . ┈┈┈┈┈┈┈┈┈.</span> + <span class="Constant"> . .</span> + ] +] + +<span class="muScenario">scenario</span> editor-moves-cursor-to-next-wrapped-line-with-right-arrow [ + assume-screen <span class="Constant">10/width</span>, <span class="Constant">5/height</span> + <span class="Constant">1</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[abcdef]</span> + <span class="Constant">2</span>:address:editor-data<span class="Special"> <- </span>new-editor <span class="Constant">1</span>:address:array:character, screen:address, <span class="Constant">0/left</span>, <span class="Constant">5/right</span> + editor-render screen, <span class="Constant">2</span>:address:editor-data +<span class="Constant"> $clear-trace</span> + assume-console [ + left-click <span class="Constant">1</span>, <span class="Constant">3</span> + press right-arrow + ] + run [ + editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data + <span class="Constant">3</span>:number<span class="Special"> <- </span>get *<span class="Constant">2</span>:address:editor-data, <span class="Constant">cursor-row:offset</span> + <span class="Constant">4</span>:number<span class="Special"> <- </span>get *<span class="Constant">2</span>:address:editor-data, <span class="Constant">cursor-column:offset</span> + ] + screen-should-contain [ + <span class="Constant"> . .</span> + <span class="Constant"> .abcd↩ .</span> + <span class="Constant"> .ef .</span> + <span class="Constant"> .┈┈┈┈┈ .</span> + <span class="Constant"> . .</span> + ] + memory-should-contain [ + <span class="Constant">3</span><span class="Special"> <- </span><span class="Constant">2</span> + <span class="Constant">4</span><span class="Special"> <- </span><span class="Constant">0</span> + ] + check-trace-count-for-label <span class="Constant">0</span>, <span class="Constant">[print-character]</span> +] + +<span class="muScenario">scenario</span> editor-moves-cursor-to-next-wrapped-line-with-right-arrow-2 [ + assume-screen <span class="Constant">10/width</span>, <span class="Constant">5/height</span> + <span class="Comment"># line just barely wrapping</span> + <span class="Constant">1</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[abcde]</span> + <span class="Constant">2</span>:address:editor-data<span class="Special"> <- </span>new-editor <span class="Constant">1</span>:address:array:character, screen:address, <span class="Constant">0/left</span>, <span class="Constant">5/right</span> + editor-render screen, <span class="Constant">2</span>:address:editor-data +<span class="Constant"> $clear-trace</span> + <span class="Comment"># position cursor at last character before wrap and hit right-arrow</span> + assume-console [ + left-click <span class="Constant">1</span>, <span class="Constant">3</span> + press right-arrow + ] + run [ + editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data + <span class="Constant">3</span>:number<span class="Special"> <- </span>get *<span class="Constant">2</span>:address:editor-data, <span class="Constant">cursor-row:offset</span> + <span class="Constant">4</span>:number<span class="Special"> <- </span>get *<span class="Constant">2</span>:address:editor-data, <span class="Constant">cursor-column:offset</span> + ] + memory-should-contain [ + <span class="Constant">3</span><span class="Special"> <- </span><span class="Constant">2</span> + <span class="Constant">4</span><span class="Special"> <- </span><span class="Constant">0</span> + ] + <span class="Comment"># now hit right arrow again</span> + assume-console [ + press right-arrow + ] + run [ + editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data + <span class="Constant">3</span>:number<span class="Special"> <- </span>get *<span class="Constant">2</span>:address:editor-data, <span class="Constant">cursor-row:offset</span> + <span class="Constant">4</span>:number<span class="Special"> <- </span>get *<span class="Constant">2</span>:address:editor-data, <span class="Constant">cursor-column:offset</span> + ] + memory-should-contain [ + <span class="Constant">3</span><span class="Special"> <- </span><span class="Constant">2</span> + <span class="Constant">4</span><span class="Special"> <- </span><span class="Constant">1</span> + ] + check-trace-count-for-label <span class="Constant">0</span>, <span class="Constant">[print-character]</span> +] + +<span class="muScenario">scenario</span> editor-moves-cursor-to-next-wrapped-line-with-right-arrow-3 [ + assume-screen <span class="Constant">10/width</span>, <span class="Constant">5/height</span> + <span class="Constant">1</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[abcdef]</span> + <span class="Constant">2</span>:address:editor-data<span class="Special"> <- </span>new-editor <span class="Constant">1</span>:address:array:character, screen:address, <span class="Constant">1/left</span>, <span class="Constant">6/right</span> + editor-render screen, <span class="Constant">2</span>:address:editor-data +<span class="Constant"> $clear-trace</span> + assume-console [ + left-click <span class="Constant">1</span>, <span class="Constant">4</span> + press right-arrow + ] + run [ + editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data + <span class="Constant">3</span>:number<span class="Special"> <- </span>get *<span class="Constant">2</span>:address:editor-data, <span class="Constant">cursor-row:offset</span> + <span class="Constant">4</span>:number<span class="Special"> <- </span>get *<span class="Constant">2</span>:address:editor-data, <span class="Constant">cursor-column:offset</span> + ] + screen-should-contain [ + <span class="Constant"> . .</span> + <span class="Constant"> . abcd↩ .</span> + <span class="Constant"> . ef .</span> + <span class="Constant"> . ┈┈┈┈┈ .</span> + <span class="Constant"> . .</span> + ] + memory-should-contain [ + <span class="Constant">3</span><span class="Special"> <- </span><span class="Constant">2</span> + <span class="Constant">4</span><span class="Special"> <- </span><span class="Constant">1</span> + ] + check-trace-count-for-label <span class="Constant">0</span>, <span class="Constant">[print-character]</span> +] + +<span class="muScenario">scenario</span> editor-moves-cursor-to-next-line-with-right-arrow-at-end-of-line [ + assume-screen <span class="Constant">10/width</span>, <span class="Constant">5/height</span> + <span class="Constant">1</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[abc</span> +<span class="Constant">d]</span> + <span class="Constant">2</span>:address:editor-data<span class="Special"> <- </span>new-editor <span class="Constant">1</span>:address:array:character, screen:address, <span class="Constant">0/left</span>, <span class="Constant">10/right</span> + editor-render screen, <span class="Constant">2</span>:address:editor-data +<span class="Constant"> $clear-trace</span> + <span class="Comment"># move to end of line, press right-arrow, type a character</span> + assume-console [ + left-click <span class="Constant">1</span>, <span class="Constant">3</span> + press right-arrow + type <span class="Constant">[0]</span> + ] + run [ + editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data + ] + <span class="Comment"># new character should be in next line</span> + screen-should-contain [ + <span class="Constant"> . .</span> + <span class="Constant"> .abc .</span> + <span class="Constant"> .0d .</span> +<span class="Constant"> .┈┈┈┈┈┈┈┈┈┈.</span> + <span class="Constant"> . .</span> + ] + check-trace-count-for-label <span class="Constant">2</span>, <span class="Constant">[print-character]</span> +] + +<span class="Comment"># todo: ctrl-right: next word-end</span> + +<span class="Comment"># left arrow</span> + +<span class="muScenario">scenario</span> editor-moves-cursor-left-with-key [ + assume-screen <span class="Constant">10/width</span>, <span class="Constant">5/height</span> + <span class="Constant">1</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[abc]</span> + <span class="Constant">2</span>:address:editor-data<span class="Special"> <- </span>new-editor <span class="Constant">1</span>:address:array:character, screen:address, <span class="Constant">0/left</span>, <span class="Constant">10/right</span> + editor-render screen, <span class="Constant">2</span>:address:editor-data +<span class="Constant"> $clear-trace</span> + assume-console [ + left-click <span class="Constant">1</span>, <span class="Constant">2</span> + press left-arrow + type <span class="Constant">[0]</span> + ] + run [ + editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data + ] + screen-should-contain [ + <span class="Constant"> . .</span> + <span class="Constant"> .a0bc .</span> +<span class="Constant"> .┈┈┈┈┈┈┈┈┈┈.</span> + <span class="Constant"> . .</span> + ] + check-trace-count-for-label <span class="Constant">3</span>, <span class="Constant">[print-character]</span> +] + +<span class="muRecipe">after</span> <span class="Constant"><handle-special-key></span> [ + <span class="Delimiter">{</span> + move-to-previous-character?:boolean<span class="Special"> <- </span>equal *k, <span class="Constant">65515/left-arrow</span> + <span class="muControl">break-unless</span> move-to-previous-character? + trace <span class="Constant">10</span>, <span class="Constant">[app]</span>, <span class="Constant">[left arrow]</span> + <span class="Comment"># if not at start of text (before-cursor at § sentinel)</span> + prev:address:duplex-list<span class="Special"> <- </span>prev-duplex *before-cursor + <span class="muControl">reply-unless</span> prev, screen/same-as-ingredient:<span class="Constant">0</span>, editor/same-as-ingredient:<span class="Constant">1</span>, <span class="Constant">0/no-more-render</span> +<span class="Constant"> <move-cursor-begin></span> + editor, go-render?<span class="Special"> <- </span>move-cursor-coordinates-left editor + *before-cursor<span class="Special"> <- </span>copy prev + undo-coalesce-tag:number<span class="Special"> <- </span>copy <span class="Constant">1/left-arrow</span> +<span class="Constant"> <move-cursor-end></span> + <span class="muControl">reply</span> screen/same-as-ingredient:<span class="Constant">0</span>, editor/same-as-ingredient:<span class="Constant">1</span>, go-render? + <span class="Delimiter">}</span> +] + +<span class="muScenario">scenario</span> editor-moves-cursor-to-previous-line-with-left-arrow-at-start-of-line [ + assume-screen <span class="Constant">10/width</span>, <span class="Constant">5/height</span> + <span class="Comment"># initialize editor with two lines</span> + <span class="Constant">1</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[abc</span> +<span class="Constant">d]</span> + <span class="Constant">2</span>:address:editor-data<span class="Special"> <- </span>new-editor <span class="Constant">1</span>:address:array:character, screen:address, <span class="Constant">0/left</span>, <span class="Constant">10/right</span> + editor-render screen, <span class="Constant">2</span>:address:editor-data +<span class="Constant"> $clear-trace</span> + <span class="Comment"># position cursor at start of second line (so there's no previous newline)</span> + assume-console [ + left-click <span class="Constant">2</span>, <span class="Constant">0</span> + press left-arrow + ] + run [ + editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data + <span class="Constant">3</span>:number<span class="Special"> <- </span>get *<span class="Constant">2</span>:address:editor-data, <span class="Constant">cursor-row:offset</span> + <span class="Constant">4</span>:number<span class="Special"> <- </span>get *<span class="Constant">2</span>:address:editor-data, <span class="Constant">cursor-column:offset</span> + ] + memory-should-contain [ + <span class="Constant">3</span><span class="Special"> <- </span><span class="Constant">1</span> + <span class="Constant">4</span><span class="Special"> <- </span><span class="Constant">3</span> + ] + check-trace-count-for-label <span class="Constant">0</span>, <span class="Constant">[print-character]</span> +] + +<span class="muScenario">scenario</span> editor-moves-cursor-to-previous-line-with-left-arrow-at-start-of-line-2 [ + assume-screen <span class="Constant">10/width</span>, <span class="Constant">5/height</span> + <span class="Comment"># initialize editor with three lines</span> + <span class="Constant">1</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[abc</span> +<span class="Constant">def</span> +<span class="Constant">g]</span> + <span class="Constant">2</span>:address:editor-data<span class="Special"> <- </span>new-editor <span class="Constant">1</span>:address:array:character, screen:address, <span class="Constant">0/left</span>, <span class="Constant">10/right</span> + editor-render screen, <span class="Constant">2</span>:address:editor-data +<span class="Constant"> $clear-trace</span> + <span class="Comment"># position cursor further down (so there's a newline before the character at</span> + <span class="Comment"># the cursor)</span> + assume-console [ + left-click <span class="Constant">3</span>, <span class="Constant">0</span> + press left-arrow + type <span class="Constant">[0]</span> + ] + run [ + editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data + ] + screen-should-contain [ + <span class="Constant"> . .</span> + <span class="Constant"> .abc .</span> + <span class="Constant"> .def0 .</span> + <span class="Constant"> .g .</span> +<span class="Constant"> .┈┈┈┈┈┈┈┈┈┈.</span> + ] + check-trace-count-for-label <span class="Constant">1</span>, <span class="Constant">[print-character]</span> <span class="Comment"># just the '0'</span> +] + +<span class="muScenario">scenario</span> editor-moves-cursor-to-previous-line-with-left-arrow-at-start-of-line-3 [ + assume-screen <span class="Constant">10/width</span>, <span class="Constant">5/height</span> + <span class="Constant">1</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[abc</span> +<span class="Constant">def</span> +<span class="Constant">g]</span> + <span class="Constant">2</span>:address:editor-data<span class="Special"> <- </span>new-editor <span class="Constant">1</span>:address:array:character, screen:address, <span class="Constant">0/left</span>, <span class="Constant">10/right</span> + editor-render screen, <span class="Constant">2</span>:address:editor-data +<span class="Constant"> $clear-trace</span> + <span class="Comment"># position cursor at start of text, press left-arrow, then type a character</span> + assume-console [ + left-click <span class="Constant">1</span>, <span class="Constant">0</span> + press left-arrow + type <span class="Constant">[0]</span> + ] + run [ + editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data + ] + <span class="Comment"># left-arrow should have had no effect</span> + screen-should-contain [ + <span class="Constant"> . .</span> + <span class="Constant"> .0abc .</span> + <span class="Constant"> .def .</span> + <span class="Constant"> .g .</span> +<span class="Constant"> .┈┈┈┈┈┈┈┈┈┈.</span> + ] + check-trace-count-for-label <span class="Constant">4</span>, <span class="Constant">[print-character]</span> <span class="Comment"># length of first line</span> +] + +<span class="muScenario">scenario</span> editor-moves-cursor-to-previous-line-with-left-arrow-at-start-of-line-4 [ + assume-screen <span class="Constant">10/width</span>, <span class="Constant">5/height</span> + <span class="Comment"># initialize editor with text containing an empty line</span> + <span class="Constant">1</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[abc</span> + +d] + <span class="Constant">2</span>:address:editor-data<span class="Special"> <- </span>new-editor <span class="Constant">1</span>:address:array:character, screen:address, <span class="Constant">0/left</span>, <span class="Constant">10/right</span> + editor-render screen, <span class="Constant">2</span>:address:editor-data +<span class="Constant"> $clear-trace</span> + <span class="Comment"># position cursor right after empty line</span> + assume-console [ + left-click <span class="Constant">3</span>, <span class="Constant">0</span> + press left-arrow + type <span class="Constant">[0]</span> + ] + run [ + editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data + ] + screen-should-contain [ + <span class="Constant"> . .</span> + <span class="Constant"> .abc .</span> + <span class="Constant"> .0 .</span> + <span class="Constant"> .d .</span> +<span class="Constant"> .┈┈┈┈┈┈┈┈┈┈.</span> + ] + check-trace-count-for-label <span class="Constant">1</span>, <span class="Constant">[print-character]</span> <span class="Comment"># just the '0'</span> +] + +<span class="muScenario">scenario</span> editor-moves-across-screen-lines-across-wrap-with-left-arrow [ + assume-screen <span class="Constant">10/width</span>, <span class="Constant">5/height</span> + <span class="Comment"># initialize editor with text containing an empty line</span> + <span class="Constant">1</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[abcdef]</span> + <span class="Constant">2</span>:address:editor-data<span class="Special"> <- </span>new-editor <span class="Constant">1</span>:address:array:character, screen:address, <span class="Constant">0/left</span>, <span class="Constant">5/right</span> + editor-render screen, <span class="Constant">2</span>:address:editor-data +<span class="Constant"> $clear-trace</span> + screen-should-contain [ + <span class="Constant"> . .</span> + <span class="Constant"> .abcd↩ .</span> + <span class="Constant"> .ef .</span> + <span class="Constant"> .┈┈┈┈┈ .</span> + <span class="Constant"> . .</span> + ] + <span class="Comment"># position cursor right after empty line</span> + assume-console [ + left-click <span class="Constant">2</span>, <span class="Constant">0</span> + press left-arrow + ] + run [ + editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data + <span class="Constant">3</span>:number<span class="Special"> <- </span>get *<span class="Constant">2</span>:address:editor-data, <span class="Constant">cursor-row:offset</span> + <span class="Constant">4</span>:number<span class="Special"> <- </span>get *<span class="Constant">2</span>:address:editor-data, <span class="Constant">cursor-column:offset</span> + ] + memory-should-contain [ + <span class="Constant">3</span><span class="Special"> <- </span><span class="Constant">1</span> <span class="Comment"># previous row</span> + <span class="Constant">4</span><span class="Special"> <- </span><span class="Constant">3</span> <span class="Comment"># end of wrapped line</span> + ] + check-trace-count-for-label <span class="Constant">0</span>, <span class="Constant">[print-character]</span> +] + +<span class="Comment"># todo: ctrl-left: previous word-start</span> + +<span class="Comment"># up arrow</span> + +<span class="muScenario">scenario</span> editor-moves-to-previous-line-with-up-arrow [ + assume-screen <span class="Constant">10/width</span>, <span class="Constant">5/height</span> + <span class="Constant">1</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[abc</span> +<span class="Constant">def]</span> + <span class="Constant">2</span>:address:editor-data<span class="Special"> <- </span>new-editor <span class="Constant">1</span>:address:array:character, screen:address, <span class="Constant">0/left</span>, <span class="Constant">10/right</span> + editor-render screen, <span class="Constant">2</span>:address:editor-data +<span class="Constant"> $clear-trace</span> + assume-console [ + left-click <span class="Constant">2</span>, <span class="Constant">1</span> + press up-arrow + ] + run [ + editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data + <span class="Constant">3</span>:number<span class="Special"> <- </span>get *<span class="Constant">2</span>:address:editor-data, <span class="Constant">cursor-row:offset</span> + <span class="Constant">4</span>:number<span class="Special"> <- </span>get *<span class="Constant">2</span>:address:editor-data, <span class="Constant">cursor-column:offset</span> + ] + memory-should-contain [ + <span class="Constant">3</span><span class="Special"> <- </span><span class="Constant">1</span> + <span class="Constant">4</span><span class="Special"> <- </span><span class="Constant">1</span> + ] + check-trace-count-for-label <span class="Constant">0</span>, <span class="Constant">[print-character]</span> + assume-console [ + type <span class="Constant">[0]</span> + ] + run [ + editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data + ] + screen-should-contain [ + <span class="Constant"> . .</span> + <span class="Constant"> .a0bc .</span> + <span class="Constant"> .def .</span> +<span class="Constant"> .┈┈┈┈┈┈┈┈┈┈.</span> + <span class="Constant"> . .</span> + ] +] + +<span class="muRecipe">after</span> <span class="Constant"><handle-special-key></span> [ + <span class="Delimiter">{</span> + move-to-previous-line?:boolean<span class="Special"> <- </span>equal *k, <span class="Constant">65517/up-arrow</span> + <span class="muControl">break-unless</span> move-to-previous-line? +<span class="Constant"> <move-cursor-begin></span> + editor, go-render?<span class="Special"> <- </span>move-to-previous-line editor + undo-coalesce-tag:number<span class="Special"> <- </span>copy <span class="Constant">3/up-arrow</span> +<span class="Constant"> <move-cursor-end></span> + <span class="muControl">reply</span> screen/same-as-ingredient:<span class="Constant">0</span>, editor/same-as-ingredient:<span class="Constant">1</span>, go-render? + <span class="Delimiter">}</span> +] + +<span class="muRecipe">recipe</span> move-to-previous-line [ + <span class="Constant">local-scope</span> + editor:address:editor-data<span class="Special"> <- </span><span class="Constant">next-ingredient</span> + cursor-row:address:number<span class="Special"> <- </span>get-address *editor, <span class="Constant">cursor-row:offset</span> + cursor-column:address:number<span class="Special"> <- </span>get-address *editor, <span class="Constant">cursor-column:offset</span> + before-cursor:address:address:duplex-list<span class="Special"> <- </span>get-address *editor, <span class="Constant">before-cursor:offset</span> + left:number<span class="Special"> <- </span>get *editor, <span class="Constant">left:offset</span> + right:number<span class="Special"> <- </span>get *editor, <span class="Constant">right:offset</span> + already-at-top?:boolean<span class="Special"> <- </span>lesser-or-equal *cursor-row, <span class="Constant">1/top</span> + <span class="Delimiter">{</span> + <span class="Comment"># if cursor not at top, move it</span> + <span class="muControl">break-if</span> already-at-top? + <span class="Comment"># if not at newline, move to start of line (previous newline)</span> + <span class="Comment"># then scan back another line</span> + <span class="Comment"># if either step fails, give up without modifying cursor or coordinates</span> + curr:address:duplex-list<span class="Special"> <- </span>copy *before-cursor + <span class="Delimiter">{</span> + old:address:duplex-list<span class="Special"> <- </span>copy curr + c2:character<span class="Special"> <- </span>get *curr, <span class="Constant">value:offset</span> + at-newline?:boolean<span class="Special"> <- </span>equal c2, <span class="Constant">10/newline</span> + <span class="muControl">break-if</span> at-newline? + curr:address:duplex-list<span class="Special"> <- </span>before-previous-line curr, editor + no-motion?:boolean<span class="Special"> <- </span>equal curr, old + <span class="muControl">reply-if</span> no-motion?, editor/same-as-ingredient:<span class="Constant">0</span>, <span class="Constant">0/no-more-render</span> + <span class="Delimiter">}</span> + <span class="Delimiter">{</span> + old<span class="Special"> <- </span>copy curr + curr<span class="Special"> <- </span>before-previous-line curr, editor + no-motion?:boolean<span class="Special"> <- </span>equal curr, old + <span class="muControl">reply-if</span> no-motion?, editor/same-as-ingredient:<span class="Constant">0</span>, <span class="Constant">0/no-more-render</span> + <span class="Delimiter">}</span> + *before-cursor<span class="Special"> <- </span>copy curr + *cursor-row<span class="Special"> <- </span>subtract *cursor-row, <span class="Constant">1</span> + <span class="Comment"># scan ahead to right column or until end of line</span> + target-column:number<span class="Special"> <- </span>copy *cursor-column + *cursor-column<span class="Special"> <- </span>copy left + <span class="Delimiter">{</span> + done?:boolean<span class="Special"> <- </span>greater-or-equal *cursor-column, target-column + <span class="muControl">break-if</span> done? + curr:address:duplex-list<span class="Special"> <- </span>next-duplex *before-cursor + <span class="muControl">break-unless</span> curr + currc:character<span class="Special"> <- </span>get *curr, <span class="Constant">value:offset</span> + at-newline?:boolean<span class="Special"> <- </span>equal currc, <span class="Constant">10/newline</span> + <span class="muControl">break-if</span> at-newline? + <span class="Comment">#</span> + *before-cursor<span class="Special"> <- </span>copy curr + *cursor-column<span class="Special"> <- </span>add *cursor-column, <span class="Constant">1</span> + <span class="muControl">loop</span> + <span class="Delimiter">}</span> + <span class="muControl">reply</span> editor/same-as-ingredient:<span class="Constant">0</span>, <span class="Constant">0/no-more-render</span> + <span class="Delimiter">}</span> + <span class="Delimiter">{</span> + <span class="Comment"># if cursor already at top, scroll up</span> + <span class="muControl">break-unless</span> already-at-top? +<span class="Constant"> <scroll-up></span> + <span class="muControl">reply</span> editor/same-as-ingredient:<span class="Constant">0</span>, <span class="Constant">1/go-render</span> + <span class="Delimiter">}</span> +] + +<span class="muScenario">scenario</span> editor-adjusts-column-at-previous-line [ + assume-screen <span class="Constant">10/width</span>, <span class="Constant">5/height</span> + <span class="Constant">1</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[ab</span> +<span class="Constant">def]</span> + <span class="Constant">2</span>:address:editor-data<span class="Special"> <- </span>new-editor <span class="Constant">1</span>:address:array:character, screen:address, <span class="Constant">0/left</span>, <span class="Constant">10/right</span> + editor-render screen, <span class="Constant">2</span>:address:editor-data +<span class="Constant"> $clear-trace</span> + assume-console [ + left-click <span class="Constant">2</span>, <span class="Constant">3</span> + press up-arrow + ] + run [ + editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data + <span class="Constant">3</span>:number<span class="Special"> <- </span>get *<span class="Constant">2</span>:address:editor-data, <span class="Constant">cursor-row:offset</span> + <span class="Constant">4</span>:number<span class="Special"> <- </span>get *<span class="Constant">2</span>:address:editor-data, <span class="Constant">cursor-column:offset</span> + ] + memory-should-contain [ + <span class="Constant">3</span><span class="Special"> <- </span><span class="Constant">1</span> + <span class="Constant">4</span><span class="Special"> <- </span><span class="Constant">2</span> + ] + check-trace-count-for-label <span class="Constant">0</span>, <span class="Constant">[print-character]</span> + assume-console [ + type <span class="Constant">[0]</span> + ] + run [ + editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data + ] + screen-should-contain [ + <span class="Constant"> . .</span> + <span class="Constant"> .ab0 .</span> + <span class="Constant"> .def .</span> +<span class="Constant"> .┈┈┈┈┈┈┈┈┈┈.</span> + <span class="Constant"> . .</span> + ] +] + +<span class="muScenario">scenario</span> editor-adjusts-column-at-empty-line [ + assume-screen <span class="Constant">10/width</span>, <span class="Constant">5/height</span> + <span class="Constant">1</span>:address:array:character<span class="Special"> <- </span>new [ +def] + <span class="Constant">2</span>:address:editor-data<span class="Special"> <- </span>new-editor <span class="Constant">1</span>:address:array:character, screen:address, <span class="Constant">0/left</span>, <span class="Constant">10/right</span> + editor-render screen, <span class="Constant">2</span>:address:editor-data +<span class="Constant"> $clear-trace</span> + assume-console [ + left-click <span class="Constant">2</span>, <span class="Constant">3</span> + press up-arrow + ] + run [ + editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data + <span class="Constant">3</span>:number<span class="Special"> <- </span>get *<span class="Constant">2</span>:address:editor-data, <span class="Constant">cursor-row:offset</span> + <span class="Constant">4</span>:number<span class="Special"> <- </span>get *<span class="Constant">2</span>:address:editor-data, <span class="Constant">cursor-column:offset</span> + ] + memory-should-contain [ + <span class="Constant">3</span><span class="Special"> <- </span><span class="Constant">1</span> + <span class="Constant">4</span><span class="Special"> <- </span><span class="Constant">0</span> + ] + check-trace-count-for-label <span class="Constant">0</span>, <span class="Constant">[print-character]</span> + assume-console [ + type <span class="Constant">[0]</span> + ] + run [ + editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data + ] + screen-should-contain [ + <span class="Constant"> . .</span> + <span class="Constant"> .0 .</span> + <span class="Constant"> .def .</span> +<span class="Constant"> .┈┈┈┈┈┈┈┈┈┈.</span> + <span class="Constant"> . .</span> + ] +] + +<span class="muScenario">scenario</span> editor-moves-to-previous-line-from-left-margin [ + assume-screen <span class="Constant">10/width</span>, <span class="Constant">5/height</span> + <span class="Comment"># start out with three lines</span> + <span class="Constant">1</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[abc</span> +<span class="Constant">def</span> +<span class="Constant">ghi]</span> + <span class="Constant">2</span>:address:editor-data<span class="Special"> <- </span>new-editor <span class="Constant">1</span>:address:array:character, screen:address, <span class="Constant">0/left</span>, <span class="Constant">10/right</span> + editor-render screen, <span class="Constant">2</span>:address:editor-data +<span class="Constant"> $clear-trace</span> + <span class="Comment"># click on the third line and hit up-arrow, so you end up just after a newline</span> + assume-console [ + left-click <span class="Constant">3</span>, <span class="Constant">0</span> + press up-arrow + ] + run [ + editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data + <span class="Constant">3</span>:number<span class="Special"> <- </span>get *<span class="Constant">2</span>:address:editor-data, <span class="Constant">cursor-row:offset</span> + <span class="Constant">4</span>:number<span class="Special"> <- </span>get *<span class="Constant">2</span>:address:editor-data, <span class="Constant">cursor-column:offset</span> + ] + memory-should-contain [ + <span class="Constant">3</span><span class="Special"> <- </span><span class="Constant">2</span> + <span class="Constant">4</span><span class="Special"> <- </span><span class="Constant">0</span> + ] + check-trace-count-for-label <span class="Constant">0</span>, <span class="Constant">[print-character]</span> + assume-console [ + type <span class="Constant">[0]</span> + ] + run [ + editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data + ] + screen-should-contain [ + <span class="Constant"> . .</span> + <span class="Constant"> .abc .</span> + <span class="Constant"> .0def .</span> + <span class="Constant"> .ghi .</span> +<span class="Constant"> .┈┈┈┈┈┈┈┈┈┈.</span> + ] +] + +<span class="Comment"># down arrow</span> + +<span class="muScenario">scenario</span> editor-moves-to-next-line-with-down-arrow [ + assume-screen <span class="Constant">10/width</span>, <span class="Constant">5/height</span> + <span class="Constant">1</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[abc</span> +<span class="Constant">def]</span> + <span class="Constant">2</span>:address:editor-data<span class="Special"> <- </span>new-editor <span class="Constant">1</span>:address:array:character, screen:address, <span class="Constant">0/left</span>, <span class="Constant">10/right</span> + editor-render screen, <span class="Constant">2</span>:address:editor-data +<span class="Constant"> $clear-trace</span> + <span class="Comment"># cursor starts out at (1, 0)</span> + assume-console [ + press down-arrow + ] + run [ + editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data + <span class="Constant">3</span>:number<span class="Special"> <- </span>get *<span class="Constant">2</span>:address:editor-data, <span class="Constant">cursor-row:offset</span> + <span class="Constant">4</span>:number<span class="Special"> <- </span>get *<span class="Constant">2</span>:address:editor-data, <span class="Constant">cursor-column:offset</span> + ] + <span class="Comment"># ..and ends at (2, 0)</span> + memory-should-contain [ + <span class="Constant">3</span><span class="Special"> <- </span><span class="Constant">2</span> + <span class="Constant">4</span><span class="Special"> <- </span><span class="Constant">0</span> + ] + check-trace-count-for-label <span class="Constant">0</span>, <span class="Constant">[print-character]</span> + assume-console [ + type <span class="Constant">[0]</span> + ] + run [ + editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data + ] + screen-should-contain [ + <span class="Constant"> . .</span> + <span class="Constant"> .abc .</span> + <span class="Constant"> .0def .</span> +<span class="Constant"> .┈┈┈┈┈┈┈┈┈┈.</span> + <span class="Constant"> . .</span> + ] +] + +<span class="muRecipe">after</span> <span class="Constant"><handle-special-key></span> [ + <span class="Delimiter">{</span> + move-to-next-line?:boolean<span class="Special"> <- </span>equal *k, <span class="Constant">65516/down-arrow</span> + <span class="muControl">break-unless</span> move-to-next-line? +<span class="Constant"> <move-cursor-begin></span> + editor, go-render?<span class="Special"> <- </span>move-to-next-line editor, screen-height + undo-coalesce-tag:number<span class="Special"> <- </span>copy <span class="Constant">4/down-arrow</span> +<span class="Constant"> <move-cursor-end></span> + <span class="muControl">reply</span> screen/same-as-ingredient:<span class="Constant">0</span>, editor/same-as-ingredient:<span class="Constant">1</span>, go-render? + <span class="Delimiter">}</span> +] + +<span class="muRecipe">recipe</span> move-to-next-line [ + <span class="Constant">local-scope</span> + editor:address:editor-data<span class="Special"> <- </span><span class="Constant">next-ingredient</span> + screen-height:number<span class="Special"> <- </span><span class="Constant">next-ingredient</span> + cursor-row:address:number<span class="Special"> <- </span>get-address *editor, <span class="Constant">cursor-row:offset</span> + cursor-column:address:number<span class="Special"> <- </span>get-address *editor, <span class="Constant">cursor-column:offset</span> + before-cursor:address:address:duplex-list<span class="Special"> <- </span>get-address *editor, <span class="Constant">before-cursor:offset</span> + left:number<span class="Special"> <- </span>get *editor, <span class="Constant">left:offset</span> + right:number<span class="Special"> <- </span>get *editor, <span class="Constant">right:offset</span> + last-line:number<span class="Special"> <- </span>subtract screen-height, <span class="Constant">1</span> + already-at-bottom?:boolean<span class="Special"> <- </span>greater-or-equal *cursor-row, last-line + <span class="Delimiter">{</span> + <span class="Comment"># if cursor not at bottom, move it</span> + <span class="muControl">break-if</span> already-at-bottom? + <span class="Comment"># scan to start of next line, then to right column or until end of line</span> + max:number<span class="Special"> <- </span>subtract right, left + next-line:address:duplex-list<span class="Special"> <- </span>before-start-of-next-line *before-cursor, max + <span class="Delimiter">{</span> + <span class="Comment"># already at end of buffer? try to scroll up (so we can see more</span> + <span class="Comment"># warnings or sandboxes below)</span> + no-motion?:boolean<span class="Special"> <- </span>equal next-line, *before-cursor + <span class="muControl">break-unless</span> no-motion? + scroll?:boolean<span class="Special"> <- </span>greater-than *cursor-row, <span class="Constant">1</span> + <span class="muControl">break-if</span> scroll?, <span class="Constant">+try-to-scroll:label</span> + <span class="muControl">reply</span> editor/same-as-ingredient:<span class="Constant">0</span>, <span class="Constant">0/no-more-render</span> + <span class="Delimiter">}</span> + *cursor-row<span class="Special"> <- </span>add *cursor-row, <span class="Constant">1</span> + *before-cursor<span class="Special"> <- </span>copy next-line + target-column:number<span class="Special"> <- </span>copy *cursor-column + *cursor-column<span class="Special"> <- </span>copy left + <span class="Delimiter">{</span> + done?:boolean<span class="Special"> <- </span>greater-or-equal *cursor-column, target-column + <span class="muControl">break-if</span> done? + curr:address:duplex-list<span class="Special"> <- </span>next-duplex *before-cursor + <span class="muControl">break-unless</span> curr + currc:character<span class="Special"> <- </span>get *curr, <span class="Constant">value:offset</span> + at-newline?:boolean<span class="Special"> <- </span>equal currc, <span class="Constant">10/newline</span> + <span class="muControl">break-if</span> at-newline? + <span class="Comment">#</span> + *before-cursor<span class="Special"> <- </span>copy curr + *cursor-column<span class="Special"> <- </span>add *cursor-column, <span class="Constant">1</span> + <span class="muControl">loop</span> + <span class="Delimiter">}</span> + <span class="muControl">reply</span> editor/same-as-ingredient:<span class="Constant">0</span>, <span class="Constant">0/no-more-render</span> + <span class="Delimiter">}</span> +<span class="Constant"> +try-to-scroll</span> +<span class="Constant"> <scroll-down></span> + <span class="muControl">reply</span> editor/same-as-ingredient:<span class="Constant">0</span>, <span class="Constant">1/go-render</span> +] + +<span class="muScenario">scenario</span> editor-adjusts-column-at-next-line [ + assume-screen <span class="Constant">10/width</span>, <span class="Constant">5/height</span> + <span class="Constant">1</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[abc</span> +<span class="Constant">de]</span> + <span class="Constant">2</span>:address:editor-data<span class="Special"> <- </span>new-editor <span class="Constant">1</span>:address:array:character, screen:address, <span class="Constant">0/left</span>, <span class="Constant">10/right</span> + editor-render screen, <span class="Constant">2</span>:address:editor-data +<span class="Constant"> $clear-trace</span> + assume-console [ + left-click <span class="Constant">1</span>, <span class="Constant">3</span> + press down-arrow + ] + run [ + editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data + <span class="Constant">3</span>:number<span class="Special"> <- </span>get *<span class="Constant">2</span>:address:editor-data, <span class="Constant">cursor-row:offset</span> + <span class="Constant">4</span>:number<span class="Special"> <- </span>get *<span class="Constant">2</span>:address:editor-data, <span class="Constant">cursor-column:offset</span> + ] + memory-should-contain [ + <span class="Constant">3</span><span class="Special"> <- </span><span class="Constant">2</span> + <span class="Constant">4</span><span class="Special"> <- </span><span class="Constant">2</span> + ] + check-trace-count-for-label <span class="Constant">0</span>, <span class="Constant">[print-character]</span> + assume-console [ + type <span class="Constant">[0]</span> + ] + run [ + editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data + ] + screen-should-contain [ + <span class="Constant"> . .</span> + <span class="Constant"> .abc .</span> + <span class="Constant"> .de0 .</span> +<span class="Constant"> .┈┈┈┈┈┈┈┈┈┈.</span> + <span class="Constant"> . .</span> + ] +] + +<span class="muScenario">scenario</span> editor-scrolls-at-end-on-down-arrow [ + assume-screen <span class="Constant">10/width</span>, <span class="Constant">5/height</span> + <span class="Constant">1</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[abc</span> +<span class="Constant">de]</span> + <span class="Constant">2</span>:address:editor-data<span class="Special"> <- </span>new-editor <span class="Constant">1</span>:address:array:character, screen:address, <span class="Constant">0/left</span>, <span class="Constant">10/right</span> + editor-render screen, <span class="Constant">2</span>:address:editor-data +<span class="Constant"> $clear-trace</span> + <span class="Comment"># try to move down past end of text</span> + assume-console [ + left-click <span class="Constant">2</span>, <span class="Constant">0</span> + press down-arrow + ] + run [ + editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data + <span class="Constant">3</span>:number<span class="Special"> <- </span>get *<span class="Constant">2</span>:address:editor-data, <span class="Constant">cursor-row:offset</span> + <span class="Constant">4</span>:number<span class="Special"> <- </span>get *<span class="Constant">2</span>:address:editor-data, <span class="Constant">cursor-column:offset</span> + ] + <span class="Comment"># screen should scroll, moving cursor to end of text</span> + memory-should-contain [ + <span class="Constant">3</span><span class="Special"> <- </span><span class="Constant">1</span> + <span class="Constant">4</span><span class="Special"> <- </span><span class="Constant">2</span> + ] + assume-console [ + type <span class="Constant">[0]</span> + ] + run [ + editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data + ] + screen-should-contain [ + <span class="Constant"> . .</span> + <span class="Constant"> .de0 .</span> +<span class="Constant"> .┈┈┈┈┈┈┈┈┈┈.</span> + <span class="Constant"> . .</span> + ] + <span class="Comment"># try to move down again</span> +<span class="Constant"> $clear-trace</span> + assume-console [ + left-click <span class="Constant">2</span>, <span class="Constant">0</span> + press down-arrow + ] + run [ + editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data + <span class="Constant">3</span>:number<span class="Special"> <- </span>get *<span class="Constant">2</span>:address:editor-data, <span class="Constant">cursor-row:offset</span> + <span class="Constant">4</span>:number<span class="Special"> <- </span>get *<span class="Constant">2</span>:address:editor-data, <span class="Constant">cursor-column:offset</span> + ] + <span class="Comment"># screen stops scrolling because cursor is already at top</span> + memory-should-contain [ + <span class="Constant">3</span><span class="Special"> <- </span><span class="Constant">1</span> + <span class="Constant">4</span><span class="Special"> <- </span><span class="Constant">3</span> + ] + check-trace-count-for-label <span class="Constant">0</span>, <span class="Constant">[print-character]</span> + assume-console [ + type <span class="Constant">[1]</span> + ] + run [ + editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data + ] + screen-should-contain [ + <span class="Constant"> . .</span> + <span class="Constant"> .de01 .</span> +<span class="Constant"> .┈┈┈┈┈┈┈┈┈┈.</span> + <span class="Constant"> . .</span> + ] +] + +<span class="Comment"># ctrl-a/home - move cursor to start of line</span> + +<span class="muScenario">scenario</span> editor-moves-to-start-of-line-with-ctrl-a [ + assume-screen <span class="Constant">10/width</span>, <span class="Constant">5/height</span> + <span class="Constant">1</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[123</span> +<span class="Constant">456]</span> + <span class="Constant">2</span>:address:editor-data<span class="Special"> <- </span>new-editor <span class="Constant">1</span>:address:array:character, screen:address, <span class="Constant">0/left</span>, <span class="Constant">10/right</span> + editor-render screen, <span class="Constant">2</span>:address:editor-data +<span class="Constant"> $clear-trace</span> + <span class="Comment"># start on second line, press ctrl-a</span> + assume-console [ + left-click <span class="Constant">2</span>, <span class="Constant">3</span> + press ctrl-a + ] + run [ + editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data + <span class="Constant">4</span>:number<span class="Special"> <- </span>get *<span class="Constant">2</span>:address:editor-data, <span class="Constant">cursor-row:offset</span> + <span class="Constant">5</span>:number<span class="Special"> <- </span>get *<span class="Constant">2</span>:address:editor-data, <span class="Constant">cursor-column:offset</span> + ] + <span class="Comment"># cursor moves to start of line</span> + memory-should-contain [ + <span class="Constant">4</span><span class="Special"> <- </span><span class="Constant">2</span> + <span class="Constant">5</span><span class="Special"> <- </span><span class="Constant">0</span> + ] + check-trace-count-for-label <span class="Constant">0</span>, <span class="Constant">[print-character]</span> +] + +<span class="muRecipe">after</span> <span class="Constant"><handle-special-character></span> [ + <span class="Delimiter">{</span> + move-to-start-of-line?:boolean<span class="Special"> <- </span>equal *c, <span class="Constant">1/ctrl-a</span> + <span class="muControl">break-unless</span> move-to-start-of-line? +<span class="Constant"> <move-cursor-begin></span> + move-to-start-of-line editor + undo-coalesce-tag:number<span class="Special"> <- </span>copy <span class="Constant">0/never</span> +<span class="Constant"> <move-cursor-end></span> + <span class="muControl">reply</span> screen/same-as-ingredient:<span class="Constant">0</span>, editor/same-as-ingredient:<span class="Constant">1</span>, <span class="Constant">0/no-more-render</span> + <span class="Delimiter">}</span> +] + +<span class="muRecipe">after</span> <span class="Constant"><handle-special-key></span> [ + <span class="Delimiter">{</span> + move-to-start-of-line?:boolean<span class="Special"> <- </span>equal *k, <span class="Constant">65521/home</span> + <span class="muControl">break-unless</span> move-to-start-of-line? +<span class="Constant"> <move-cursor-begin></span> + move-to-start-of-line editor + undo-coalesce-tag:number<span class="Special"> <- </span>copy <span class="Constant">0/never</span> +<span class="Constant"> <move-cursor-end></span> + <span class="muControl">reply</span> screen/same-as-ingredient:<span class="Constant">0</span>, editor/same-as-ingredient:<span class="Constant">1</span>, <span class="Constant">0/no-more-render</span> + <span class="Delimiter">}</span> +] + +<span class="muRecipe">recipe</span> move-to-start-of-line [ + <span class="Constant">local-scope</span> + editor:address:editor-data<span class="Special"> <- </span><span class="Constant">next-ingredient</span> + <span class="Comment"># update cursor column</span> + left:number<span class="Special"> <- </span>get *editor, <span class="Constant">left:offset</span> + cursor-column:address:number<span class="Special"> <- </span>get-address *editor, <span class="Constant">cursor-column:offset</span> + *cursor-column<span class="Special"> <- </span>copy left + <span class="Comment"># update before-cursor</span> + before-cursor:address:address:duplex-list<span class="Special"> <- </span>get-address *editor, <span class="Constant">before-cursor:offset</span> + init:address:duplex-list<span class="Special"> <- </span>get *editor, <span class="Constant">data:offset</span> + <span class="Comment"># while not at start of line, move </span> + <span class="Delimiter">{</span> + at-start-of-text?:boolean<span class="Special"> <- </span>equal *before-cursor, init + <span class="muControl">break-if</span> at-start-of-text? + prev:character<span class="Special"> <- </span>get **before-cursor, <span class="Constant">value:offset</span> + at-start-of-line?:boolean<span class="Special"> <- </span>equal prev, <span class="Constant">10/newline</span> + <span class="muControl">break-if</span> at-start-of-line? + *before-cursor<span class="Special"> <- </span>prev-duplex *before-cursor + assert *before-cursor, <span class="Constant">[move-to-start-of-line tried to move before start of text]</span> + <span class="muControl">loop</span> + <span class="Delimiter">}</span> +] + +<span class="muScenario">scenario</span> editor-moves-to-start-of-line-with-ctrl-a-2 [ + assume-screen <span class="Constant">10/width</span>, <span class="Constant">5/height</span> + <span class="Constant">1</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[123</span> +<span class="Constant">456]</span> + <span class="Constant">2</span>:address:editor-data<span class="Special"> <- </span>new-editor <span class="Constant">1</span>:address:array:character, screen:address, <span class="Constant">0/left</span>, <span class="Constant">10/right</span> + editor-render screen, <span class="Constant">2</span>:address:editor-data +<span class="Constant"> $clear-trace</span> + <span class="Comment"># start on first line (no newline before), press ctrl-a</span> + assume-console [ + left-click <span class="Constant">1</span>, <span class="Constant">3</span> + press ctrl-a + ] + run [ + editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data + <span class="Constant">4</span>:number<span class="Special"> <- </span>get *<span class="Constant">2</span>:address:editor-data, <span class="Constant">cursor-row:offset</span> + <span class="Constant">5</span>:number<span class="Special"> <- </span>get *<span class="Constant">2</span>:address:editor-data, <span class="Constant">cursor-column:offset</span> + ] + <span class="Comment"># cursor moves to start of line</span> + memory-should-contain [ + <span class="Constant">4</span><span class="Special"> <- </span><span class="Constant">1</span> + <span class="Constant">5</span><span class="Special"> <- </span><span class="Constant">0</span> + ] + check-trace-count-for-label <span class="Constant">0</span>, <span class="Constant">[print-character]</span> +] + +<span class="muScenario">scenario</span> editor-moves-to-start-of-line-with-home [ + assume-screen <span class="Constant">10/width</span>, <span class="Constant">5/height</span> + <span class="Constant">1</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[123</span> +<span class="Constant">456]</span> + <span class="Constant">2</span>:address:editor-data<span class="Special"> <- </span>new-editor <span class="Constant">1</span>:address:array:character, screen:address, <span class="Constant">0/left</span>, <span class="Constant">10/right</span> +<span class="Constant"> $clear-trace</span> + <span class="Comment"># start on second line, press 'home'</span> + assume-console [ + left-click <span class="Constant">2</span>, <span class="Constant">3</span> + press home + ] + run [ + editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data + <span class="Constant">3</span>:number<span class="Special"> <- </span>get *<span class="Constant">2</span>:address:editor-data, <span class="Constant">cursor-row:offset</span> + <span class="Constant">4</span>:number<span class="Special"> <- </span>get *<span class="Constant">2</span>:address:editor-data, <span class="Constant">cursor-column:offset</span> + ] + <span class="Comment"># cursor moves to start of line</span> + memory-should-contain [ + <span class="Constant">3</span><span class="Special"> <- </span><span class="Constant">2</span> + <span class="Constant">4</span><span class="Special"> <- </span><span class="Constant">0</span> + ] + check-trace-count-for-label <span class="Constant">0</span>, <span class="Constant">[print-character]</span> +] + +<span class="muScenario">scenario</span> editor-moves-to-start-of-line-with-home-2 [ + assume-screen <span class="Constant">10/width</span>, <span class="Constant">5/height</span> + <span class="Constant">1</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[123</span> +<span class="Constant">456]</span> + <span class="Constant">2</span>:address:editor-data<span class="Special"> <- </span>new-editor <span class="Constant">1</span>:address:array:character, screen:address, <span class="Constant">0/left</span>, <span class="Constant">10/right</span> + editor-render screen, <span class="Constant">2</span>:address:editor-data +<span class="Constant"> $clear-trace</span> + <span class="Comment"># start on first line (no newline before), press 'home'</span> + assume-console [ + left-click <span class="Constant">1</span>, <span class="Constant">3</span> + press home + ] + run [ + editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data + <span class="Constant">3</span>:number<span class="Special"> <- </span>get *<span class="Constant">2</span>:address:editor-data, <span class="Constant">cursor-row:offset</span> + <span class="Constant">4</span>:number<span class="Special"> <- </span>get *<span class="Constant">2</span>:address:editor-data, <span class="Constant">cursor-column:offset</span> + ] + <span class="Comment"># cursor moves to start of line</span> + memory-should-contain [ + <span class="Constant">3</span><span class="Special"> <- </span><span class="Constant">1</span> + <span class="Constant">4</span><span class="Special"> <- </span><span class="Constant">0</span> + ] + check-trace-count-for-label <span class="Constant">0</span>, <span class="Constant">[print-character]</span> +] + +<span class="Comment"># ctrl-e/end - move cursor to end of line</span> + +<span class="muScenario">scenario</span> editor-moves-to-end-of-line-with-ctrl-e [ + assume-screen <span class="Constant">10/width</span>, <span class="Constant">5/height</span> + <span class="Constant">1</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[123</span> +<span class="Constant">456]</span> + <span class="Constant">2</span>:address:editor-data<span class="Special"> <- </span>new-editor <span class="Constant">1</span>:address:array:character, screen:address, <span class="Constant">0/left</span>, <span class="Constant">10/right</span> + editor-render screen, <span class="Constant">2</span>:address:editor-data +<span class="Constant"> $clear-trace</span> + <span class="Comment"># start on first line, press ctrl-e</span> + assume-console [ + left-click <span class="Constant">1</span>, <span class="Constant">1</span> + press ctrl-e + ] + run [ + editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data + <span class="Constant">4</span>:number<span class="Special"> <- </span>get *<span class="Constant">2</span>:address:editor-data, <span class="Constant">cursor-row:offset</span> + <span class="Constant">5</span>:number<span class="Special"> <- </span>get *<span class="Constant">2</span>:address:editor-data, <span class="Constant">cursor-column:offset</span> + ] + <span class="Comment"># cursor moves to end of line</span> + memory-should-contain [ + <span class="Constant">4</span><span class="Special"> <- </span><span class="Constant">1</span> + <span class="Constant">5</span><span class="Special"> <- </span><span class="Constant">3</span> + ] + check-trace-count-for-label <span class="Constant">0</span>, <span class="Constant">[print-character]</span> + <span class="Comment"># editor inserts future characters at cursor</span> + assume-console [ + type <span class="Constant">[z]</span> + ] + run [ + editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data + <span class="Constant">4</span>:number<span class="Special"> <- </span>get *<span class="Constant">2</span>:address:editor-data, <span class="Constant">cursor-row:offset</span> + <span class="Constant">5</span>:number<span class="Special"> <- </span>get *<span class="Constant">2</span>:address:editor-data, <span class="Constant">cursor-column:offset</span> + ] + memory-should-contain [ + <span class="Constant">4</span><span class="Special"> <- </span><span class="Constant">1</span> + <span class="Constant">5</span><span class="Special"> <- </span><span class="Constant">4</span> + ] + screen-should-contain [ + <span class="Constant"> . .</span> + <span class="Constant"> .123z .</span> + <span class="Constant"> .456 .</span> +<span class="Constant"> .┈┈┈┈┈┈┈┈┈┈.</span> + <span class="Constant"> . .</span> + ] + check-trace-count-for-label <span class="Constant">1</span>, <span class="Constant">[print-character]</span> +] + +<span class="muRecipe">after</span> <span class="Constant"><handle-special-character></span> [ + <span class="Delimiter">{</span> + move-to-end-of-line?:boolean<span class="Special"> <- </span>equal *c, <span class="Constant">5/ctrl-e</span> + <span class="muControl">break-unless</span> move-to-end-of-line? +<span class="Constant"> <move-cursor-begin></span> + move-to-end-of-line editor + undo-coalesce-tag:number<span class="Special"> <- </span>copy <span class="Constant">0/never</span> +<span class="Constant"> <move-cursor-end></span> + <span class="muControl">reply</span> screen/same-as-ingredient:<span class="Constant">0</span>, editor/same-as-ingredient:<span class="Constant">1</span>, <span class="Constant">0/no-more-render</span> + <span class="Delimiter">}</span> +] + +<span class="muRecipe">after</span> <span class="Constant"><handle-special-key></span> [ + <span class="Delimiter">{</span> + move-to-end-of-line?:boolean<span class="Special"> <- </span>equal *k, <span class="Constant">65520/end</span> + <span class="muControl">break-unless</span> move-to-end-of-line? +<span class="Constant"> <move-cursor-begin></span> + move-to-end-of-line editor + undo-coalesce-tag:number<span class="Special"> <- </span>copy <span class="Constant">0/never</span> +<span class="Constant"> <move-cursor-end></span> + <span class="muControl">reply</span> screen/same-as-ingredient:<span class="Constant">0</span>, editor/same-as-ingredient:<span class="Constant">1</span>, <span class="Constant">0/no-more-render</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, <span class="Constant">before-cursor:offset</span> + cursor-column:address:number<span class="Special"> <- </span>get-address *editor, <span class="Constant">cursor-column:offset</span> + <span class="Comment"># while not at start of line, move </span> + <span class="Delimiter">{</span> + next:address:duplex-list<span class="Special"> <- </span>next-duplex *before-cursor + <span class="muControl">break-unless</span> next <span class="Comment"># end of text</span> + nextc:character<span class="Special"> <- </span>get *next, <span class="Constant">value:offset</span> + at-end-of-line?:boolean<span class="Special"> <- </span>equal nextc, <span class="Constant">10/newline</span> + <span class="muControl">break-if</span> at-end-of-line? + *before-cursor<span class="Special"> <- </span>copy next + *cursor-column<span class="Special"> <- </span>add *cursor-column, <span class="Constant">1</span> + <span class="muControl">loop</span> + <span class="Delimiter">}</span> +] + +<span class="muScenario">scenario</span> editor-moves-to-end-of-line-with-ctrl-e-2 [ + assume-screen <span class="Constant">10/width</span>, <span class="Constant">5/height</span> + <span class="Constant">1</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[123</span> +<span class="Constant">456]</span> + <span class="Constant">2</span>:address:editor-data<span class="Special"> <- </span>new-editor <span class="Constant">1</span>:address:array:character, screen:address, <span class="Constant">0/left</span>, <span class="Constant">10/right</span> + editor-render screen, <span class="Constant">2</span>:address:editor-data +<span class="Constant"> $clear-trace</span> + <span class="Comment"># start on second line (no newline after), press ctrl-e</span> + assume-console [ + left-click <span class="Constant">2</span>, <span class="Constant">1</span> + press ctrl-e + ] + run [ + editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data + <span class="Constant">4</span>:number<span class="Special"> <- </span>get *<span class="Constant">2</span>:address:editor-data, <span class="Constant">cursor-row:offset</span> + <span class="Constant">5</span>:number<span class="Special"> <- </span>get *<span class="Constant">2</span>:address:editor-data, <span class="Constant">cursor-column:offset</span> + ] + <span class="Comment"># cursor moves to end of line</span> + memory-should-contain [ + <span class="Constant">4</span><span class="Special"> <- </span><span class="Constant">2</span> + <span class="Constant">5</span><span class="Special"> <- </span><span class="Constant">3</span> + ] + check-trace-count-for-label <span class="Constant">0</span>, <span class="Constant">[print-character]</span> +] + +<span class="muScenario">scenario</span> editor-moves-to-end-of-line-with-end [ + assume-screen <span class="Constant">10/width</span>, <span class="Constant">5/height</span> + <span class="Constant">1</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[123</span> +<span class="Constant">456]</span> + <span class="Constant">2</span>:address:editor-data<span class="Special"> <- </span>new-editor <span class="Constant">1</span>:address:array:character, screen:address, <span class="Constant">0/left</span>, <span class="Constant">10/right</span> + editor-render screen, <span class="Constant">2</span>:address:editor-data +<span class="Constant"> $clear-trace</span> + <span class="Comment"># start on first line, press 'end'</span> + assume-console [ + left-click <span class="Constant">1</span>, <span class="Constant">1</span> + press end + ] + run [ + editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data + <span class="Constant">3</span>:number<span class="Special"> <- </span>get *<span class="Constant">2</span>:address:editor-data, <span class="Constant">cursor-row:offset</span> + <span class="Constant">4</span>:number<span class="Special"> <- </span>get *<span class="Constant">2</span>:address:editor-data, <span class="Constant">cursor-column:offset</span> + ] + <span class="Comment"># cursor moves to end of line</span> + memory-should-contain [ + <span class="Constant">3</span><span class="Special"> <- </span><span class="Constant">1</span> + <span class="Constant">4</span><span class="Special"> <- </span><span class="Constant">3</span> + ] + check-trace-count-for-label <span class="Constant">0</span>, <span class="Constant">[print-character]</span> +] + +<span class="muScenario">scenario</span> editor-moves-to-end-of-line-with-end-2 [ + assume-screen <span class="Constant">10/width</span>, <span class="Constant">5/height</span> + <span class="Constant">1</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[123</span> +<span class="Constant">456]</span> + <span class="Constant">2</span>:address:editor-data<span class="Special"> <- </span>new-editor <span class="Constant">1</span>:address:array:character, screen:address, <span class="Constant">0/left</span>, <span class="Constant">10/right</span> + editor-render screen, <span class="Constant">2</span>:address:editor-data +<span class="Constant"> $clear-trace</span> + <span class="Comment"># start on second line (no newline after), press 'end'</span> + assume-console [ + left-click <span class="Constant">2</span>, <span class="Constant">1</span> + press end + ] + run [ + editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data + <span class="Constant">3</span>:number<span class="Special"> <- </span>get *<span class="Constant">2</span>:address:editor-data, <span class="Constant">cursor-row:offset</span> + <span class="Constant">4</span>:number<span class="Special"> <- </span>get *<span class="Constant">2</span>:address:editor-data, <span class="Constant">cursor-column:offset</span> + ] + <span class="Comment"># cursor moves to end of line</span> + memory-should-contain [ + <span class="Constant">3</span><span class="Special"> <- </span><span class="Constant">2</span> + <span class="Constant">4</span><span class="Special"> <- </span><span class="Constant">3</span> + ] + check-trace-count-for-label <span class="Constant">0</span>, <span class="Constant">[print-character]</span> +] + +<span class="Comment"># ctrl-u - delete text from start of line until (but not at) cursor</span> + +<span class="muScenario">scenario</span> editor-deletes-to-start-of-line-with-ctrl-u [ + assume-screen <span class="Constant">10/width</span>, <span class="Constant">5/height</span> + <span class="Constant">1</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[123</span> +<span class="Constant">456]</span> + <span class="Constant">2</span>:address:editor-data<span class="Special"> <- </span>new-editor <span class="Constant">1</span>:address:array:character, screen:address, <span class="Constant">0/left</span>, <span class="Constant">10/right</span> + <span class="Comment"># start on second line, press ctrl-u</span> + assume-console [ + left-click <span class="Constant">2</span>, <span class="Constant">2</span> + press ctrl-u + ] + run [ + editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data + ] + <span class="Comment"># cursor deletes to start of line</span> + screen-should-contain [ + <span class="Constant"> . .</span> + <span class="Constant"> .123 .</span> + <span class="Constant"> .6 .</span> +<span class="Constant"> .┈┈┈┈┈┈┈┈┈┈.</span> + <span class="Constant"> . .</span> + ] +] + +<span class="muRecipe">after</span> <span class="Constant"><handle-special-character></span> [ + <span class="Delimiter">{</span> + delete-to-start-of-line?:boolean<span class="Special"> <- </span>equal *c, <span class="Constant">21/ctrl-u</span> + <span class="muControl">break-unless</span> delete-to-start-of-line? +<span class="Constant"> <delete-to-start-of-line-begin></span> + deleted-cells:address:duplex-list<span class="Special"> <- </span>delete-to-start-of-line editor +<span class="Constant"> <delete-to-start-of-line-end></span> + <span class="muControl">reply</span> screen/same-as-ingredient:<span class="Constant">0</span>, editor/same-as-ingredient:<span class="Constant">1</span>, <span class="Constant">1/go-render</span> + <span class="Delimiter">}</span> +] + +<span class="muRecipe">recipe</span> delete-to-start-of-line [ + <span class="Constant">local-scope</span> + editor:address:editor-data<span class="Special"> <- </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, <span class="Constant">data:offset</span> + before-cursor:address:address:duplex-list<span class="Special"> <- </span>get-address *editor, <span class="Constant">before-cursor:offset</span> + start:address:duplex-list<span class="Special"> <- </span>copy *before-cursor + end:address:duplex-list<span class="Special"> <- </span>next-duplex *before-cursor + <span class="Delimiter">{</span> + at-start-of-text?:boolean<span class="Special"> <- </span>equal start, init + <span class="muControl">break-if</span> at-start-of-text? + curr:character<span class="Special"> <- </span>get *start, <span class="Constant">value:offset</span> + at-start-of-line?:boolean<span class="Special"> <- </span>equal curr, <span class="Constant">10/newline</span> + <span class="muControl">break-if</span> at-start-of-line? + start<span class="Special"> <- </span>prev-duplex start + assert start, <span class="Constant">[delete-to-start-of-line tried to move before start of text]</span> + <span class="muControl">loop</span> + <span class="Delimiter">}</span> + <span class="Comment"># snip it out</span> + result:address:duplex-list<span class="Special"> <- </span>next-duplex start + remove-duplex-between start, end + <span class="Comment"># adjust cursor</span> + *before-cursor<span class="Special"> <- </span>prev-duplex end + left:number<span class="Special"> <- </span>get *editor, <span class="Constant">left:offset</span> + cursor-column:address:number<span class="Special"> <- </span>get-address *editor, <span class="Constant">cursor-column:offset</span> + *cursor-column<span class="Special"> <- </span>copy left + <span class="muControl">reply</span> result +] + +<span class="muScenario">scenario</span> editor-deletes-to-start-of-line-with-ctrl-u-2 [ + assume-screen <span class="Constant">10/width</span>, <span class="Constant">5/height</span> + <span class="Constant">1</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[123</span> +<span class="Constant">456]</span> + <span class="Constant">2</span>:address:editor-data<span class="Special"> <- </span>new-editor <span class="Constant">1</span>:address:array:character, screen:address, <span class="Constant">0/left</span>, <span class="Constant">10/right</span> + <span class="Comment"># start on first line (no newline before), press ctrl-u</span> + assume-console [ + left-click <span class="Constant">1</span>, <span class="Constant">2</span> + press ctrl-u + ] + run [ + editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data + ] + <span class="Comment"># cursor deletes to start of line</span> + screen-should-contain [ + <span class="Constant"> . .</span> + <span class="Constant"> .3 .</span> + <span class="Constant"> .456 .</span> +<span class="Constant"> .┈┈┈┈┈┈┈┈┈┈.</span> + <span class="Constant"> . .</span> + ] +] + +<span class="muScenario">scenario</span> editor-deletes-to-start-of-line-with-ctrl-u-3 [ + assume-screen <span class="Constant">10/width</span>, <span class="Constant">5/height</span> + <span class="Constant">1</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[123</span> +<span class="Constant">456]</span> + <span class="Constant">2</span>:address:editor-data<span class="Special"> <- </span>new-editor <span class="Constant">1</span>:address:array:character, screen:address, <span class="Constant">0/left</span>, <span class="Constant">10/right</span> + <span class="Comment"># start past end of line, press ctrl-u</span> + assume-console [ + left-click <span class="Constant">1</span>, <span class="Constant">3</span> + press ctrl-u + ] + run [ + editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data + ] + <span class="Comment"># cursor deletes to start of line</span> + screen-should-contain [ + <span class="Constant"> . .</span> + <span class="Constant"> . .</span> + <span class="Constant"> .456 .</span> +<span class="Constant"> .┈┈┈┈┈┈┈┈┈┈.</span> + <span class="Constant"> . .</span> + ] +] + +<span class="muScenario">scenario</span> editor-deletes-to-start-of-final-line-with-ctrl-u [ + assume-screen <span class="Constant">10/width</span>, <span class="Constant">5/height</span> + <span class="Constant">1</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[123</span> +<span class="Constant">456]</span> + <span class="Constant">2</span>:address:editor-data<span class="Special"> <- </span>new-editor <span class="Constant">1</span>:address:array:character, screen:address, <span class="Constant">0/left</span>, <span class="Constant">10/right</span> + <span class="Comment"># start past end of final line, press ctrl-u</span> + assume-console [ + left-click <span class="Constant">2</span>, <span class="Constant">3</span> + press ctrl-u + ] + run [ + editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data + ] + <span class="Comment"># cursor deletes to start of line</span> + screen-should-contain [ + <span class="Constant"> . .</span> + <span class="Constant"> .123 .</span> + <span class="Constant"> . .</span> +<span class="Constant"> .┈┈┈┈┈┈┈┈┈┈.</span> + <span class="Constant"> . .</span> + ] +] + +<span class="Comment"># ctrl-k - delete text from cursor to end of line (but not the newline)</span> + +<span class="muScenario">scenario</span> editor-deletes-to-end-of-line-with-ctrl-k [ + assume-screen <span class="Constant">10/width</span>, <span class="Constant">5/height</span> + <span class="Constant">1</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[123</span> +<span class="Constant">456]</span> + <span class="Constant">2</span>:address:editor-data<span class="Special"> <- </span>new-editor <span class="Constant">1</span>:address:array:character, screen:address, <span class="Constant">0/left</span>, <span class="Constant">10/right</span> + <span class="Comment"># start on first line, press ctrl-k</span> + assume-console [ + left-click <span class="Constant">1</span>, <span class="Constant">1</span> + press ctrl-k + ] + run [ + editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data + ] + <span class="Comment"># cursor deletes to end of line</span> + screen-should-contain [ + <span class="Constant"> . .</span> + <span class="Constant"> .1 .</span> + <span class="Constant"> .456 .</span> +<span class="Constant"> .┈┈┈┈┈┈┈┈┈┈.</span> + <span class="Constant"> . .</span> + ] +] + +<span class="muRecipe">after</span> <span class="Constant"><handle-special-character></span> [ + <span class="Delimiter">{</span> + delete-to-end-of-line?:boolean<span class="Special"> <- </span>equal *c, <span class="Constant">11/ctrl-k</span> + <span class="muControl">break-unless</span> delete-to-end-of-line? +<span class="Constant"> <delete-to-end-of-line-begin></span> + deleted-cells:address:duplex-list<span class="Special"> <- </span>delete-to-end-of-line editor +<span class="Constant"> <delete-to-end-of-line-end></span> + <span class="muControl">reply</span> screen/same-as-ingredient:<span class="Constant">0</span>, editor/same-as-ingredient:<span class="Constant">1</span>, <span class="Constant">1/go-render</span> + <span class="Delimiter">}</span> +] + +<span class="muRecipe">recipe</span> delete-to-end-of-line [ + <span class="Constant">local-scope</span> + editor:address:editor-data<span class="Special"> <- </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, <span class="Constant">before-cursor:offset</span> + end:address:duplex-list<span class="Special"> <- </span>next-duplex start + <span class="Delimiter">{</span> + at-end-of-text?:boolean<span class="Special"> <- </span>equal end, <span class="Constant">0/null</span> + <span class="muControl">break-if</span> at-end-of-text? + curr:character<span class="Special"> <- </span>get *end, <span class="Constant">value:offset</span> + at-end-of-line?:boolean<span class="Special"> <- </span>equal curr, <span class="Constant">10/newline</span> + <span class="muControl">break-if</span> at-end-of-line? + end<span class="Special"> <- </span>next-duplex end + <span class="muControl">loop</span> + <span class="Delimiter">}</span> + <span class="Comment"># snip it out</span> + result:address:duplex-list<span class="Special"> <- </span>next-duplex start + remove-duplex-between start, end + <span class="muControl">reply</span> result +] + +<span class="muScenario">scenario</span> editor-deletes-to-end-of-line-with-ctrl-k-2 [ + assume-screen <span class="Constant">10/width</span>, <span class="Constant">5/height</span> + <span class="Constant">1</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[123</span> +<span class="Constant">456]</span> + <span class="Constant">2</span>:address:editor-data<span class="Special"> <- </span>new-editor <span class="Constant">1</span>:address:array:character, screen:address, <span class="Constant">0/left</span>, <span class="Constant">10/right</span> + <span class="Comment"># start on second line (no newline after), press ctrl-k</span> + assume-console [ + left-click <span class="Constant">2</span>, <span class="Constant">1</span> + press ctrl-k + ] + run [ + editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data + ] + <span class="Comment"># cursor deletes to end of line</span> + screen-should-contain [ + <span class="Constant"> . .</span> + <span class="Constant"> .123 .</span> + <span class="Constant"> .4 .</span> +<span class="Constant"> .┈┈┈┈┈┈┈┈┈┈.</span> + <span class="Constant"> . .</span> + ] +] + +<span class="muScenario">scenario</span> editor-deletes-to-end-of-line-with-ctrl-k-3 [ + assume-screen <span class="Constant">10/width</span>, <span class="Constant">5/height</span> + <span class="Constant">1</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[123</span> +<span class="Constant">456]</span> + <span class="Constant">2</span>:address:editor-data<span class="Special"> <- </span>new-editor <span class="Constant">1</span>:address:array:character, screen:address, <span class="Constant">0/left</span>, <span class="Constant">10/right</span> + <span class="Comment"># start at end of line</span> + assume-console [ + left-click <span class="Constant">1</span>, <span class="Constant">2</span> + press ctrl-k + ] + run [ + editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data + ] + <span class="Comment"># cursor deletes just last character</span> + screen-should-contain [ + <span class="Constant"> . .</span> + <span class="Constant"> .12 .</span> + <span class="Constant"> .456 .</span> +<span class="Constant"> .┈┈┈┈┈┈┈┈┈┈.</span> + <span class="Constant"> . .</span> + ] +] + +<span class="muScenario">scenario</span> editor-deletes-to-end-of-line-with-ctrl-k-4 [ + assume-screen <span class="Constant">10/width</span>, <span class="Constant">5/height</span> + <span class="Constant">1</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[123</span> +<span class="Constant">456]</span> + <span class="Constant">2</span>:address:editor-data<span class="Special"> <- </span>new-editor <span class="Constant">1</span>:address:array:character, screen:address, <span class="Constant">0/left</span>, <span class="Constant">10/right</span> + <span class="Comment"># start past end of line</span> + assume-console [ + left-click <span class="Constant">1</span>, <span class="Constant">3</span> + press ctrl-k + ] + run [ + editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data + ] + <span class="Comment"># cursor deletes nothing</span> + screen-should-contain [ + <span class="Constant"> . .</span> + <span class="Constant"> .123 .</span> + <span class="Constant"> .456 .</span> +<span class="Constant"> .┈┈┈┈┈┈┈┈┈┈.</span> + <span class="Constant"> . .</span> + ] +] + +<span class="muScenario">scenario</span> editor-deletes-to-end-of-line-with-ctrl-k-5 [ + assume-screen <span class="Constant">10/width</span>, <span class="Constant">5/height</span> + <span class="Constant">1</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[123</span> +<span class="Constant">456]</span> + <span class="Constant">2</span>:address:editor-data<span class="Special"> <- </span>new-editor <span class="Constant">1</span>:address:array:character, screen:address, <span class="Constant">0/left</span>, <span class="Constant">10/right</span> + <span class="Comment"># start at end of text</span> + assume-console [ + left-click <span class="Constant">2</span>, <span class="Constant">2</span> + press ctrl-k + ] + run [ + editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data + ] + <span class="Comment"># cursor deletes just the final character</span> + screen-should-contain [ + <span class="Constant"> . .</span> + <span class="Constant"> .123 .</span> + <span class="Constant"> .45 .</span> +<span class="Constant"> .┈┈┈┈┈┈┈┈┈┈.</span> + <span class="Constant"> . .</span> + ] +] + +<span class="muScenario">scenario</span> editor-deletes-to-end-of-line-with-ctrl-k-6 [ + assume-screen <span class="Constant">10/width</span>, <span class="Constant">5/height</span> + <span class="Constant">1</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[123</span> +<span class="Constant">456]</span> + <span class="Constant">2</span>:address:editor-data<span class="Special"> <- </span>new-editor <span class="Constant">1</span>:address:array:character, screen:address, <span class="Constant">0/left</span>, <span class="Constant">10/right</span> + <span class="Comment"># start past end of text</span> + assume-console [ + left-click <span class="Constant">2</span>, <span class="Constant">3</span> + press ctrl-k + ] + run [ + editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data + ] + <span class="Comment"># cursor deletes nothing</span> + screen-should-contain [ + <span class="Constant"> . .</span> + <span class="Constant"> .123 .</span> + <span class="Constant"> .456 .</span> +<span class="Constant"> .┈┈┈┈┈┈┈┈┈┈.</span> + <span class="Constant"> . .</span> + ] +] + +<span class="Comment"># cursor-down can scroll if necessary</span> + +<span class="muScenario">scenario</span> editor-can-scroll-down-using-arrow-keys [ + <span class="Comment"># screen has 1 line for menu + 3 lines</span> + assume-screen <span class="Constant">10/width</span>, <span class="Constant">4/height</span> + <span class="Comment"># initialize editor with >3 lines</span> + <span class="Constant">1</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[a</span> +<span class="Constant">b</span> +<span class="Constant">c</span> +<span class="Constant">d]</span> + <span class="Constant">2</span>:address:editor-data<span class="Special"> <- </span>new-editor <span class="Constant">1</span>:address:array:character, screen:address, <span class="Constant">0/left</span>, <span class="Constant">10/right</span> + screen-should-contain [ + <span class="Constant"> . .</span> + <span class="Constant"> .a .</span> + <span class="Constant"> .b .</span> + <span class="Constant"> .c .</span> + ] + <span class="Comment"># position cursor at last line, then try to move further down</span> + assume-console [ + left-click <span class="Constant">3</span>, <span class="Constant">0</span> + press down-arrow + ] + run [ + editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data + ] + <span class="Comment"># screen slides by one line</span> + screen-should-contain [ + <span class="Constant"> . .</span> + <span class="Constant"> .b .</span> + <span class="Constant"> .c .</span> + <span class="Constant"> .d .</span> + ] +] + +<span class="muRecipe">after</span> <span class="Constant"><scroll-down></span> [ + trace <span class="Constant">10</span>, <span class="Constant">[app]</span>, <span class="Constant">[scroll down]</span> + top-of-screen:address:address:duplex-list<span class="Special"> <- </span>get-address *editor, <span class="Constant">top-of-screen:offset</span> + left:number<span class="Special"> <- </span>get *editor, <span class="Constant">left:offset</span> + right:number<span class="Special"> <- </span>get *editor, <span class="Constant">right:offset</span> + max:number<span class="Special"> <- </span>subtract right, left + old-top:address:duplex-list<span class="Special"> <- </span>copy *top-of-screen + *top-of-screen<span class="Special"> <- </span>before-start-of-next-line *top-of-screen, max + no-movement?:boolean<span class="Special"> <- </span>equal old-top, *top-of-screen + <span class="Comment"># Hack: this reply doesn't match one of the locations of <scroll-down>,</span> + <span class="Comment"># directly within insert-at-cursor. However, I'm unable to trigger the</span> + <span class="Comment"># error.. If necessary create a duplicate copy of <scroll-down> with the</span> + <span class="Comment"># right 'reply-if'.</span> + <span class="muControl">reply-if</span> no-movement?, editor/same-as-ingredient:<span class="Constant">0</span>, <span class="Constant">0/no-more-render</span> +] + +<span class="Comment"># takes a pointer into the doubly-linked list, scans ahead at most 'max'</span> +<span class="Comment"># positions until the next newline</span> +<span class="Comment"># beware: never return null pointer.</span> +<span class="muRecipe">recipe</span> before-start-of-next-line [ + <span class="Constant">local-scope</span> + original:address:duplex-list<span class="Special"> <- </span><span class="Constant">next-ingredient</span> + max:number<span class="Special"> <- </span><span class="Constant">next-ingredient</span> + count:number<span class="Special"> <- </span>copy <span class="Constant">0</span> + curr:address:duplex-list<span class="Special"> <- </span>copy original + <span class="Comment"># skip the initial newline if it exists</span> + <span class="Delimiter">{</span> + c:character<span class="Special"> <- </span>get *curr, <span class="Constant">value:offset</span> + at-newline?:boolean<span class="Special"> <- </span>equal c, <span class="Constant">10/newline</span> + <span class="muControl">break-unless</span> at-newline? + curr<span class="Special"> <- </span>next-duplex curr + count<span class="Special"> <- </span>add count, <span class="Constant">1</span> + <span class="Delimiter">}</span> + <span class="Delimiter">{</span> + <span class="muControl">reply-unless</span> curr, original + done?:boolean<span class="Special"> <- </span>greater-or-equal count, max + <span class="muControl">break-if</span> done? + c:character<span class="Special"> <- </span>get *curr, <span class="Constant">value:offset</span> + at-newline?:boolean<span class="Special"> <- </span>equal c, <span class="Constant">10/newline</span> + <span class="muControl">break-if</span> at-newline? + curr<span class="Special"> <- </span>next-duplex curr + count<span class="Special"> <- </span>add count, <span class="Constant">1</span> + <span class="muControl">loop</span> + <span class="Delimiter">}</span> + <span class="muControl">reply-unless</span> curr, original + <span class="muControl">reply</span> curr +] + +<span class="muScenario">scenario</span> editor-scrolls-down-past-wrapped-line-using-arrow-keys [ + <span class="Comment"># screen has 1 line for menu + 3 lines</span> + assume-screen <span class="Constant">10/width</span>, <span class="Constant">4/height</span> + <span class="Comment"># initialize editor with a long, wrapped line and more than a screen of</span> + <span class="Comment"># other lines</span> + <span class="Constant">1</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[abcdef</span> +<span class="Constant">g</span> +<span class="Constant">h</span> +<span class="Constant">i]</span> + <span class="Constant">2</span>:address:editor-data<span class="Special"> <- </span>new-editor <span class="Constant">1</span>:address:array:character, screen:address, <span class="Constant">0/left</span>, <span class="Constant">5/right</span> + screen-should-contain [ + <span class="Constant"> . .</span> + <span class="Constant"> .abcd↩ .</span> + <span class="Constant"> .ef .</span> + <span class="Constant"> .g .</span> + ] + <span class="Comment"># position cursor at last line, then try to move further down</span> + assume-console [ + left-click <span class="Constant">3</span>, <span class="Constant">0</span> + press down-arrow + ] + run [ + editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data + ] + <span class="Comment"># screen shows partial wrapped line</span> + screen-should-contain [ + <span class="Constant"> . .</span> + <span class="Constant"> .ef .</span> + <span class="Constant"> .g .</span> + <span class="Constant"> .h .</span> + ] +] + +<span class="muScenario">scenario</span> editor-scrolls-down-past-wrapped-line-using-arrow-keys-2 [ + <span class="Comment"># screen has 1 line for menu + 3 lines</span> + assume-screen <span class="Constant">10/width</span>, <span class="Constant">4/height</span> + <span class="Comment"># editor starts with a long line wrapping twice</span> + <span class="Constant">1</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[abcdefghij</span> +<span class="Constant">k</span> +<span class="Constant">l</span> +<span class="Constant">m]</span> + <span class="Constant">2</span>:address:editor-data<span class="Special"> <- </span>new-editor <span class="Constant">1</span>:address:array:character, screen:address, <span class="Constant">0/left</span>, <span class="Constant">5/right</span> + <span class="Comment"># position cursor at last line, then try to move further down</span> + assume-console [ + left-click <span class="Constant">3</span>, <span class="Constant">0</span> + press down-arrow + ] + run [ + editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data + ] + <span class="Comment"># screen shows partial wrapped line containing a wrap icon</span> + screen-should-contain [ + <span class="Constant"> . .</span> + <span class="Constant"> .efgh↩ .</span> + <span class="Constant"> .ij .</span> + <span class="Constant"> .k .</span> + ] + <span class="Comment"># scroll down again</span> + assume-console [ + press down-arrow + ] + run [ + editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data + ] + <span class="Comment"># screen shows partial wrapped line</span> + screen-should-contain [ + <span class="Constant"> . .</span> + <span class="Constant"> .ij .</span> + <span class="Constant"> .k .</span> + <span class="Constant"> .l .</span> + ] +] + +<span class="muScenario">scenario</span> editor-scrolls-down-when-line-wraps [ + <span class="Comment"># screen has 1 line for menu + 3 lines</span> + assume-screen <span class="Constant">5/width</span>, <span class="Constant">4/height</span> + <span class="Comment"># editor contains a long line in the third line</span> + <span class="Constant">1</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[a</span> +<span class="Constant">b</span> +<span class="Constant">cdef]</span> + <span class="Constant">2</span>:address:editor-data<span class="Special"> <- </span>new-editor <span class="Constant">1</span>:address:array:character, screen:address, <span class="Constant">0/left</span>, <span class="Constant">5/right</span> + <span class="Comment"># position cursor at end, type a character</span> + assume-console [ + left-click <span class="Constant">3</span>, <span class="Constant">4</span> + type <span class="Constant">[g]</span> + ] + run [ + editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data + <span class="Constant">3</span>:number<span class="Special"> <- </span>get *<span class="Constant">2</span>:address:editor-data, <span class="Constant">cursor-row:offset</span> + <span class="Constant">4</span>:number<span class="Special"> <- </span>get *<span class="Constant">2</span>:address:editor-data, <span class="Constant">cursor-column:offset</span> + ] + <span class="Comment"># screen scrolls</span> + screen-should-contain [ + <span class="Constant"> . .</span> + <span class="Constant"> .b .</span> +<span class="Constant"> .cdef↩.</span> + <span class="Constant"> .g .</span> + ] + memory-should-contain [ + <span class="Constant">3</span><span class="Special"> <- </span><span class="Constant">3</span> + <span class="Constant">4</span><span class="Special"> <- </span><span class="Constant">1</span> + ] +] + +<span class="muScenario">scenario</span> editor-scrolls-down-on-newline [ + assume-screen <span class="Constant">5/width</span>, <span class="Constant">4/height</span> + <span class="Comment"># position cursor after last line and type newline</span> + <span class="Constant">1</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[a</span> +<span class="Constant">b</span> +<span class="Constant">c]</span> + <span class="Constant">2</span>:address:editor-data<span class="Special"> <- </span>new-editor <span class="Constant">1</span>:address:array:character, screen:address, <span class="Constant">0/left</span>, <span class="Constant">5/right</span> + assume-console [ + left-click <span class="Constant">3</span>, <span class="Constant">4</span> + type [ +] + ] + run [ + editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data + <span class="Constant">3</span>:number<span class="Special"> <- </span>get *<span class="Constant">2</span>:address:editor-data, <span class="Constant">cursor-row:offset</span> + <span class="Constant">4</span>:number<span class="Special"> <- </span>get *<span class="Constant">2</span>:address:editor-data, <span class="Constant">cursor-column:offset</span> + ] + <span class="Comment"># screen scrolls</span> + screen-should-contain [ + <span class="Constant"> . .</span> + <span class="Constant"> .b .</span> + <span class="Constant"> .c .</span> + <span class="Constant"> . .</span> + ] + memory-should-contain [ + <span class="Constant">3</span><span class="Special"> <- </span><span class="Constant">3</span> + <span class="Constant">4</span><span class="Special"> <- </span><span class="Constant">0</span> + ] +] + +<span class="muScenario">scenario</span> editor-scrolls-down-on-right-arrow [ + <span class="Comment"># screen has 1 line for menu + 3 lines</span> + assume-screen <span class="Constant">5/width</span>, <span class="Constant">4/height</span> + <span class="Comment"># editor contains a wrapped line</span> + <span class="Constant">1</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[a</span> +<span class="Constant">b</span> +<span class="Constant">cdefgh]</span> + <span class="Constant">2</span>:address:editor-data<span class="Special"> <- </span>new-editor <span class="Constant">1</span>:address:array:character, screen:address, <span class="Constant">0/left</span>, <span class="Constant">5/right</span> + <span class="Comment"># position cursor at end of screen and try to move right</span> + assume-console [ + left-click <span class="Constant">3</span>, <span class="Constant">3</span> + press right-arrow + ] + run [ + editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data + <span class="Constant">3</span>:number<span class="Special"> <- </span>get *<span class="Constant">2</span>:address:editor-data, <span class="Constant">cursor-row:offset</span> + <span class="Constant">4</span>:number<span class="Special"> <- </span>get *<span class="Constant">2</span>:address:editor-data, <span class="Constant">cursor-column:offset</span> + ] + <span class="Comment"># screen scrolls</span> + screen-should-contain [ + <span class="Constant"> . .</span> + <span class="Constant"> .b .</span> +<span class="Constant"> .cdef↩.</span> + <span class="Constant"> .gh .</span> + ] + memory-should-contain [ + <span class="Constant">3</span><span class="Special"> <- </span><span class="Constant">3</span> + <span class="Constant">4</span><span class="Special"> <- </span><span class="Constant">0</span> + ] +] + +<span class="muScenario">scenario</span> editor-scrolls-down-on-right-arrow-2 [ + <span class="Comment"># screen has 1 line for menu + 3 lines</span> + assume-screen <span class="Constant">5/width</span>, <span class="Constant">4/height</span> + <span class="Comment"># editor contains more lines than can fit on screen</span> + <span class="Constant">1</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[a</span> +<span class="Constant">b</span> +<span class="Constant">c</span> +<span class="Constant">d]</span> + <span class="Constant">2</span>:address:editor-data<span class="Special"> <- </span>new-editor <span class="Constant">1</span>:address:array:character, screen:address, <span class="Constant">0/left</span>, <span class="Constant">5/right</span> + <span class="Comment"># position cursor at end of screen and try to move right</span> + assume-console [ + left-click <span class="Constant">3</span>, <span class="Constant">3</span> + press right-arrow + ] + run [ + editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data + <span class="Constant">3</span>:number<span class="Special"> <- </span>get *<span class="Constant">2</span>:address:editor-data, <span class="Constant">cursor-row:offset</span> + <span class="Constant">4</span>:number<span class="Special"> <- </span>get *<span class="Constant">2</span>:address:editor-data, <span class="Constant">cursor-column:offset</span> + ] + <span class="Comment"># screen scrolls</span> + screen-should-contain [ + <span class="Constant"> . .</span> + <span class="Constant"> .b .</span> + <span class="Constant"> .c .</span> + <span class="Constant"> .d .</span> + ] + memory-should-contain [ + <span class="Constant">3</span><span class="Special"> <- </span><span class="Constant">3</span> + <span class="Constant">4</span><span class="Special"> <- </span><span class="Constant">0</span> + ] +] + +<span class="muScenario">scenario</span> editor-combines-page-and-line-scroll [ + <span class="Comment"># screen has 1 line for menu + 3 lines</span> + assume-screen <span class="Constant">10/width</span>, <span class="Constant">4/height</span> + <span class="Comment"># initialize editor with a few pages of lines</span> + <span class="Constant">1</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[a</span> +<span class="Constant">b</span> +<span class="Constant">c</span> +<span class="Constant">d</span> +<span class="Constant">e</span> +<span class="Constant">f</span> +<span class="Constant">g]</span> + <span class="Constant">2</span>:address:editor-data<span class="Special"> <- </span>new-editor <span class="Constant">1</span>:address:array:character, screen:address, <span class="Constant">0/left</span>, <span class="Constant">5/right</span> + <span class="Comment"># scroll down one page and one line</span> + assume-console [ + press page-down + left-click <span class="Constant">3</span>, <span class="Constant">0</span> + press down-arrow + ] + run [ + editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data + ] + <span class="Comment"># screen scrolls down 3 lines</span> + screen-should-contain [ + <span class="Constant"> . .</span> + <span class="Constant"> .d .</span> + <span class="Constant"> .e .</span> + <span class="Constant"> .f .</span> + ] +] + +<span class="Comment"># cursor-up can scroll if necessary</span> + +<span class="muScenario">scenario</span> editor-can-scroll-up-using-arrow-keys [ + <span class="Comment"># screen has 1 line for menu + 3 lines</span> + assume-screen <span class="Constant">10/width</span>, <span class="Constant">4/height</span> + <span class="Comment"># initialize editor with >3 lines</span> + <span class="Constant">1</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[a</span> +<span class="Constant">b</span> +<span class="Constant">c</span> +<span class="Constant">d]</span> + <span class="Constant">2</span>:address:editor-data<span class="Special"> <- </span>new-editor <span class="Constant">1</span>:address:array:character, screen:address, <span class="Constant">0/left</span>, <span class="Constant">10/right</span> + screen-should-contain [ + <span class="Constant"> . .</span> + <span class="Constant"> .a .</span> + <span class="Constant"> .b .</span> + <span class="Constant"> .c .</span> + ] + <span class="Comment"># position cursor at top of second page, then try to move up</span> + assume-console [ + press page-down + press up-arrow + ] + run [ + editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data + ] + <span class="Comment"># screen slides by one line</span> + screen-should-contain [ + <span class="Constant"> . .</span> + <span class="Constant"> .b .</span> + <span class="Constant"> .c .</span> + <span class="Constant"> .d .</span> + ] +] + +<span class="muRecipe">after</span> <span class="Constant"><scroll-up></span> [ + trace <span class="Constant">10</span>, <span class="Constant">[app]</span>, <span class="Constant">[scroll up]</span> + top-of-screen:address:address:duplex-list<span class="Special"> <- </span>get-address *editor, <span class="Constant">top-of-screen:offset</span> + old-top:address:duplex-list<span class="Special"> <- </span>copy *top-of-screen + *top-of-screen<span class="Special"> <- </span>before-previous-line *top-of-screen, editor + no-movement?:boolean<span class="Special"> <- </span>equal old-top, *top-of-screen + <span class="muControl">reply-if</span> no-movement?, editor/same-as-ingredient:<span class="Constant">0</span>, <span class="Constant">0/no-more-render</span> +] + +<span class="Comment"># takes a pointer into the doubly-linked list, scans back to before start of</span> +<span class="Comment"># previous *wrapped* line</span> +<span class="Comment"># beware: never return null pointer</span> +<span class="muRecipe">recipe</span> before-previous-line [ + <span class="Constant">local-scope</span> + curr:address:duplex-list<span class="Special"> <- </span><span class="Constant">next-ingredient</span> + c:character<span class="Special"> <- </span>get *curr, <span class="Constant">value:offset</span> + <span class="Comment"># compute max, number of characters to skip</span> + <span class="Comment"># 1 + len%(width-1)</span> + <span class="Comment"># except rotate second term to vary from 1 to width-1 rather than 0 to width-2</span> + editor:address:editor-data<span class="Special"> <- </span><span class="Constant">next-ingredient</span> + left:number<span class="Special"> <- </span>get *editor, <span class="Constant">left:offset</span> + right:number<span class="Special"> <- </span>get *editor, <span class="Constant">right:offset</span> + max-line-length:number<span class="Special"> <- </span>subtract right, left, <span class="Constant">-1/exclusive-right</span>, <span class="Constant">1/wrap-icon</span> + sentinel:address:duplex-list<span class="Special"> <- </span>get *editor, <span class="Constant">data:offset</span> + len:number<span class="Special"> <- </span>previous-line-length curr, sentinel + <span class="Delimiter">{</span> + <span class="muControl">break-if</span> len + <span class="Comment"># empty line; just skip this newline</span> + prev:address:duplex-list<span class="Special"> <- </span>prev-duplex curr + <span class="muControl">reply-unless</span> prev, curr + <span class="muControl">reply</span> prev + <span class="Delimiter">}</span> + _, max:number<span class="Special"> <- </span>divide-with-remainder len, max-line-length + <span class="Comment"># remainder 0 => scan one width-worth</span> + <span class="Delimiter">{</span> + <span class="muControl">break-if</span> max + max<span class="Special"> <- </span>copy max-line-length + <span class="Delimiter">}</span> + max<span class="Special"> <- </span>add max, <span class="Constant">1</span> + count:number<span class="Special"> <- </span>copy <span class="Constant">0</span> + <span class="Comment"># skip 'max' characters</span> + <span class="Delimiter">{</span> + done?:boolean<span class="Special"> <- </span>greater-or-equal count, max + <span class="muControl">break-if</span> done? + prev:address:duplex-list<span class="Special"> <- </span>prev-duplex curr + <span class="muControl">break-unless</span> prev + curr<span class="Special"> <- </span>copy prev + count<span class="Special"> <- </span>add count, <span class="Constant">1</span> + <span class="muControl">loop</span> + <span class="Delimiter">}</span> + <span class="muControl">reply</span> curr +] + +<span class="muScenario">scenario</span> editor-scrolls-up-past-wrapped-line-using-arrow-keys [ + <span class="Comment"># screen has 1 line for menu + 3 lines</span> + assume-screen <span class="Constant">10/width</span>, <span class="Constant">4/height</span> + <span class="Comment"># initialize editor with a long, wrapped line and more than a screen of</span> + <span class="Comment"># other lines</span> + <span class="Constant">1</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[abcdef</span> +<span class="Constant">g</span> +<span class="Constant">h</span> +<span class="Constant">i]</span> + <span class="Constant">2</span>:address:editor-data<span class="Special"> <- </span>new-editor <span class="Constant">1</span>:address:array:character, screen:address, <span class="Constant">0/left</span>, <span class="Constant">5/right</span> + screen-should-contain [ + <span class="Constant"> . .</span> + <span class="Constant"> .abcd↩ .</span> + <span class="Constant"> .ef .</span> + <span class="Constant"> .g .</span> + ] + <span class="Comment"># position cursor at top of second page, just below wrapped line</span> + assume-console [ + press page-down + ] + run [ + editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data + ] + screen-should-contain [ + <span class="Constant"> . .</span> + <span class="Constant"> .g .</span> + <span class="Constant"> .h .</span> + <span class="Constant"> .i .</span> + ] + <span class="Comment"># now move up one line</span> + assume-console [ + press up-arrow + ] + run [ + editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data + ] + <span class="Comment"># screen shows partial wrapped line</span> + screen-should-contain [ + <span class="Constant"> . .</span> + <span class="Constant"> .ef .</span> + <span class="Constant"> .g .</span> + <span class="Constant"> .h .</span> + ] +] + +<span class="muScenario">scenario</span> editor-scrolls-up-past-wrapped-line-using-arrow-keys-2 [ + <span class="Comment"># screen has 1 line for menu + 4 lines</span> + assume-screen <span class="Constant">10/width</span>, <span class="Constant">5/height</span> + <span class="Comment"># editor starts with a long line wrapping twice, occupying 3 of the 4 lines</span> + <span class="Constant">1</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[abcdefghij</span> +<span class="Constant">k</span> +<span class="Constant">l</span> +<span class="Constant">m]</span> + <span class="Constant">2</span>:address:editor-data<span class="Special"> <- </span>new-editor <span class="Constant">1</span>:address:array:character, screen:address, <span class="Constant">0/left</span>, <span class="Constant">5/right</span> + <span class="Comment"># position cursor at top of second page</span> + assume-console [ + press page-down + ] + run [ + editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data + ] + screen-should-contain [ + <span class="Constant"> . .</span> + <span class="Constant"> .k .</span> + <span class="Constant"> .l .</span> + <span class="Constant"> .m .</span> + <span class="Constant"> .┈┈┈┈┈ .</span> + ] + <span class="Comment"># move up one line</span> + assume-console [ + press up-arrow + ] + run [ + editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data + ] + <span class="Comment"># screen shows partial wrapped line</span> + screen-should-contain [ + <span class="Constant"> . .</span> + <span class="Constant"> .ij .</span> + <span class="Constant"> .k .</span> + <span class="Constant"> .l .</span> + <span class="Constant"> .m .</span> + ] + <span class="Comment"># move up a second line</span> + assume-console [ + press up-arrow + ] + run [ + editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data + ] + <span class="Comment"># screen shows partial wrapped line</span> + screen-should-contain [ + <span class="Constant"> . .</span> + <span class="Constant"> .efgh↩ .</span> + <span class="Constant"> .ij .</span> + <span class="Constant"> .k .</span> + <span class="Constant"> .l .</span> + ] + <span class="Comment"># move up a third line</span> + assume-console [ + press up-arrow + ] + run [ + editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data + ] + <span class="Comment"># screen shows partial wrapped line</span> + screen-should-contain [ + <span class="Constant"> . .</span> + <span class="Constant"> .abcd↩ .</span> + <span class="Constant"> .efgh↩ .</span> + <span class="Constant"> .ij .</span> + <span class="Constant"> .k .</span> + ] +] + +<span class="Comment"># same as editor-scrolls-up-past-wrapped-line-using-arrow-keys but length</span> +<span class="Comment"># slightly off, just to prevent over-training</span> +<span class="muScenario">scenario</span> editor-scrolls-up-past-wrapped-line-using-arrow-keys-3 [ + <span class="Comment"># screen has 1 line for menu + 3 lines</span> + assume-screen <span class="Constant">10/width</span>, <span class="Constant">4/height</span> + <span class="Comment"># initialize editor with a long, wrapped line and more than a screen of</span> + <span class="Comment"># other lines</span> + <span class="Constant">1</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[abcdef</span> +<span class="Constant">g</span> +<span class="Constant">h</span> +<span class="Constant">i]</span> + <span class="Constant">2</span>:address:editor-data<span class="Special"> <- </span>new-editor <span class="Constant">1</span>:address:array:character, screen:address, <span class="Constant">0/left</span>, <span class="Constant">6/right</span> + screen-should-contain [ + <span class="Constant"> . .</span> + <span class="Constant"> .abcde↩ .</span> + <span class="Constant"> .f .</span> + <span class="Constant"> .g .</span> + ] + <span class="Comment"># position cursor at top of second page, just below wrapped line</span> + assume-console [ + press page-down + ] + run [ + editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data + ] + screen-should-contain [ + <span class="Constant"> . .</span> + <span class="Constant"> .g .</span> + <span class="Constant"> .h .</span> + <span class="Constant"> .i .</span> + ] + <span class="Comment"># now move up one line</span> + assume-console [ + press up-arrow + ] + run [ + editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data + ] + <span class="Comment"># screen shows partial wrapped line</span> + screen-should-contain [ + <span class="Constant"> . .</span> + <span class="Constant"> .f .</span> + <span class="Constant"> .g .</span> + <span class="Constant"> .h .</span> + ] +] + +<span class="Comment"># check empty lines</span> +<span class="muScenario">scenario</span> editor-scrolls-up-past-wrapped-line-using-arrow-keys-4 [ + assume-screen <span class="Constant">10/width</span>, <span class="Constant">4/height</span> + <span class="Comment"># initialize editor with some lines around an empty line</span> + <span class="Constant">1</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[a</span> +<span class="Constant">b</span> + +c +d +e] + <span class="Constant">2</span>:address:editor-data<span class="Special"> <- </span>new-editor <span class="Constant">1</span>:address:array:character, screen:address, <span class="Constant">0/left</span>, <span class="Constant">6/right</span> + assume-console [ + press page-down + ] + run [ + editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data + ] + screen-should-contain [ + <span class="Constant"> . .</span> + <span class="Constant"> . .</span> + <span class="Constant"> .c .</span> + <span class="Constant"> .d .</span> + ] + assume-console [ + press page-down + ] + run [ + editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data + ] + screen-should-contain [ + <span class="Constant"> . .</span> + <span class="Constant"> .d .</span> + <span class="Constant"> .e .</span> + <span class="Constant"> .┈┈┈┈┈┈ .</span> + ] + assume-console [ + press page-up + ] + run [ + editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data + ] + screen-should-contain [ + <span class="Constant"> . .</span> + <span class="Constant"> . .</span> + <span class="Constant"> .c .</span> + <span class="Constant"> .d .</span> + ] +] + +<span class="muScenario">scenario</span> editor-scrolls-up-on-left-arrow [ + <span class="Comment"># screen has 1 line for menu + 3 lines</span> + assume-screen <span class="Constant">5/width</span>, <span class="Constant">4/height</span> + <span class="Comment"># editor contains >3 lines</span> + <span class="Constant">1</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[a</span> +<span class="Constant">b</span> +<span class="Constant">c</span> +<span class="Constant">d</span> +<span class="Constant">e]</span> + <span class="Constant">2</span>:address:editor-data<span class="Special"> <- </span>new-editor <span class="Constant">1</span>:address:array:character, screen:address, <span class="Constant">0/left</span>, <span class="Constant">5/right</span> + <span class="Comment"># position cursor at top of second page</span> + assume-console [ + press page-down + ] + run [ + editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data + ] + screen-should-contain [ + <span class="Constant"> . .</span> + <span class="Constant"> .c .</span> + <span class="Constant"> .d .</span> + <span class="Constant"> .e .</span> + ] + <span class="Comment"># now try to move left</span> + assume-console [ + press left-arrow + ] + run [ + editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data + <span class="Constant">3</span>:number<span class="Special"> <- </span>get *<span class="Constant">2</span>:address:editor-data, <span class="Constant">cursor-row:offset</span> + <span class="Constant">4</span>:number<span class="Special"> <- </span>get *<span class="Constant">2</span>:address:editor-data, <span class="Constant">cursor-column:offset</span> + ] + <span class="Comment"># screen scrolls</span> + screen-should-contain [ + <span class="Constant"> . .</span> + <span class="Constant"> .b .</span> + <span class="Constant"> .c .</span> + <span class="Constant"> .d .</span> + ] + memory-should-contain [ + <span class="Constant">3</span><span class="Special"> <- </span><span class="Constant">1</span> + <span class="Constant">4</span><span class="Special"> <- </span><span class="Constant">1</span> + ] +] + +<span class="muScenario">scenario</span> editor-can-scroll-up-to-start-of-file [ + <span class="Comment"># screen has 1 line for menu + 3 lines</span> + assume-screen <span class="Constant">10/width</span>, <span class="Constant">4/height</span> + <span class="Comment"># initialize editor with >3 lines</span> + <span class="Constant">1</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[a</span> +<span class="Constant">b</span> +<span class="Constant">c</span> +<span class="Constant">d]</span> + <span class="Constant">2</span>:address:editor-data<span class="Special"> <- </span>new-editor <span class="Constant">1</span>:address:array:character, screen:address, <span class="Constant">0/left</span>, <span class="Constant">10/right</span> + screen-should-contain [ + <span class="Constant"> . .</span> + <span class="Constant"> .a .</span> + <span class="Constant"> .b .</span> + <span class="Constant"> .c .</span> + ] + <span class="Comment"># position cursor at top of second page, then try to move up to start of</span> + <span class="Comment"># text</span> + assume-console [ + press page-down + press up-arrow + press up-arrow + ] + run [ + editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data + ] + <span class="Comment"># screen slides by one line</span> + screen-should-contain [ + <span class="Constant"> . .</span> + <span class="Constant"> .a .</span> + <span class="Constant"> .b .</span> + <span class="Constant"> .c .</span> + ] + <span class="Comment"># try to move up again</span> + assume-console [ + press up-arrow + ] + run [ + editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data + ] + <span class="Comment"># screen remains unchanged</span> + screen-should-contain [ + <span class="Constant"> . .</span> + <span class="Constant"> .a .</span> + <span class="Constant"> .b .</span> + <span class="Constant"> .c .</span> + ] +] + +<span class="Comment"># ctrl-f/page-down - render next page if it exists</span> + +<span class="muScenario">scenario</span> editor-can-scroll [ + assume-screen <span class="Constant">10/width</span>, <span class="Constant">4/height</span> + <span class="Constant">1</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[a</span> +<span class="Constant">b</span> +<span class="Constant">c</span> +<span class="Constant">d]</span> + <span class="Constant">2</span>:address:editor-data<span class="Special"> <- </span>new-editor <span class="Constant">1</span>:address:array:character, screen:address, <span class="Constant">0/left</span>, <span class="Constant">10/right</span> + screen-should-contain [ + <span class="Constant"> . .</span> + <span class="Constant"> .a .</span> + <span class="Constant"> .b .</span> + <span class="Constant"> .c .</span> + ] + <span class="Comment"># scroll down</span> + assume-console [ + press page-down + ] + run [ + editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data + ] + <span class="Comment"># screen shows next page</span> + screen-should-contain [ + <span class="Constant"> . .</span> + <span class="Constant"> .c .</span> + <span class="Constant"> .d .</span> +<span class="Constant"> .┈┈┈┈┈┈┈┈┈┈.</span> + ] +] + +<span class="muRecipe">after</span> <span class="Constant"><handle-special-character></span> [ + <span class="Delimiter">{</span> + page-down?:boolean<span class="Special"> <- </span>equal *c, <span class="Constant">6/ctrl-f</span> + <span class="muControl">break-unless</span> page-down? + top-of-screen:address:address:duplex-list<span class="Special"> <- </span>get-address *editor, <span class="Constant">top-of-screen:offset</span> + old-top:address:duplex-list<span class="Special"> <- </span>copy *top-of-screen +<span class="Constant"> <move-cursor-begin></span> + page-down editor + undo-coalesce-tag:number<span class="Special"> <- </span>copy <span class="Constant">0/never</span> +<span class="Constant"> <move-cursor-end></span> + no-movement?:boolean<span class="Special"> <- </span>equal *top-of-screen, old-top + <span class="muControl">reply-if</span> no-movement?, screen/same-as-ingredient:<span class="Constant">0</span>, editor/same-as-ingredient:<span class="Constant">1</span>, <span class="Constant">0/no-more-render</span> + <span class="muControl">reply</span> screen/same-as-ingredient:<span class="Constant">0</span>, editor/same-as-ingredient:<span class="Constant">1</span>, <span class="Constant">1/go-render</span> + <span class="Delimiter">}</span> +] + +<span class="muRecipe">after</span> <span class="Constant"><handle-special-key></span> [ + <span class="Delimiter">{</span> + page-down?:boolean<span class="Special"> <- </span>equal *k, <span class="Constant">65518/page-down</span> + <span class="muControl">break-unless</span> page-down? + top-of-screen:address:address:duplex-list<span class="Special"> <- </span>get-address *editor, <span class="Constant">top-of-screen:offset</span> + old-top:address:duplex-list<span class="Special"> <- </span>copy *top-of-screen +<span class="Constant"> <move-cursor-begin></span> + page-down editor + undo-coalesce-tag:number<span class="Special"> <- </span>copy <span class="Constant">0/never</span> +<span class="Constant"> <move-cursor-end></span> + no-movement?:boolean<span class="Special"> <- </span>equal *top-of-screen, old-top + <span class="muControl">reply-if</span> no-movement?, screen/same-as-ingredient:<span class="Constant">0</span>, editor/same-as-ingredient:<span class="Constant">1</span>, <span class="Constant">0/no-more-render</span> + <span class="muControl">reply</span> screen/same-as-ingredient:<span class="Constant">0</span>, editor/same-as-ingredient:<span class="Constant">1</span>, <span class="Constant">1/go-render</span> + <span class="Delimiter">}</span> +] + +<span class="Comment"># page-down skips entire wrapped lines, so it can't scroll past lines</span> +<span class="Comment"># taking up the entire screen</span> +<span class="muRecipe">recipe</span> page-down [ + <span class="Constant">local-scope</span> + editor:address:editor-data<span class="Special"> <- </span><span class="Constant">next-ingredient</span> + <span class="Comment"># if editor contents don't overflow screen, do nothing</span> + bottom-of-screen:address:duplex-list<span class="Special"> <- </span>get *editor, <span class="Constant">bottom-of-screen:offset</span> + <span class="muControl">reply-unless</span> bottom-of-screen, editor/same-as-ingredient:<span class="Constant">0</span> + <span class="Comment"># if not, position cursor at final character</span> + before-cursor:address:address:duplex-list<span class="Special"> <- </span>get-address *editor, <span class="Constant">before-cursor:offset</span> + *before-cursor<span class="Special"> <- </span>prev-duplex bottom-of-screen + <span class="Comment"># keep one line in common with previous page</span> + <span class="Delimiter">{</span> + last:character<span class="Special"> <- </span>get **before-cursor, <span class="Constant">value:offset</span> + newline?:boolean<span class="Special"> <- </span>equal last, <span class="Constant">10/newline</span> + <span class="muControl">break-unless</span> newline?:boolean + *before-cursor<span class="Special"> <- </span>prev-duplex *before-cursor + <span class="Delimiter">}</span> + <span class="Comment"># move cursor and top-of-screen to start of that line</span> + move-to-start-of-line editor + top-of-screen:address:address:duplex-list<span class="Special"> <- </span>get-address *editor, <span class="Constant">top-of-screen:offset</span> + *top-of-screen<span class="Special"> <- </span>copy *before-cursor + <span class="muControl">reply</span> editor/same-as-ingredient:<span class="Constant">0</span> +] + +<span class="muScenario">scenario</span> editor-does-not-scroll-past-end [ + assume-screen <span class="Constant">10/width</span>, <span class="Constant">4/height</span> + <span class="Constant">1</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[a</span> +<span class="Constant">b]</span> + <span class="Constant">2</span>:address:editor-data<span class="Special"> <- </span>new-editor <span class="Constant">1</span>:address:array:character, screen:address, <span class="Constant">0/left</span>, <span class="Constant">10/right</span> + editor-render screen, <span class="Constant">2</span>:address:editor-data + screen-should-contain [ + <span class="Constant"> . .</span> + <span class="Constant"> .a .</span> + <span class="Constant"> .b .</span> +<span class="Constant"> .┈┈┈┈┈┈┈┈┈┈.</span> + ] + <span class="Comment"># scroll down</span> + assume-console [ + press page-down + ] + run [ + editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data + ] + <span class="Comment"># screen remains unmodified</span> + screen-should-contain [ + <span class="Constant"> . .</span> + <span class="Constant"> .a .</span> + <span class="Constant"> .b .</span> +<span class="Constant"> .┈┈┈┈┈┈┈┈┈┈.</span> + ] +] + +<span class="muScenario">scenario</span> editor-starts-next-page-at-start-of-wrapped-line [ + <span class="Comment"># screen has 1 line for menu + 3 lines for text</span> + assume-screen <span class="Constant">10/width</span>, <span class="Constant">4/height</span> + <span class="Comment"># editor contains a long last line</span> + <span class="Constant">1</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[a</span> +<span class="Constant">b</span> +<span class="Constant">cdefgh]</span> + <span class="Comment"># editor screen triggers wrap of last line</span> + <span class="Constant">2</span>:address:editor-data<span class="Special"> <- </span>new-editor <span class="Constant">1</span>:address:array:character, screen:address, <span class="Constant">0/left</span>, <span class="Constant">4/right</span> + <span class="Comment"># some part of last line is not displayed</span> + screen-should-contain [ + <span class="Constant"> . .</span> + <span class="Constant"> .a .</span> + <span class="Constant"> .b .</span> + <span class="Constant"> .cde↩ .</span> + ] + <span class="Comment"># scroll down</span> + assume-console [ + press page-down + ] + run [ + editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data + ] + <span class="Comment"># screen shows entire wrapped line</span> + screen-should-contain [ + <span class="Constant"> . .</span> + <span class="Constant"> .cde↩ .</span> + <span class="Constant"> .fgh .</span> + <span class="Constant"> .┈┈┈┈ .</span> + ] +] + +<span class="muScenario">scenario</span> editor-starts-next-page-at-start-of-wrapped-line-2 [ + <span class="Comment"># screen has 1 line for menu + 3 lines for text</span> + assume-screen <span class="Constant">10/width</span>, <span class="Constant">4/height</span> + <span class="Comment"># editor contains a very long line that occupies last two lines of screen</span> + <span class="Comment"># and still has something left over</span> + <span class="Constant">1</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[a</span> +<span class="Constant">bcdefgh]</span> + <span class="Constant">2</span>:address:editor-data<span class="Special"> <- </span>new-editor <span class="Constant">1</span>:address:array:character, screen:address, <span class="Constant">0/left</span>, <span class="Constant">4/right</span> + <span class="Comment"># some part of last line is not displayed</span> + screen-should-contain [ + <span class="Constant"> . .</span> + <span class="Constant"> .a .</span> + <span class="Constant"> .bcd↩ .</span> + <span class="Constant"> .efg↩ .</span> + ] + <span class="Comment"># scroll down</span> + assume-console [ + press page-down + ] + run [ + editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data + ] + <span class="Comment"># screen shows entire wrapped line</span> + screen-should-contain [ + <span class="Constant"> . .</span> + <span class="Constant"> .bcd↩ .</span> + <span class="Constant"> .efg↩ .</span> + <span class="Constant"> .h .</span> + ] +] + +<span class="Comment"># ctrl-b/page-up - render previous page if it exists</span> + +<span class="muScenario">scenario</span> editor-can-scroll-up [ + assume-screen <span class="Constant">10/width</span>, <span class="Constant">4/height</span> + <span class="Constant">1</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[a</span> +<span class="Constant">b</span> +<span class="Constant">c</span> +<span class="Constant">d]</span> + <span class="Constant">2</span>:address:editor-data<span class="Special"> <- </span>new-editor <span class="Constant">1</span>:address:array:character, screen:address, <span class="Constant">0/left</span>, <span class="Constant">10/right</span> + screen-should-contain [ + <span class="Constant"> . .</span> + <span class="Constant"> .a .</span> + <span class="Constant"> .b .</span> + <span class="Constant"> .c .</span> + ] + <span class="Comment"># scroll down</span> + assume-console [ + press page-down + ] + run [ + editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data + ] + <span class="Comment"># screen shows next page</span> + screen-should-contain [ + <span class="Constant"> . .</span> + <span class="Constant"> .c .</span> + <span class="Constant"> .d .</span> +<span class="Constant"> .┈┈┈┈┈┈┈┈┈┈.</span> + ] + <span class="Comment"># scroll back up</span> + assume-console [ + press page-up + ] + run [ + editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data + ] + <span class="Comment"># screen shows original page again</span> + screen-should-contain [ + <span class="Constant"> . .</span> + <span class="Constant"> .a .</span> + <span class="Constant"> .b .</span> + <span class="Constant"> .c .</span> + ] +] + +<span class="muRecipe">after</span> <span class="Constant"><handle-special-character></span> [ + <span class="Delimiter">{</span> + page-up?:boolean<span class="Special"> <- </span>equal *c, <span class="Constant">2/ctrl-b</span> + <span class="muControl">break-unless</span> page-up? + top-of-screen:address:address:duplex-list<span class="Special"> <- </span>get-address *editor, <span class="Constant">top-of-screen:offset</span> + old-top:address:duplex-list<span class="Special"> <- </span>copy *top-of-screen +<span class="Constant"> <move-cursor-begin></span> + editor<span class="Special"> <- </span>page-up editor, screen-height + undo-coalesce-tag:number<span class="Special"> <- </span>copy <span class="Constant">0/never</span> +<span class="Constant"> <move-cursor-end></span> + no-movement?:boolean<span class="Special"> <- </span>equal *top-of-screen, old-top + <span class="muControl">reply-if</span> no-movement?, screen/same-as-ingredient:<span class="Constant">0</span>, editor/same-as-ingredient:<span class="Constant">1</span>, <span class="Constant">0/no-more-render</span> + <span class="muControl">reply</span> screen/same-as-ingredient:<span class="Constant">0</span>, editor/same-as-ingredient:<span class="Constant">1</span>, <span class="Constant">1/go-render</span> + <span class="Delimiter">}</span> +] + +<span class="muRecipe">after</span> <span class="Constant"><handle-special-key></span> [ + <span class="Delimiter">{</span> + page-up?:boolean<span class="Special"> <- </span>equal *k, <span class="Constant">65519/page-up</span> + <span class="muControl">break-unless</span> page-up? + top-of-screen:address:address:duplex-list<span class="Special"> <- </span>get-address *editor, <span class="Constant">top-of-screen:offset</span> + old-top:address:duplex-list<span class="Special"> <- </span>copy *top-of-screen +<span class="Constant"> <move-cursor-begin></span> + editor<span class="Special"> <- </span>page-up editor, screen-height + undo-coalesce-tag:number<span class="Special"> <- </span>copy <span class="Constant">0/never</span> +<span class="Constant"> <move-cursor-end></span> + no-movement?:boolean<span class="Special"> <- </span>equal *top-of-screen, old-top + <span class="Comment"># don't bother re-rendering if nothing changed. todo: test this</span> + <span class="muControl">reply-if</span> no-movement?, screen/same-as-ingredient:<span class="Constant">0</span>, editor/same-as-ingredient:<span class="Constant">1</span>, <span class="Constant">0/no-more-render</span> + <span class="muControl">reply</span> screen/same-as-ingredient:<span class="Constant">0</span>, editor/same-as-ingredient:<span class="Constant">1</span>, <span class="Constant">1/go-render</span> + <span class="Delimiter">}</span> +] + +<span class="muRecipe">recipe</span> page-up [ + <span class="Constant">local-scope</span> + editor:address:editor-data<span class="Special"> <- </span><span class="Constant">next-ingredient</span> + screen-height:number<span class="Special"> <- </span><span class="Constant">next-ingredient</span> + max:number<span class="Special"> <- </span>subtract screen-height, <span class="Constant">1/menu-bar</span>, <span class="Constant">1/overlapping-line</span> + count:number<span class="Special"> <- </span>copy <span class="Constant">0</span> + top-of-screen:address:address:duplex-list<span class="Special"> <- </span>get-address *editor, <span class="Constant">top-of-screen:offset</span> + <span class="Delimiter">{</span> + done?:boolean<span class="Special"> <- </span>greater-or-equal count, max + <span class="muControl">break-if</span> done? + prev:address:duplex-list<span class="Special"> <- </span>before-previous-line *top-of-screen, editor + <span class="muControl">break-unless</span> prev + *top-of-screen<span class="Special"> <- </span>copy prev + count<span class="Special"> <- </span>add count, <span class="Constant">1</span> + <span class="muControl">loop</span> + <span class="Delimiter">}</span> + <span class="muControl">reply</span> editor/same-as-ingredient:<span class="Constant">0</span> +] + +<span class="muScenario">scenario</span> editor-can-scroll-up-multiple-pages [ + <span class="Comment"># screen has 1 line for menu + 3 lines</span> + assume-screen <span class="Constant">10/width</span>, <span class="Constant">4/height</span> + <span class="Comment"># initialize editor with 8 lines</span> + <span class="Constant">1</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[a</span> +<span class="Constant">b</span> +<span class="Constant">c</span> +<span class="Constant">d</span> +<span class="Constant">e</span> +<span class="Constant">f</span> +<span class="Constant">g</span> +<span class="Constant">h]</span> + <span class="Constant">2</span>:address:editor-data<span class="Special"> <- </span>new-editor <span class="Constant">1</span>:address:array:character, screen:address, <span class="Constant">0/left</span>, <span class="Constant">10/right</span> + screen-should-contain [ + <span class="Constant"> . .</span> + <span class="Constant"> .a .</span> + <span class="Constant"> .b .</span> + <span class="Constant"> .c .</span> + ] + <span class="Comment"># scroll down two pages</span> + assume-console [ + press page-down + press page-down + ] + run [ + editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data + ] + <span class="Comment"># screen shows third page</span> + screen-should-contain [ + <span class="Constant"> . .</span> + <span class="Constant"> .e .</span> + <span class="Constant"> .f .</span> + <span class="Constant"> .g .</span> + ] + <span class="Comment"># scroll up</span> + assume-console [ + press page-up + ] + run [ + editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data + ] + <span class="Comment"># screen shows second page</span> + screen-should-contain [ + <span class="Constant"> . .</span> + <span class="Constant"> .c .</span> + <span class="Constant"> .d .</span> + <span class="Constant"> .e .</span> + ] + <span class="Comment"># scroll up again</span> + assume-console [ + press page-up + ] + run [ + editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data + ] + <span class="Comment"># screen shows original page again</span> + screen-should-contain [ + <span class="Constant"> . .</span> + <span class="Constant"> .a .</span> + <span class="Constant"> .b .</span> + <span class="Constant"> .c .</span> + ] +] + +<span class="muScenario">scenario</span> editor-can-scroll-up-wrapped-lines [ + <span class="Comment"># screen has 1 line for menu + 5 lines for text</span> + assume-screen <span class="Constant">10/width</span>, <span class="Constant">6/height</span> + <span class="Comment"># editor contains a long line in the first page</span> + <span class="Constant">1</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[a</span> +<span class="Constant">b</span> +<span class="Constant">cdefgh</span> +<span class="Constant">i</span> +<span class="Constant">j</span> +<span class="Constant">k</span> +<span class="Constant">l</span> +<span class="Constant">m</span> +<span class="Constant">n</span> +<span class="Constant">o]</span> + <span class="Comment"># editor screen triggers wrap of last line</span> + <span class="Constant">2</span>:address:editor-data<span class="Special"> <- </span>new-editor <span class="Constant">1</span>:address:array:character, screen:address, <span class="Constant">0/left</span>, <span class="Constant">4/right</span> + <span class="Comment"># some part of last line is not displayed</span> + screen-should-contain [ + <span class="Constant"> . .</span> + <span class="Constant"> .a .</span> + <span class="Constant"> .b .</span> + <span class="Constant"> .cde↩ .</span> + <span class="Constant"> .fgh .</span> + <span class="Constant"> .i .</span> + ] + <span class="Comment"># scroll down a page and a line</span> + assume-console [ + press page-down + left-click <span class="Constant">5</span>, <span class="Constant">0</span> + press down-arrow + ] + run [ + editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data + ] + <span class="Comment"># screen shows entire wrapped line</span> + screen-should-contain [ + <span class="Constant"> . .</span> + <span class="Constant"> .j .</span> + <span class="Constant"> .k .</span> + <span class="Constant"> .l .</span> + <span class="Constant"> .m .</span> + <span class="Constant"> .n .</span> + ] + <span class="Comment"># now scroll up one page</span> + assume-console [ + press page-up + ] + run [ + editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data + ] + <span class="Comment"># screen resets</span> + screen-should-contain [ + <span class="Constant"> . .</span> + <span class="Constant"> .b .</span> + <span class="Constant"> .cde↩ .</span> + <span class="Constant"> .fgh .</span> + <span class="Constant"> .i .</span> + <span class="Constant"> .j .</span> + ] +] + +<span class="muScenario">scenario</span> editor-can-scroll-up-wrapped-lines-2 [ + <span class="Comment"># screen has 1 line for menu + 3 lines for text</span> + assume-screen <span class="Constant">10/width</span>, <span class="Constant">4/height</span> + <span class="Comment"># editor contains a very long line that occupies last two lines of screen</span> + <span class="Comment"># and still has something left over</span> + <span class="Constant">1</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[a</span> +<span class="Constant">bcdefgh]</span> + <span class="Constant">2</span>:address:editor-data<span class="Special"> <- </span>new-editor <span class="Constant">1</span>:address:array:character, screen:address, <span class="Constant">0/left</span>, <span class="Constant">4/right</span> + <span class="Comment"># some part of last line is not displayed</span> + screen-should-contain [ + <span class="Constant"> . .</span> + <span class="Constant"> .a .</span> + <span class="Constant"> .bcd↩ .</span> + <span class="Constant"> .efg↩ .</span> + ] + <span class="Comment"># scroll down</span> + assume-console [ + press page-down + ] + run [ + editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data + ] + <span class="Comment"># screen shows entire wrapped line</span> + screen-should-contain [ + <span class="Constant"> . .</span> + <span class="Constant"> .bcd↩ .</span> + <span class="Constant"> .efg↩ .</span> + <span class="Constant"> .h .</span> + ] + <span class="Comment"># scroll back up</span> + assume-console [ + press page-up + ] + run [ + editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data + ] + <span class="Comment"># screen resets</span> + screen-should-contain [ + <span class="Constant"> . .</span> + <span class="Constant"> .a .</span> + <span class="Constant"> .bcd↩ .</span> + <span class="Constant"> .efg↩ .</span> + ] +] + +<span class="muScenario">scenario</span> editor-can-scroll-up-past-nonempty-lines [ + assume-screen <span class="Constant">10/width</span>, <span class="Constant">4/height</span> + <span class="Comment"># text with empty line in second screen</span> + <span class="Constant">1</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[axx</span> +<span class="Constant">bxx</span> +<span class="Constant">cxx</span> +<span class="Constant">dxx</span> +<span class="Constant">exx</span> +<span class="Constant">fxx</span> +<span class="Constant">gxx</span> +<span class="Constant">hxx</span> +<span class="Constant">]</span> + <span class="Constant">2</span>:address:editor-data<span class="Special"> <- </span>new-editor <span class="Constant">1</span>:address:array:character, screen:address, <span class="Constant">0/left</span>, <span class="Constant">4/right</span> + screen-should-contain [ + <span class="Constant"> . .</span> + <span class="Constant"> .axx .</span> + <span class="Constant"> .bxx .</span> + <span class="Constant"> .cxx .</span> + ] + assume-console [ + press page-down + ] + run [ + editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data + ] + screen-should-contain [ + <span class="Constant"> . .</span> + <span class="Constant"> .cxx .</span> + <span class="Constant"> .dxx .</span> + <span class="Constant"> .exx .</span> + ] + assume-console [ + press page-down + ] + run [ + editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data + ] + screen-should-contain [ + <span class="Constant"> . .</span> + <span class="Constant"> .exx .</span> + <span class="Constant"> .fxx .</span> + <span class="Constant"> .gxx .</span> + ] + <span class="Comment"># scroll back up past empty line</span> + assume-console [ + press page-up + ] + run [ + editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data + ] + screen-should-contain [ + <span class="Constant"> . .</span> + <span class="Constant"> .cxx .</span> + <span class="Constant"> .dxx .</span> + <span class="Constant"> .exx .</span> + ] +] + +<span class="muScenario">scenario</span> editor-can-scroll-up-past-empty-lines [ + assume-screen <span class="Constant">10/width</span>, <span class="Constant">4/height</span> + <span class="Comment"># text with empty line in second screen</span> + <span class="Constant">1</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[axy</span> +<span class="Constant">bxy</span> +<span class="Constant">cxy</span> + +dxy +exy +fxy +gxy +] + <span class="Constant">2</span>:address:editor-data<span class="Special"> <- </span>new-editor <span class="Constant">1</span>:address:array:character, screen:address, <span class="Constant">0/left</span>, <span class="Constant">4/right</span> + screen-should-contain [ + <span class="Constant"> . .</span> + <span class="Constant"> .axy .</span> + <span class="Constant"> .bxy .</span> + <span class="Constant"> .cxy .</span> + ] + assume-console [ + press page-down + ] + run [ + editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data + ] + screen-should-contain [ + <span class="Constant"> . .</span> + <span class="Constant"> .cxy .</span> + <span class="Constant"> . .</span> + <span class="Constant"> .dxy .</span> + ] + assume-console [ + press page-down + ] + run [ + editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data + ] + screen-should-contain [ + <span class="Constant"> . .</span> + <span class="Constant"> .dxy .</span> + <span class="Constant"> .exy .</span> + <span class="Constant"> .fxy .</span> + ] + <span class="Comment"># scroll back up past empty line</span> + assume-console [ + press page-up + ] + run [ + editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data + ] + screen-should-contain [ + <span class="Constant"> . .</span> + <span class="Constant"> .cxy .</span> + <span class="Constant"> . .</span> + <span class="Constant"> .dxy .</span> + ] +] +</pre> +</body> +</html> +<!-- vim: set foldmethod=manual : --> diff --git a/html/edit/004-programming-environment.mu.html b/html/edit/004-programming-environment.mu.html new file mode 100644 index 00000000..406c19a9 --- /dev/null +++ b/html/edit/004-programming-environment.mu.html @@ -0,0 +1,826 @@ +<!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/004-programming-environment.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; } +.muRecipe { color: #ff8700; } +.muData { color: #ffff00; } +.Special { color: #ff6060; } +.muScenario { color: #00af00; } +.Comment { color: #9090ff; } +.Constant { color: #00a0a0; } +.SalientComment { color: #00ffff; } +.CommentedCode { color: #6c6c6c; } +.Delimiter { color: #a04060; } +.muControl { color: #c0a020; } +--> +</style> + +<script type='text/javascript'> +<!-- + +--> +</script> +</head> +<body> +<pre id='vimCodeElement'> +<span class="SalientComment">## putting the environment together out of editors</span> +<span class="Comment">#</span> +<span class="Comment"># Consists of one editor on the left for recipes and one on the right for the</span> +<span class="Comment"># sandbox.</span> + +<span class="muRecipe">recipe!</span> main [ + <span class="Constant">local-scope</span> + open-console + initial-recipe:address:array:character<span class="Special"> <- </span>restore <span class="Constant">[recipes.mu]</span> + initial-sandbox:address:array:character<span class="Special"> <- </span>new <span class="Constant">[]</span> + hide-screen <span class="Constant">0/screen</span> + env:address:programming-environment-data<span class="Special"> <- </span>new-programming-environment <span class="Constant">0/screen</span>, initial-recipe, initial-sandbox + env<span class="Special"> <- </span>restore-sandboxes env + render-all <span class="Constant">0/screen</span>, env + event-loop <span class="Constant">0/screen</span>, <span class="Constant">0/console</span>, env + <span class="Comment"># never gets here</span> +] + +<span class="muData">container</span> programming-environment-data [ + recipes:address:editor-data + current-sandbox:address:editor-data + sandbox-in-focus?:boolean <span class="Comment"># false => cursor in recipes; true => cursor 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 + height:number<span class="Special"> <- </span>screen-height screen + <span class="Comment"># top menu</span> + result:address:programming-environment-data<span class="Special"> <- </span>new <span class="Constant">programming-environment-data:type</span> + draw-horizontal screen, <span class="Constant">0</span>, <span class="Constant">0/left</span>, width, <span class="Constant">32/space</span>, <span class="Constant">0/black</span>, <span class="Constant">238/grey</span> + button-start:number<span class="Special"> <- </span>subtract width, <span class="Constant">20</span> + button-on-screen?:boolean<span class="Special"> <- </span>greater-or-equal button-start, <span class="Constant">0</span> + assert button-on-screen?, <span class="Constant">[screen too narrow for menu]</span> + screen<span class="Special"> <- </span>move-cursor screen, <span class="Constant">0/row</span>, button-start + run-button:address:array:character<span class="Special"> <- </span>new <span class="Constant">[ run (F4) ]</span> + print-string screen, run-button, <span class="Constant">255/white</span>, <span class="Constant">161/reddish</span> + <span class="Comment"># dotted line down the middle</span> + divider:number, _<span class="Special"> <- </span>divide-with-remainder width, <span class="Constant">2</span> + draw-vertical screen, divider, <span class="Constant">1/top</span>, height, <span class="Constant">9482/vertical-dotted</span> + <span class="Comment"># recipe editor on the left</span> + recipes:address:address:editor-data<span class="Special"> <- </span>get-address *result, <span class="Constant">recipes:offset</span> + *recipes<span class="Special"> <- </span>new-editor initial-recipe-contents, screen, <span class="Constant">0/left</span>, divider/right + <span class="Comment"># sandbox editor on the right</span> + new-left:number<span class="Special"> <- </span>add divider, <span class="Constant">1</span> + current-sandbox:address:address:editor-data<span class="Special"> <- </span>get-address *result, <span class="Constant">current-sandbox:offset</span> + *current-sandbox<span class="Special"> <- </span>new-editor initial-sandbox-contents, screen, new-left, width/right +<span class="Constant"> +programming-environment-initialization</span> + <span class="muControl">reply</span> result +] + +<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, <span class="Constant">recipes:offset</span> + current-sandbox:address:editor-data<span class="Special"> <- </span>get *env, <span class="Constant">current-sandbox:offset</span> + sandbox-in-focus?:address:boolean<span class="Special"> <- </span>get-address *env, <span class="Constant">sandbox-in-focus?:offset</span> + <span class="Comment"># if we fall behind we'll stop updating the screen, but then we have to</span> + <span class="Comment"># render the entire screen when we catch up.</span> + <span class="Comment"># todo: test this</span> + render-all-on-no-more-events?:boolean<span class="Special"> <- </span>copy <span class="Constant">0/false</span> + <span class="Delimiter">{</span> + <span class="Comment"># looping over each (keyboard or touch) event as it occurs</span> +<span class="Constant"> +next-event</span> + e:event, console, found?:boolean, quit?:boolean<span class="Special"> <- </span>read-event console + <span class="muControl">loop-unless</span> found? + <span class="muControl">break-if</span> quit? <span class="Comment"># only in tests</span> + trace <span class="Constant">10</span>, <span class="Constant">[app]</span>, <span class="Constant">[next-event]</span> +<span class="Constant"> <handle-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, <span class="Constant">keycode:variant</span> + <span class="muControl">break-unless</span> k +<span class="Constant"> <global-keypress></span> + <span class="Delimiter">}</span> + <span class="Delimiter">{</span> + c:address:character<span class="Special"> <- </span>maybe-convert e:event, <span class="Constant">text:variant</span> + <span class="muControl">break-unless</span> c +<span class="Constant"> <global-type></span> + <span class="Delimiter">}</span> + <span class="Comment"># 'touch' event - send to both sides, see what picks it up</span> + <span class="Delimiter">{</span> + t:address:touch-event<span class="Special"> <- </span>maybe-convert e:event, <span class="Constant">touch:variant</span> + <span class="muControl">break-unless</span> t + <span class="Comment"># ignore all but 'left-click' events for now</span> + <span class="Comment"># todo: test this</span> + touch-type:number<span class="Special"> <- </span>get *t, <span class="Constant">type:offset</span> + is-left-click?:boolean<span class="Special"> <- </span>equal touch-type, <span class="Constant">65513/mouse-left</span> + <span class="muControl">loop-unless</span> is-left-click?, <span class="Constant">+next-event:label</span> + <span class="Comment"># later exceptions for non-editor touches will go here</span> +<span class="Constant"> <global-touch></span> + <span class="Comment"># send to both editors</span> + _<span class="Special"> <- </span>move-cursor-in-editor screen, recipes, *t + *sandbox-in-focus?<span class="Special"> <- </span>move-cursor-in-editor screen, current-sandbox, *t + screen<span class="Special"> <- </span>update-cursor screen, recipes, current-sandbox, *sandbox-in-focus? + <span class="muControl">loop</span> <span class="Constant">+next-event:label</span> + <span class="Delimiter">}</span> + <span class="Comment"># 'resize' event - redraw editor</span> + <span class="Comment"># todo: test this after supporting resize in assume-console</span> + <span class="Delimiter">{</span> + r:address:resize-event<span class="Special"> <- </span>maybe-convert e:event, <span class="Constant">resize:variant</span> + <span class="muControl">break-unless</span> r + <span class="Comment"># if more events, we're still resizing; wait until we stop</span> + more-events?:boolean<span class="Special"> <- </span>has-more-events? console + <span class="Delimiter">{</span> + <span class="muControl">break-unless</span> more-events? + render-all-on-no-more-events?<span class="Special"> <- </span>copy <span class="Constant">1/true</span> <span class="Comment"># no rendering now, full rendering on some future event</span> + <span class="Delimiter">}</span> + <span class="Delimiter">{</span> + <span class="muControl">break-if</span> more-events? + env<span class="Special"> <- </span>resize screen, env + screen<span class="Special"> <- </span>render-all screen, env + render-all-on-no-more-events?<span class="Special"> <- </span>copy <span class="Constant">0/false</span> <span class="Comment"># full render done</span> + <span class="Delimiter">}</span> + <span class="muControl">loop</span> <span class="Constant">+next-event:label</span> + <span class="Delimiter">}</span> + <span class="Comment"># if it's not global and not a touch event, send to appropriate editor</span> + <span class="Delimiter">{</span> + hide-screen screen + <span class="Delimiter">{</span> + <span class="muControl">break-if</span> *sandbox-in-focus? + screen, recipes, render?:boolean<span class="Special"> <- </span>handle-keyboard-event screen, recipes, e:event + <span class="Comment"># refresh screen only if no more events</span> + <span class="Comment"># if there are more events to process, wait for them to clear up, then make sure you render-all afterward.</span> + more-events?:boolean<span class="Special"> <- </span>has-more-events? console + <span class="Delimiter">{</span> + <span class="muControl">break-unless</span> more-events? + render-all-on-no-more-events?<span class="Special"> <- </span>copy <span class="Constant">1/true</span> <span class="Comment"># no rendering now, full rendering on some future event</span> + <span class="muControl">jump</span> <span class="Constant">+finish-event:label</span> + <span class="Delimiter">}</span> + <span class="Delimiter">{</span> + <span class="muControl">break-if</span> more-events? + <span class="Delimiter">{</span> + <span class="muControl">break-unless</span> render-all-on-no-more-events? + <span class="Comment"># no more events, and we have to force render</span> + screen<span class="Special"> <- </span>render-all screen, env + render-all-on-no-more-events?<span class="Special"> <- </span>copy <span class="Constant">0/false</span> + <span class="muControl">jump</span> <span class="Constant">+finish-event:label</span> + <span class="Delimiter">}</span> + <span class="Comment"># no more events, no force render</span> + <span class="Delimiter">{</span> + <span class="muControl">break-unless</span> render? + screen<span class="Special"> <- </span>render-recipes screen, env + <span class="muControl">jump</span> <span class="Constant">+finish-event:label</span> + <span class="Delimiter">}</span> + <span class="Delimiter">}</span> + <span class="Delimiter">}</span> + <span class="Delimiter">{</span> + <span class="muControl">break-unless</span> *sandbox-in-focus? + screen, current-sandbox, render?:boolean<span class="Special"> <- </span>handle-keyboard-event screen, current-sandbox, e:event + <span class="Comment"># refresh screen only if no more events</span> + <span class="Comment"># if there are more events to process, wait for them to clear up, then make sure you render-all afterward.</span> + more-events?:boolean<span class="Special"> <- </span>has-more-events? console + <span class="Delimiter">{</span> + <span class="muControl">break-unless</span> more-events? + render-all-on-no-more-events?<span class="Special"> <- </span>copy <span class="Constant">1/true</span> <span class="Comment"># no rendering now, full rendering on some future event</span> + <span class="muControl">jump</span> <span class="Constant">+finish-event:label</span> + <span class="Delimiter">}</span> + <span class="Delimiter">{</span> + <span class="muControl">break-if</span> more-events? + <span class="Delimiter">{</span> + <span class="muControl">break-unless</span> render-all-on-no-more-events? + <span class="Comment"># no more events, and we have to force render</span> + screen<span class="Special"> <- </span>render-all screen, env + render-all-on-no-more-events?<span class="Special"> <- </span>copy <span class="Constant">0/false</span> + <span class="muControl">jump</span> <span class="Constant">+finish-event:label</span> + <span class="Delimiter">}</span> + <span class="Comment"># no more events, no force render</span> + <span class="Delimiter">{</span> + <span class="muControl">break-unless</span> render? + screen<span class="Special"> <- </span>render-sandbox-side screen, env + <span class="muControl">jump</span> <span class="Constant">+finish-event:label</span> + <span class="Delimiter">}</span> + <span class="Delimiter">}</span> + <span class="Delimiter">}</span> +<span class="Constant"> +finish-event</span> + screen<span class="Special"> <- </span>update-cursor screen, recipes, current-sandbox, *sandbox-in-focus? + show-screen screen + <span class="Delimiter">}</span> + <span class="muControl">loop</span> + <span class="Delimiter">}</span> +] + +<span class="muRecipe">recipe</span> resize [ + <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-screen screen <span class="Comment"># update screen dimensions</span> + width:number<span class="Special"> <- </span>screen-width screen + divider:number, _<span class="Special"> <- </span>divide-with-remainder width, <span class="Constant">2</span> + <span class="Comment"># update recipe editor</span> + recipes:address:editor-data<span class="Special"> <- </span>get *env, <span class="Constant">recipes:offset</span> + right:address:number<span class="Special"> <- </span>get-address *recipes, <span class="Constant">right:offset</span> + *right<span class="Special"> <- </span>subtract divider, <span class="Constant">1</span> + <span class="Comment"># reset cursor (later we'll try to preserve its position)</span> + cursor-row:address:number<span class="Special"> <- </span>get-address *recipes, <span class="Constant">cursor-row:offset</span> + *cursor-row<span class="Special"> <- </span>copy <span class="Constant">1</span> + cursor-column:address:number<span class="Special"> <- </span>get-address *recipes, <span class="Constant">cursor-column:offset</span> + *cursor-column<span class="Special"> <- </span>copy <span class="Constant">0</span> + <span class="Comment"># update sandbox editor</span> + current-sandbox:address:editor-data<span class="Special"> <- </span>get *env, <span class="Constant">current-sandbox:offset</span> + left:address:number<span class="Special"> <- </span>get-address *current-sandbox, <span class="Constant">left:offset</span> + right:address:number<span class="Special"> <- </span>get-address *current-sandbox, <span class="Constant">right:offset</span> + *left<span class="Special"> <- </span>add divider, <span class="Constant">1</span> + *right<span class="Special"> <- </span>subtract width, <span class="Constant">1</span> + <span class="Comment"># reset cursor (later we'll try to preserve its position)</span> + cursor-row:address:number<span class="Special"> <- </span>get-address *current-sandbox, <span class="Constant">cursor-row:offset</span> + *cursor-row<span class="Special"> <- </span>copy <span class="Constant">1</span> + cursor-column:address:number<span class="Special"> <- </span>get-address *current-sandbox, <span class="Constant">cursor-column:offset</span> + *cursor-column<span class="Special"> <- </span>copy *left + <span class="muControl">reply</span> env/same-as-ingredient:<span class="Constant">1</span> +] + +<span class="muScenario">scenario</span> point-at-multiple-editors [ + $close-trace <span class="Comment"># trace too long</span> + assume-screen <span class="Constant">30/width</span>, <span class="Constant">5/height</span> + <span class="Comment"># initialize both halves of screen</span> + <span class="Constant">1</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[abc]</span> + <span class="Constant">2</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[def]</span> + <span class="Constant">3</span>:address:programming-environment-data<span class="Special"> <- </span>new-programming-environment screen:address, <span class="Constant">1</span>:address:array:character, <span class="Constant">2</span>:address:array:character + <span class="Comment"># focus on both sides</span> + assume-console [ + left-click <span class="Constant">1</span>, <span class="Constant">1</span> + left-click <span class="Constant">1</span>, <span class="Constant">17</span> + ] + <span class="Comment"># check cursor column in each</span> + run [ + event-loop screen:address, console:address, <span class="Constant">3</span>:address:programming-environment-data + <span class="Constant">4</span>:address:editor-data<span class="Special"> <- </span>get *<span class="Constant">3</span>:address:programming-environment-data, <span class="Constant">recipes:offset</span> + <span class="Constant">5</span>:number<span class="Special"> <- </span>get *<span class="Constant">4</span>:address:editor-data, <span class="Constant">cursor-column:offset</span> + <span class="Constant">6</span>:address:editor-data<span class="Special"> <- </span>get *<span class="Constant">3</span>:address:programming-environment-data, <span class="Constant">current-sandbox:offset</span> + <span class="Constant">7</span>:number<span class="Special"> <- </span>get *<span class="Constant">6</span>:address:editor-data, <span class="Constant">cursor-column:offset</span> + ] + memory-should-contain [ + <span class="Constant">5</span><span class="Special"> <- </span><span class="Constant">1</span> + <span class="Constant">7</span><span class="Special"> <- </span><span class="Constant">17</span> + ] +] + +<span class="muScenario">scenario</span> edit-multiple-editors [ + $close-trace <span class="Comment"># trace too long</span> + assume-screen <span class="Constant">30/width</span>, <span class="Constant">5/height</span> + <span class="Comment"># initialize both halves of screen</span> + <span class="Constant">1</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[abc]</span> + <span class="Constant">2</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[def]</span> + <span class="Constant">3</span>:address:programming-environment-data<span class="Special"> <- </span>new-programming-environment screen:address, <span class="Constant">1</span>:address:array:character, <span class="Constant">2</span>:address:array:character + render-all screen, <span class="Constant">3</span>:address:programming-environment-data + <span class="Comment"># type one letter in each of them</span> + assume-console [ + left-click <span class="Constant">1</span>, <span class="Constant">1</span> + type <span class="Constant">[0]</span> + left-click <span class="Constant">1</span>, <span class="Constant">17</span> + type <span class="Constant">[1]</span> + ] + run [ + event-loop screen:address, console:address, <span class="Constant">3</span>:address:programming-environment-data + <span class="Constant">4</span>:address:editor-data<span class="Special"> <- </span>get *<span class="Constant">3</span>:address:programming-environment-data, <span class="Constant">recipes:offset</span> + <span class="Constant">5</span>:number<span class="Special"> <- </span>get *<span class="Constant">4</span>:address:editor-data, <span class="Constant">cursor-column:offset</span> + <span class="Constant">6</span>:address:editor-data<span class="Special"> <- </span>get *<span class="Constant">3</span>:address:programming-environment-data, <span class="Constant">current-sandbox:offset</span> + <span class="Constant">7</span>:number<span class="Special"> <- </span>get *<span class="Constant">6</span>:address:editor-data, <span class="Constant">cursor-column:offset</span> + ] + screen-should-contain [ + <span class="Constant"> . run (F4) . # this line has a different background, but we don't test that yet</span> + <span class="Constant"> .a0bc ┊d1ef .</span> +<span class="Constant"> .┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┊━━━━━━━━━━━━━━.</span> + <span class="Constant"> . ┊ .</span> + ] + memory-should-contain [ + <span class="Constant">5</span><span class="Special"> <- </span><span class="Constant">2</span> <span class="Comment"># cursor column of recipe editor</span> + <span class="Constant">7</span><span class="Special"> <- </span><span class="Constant">18</span> <span class="Comment"># cursor column of sandbox editor</span> + ] + <span class="Comment"># show the cursor at the right window</span> + run [ + print-character screen:address, <span class="Constant">9251/␣/cursor</span> + ] + screen-should-contain [ + <span class="Constant"> . run (F4) .</span> + <span class="Constant"> .a0bc ┊d1␣f .</span> +<span class="Constant"> .┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┊━━━━━━━━━━━━━━.</span> + <span class="Constant"> . ┊ .</span> + ] +] + +<span class="muScenario">scenario</span> multiple-editors-cover-only-their-own-areas [ + $close-trace <span class="Comment"># trace too long</span> + assume-screen <span class="Constant">60/width</span>, <span class="Constant">10/height</span> + run [ + <span class="Constant">1</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[abc]</span> + <span class="Constant">2</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[def]</span> + <span class="Constant">3</span>:address:programming-environment-data<span class="Special"> <- </span>new-programming-environment screen:address, <span class="Constant">1</span>:address:array:character, <span class="Constant">2</span>:address:array:character + render-all screen, <span class="Constant">3</span>:address:programming-environment-data + ] + <span class="Comment"># divider isn't messed up</span> + screen-should-contain [ + <span class="Constant"> . run (F4) .</span> + <span class="Constant"> .abc ┊def .</span> +<span class="Constant"> .┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┊━━━━━━━━━━━━━━━━━━━━━━━━━━━━━.</span> + <span class="Constant"> . ┊ .</span> + <span class="Constant"> . ┊ .</span> + ] +] + +<span class="muScenario">scenario</span> editor-in-focus-keeps-cursor [ + $close-trace <span class="Comment"># trace too long</span> + assume-screen <span class="Constant">30/width</span>, <span class="Constant">5/height</span> + <span class="Constant">1</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[abc]</span> + <span class="Constant">2</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[def]</span> + <span class="Constant">3</span>:address:programming-environment-data<span class="Special"> <- </span>new-programming-environment screen:address, <span class="Constant">1</span>:address:array:character, <span class="Constant">2</span>:address:array:character + render-all screen, <span class="Constant">3</span>:address:programming-environment-data + <span class="Comment"># initialize programming environment and highlight cursor</span> + assume-console <span class="Constant">[]</span> + run [ + event-loop screen:address, console:address, <span class="Constant">3</span>:address:programming-environment-data + print-character screen:address, <span class="Constant">9251/␣/cursor</span> + ] + <span class="Comment"># is cursor at the right place?</span> + screen-should-contain [ + <span class="Constant"> . run (F4) .</span> + <span class="Constant"> .␣bc ┊def .</span> +<span class="Constant"> .┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┊━━━━━━━━━━━━━━.</span> + <span class="Constant"> . ┊ .</span> + ] + <span class="Comment"># now try typing a letter</span> + assume-console [ + type <span class="Constant">[z]</span> + ] + run [ + event-loop screen:address, console:address, <span class="Constant">3</span>:address:programming-environment-data + print-character screen:address, <span class="Constant">9251/␣/cursor</span> + ] + <span class="Comment"># cursor should still be right</span> + screen-should-contain [ + <span class="Constant"> . run (F4) .</span> + <span class="Constant"> .z␣bc ┊def .</span> +<span class="Constant"> .┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┊━━━━━━━━━━━━━━.</span> + <span class="Constant"> . ┊ .</span> + ] +] + +<span class="muScenario">scenario</span> backspace-in-sandbox-editor-joins-lines [ + $close-trace <span class="Comment"># trace too long</span> + assume-screen <span class="Constant">30/width</span>, <span class="Constant">5/height</span> + <span class="Comment"># initialize sandbox side with two lines</span> + <span class="Constant">1</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[]</span> + <span class="Constant">2</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[abc</span> +<span class="Constant">def]</span> + <span class="Constant">3</span>:address:programming-environment-data<span class="Special"> <- </span>new-programming-environment screen:address, <span class="Constant">1</span>:address:array:character, <span class="Constant">2</span>:address:array:character + render-all screen, <span class="Constant">3</span>:address:programming-environment-data + screen-should-contain [ + <span class="Constant"> . run (F4) .</span> + <span class="Constant"> . ┊abc .</span> + <span class="Constant"> .┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┊def .</span> + <span class="Constant"> . ┊━━━━━━━━━━━━━━.</span> + <span class="Constant"> . ┊ .</span> + ] + <span class="Comment"># position cursor at start of second line and hit backspace</span> + assume-console [ + left-click <span class="Constant">2</span>, <span class="Constant">16</span> + press backspace + ] + run [ + event-loop screen:address, console:address, <span class="Constant">3</span>:address:programming-environment-data + print-character screen:address, <span class="Constant">9251/␣/cursor</span> + ] + <span class="Comment"># cursor moves to end of old line</span> + screen-should-contain [ + <span class="Constant"> . run (F4) .</span> + <span class="Constant"> . ┊abc␣ef .</span> +<span class="Constant"> .┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┊━━━━━━━━━━━━━━.</span> + <span class="Constant"> . ┊ .</span> + ] +] + +<span class="muRecipe">recipe</span> render-all [ + <span class="Constant">local-scope</span> + screen:address<span class="Special"> <- </span><span class="Constant">next-ingredient</span> + env:address:programming-environment-data<span class="Special"> <- </span><span class="Constant">next-ingredient</span> + trace <span class="Constant">10</span>, <span class="Constant">[app]</span>, <span class="Constant">[render all]</span> + hide-screen screen + <span class="Comment"># top menu</span> + trace <span class="Constant">11</span>, <span class="Constant">[app]</span>, <span class="Constant">[render top menu]</span> + width:number<span class="Special"> <- </span>screen-width screen + draw-horizontal screen, <span class="Constant">0</span>, <span class="Constant">0/left</span>, width, <span class="Constant">32/space</span>, <span class="Constant">0/black</span>, <span class="Constant">238/grey</span> + button-start:number<span class="Special"> <- </span>subtract width, <span class="Constant">20</span> + button-on-screen?:boolean<span class="Special"> <- </span>greater-or-equal button-start, <span class="Constant">0</span> + assert button-on-screen?, <span class="Constant">[screen too narrow for menu]</span> + screen<span class="Special"> <- </span>move-cursor screen, <span class="Constant">0/row</span>, button-start + run-button:address:array:character<span class="Special"> <- </span>new <span class="Constant">[ run (F4) ]</span> + print-string screen, run-button, <span class="Constant">255/white</span>, <span class="Constant">161/reddish</span> + <span class="Comment"># dotted line down the middle</span> + trace <span class="Constant">11</span>, <span class="Constant">[app]</span>, <span class="Constant">[render divider]</span> + divider:number, _<span class="Special"> <- </span>divide-with-remainder width, <span class="Constant">2</span> + height:number<span class="Special"> <- </span>screen-height screen + draw-vertical screen, divider, <span class="Constant">1/top</span>, height, <span class="Constant">9482/vertical-dotted</span> + <span class="Comment">#</span> + screen<span class="Special"> <- </span>render-recipes screen, env + screen<span class="Special"> <- </span>render-sandbox-side screen, env +<span class="Constant"> <render-components-end></span> + <span class="Comment">#</span> + recipes:address:editor-data<span class="Special"> <- </span>get *env, <span class="Constant">recipes:offset</span> + current-sandbox:address:editor-data<span class="Special"> <- </span>get *env, <span class="Constant">current-sandbox:offset</span> + sandbox-in-focus?:boolean<span class="Special"> <- </span>get *env, <span class="Constant">sandbox-in-focus?:offset</span> + screen<span class="Special"> <- </span>update-cursor screen, recipes, current-sandbox, sandbox-in-focus? + <span class="Comment">#</span> + show-screen screen + <span class="muControl">reply</span> screen/same-as-ingredient:<span class="Constant">0</span> +] + +<span class="muRecipe">recipe</span> render-recipes [ + <span class="Constant">local-scope</span> + screen:address<span class="Special"> <- </span><span class="Constant">next-ingredient</span> + env:address:programming-environment-data<span class="Special"> <- </span><span class="Constant">next-ingredient</span> + trace <span class="Constant">11</span>, <span class="Constant">[app]</span>, <span class="Constant">[render recipes]</span> + recipes:address:editor-data<span class="Special"> <- </span>get *env, <span class="Constant">recipes:offset</span> + <span class="Comment"># render recipes</span> + left:number<span class="Special"> <- </span>get *recipes, <span class="Constant">left:offset</span> + right:number<span class="Special"> <- </span>get *recipes, <span class="Constant">right:offset</span> + row:number, column:number, screen<span class="Special"> <- </span>render screen, recipes + clear-line-delimited screen, column, right + row<span class="Special"> <- </span>add row, <span class="Constant">1</span> +<span class="Constant"> <render-recipe-components-end></span> + <span class="Comment"># draw dotted line after recipes</span> + draw-horizontal screen, row, left, right, <span class="Constant">9480/horizontal-dotted</span> + row<span class="Special"> <- </span>add row, <span class="Constant">1</span> + clear-screen-from screen, row, left, left, right + <span class="muControl">reply</span> screen/same-as-ingredient:<span class="Constant">0</span> +] + +<span class="Comment"># replaced in a later layer</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> + current-sandbox:address:editor-data<span class="Special"> <- </span>get *env, <span class="Constant">current-sandbox:offset</span> + left:number<span class="Special"> <- </span>get *current-sandbox, <span class="Constant">left:offset</span> + right:number<span class="Special"> <- </span>get *current-sandbox, <span class="Constant">right:offset</span> + row:number, column:number, screen, current-sandbox<span class="Special"> <- </span>render screen, current-sandbox + clear-line-delimited screen, column, right + row<span class="Special"> <- </span>add row, <span class="Constant">1</span> + <span class="Comment"># draw solid line after recipes (you'll see why in later layers)</span> + draw-horizontal screen, row, left, right, <span class="Constant">9473/horizontal</span> + row<span class="Special"> <- </span>add row, <span class="Constant">1</span> + clear-screen-from screen, row, left, left, right + <span class="muControl">reply</span> screen/same-as-ingredient:<span class="Constant">0</span> +] + +<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? + cursor-row:number<span class="Special"> <- </span>get *recipes, <span class="Constant">cursor-row:offset</span> + cursor-column:number<span class="Special"> <- </span>get *recipes, <span class="Constant">cursor-column:offset</span> + <span class="Delimiter">}</span> + <span class="Delimiter">{</span> + <span class="muControl">break-unless</span> sandbox-in-focus? + cursor-row:number<span class="Special"> <- </span>get *current-sandbox, <span class="Constant">cursor-row:offset</span> + cursor-column:number<span class="Special"> <- </span>get *current-sandbox, <span class="Constant">cursor-column:offset</span> + <span class="Delimiter">}</span> + screen<span class="Special"> <- </span>move-cursor screen, cursor-row, cursor-column + <span class="muControl">reply</span> screen/same-as-ingredient:<span class="Constant">0</span> +] + +<span class="Comment"># row, screen <- render-string screen:address, s:address:array:character, left:number, right:number, color:number, row:number</span> +<span class="Comment"># print a string 's' to 'editor' in 'color' starting at 'row'</span> +<span class="Comment"># clear rest of last line, 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> + <span class="muControl">reply-unless</span> s, row/same-as-ingredient:<span class="Constant">5</span>, screen/same-as-ingredient:<span class="Constant">0</span> + column:number<span class="Special"> <- </span>copy left + screen<span class="Special"> <- </span>move-cursor screen, row, column + screen-height:number<span class="Special"> <- </span>screen-height screen + i:number<span class="Special"> <- </span>copy <span class="Constant">0</span> + len:number<span class="Special"> <- </span>length *s + <span class="Delimiter">{</span> +<span class="Constant"> +next-character</span> + done?:boolean<span class="Special"> <- </span>greater-or-equal i, len + <span class="muControl">break-if</span> done? + done?<span class="Special"> <- </span>greater-or-equal row, screen-height + <span class="muControl">break-if</span> done? + c:character<span class="Special"> <- </span>index *s, i + <span class="Delimiter">{</span> + <span class="Comment"># at right? wrap.</span> + at-right?:boolean<span class="Special"> <- </span>equal column, right + <span class="muControl">break-unless</span> at-right? + <span class="Comment"># print wrap icon</span> + print-character screen, <span class="Constant">8617/loop-back-to-left</span>, <span class="Constant">245/grey</span> + column<span class="Special"> <- </span>copy left + row<span class="Special"> <- </span>add row, <span class="Constant">1</span> + screen<span class="Special"> <- </span>move-cursor screen, row, column + <span class="muControl">loop</span> <span class="Constant">+next-character:label</span> <span class="Comment"># retry i</span> + <span class="Delimiter">}</span> + i<span class="Special"> <- </span>add i, <span class="Constant">1</span> + <span class="Delimiter">{</span> + <span class="Comment"># newline? move to left rather than 0</span> + newline?:boolean<span class="Special"> <- </span>equal c, <span class="Constant">10/newline</span> + <span class="muControl">break-unless</span> newline? + <span class="Comment"># clear rest of line in this window</span> + <span class="Delimiter">{</span> + done?:boolean<span class="Special"> <- </span>greater-than column, right + <span class="muControl">break-if</span> done? + print-character screen, <span class="Constant">32/space</span> + column<span class="Special"> <- </span>add column, <span class="Constant">1</span> + <span class="muControl">loop</span> + <span class="Delimiter">}</span> + row<span class="Special"> <- </span>add row, <span class="Constant">1</span> + column<span class="Special"> <- </span>copy left + screen<span class="Special"> <- </span>move-cursor screen, row, column + <span class="muControl">loop</span> <span class="Constant">+next-character:label</span> + <span class="Delimiter">}</span> + print-character screen, c, color + column<span class="Special"> <- </span>add column, <span class="Constant">1</span> + <span class="muControl">loop</span> + <span class="Delimiter">}</span> + was-at-left?:boolean<span class="Special"> <- </span>equal column, left + clear-line-delimited screen, column, right + <span class="Delimiter">{</span> + <span class="muControl">break-if</span> was-at-left? + row<span class="Special"> <- </span>add row, <span class="Constant">1</span> + <span class="Delimiter">}</span> + move-cursor row, left + <span class="muControl">reply</span> row/same-as-ingredient:<span class="Constant">5</span>, screen/same-as-ingredient:<span class="Constant">0</span> +] + +<span class="Comment"># row, screen <- render-code-string screen:address, s:address:array:character, left:number, right:number, row:number</span> +<span class="Comment"># like 'render-string' but with colorization for comments like in the editor</span> +<span class="muRecipe">recipe</span> render-code-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> + row:number<span class="Special"> <- </span><span class="Constant">next-ingredient</span> + <span class="muControl">reply-unless</span> s, row/same-as-ingredient:<span class="Constant">4</span>, screen/same-as-ingredient:<span class="Constant">0</span> + color:number<span class="Special"> <- </span>copy <span class="Constant">7/white</span> + column:number<span class="Special"> <- </span>copy left + screen<span class="Special"> <- </span>move-cursor screen, row, column + screen-height:number<span class="Special"> <- </span>screen-height screen + i:number<span class="Special"> <- </span>copy <span class="Constant">0</span> + len:number<span class="Special"> <- </span>length *s + <span class="Delimiter">{</span> +<span class="Constant"> +next-character</span> + done?:boolean<span class="Special"> <- </span>greater-or-equal i, len + <span class="muControl">break-if</span> done? + done?<span class="Special"> <- </span>greater-or-equal row, screen-height + <span class="muControl">break-if</span> done? + c:character<span class="Special"> <- </span>index *s, i + <span class="Constant"><character-c-received></span> <span class="Comment"># only line different from render-string</span> + <span class="Delimiter">{</span> + <span class="Comment"># at right? wrap.</span> + at-right?:boolean<span class="Special"> <- </span>equal column, right + <span class="muControl">break-unless</span> at-right? + <span class="Comment"># print wrap icon</span> + print-character screen, <span class="Constant">8617/loop-back-to-left</span>, <span class="Constant">245/grey</span> + column<span class="Special"> <- </span>copy left + row<span class="Special"> <- </span>add row, <span class="Constant">1</span> + screen<span class="Special"> <- </span>move-cursor screen, row, column + <span class="muControl">loop</span> <span class="Constant">+next-character:label</span> <span class="Comment"># retry i</span> + <span class="Delimiter">}</span> + i<span class="Special"> <- </span>add i, <span class="Constant">1</span> + <span class="Delimiter">{</span> + <span class="Comment"># newline? move to left rather than 0</span> + newline?:boolean<span class="Special"> <- </span>equal c, <span class="Constant">10/newline</span> + <span class="muControl">break-unless</span> newline? + <span class="Comment"># clear rest of line in this window</span> + <span class="Delimiter">{</span> + done?:boolean<span class="Special"> <- </span>greater-than column, right + <span class="muControl">break-if</span> done? + print-character screen, <span class="Constant">32/space</span> + column<span class="Special"> <- </span>add column, <span class="Constant">1</span> + <span class="muControl">loop</span> + <span class="Delimiter">}</span> + row<span class="Special"> <- </span>add row, <span class="Constant">1</span> + column<span class="Special"> <- </span>copy left + screen<span class="Special"> <- </span>move-cursor screen, row, column + <span class="muControl">loop</span> <span class="Constant">+next-character:label</span> + <span class="Delimiter">}</span> + print-character screen, c, color + column<span class="Special"> <- </span>add column, <span class="Constant">1</span> + <span class="muControl">loop</span> + <span class="Delimiter">}</span> + was-at-left?:boolean<span class="Special"> <- </span>equal column, left + clear-line-delimited screen, column, right + <span class="Delimiter">{</span> + <span class="muControl">break-if</span> was-at-left? + row<span class="Special"> <- </span>add row, <span class="Constant">1</span> + <span class="Delimiter">}</span> + move-cursor row, left + <span class="muControl">reply</span> row/same-as-ingredient:<span class="Constant">4</span>, screen/same-as-ingredient:<span class="Constant">0</span> +] + +<span class="Comment"># ctrl-l - redraw screen (just in case it printed junk somehow)</span> + +<span class="muRecipe">after</span> <span class="Constant"><global-type></span> [ + <span class="Delimiter">{</span> + redraw-screen?:boolean<span class="Special"> <- </span>equal *c, <span class="Constant">12/ctrl-l</span> + <span class="muControl">break-unless</span> redraw-screen? + screen<span class="Special"> <- </span>render-all screen, env:address:programming-environment-data + sync-screen screen + <span class="muControl">loop</span> <span class="Constant">+next-event:label</span> + <span class="Delimiter">}</span> +] + +<span class="Comment"># ctrl-n - switch focus</span> +<span class="Comment"># todo: test this</span> + +<span class="muRecipe">after</span> <span class="Constant"><global-type></span> [ + <span class="Delimiter">{</span> + switch-side?:boolean<span class="Special"> <- </span>equal *c, <span class="Constant">14/ctrl-n</span> + <span class="muControl">break-unless</span> switch-side? + *sandbox-in-focus?<span class="Special"> <- </span>not *sandbox-in-focus? + screen<span class="Special"> <- </span>update-cursor screen, recipes, current-sandbox, *sandbox-in-focus? + <span class="muControl">loop</span> <span class="Constant">+next-event:label</span> + <span class="Delimiter">}</span> +] + +<span class="Comment"># ctrl-x - maximize/unmaximize the side with focus</span> + +<span class="muScenario">scenario</span> maximize-side [ + $close-trace <span class="Comment"># trace too long</span> + assume-screen <span class="Constant">30/width</span>, <span class="Constant">5/height</span> + <span class="Comment"># initialize both halves of screen</span> + <span class="Constant">1</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[abc]</span> + <span class="Constant">2</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[def]</span> + <span class="Constant">3</span>:address:programming-environment-data<span class="Special"> <- </span>new-programming-environment screen:address, <span class="Constant">1</span>:address:array:character, <span class="Constant">2</span>:address:array:character + screen<span class="Special"> <- </span>render-all screen, <span class="Constant">3</span>:address:programming-environment-data + screen-should-contain [ + <span class="Constant"> . run (F4) .</span> + <span class="Constant"> .abc ┊def .</span> +<span class="Constant"> .┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┊━━━━━━━━━━━━━━.</span> + <span class="Constant"> . ┊ .</span> + ] + <span class="Comment"># hit ctrl-x</span> + assume-console [ + press ctrl-x + ] + run [ + event-loop screen:address, console:address, <span class="Constant">3</span>:address:programming-environment-data + ] + <span class="Comment"># only left side visible</span> + screen-should-contain [ + <span class="Constant"> . run (F4) .</span> + <span class="Constant"> .abc .</span> +<span class="Constant"> .┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈.</span> + <span class="Constant"> . .</span> + ] + <span class="Comment"># hit any key to toggle back</span> + assume-console [ + press ctrl-x + ] + run [ + event-loop screen:address, console:address, <span class="Constant">3</span>:address:programming-environment-data + ] + screen-should-contain [ + <span class="Constant"> . run (F4) .</span> + <span class="Constant"> .abc ┊def .</span> +<span class="Constant"> .┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┊━━━━━━━━━━━━━━.</span> + <span class="Constant"> . ┊ .</span> + ] +] + +<span class="CommentedCode">#? # ctrl-t - browse trace</span> +<span class="CommentedCode">#? after <global-type> [</span> +<span class="CommentedCode">#? {</span> +<span class="CommentedCode">#? browse-trace?:boolean <- equal *c, 20/ctrl-t</span> +<span class="CommentedCode">#? break-unless browse-trace?</span> +<span class="CommentedCode">#? $browse-trace</span> +<span class="CommentedCode">#? screen <- render-all screen, env:address:programming-environment-data</span> +<span class="CommentedCode">#? loop +next-event:label</span> +<span class="CommentedCode">#? }</span> +<span class="CommentedCode">#? ]</span> + +<span class="muData">container</span> programming-environment-data [ + maximized?:boolean +] + +<span class="muRecipe">after</span> <span class="Constant"><global-type></span> [ + <span class="Delimiter">{</span> + maximize?:boolean<span class="Special"> <- </span>equal *c, <span class="Constant">24/ctrl-x</span> + <span class="muControl">break-unless</span> maximize? + screen, console<span class="Special"> <- </span>maximize screen, console, env:address:programming-environment-data + <span class="muControl">loop</span> <span class="Constant">+next-event:label</span> + <span class="Delimiter">}</span> +] + +<span class="muRecipe">recipe</span> maximize [ + <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> + hide-screen screen + <span class="Comment"># maximize one of the sides</span> + maximized?:address:boolean<span class="Special"> <- </span>get-address *env, <span class="Constant">maximized?:offset</span> + *maximized?<span class="Special"> <- </span>copy <span class="Constant">1/true</span> + <span class="Comment">#</span> + sandbox-in-focus?:boolean<span class="Special"> <- </span>get *env, <span class="Constant">sandbox-in-focus?:offset</span> + <span class="Delimiter">{</span> + <span class="muControl">break-if</span> sandbox-in-focus? + editor:address:editor-data<span class="Special"> <- </span>get *env, <span class="Constant">recipes:offset</span> + right:address:number<span class="Special"> <- </span>get-address *editor, <span class="Constant">right:offset</span> + *right<span class="Special"> <- </span>screen-width screen + *right<span class="Special"> <- </span>subtract *right, <span class="Constant">1</span> + screen<span class="Special"> <- </span>render-recipes screen, env + <span class="Delimiter">}</span> + <span class="Delimiter">{</span> + <span class="muControl">break-unless</span> sandbox-in-focus? + editor:address:editor-data<span class="Special"> <- </span>get *env, <span class="Constant">current-sandbox:offset</span> + left:address:number<span class="Special"> <- </span>get-address *editor, <span class="Constant">left:offset</span> + *left<span class="Special"> <- </span>copy <span class="Constant">0</span> + screen<span class="Special"> <- </span>render-sandbox-side screen, env + <span class="Delimiter">}</span> + show-screen screen + <span class="muControl">reply</span> screen/same-as-ingredient:<span class="Constant">0</span>, console/same-as-ingredient:<span class="Constant">1</span> +] + +<span class="Comment"># when maximized, wait for any event and simply unmaximize</span> +<span class="muRecipe">after</span> <span class="Constant"><handle-event></span> [ + <span class="Delimiter">{</span> + maximized?:address:boolean<span class="Special"> <- </span>get-address *env, <span class="Constant">maximized?:offset</span> + <span class="muControl">break-unless</span> *maximized? + *maximized?<span class="Special"> <- </span>copy <span class="Constant">0/false</span> + <span class="Comment"># undo maximize</span> + <span class="Delimiter">{</span> + <span class="muControl">break-if</span> *sandbox-in-focus? + editor:address:editor-data<span class="Special"> <- </span>get *env, <span class="Constant">recipes:offset</span> + right:address:number<span class="Special"> <- </span>get-address *editor, <span class="Constant">right:offset</span> + *right<span class="Special"> <- </span>screen-width screen + *right<span class="Special"> <- </span>divide *right, <span class="Constant">2</span> + *right<span class="Special"> <- </span>subtract *right, <span class="Constant">1</span> + <span class="Delimiter">}</span> + <span class="Delimiter">{</span> + <span class="muControl">break-unless</span> *sandbox-in-focus? + editor:address:editor-data<span class="Special"> <- </span>get *env, <span class="Constant">current-sandbox:offset</span> + left:address:number<span class="Special"> <- </span>get-address *editor, <span class="Constant">left:offset</span> + *left<span class="Special"> <- </span>screen-width screen + *left<span class="Special"> <- </span>divide *left, <span class="Constant">2</span> + *left<span class="Special"> <- </span>add *left, <span class="Constant">1</span> + <span class="Delimiter">}</span> + render-all screen, env + show-screen screen + <span class="muControl">loop</span> <span class="Constant">+next-event:label</span> + <span class="Delimiter">}</span> +] + +<span class="SalientComment">## helpers</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> + y: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? + style<span class="Special"> <- </span>copy <span class="Constant">9474/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? + color<span class="Special"> <- </span>copy <span class="Constant">245/grey</span> + <span class="Delimiter">}</span> + <span class="Delimiter">{</span> + continue?:boolean<span class="Special"> <- </span>lesser-than y, bottom + <span class="muControl">break-unless</span> continue? + screen<span class="Special"> <- </span>move-cursor screen, y, col + print-character screen, style, color + y<span class="Special"> <- </span>add y, <span class="Constant">1</span> + <span class="muControl">loop</span> + <span class="Delimiter">}</span> +] +</pre> +</body> +</html> +<!-- vim: set foldmethod=manual : --> diff --git a/html/edit/005-sandbox.mu.html b/html/edit/005-sandbox.mu.html new file mode 100644 index 00000000..7115ca00 --- /dev/null +++ b/html/edit/005-sandbox.mu.html @@ -0,0 +1,555 @@ +<!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/005-sandbox.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; } +.muData { color: #ffff00; } +.Special { color: #ff6060; } +.muRecipe { color: #ff8700; } +.Comment { color: #9090ff; } +.Constant { color: #00a0a0; } +.SalientComment { color: #00ffff; } +.Delimiter { color: #a04060; } +.muControl { color: #c0a020; } +--> +</style> + +<script type='text/javascript'> +<!-- + +--> +</script> +</head> +<body> +<pre id='vimCodeElement'> +<span class="SalientComment">## running code from the editor and creating sandboxes</span> +<span class="Comment">#</span> +<span class="Comment"># Running code in the sandbox editor prepends its contents to a list of</span> +<span class="Comment"># (non-editable) sandboxes below the editor, showing the result and a maybe</span> +<span class="Comment"># few other things.</span> + +<span class="muData">container</span> programming-environment-data [ + sandbox:address:sandbox-data <span class="Comment"># list of sandboxes, from top to bottom</span> +] + +<span class="muData">container</span> sandbox-data [ + data:address:array:character + response:address:array:character + expected-response:address:array:character + <span class="Comment"># coordinates to track clicks</span> + starting-row-on-screen:number + code-ending-row-on-screen:number <span class="Comment"># past end of code</span> + response-starting-row-on-screen:number + 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</span> + assume-screen <span class="Constant">100/width</span>, <span class="Constant">15/height</span> + <span class="Comment"># recipe editor is empty</span> + <span class="Constant">1</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[]</span> + <span class="Comment"># sandbox editor contains an instruction without storing outputs</span> + <span class="Constant">2</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[divide-with-remainder 11, 3]</span> + <span class="Constant">3</span>:address:programming-environment-data<span class="Special"> <- </span>new-programming-environment screen:address, <span class="Constant">1</span>:address:array:character, <span class="Constant">2</span>:address:array:character + <span class="Comment"># run the code in the editors</span> + assume-console [ + press F4 + ] + run [ + event-loop screen:address, console:address, <span class="Constant">3</span>:address:programming-environment-data + ] + <span class="Comment"># check that screen prints the results</span> + screen-should-contain [ + <span class="Constant"> . run (F4) .</span> + <span class="Constant"> . ┊ .</span> +<span class="Constant"> .┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┊━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━.</span> + <span class="Constant"> . ┊ x.</span> + <span class="Constant"> . ┊divide-with-remainder 11, 3 .</span> + <span class="Constant"> . ┊3 .</span> + <span class="Constant"> . ┊2 .</span> + <span class="Constant"> . ┊━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━.</span> + <span class="Constant"> . ┊ .</span> + ] + screen-should-contain-in-color <span class="Constant">7/white</span>, [ + <span class="Constant"> . .</span> + <span class="Constant"> . .</span> + <span class="Constant"> . .</span> + <span class="Constant"> . .</span> + <span class="Constant"> . divide-with-remainder 11, 3 .</span> + <span class="Constant"> . .</span> + <span class="Constant"> . .</span> + <span class="Constant"> . .</span> + <span class="Constant"> . .</span> + ] + screen-should-contain-in-color <span class="Constant">245/grey</span>, [ + <span class="Constant"> . .</span> + <span class="Constant"> . ┊ .</span> +<span class="Constant"> .┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┊━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━.</span> + <span class="Constant"> . ┊ x.</span> + <span class="Constant"> . ┊ .</span> + <span class="Constant"> . ┊3 .</span> + <span class="Constant"> . ┊2 .</span> + <span class="Constant"> . ┊━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━.</span> + <span class="Constant"> . ┊ .</span> + ] + <span class="Comment"># run another command</span> + assume-console [ + left-click <span class="Constant">1</span>, <span class="Constant">80</span> + type <span class="Constant">[add 2, 2]</span> + press F4 + ] + run [ + event-loop screen:address, console:address, <span class="Constant">3</span>:address:programming-environment-data + ] + <span class="Comment"># check that screen prints the results</span> + screen-should-contain [ + <span class="Constant"> . run (F4) .</span> + <span class="Constant"> . ┊ .</span> +<span class="Constant"> .┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┊━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━.</span> + <span class="Constant"> . ┊ x.</span> + <span class="Constant"> . ┊add 2, 2 .</span> + <span class="Constant"> . ┊4 .</span> + <span class="Constant"> . ┊━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━.</span> + <span class="Constant"> . ┊ x.</span> + <span class="Constant"> . ┊divide-with-remainder 11, 3 .</span> + <span class="Constant"> . ┊3 .</span> + <span class="Constant"> . ┊2 .</span> + <span class="Constant"> . ┊━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━.</span> + <span class="Constant"> . ┊ .</span> + ] +] + +<span class="Comment"># hook into event-loop recipe: read non-unicode keypress from k, process it if</span> +<span class="Comment"># necessary, then go to next level</span> +<span class="muRecipe">after</span> <span class="Constant"><global-keypress></span> [ + <span class="Comment"># F4? load all code and run all sandboxes.</span> + <span class="Delimiter">{</span> + do-run?:boolean<span class="Special"> <- </span>equal *k, <span class="Constant">65532/F4</span> + <span class="muControl">break-unless</span> do-run? + status:address:array:character<span class="Special"> <- </span>new <span class="Constant">[running... ]</span> + screen<span class="Special"> <- </span>update-status screen, status, <span class="Constant">245/grey</span> + error?:boolean, env, screen<span class="Special"> <- </span>run-sandboxes env, screen + <span class="Comment"># F4 might update warnings and results on both sides</span> + screen<span class="Special"> <- </span>render-all screen, env + <span class="Delimiter">{</span> + <span class="muControl">break-if</span> error? + status:address:array:character<span class="Special"> <- </span>new <span class="Constant">[ ]</span> + screen<span class="Special"> <- </span>update-status screen, status, <span class="Constant">245/grey</span> + <span class="Delimiter">}</span> + screen<span class="Special"> <- </span>update-cursor screen, recipes, current-sandbox, *sandbox-in-focus? + <span class="muControl">loop</span> <span class="Constant">+next-event:label</span> + <span class="Delimiter">}</span> +] + +<span class="muRecipe">recipe</span> run-sandboxes [ + <span class="Constant">local-scope</span> + env:address:programming-environment-data<span class="Special"> <- </span><span class="Constant">next-ingredient</span> + screen:address<span class="Special"> <- </span><span class="Constant">next-ingredient</span> + stop?:boolean, env, screen<span class="Special"> <- </span>update-recipes env, screen + <span class="muControl">reply-if</span> stop?, <span class="Constant">1/errors-found</span>, env/same-as-ingredient:<span class="Constant">0</span>, screen/same-as-ingredient:<span class="Constant">1</span> + <span class="Comment"># check contents of right editor (sandbox)</span> + current-sandbox:address:editor-data<span class="Special"> <- </span>get *env, <span class="Constant">current-sandbox:offset</span> + <span class="Delimiter">{</span> + sandbox-contents:address:array:character<span class="Special"> <- </span>editor-contents current-sandbox + <span class="muControl">break-unless</span> sandbox-contents + <span class="Comment"># if contents exist, first save them</span> + <span class="Comment"># run them and turn them into a new sandbox-data</span> + new-sandbox:address:sandbox-data<span class="Special"> <- </span>new <span class="Constant">sandbox-data:type</span> + data:address:address:array:character<span class="Special"> <- </span>get-address *new-sandbox, <span class="Constant">data:offset</span> + *data<span class="Special"> <- </span>copy sandbox-contents + <span class="Comment"># push to head of sandbox list</span> + dest:address:address:sandbox-data<span class="Special"> <- </span>get-address *env, <span class="Constant">sandbox:offset</span> + next:address:address:sandbox-data<span class="Special"> <- </span>get-address *new-sandbox, <span class="Constant">next-sandbox:offset</span> + *next<span class="Special"> <- </span>copy *dest + *dest<span class="Special"> <- </span>copy new-sandbox + <span class="Comment"># clear sandbox editor</span> + init:address:address:duplex-list<span class="Special"> <- </span>get-address *current-sandbox, <span class="Constant">data:offset</span> + *init<span class="Special"> <- </span>push-duplex <span class="Constant">167/§</span>, <span class="Constant">0/tail</span> + top-of-screen:address:address:duplex-list<span class="Special"> <- </span>get-address *current-sandbox, <span class="Constant">top-of-screen:offset</span> + *top-of-screen<span class="Special"> <- </span>copy *init + <span class="Delimiter">}</span> + <span class="Comment"># save all sandboxes before running, just in case we die when running</span> + save-sandboxes env + <span class="Comment"># run all sandboxes</span> + curr:address:sandbox-data<span class="Special"> <- </span>get *env, <span class="Constant">sandbox:offset</span> + <span class="Delimiter">{</span> + <span class="muControl">break-unless</span> curr + update-sandbox curr + curr<span class="Special"> <- </span>get *curr, <span class="Constant">next-sandbox:offset</span> + <span class="muControl">loop</span> + <span class="Delimiter">}</span> + <span class="muControl">reply</span> <span class="Constant">0/no-errors-found</span>, env/same-as-ingredient:<span class="Constant">0</span>, screen/same-as-ingredient:<span class="Constant">1</span> +] + +<span class="Comment"># copy code from recipe editor, persist, load into mu</span> +<span class="Comment"># replaced in a later layer</span> +<span class="muRecipe">recipe</span> update-recipes [ + <span class="Constant">local-scope</span> + env:address:programming-environment-data<span class="Special"> <- </span><span class="Constant">next-ingredient</span> + screen:address<span class="Special"> <- </span><span class="Constant">next-ingredient</span> + recipes:address:editor-data<span class="Special"> <- </span>get *env, <span class="Constant">recipes:offset</span> + in:address:array:character<span class="Special"> <- </span>editor-contents recipes + save <span class="Constant">[recipes.mu]</span>, in + reload in + <span class="muControl">reply</span> <span class="Constant">0/no-errors-found</span>, env/same-as-ingredient:<span class="Constant">0</span>, screen/same-as-ingredient:<span class="Constant">1</span> +] + +<span class="Comment"># replaced in a later layer</span> +<span class="muRecipe">recipe</span> update-sandbox [ + <span class="Constant">local-scope</span> + sandbox:address:sandbox-data<span class="Special"> <- </span><span class="Constant">next-ingredient</span> + data:address:array:character<span class="Special"> <- </span>get *sandbox, <span class="Constant">data:offset</span> + response:address:address:array:character<span class="Special"> <- </span>get-address *sandbox, <span class="Constant">response:offset</span> + fake-screen:address:address:screen<span class="Special"> <- </span>get-address *sandbox, <span class="Constant">screen:offset</span> + *response, _, *fake-screen<span class="Special"> <- </span>run-interactive data +] + +<span class="muRecipe">recipe</span> update-status [ + <span class="Constant">local-scope</span> + screen:address<span class="Special"> <- </span><span class="Constant">next-ingredient</span> + msg: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> + screen<span class="Special"> <- </span>move-cursor screen, <span class="Constant">0</span>, <span class="Constant">2</span> + screen<span class="Special"> <- </span>print-string screen, msg, color, <span class="Constant">238/grey/background</span> + <span class="muControl">reply</span> screen/same-as-ingredient:<span class="Constant">0</span> +] + +<span class="muRecipe">recipe</span> save-sandboxes [ + <span class="Constant">local-scope</span> + env:address:programming-environment-data<span class="Special"> <- </span><span class="Constant">next-ingredient</span> + current-sandbox:address:editor-data<span class="Special"> <- </span>get *env, <span class="Constant">current-sandbox:offset</span> + <span class="Comment"># first clear previous versions, in case we deleted some sandbox</span> + $system <span class="Constant">[rm lesson/[0-9]</span>* >/dev/null <span class="Constant">2</span>>/dev/null] <span class="Comment"># some shells can't handle '>&'</span> + curr:address:sandbox-data<span class="Special"> <- </span>get *env, <span class="Constant">sandbox:offset</span> + suffix:address:array:character<span class="Special"> <- </span>new <span class="Constant">[.out]</span> + idx:number<span class="Special"> <- </span>copy <span class="Constant">0</span> + <span class="Delimiter">{</span> + <span class="muControl">break-unless</span> curr + data:address:array:character<span class="Special"> <- </span>get *curr, <span class="Constant">data:offset</span> + filename:address:array:character<span class="Special"> <- </span>integer-to-decimal-string idx + save filename, data + <span class="Delimiter">{</span> + expected-response:address:array:character<span class="Special"> <- </span>get *curr, <span class="Constant">expected-response:offset</span> + <span class="muControl">break-unless</span> expected-response + filename<span class="Special"> <- </span>string-append filename, suffix + save filename, expected-response + <span class="Delimiter">}</span> + idx<span class="Special"> <- </span>add idx, <span class="Constant">1</span> + curr<span class="Special"> <- </span>get *curr, <span class="Constant">next-sandbox:offset</span> + <span class="muControl">loop</span> + <span class="Delimiter">}</span> +] + +<span class="muRecipe">recipe!</span> render-sandbox-side [ + <span class="Constant">local-scope</span> + screen:address<span class="Special"> <- </span><span class="Constant">next-ingredient</span> + env:address:programming-environment-data<span class="Special"> <- </span><span class="Constant">next-ingredient</span> + trace <span class="Constant">11</span>, <span class="Constant">[app]</span>, <span class="Constant">[render sandbox side]</span> + current-sandbox:address:editor-data<span class="Special"> <- </span>get *env, <span class="Constant">current-sandbox:offset</span> + left:number<span class="Special"> <- </span>get *current-sandbox, <span class="Constant">left:offset</span> + right:number<span class="Special"> <- </span>get *current-sandbox, <span class="Constant">right:offset</span> + row:number, column:number, screen, current-sandbox<span class="Special"> <- </span>render screen, current-sandbox + clear-screen-from screen, row, column, left, right + row<span class="Special"> <- </span>add row, <span class="Constant">1</span> + draw-horizontal screen, row, left, right, <span class="Constant">9473/horizontal-double</span> + sandbox:address:sandbox-data<span class="Special"> <- </span>get *env, <span class="Constant">sandbox:offset</span> + row, screen<span class="Special"> <- </span>render-sandboxes screen, sandbox, left, right, row + clear-rest-of-screen screen, row, left, left, right + <span class="muControl">reply</span> screen/same-as-ingredient:<span class="Constant">0</span> +] + +<span class="muRecipe">recipe</span> render-sandboxes [ + <span class="Constant">local-scope</span> + screen:address<span class="Special"> <- </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, row/same-as-ingredient:<span class="Constant">4</span>, screen/same-as-ingredient:<span class="Constant">0</span> + screen-height:number<span class="Special"> <- </span>screen-height screen + at-bottom?:boolean<span class="Special"> <- </span>greater-or-equal row, screen-height + <span class="muControl">reply-if</span> at-bottom?:boolean, row/same-as-ingredient:<span class="Constant">4</span>, screen/same-as-ingredient:<span class="Constant">0</span> + <span class="Comment"># render sandbox menu</span> + row<span class="Special"> <- </span>add row, <span class="Constant">1</span> + screen<span class="Special"> <- </span>move-cursor screen, row, left + clear-line-delimited screen, left, right + print-character screen, <span class="Constant">120/x</span>, <span class="Constant">245/grey</span> + <span class="Comment"># save menu row so we can detect clicks to it later</span> + starting-row:address:number<span class="Special"> <- </span>get-address *sandbox, <span class="Constant">starting-row-on-screen:offset</span> + *starting-row<span class="Special"> <- </span>copy row + <span class="Comment"># render sandbox contents</span> + row<span class="Special"> <- </span>add row, <span class="Constant">1</span> + screen<span class="Special"> <- </span>move-cursor screen, row, left + sandbox-data:address:array:character<span class="Special"> <- </span>get *sandbox, <span class="Constant">data:offset</span> + row, screen<span class="Special"> <- </span>render-code-string screen, sandbox-data, left, right, row + code-ending-row:address:number<span class="Special"> <- </span>get-address *sandbox, <span class="Constant">code-ending-row-on-screen:offset</span> + *code-ending-row<span class="Special"> <- </span>copy row + <span class="Comment"># render sandbox warnings, screen or response, in that order</span> + response-starting-row:address:number<span class="Special"> <- </span>get-address *sandbox, <span class="Constant">response-starting-row-on-screen:offset</span> + sandbox-response:address:array:character<span class="Special"> <- </span>get *sandbox, <span class="Constant">response:offset</span> +<span class="Constant"> <render-sandbox-results></span> + <span class="Delimiter">{</span> + sandbox-screen:address<span class="Special"> <- </span>get *sandbox, <span class="Constant">screen:offset</span> + empty-screen?:boolean<span class="Special"> <- </span>fake-screen-is-empty? sandbox-screen + <span class="muControl">break-if</span> empty-screen? + row, screen<span class="Special"> <- </span>render-screen screen, sandbox-screen, left, right, row + <span class="Delimiter">}</span> + <span class="Delimiter">{</span> + <span class="muControl">break-unless</span> empty-screen? + *response-starting-row<span class="Special"> <- </span>copy row +<span class="Constant"> <render-sandbox-response></span> + row, screen<span class="Special"> <- </span>render-string screen, sandbox-response, left, right, <span class="Constant">245/grey</span>, row + <span class="Delimiter">}</span> +<span class="Constant"> +render-sandbox-end</span> + at-bottom?:boolean<span class="Special"> <- </span>greater-or-equal row, screen-height + <span class="muControl">reply-if</span> at-bottom?, row/same-as-ingredient:<span class="Constant">4</span>, screen/same-as-ingredient:<span class="Constant">0</span> + <span class="Comment"># draw solid line after sandbox</span> + draw-horizontal screen, row, left, right, <span class="Constant">9473/horizontal-double</span> + <span class="Comment"># draw next sandbox</span> + next-sandbox:address:sandbox-data<span class="Special"> <- </span>get *sandbox, <span class="Constant">next-sandbox:offset</span> + row, screen<span class="Special"> <- </span>render-sandboxes screen, next-sandbox, left, right, row + <span class="muControl">reply</span> row/same-as-ingredient:<span class="Constant">4</span>, screen/same-as-ingredient:<span class="Constant">0</span> +] + +<span class="Comment"># assumes programming environment has no sandboxes; restores them from previous session</span> +<span class="muRecipe">recipe</span> restore-sandboxes [ + <span class="Constant">local-scope</span> + env:address:programming-environment-data<span class="Special"> <- </span><span class="Constant">next-ingredient</span> + <span class="Comment"># read all scenarios, pushing them to end of a list of scenarios</span> + suffix:address:array:character<span class="Special"> <- </span>new <span class="Constant">[.out]</span> + idx:number<span class="Special"> <- </span>copy <span class="Constant">0</span> + curr:address:address:sandbox-data<span class="Special"> <- </span>get-address *env, <span class="Constant">sandbox:offset</span> + <span class="Delimiter">{</span> + filename:address:array:character<span class="Special"> <- </span>integer-to-decimal-string idx + contents:address:array:character<span class="Special"> <- </span>restore filename + <span class="muControl">break-unless</span> contents <span class="Comment"># stop at first error; assuming file didn't exist</span> + <span class="Comment"># create new sandbox for file</span> + *curr<span class="Special"> <- </span>new <span class="Constant">sandbox-data:type</span> + data:address:address:array:character<span class="Special"> <- </span>get-address **curr, <span class="Constant">data:offset</span> + *data<span class="Special"> <- </span>copy contents + <span class="Comment"># restore expected output for sandbox if it exists</span> + <span class="Delimiter">{</span> + filename<span class="Special"> <- </span>string-append filename, suffix + contents<span class="Special"> <- </span>restore filename + <span class="muControl">break-unless</span> contents + expected-response:address:address:array:character<span class="Special"> <- </span>get-address **curr, <span class="Constant">expected-response:offset</span> + *expected-response<span class="Special"> <- </span>copy contents + <span class="Delimiter">}</span> +<span class="Constant"> +continue</span> + idx<span class="Special"> <- </span>add idx, <span class="Constant">1</span> + curr<span class="Special"> <- </span>get-address **curr, <span class="Constant">next-sandbox:offset</span> + <span class="muControl">loop</span> + <span class="Delimiter">}</span> + <span class="muControl">reply</span> env/same-as-ingredient:<span class="Constant">0</span> +] + +<span class="Comment"># row, screen <- 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> + <span class="muControl">reply-unless</span> s, row/same-as-ingredient:<span class="Constant">4</span>, screen/same-as-ingredient:<span class="Constant">0</span> + <span class="Comment"># print 'screen:'</span> + header:address:array:character<span class="Special"> <- </span>new <span class="Constant">[screen:]</span> + row<span class="Special"> <- </span>render-string screen, header, left, right, <span class="Constant">245/grey</span>, row + screen<span class="Special"> <- </span>move-cursor screen, row, left + <span class="Comment"># start printing s</span> + column:number<span class="Special"> <- </span>copy left + s-width:number<span class="Special"> <- </span>screen-width s + s-height:number<span class="Special"> <- </span>screen-height s + buf:address:array:screen-cell<span class="Special"> <- </span>get *s, <span class="Constant">data:offset</span> + stop-printing:number<span class="Special"> <- </span>add left, s-width, <span class="Constant">3</span> + max-column:number<span class="Special"> <- </span>min stop-printing, right + i:number<span class="Special"> <- </span>copy <span class="Constant">0</span> + len:number<span class="Special"> <- </span>length *buf + screen-height:number<span class="Special"> <- </span>screen-height screen + <span class="Delimiter">{</span> + done?:boolean<span class="Special"> <- </span>greater-or-equal i, len + <span class="muControl">break-if</span> done? + done?<span class="Special"> <- </span>greater-or-equal row, screen-height + <span class="muControl">break-if</span> done? + column<span class="Special"> <- </span>copy left + screen<span class="Special"> <- </span>move-cursor screen, row, column + <span class="Comment"># initial leader for each row: two spaces and a '.'</span> + print-character screen, <span class="Constant">32/space</span>, <span class="Constant">245/grey</span> + print-character screen, <span class="Constant">32/space</span>, <span class="Constant">245/grey</span> + print-character screen, <span class="Constant">46/full-stop</span>, <span class="Constant">245/grey</span> + column<span class="Special"> <- </span>add left, <span class="Constant">3</span> + <span class="Delimiter">{</span> + <span class="Comment"># print row</span> + row-done?:boolean<span class="Special"> <- </span>greater-or-equal column, max-column + <span class="muControl">break-if</span> row-done? + curr:screen-cell<span class="Special"> <- </span>index *buf, i + c:character<span class="Special"> <- </span>get curr, <span class="Constant">contents:offset</span> + color:number<span class="Special"> <- </span>get curr, <span class="Constant">color:offset</span> + <span class="Delimiter">{</span> + <span class="Comment"># damp whites down to grey</span> + white?:boolean<span class="Special"> <- </span>equal color, <span class="Constant">7/white</span> + <span class="muControl">break-unless</span> white? + color<span class="Special"> <- </span>copy <span class="Constant">245/grey</span> + <span class="Delimiter">}</span> + print-character screen, c, color + column<span class="Special"> <- </span>add column, <span class="Constant">1</span> + i<span class="Special"> <- </span>add i, <span class="Constant">1</span> + <span class="muControl">loop</span> + <span class="Delimiter">}</span> + <span class="Comment"># print final '.'</span> + print-character screen, <span class="Constant">46/full-stop</span>, <span class="Constant">245/grey</span> + column<span class="Special"> <- </span>add column, <span class="Constant">1</span> + <span class="Delimiter">{</span> + <span class="Comment"># clear rest of current line</span> + line-done?:boolean<span class="Special"> <- </span>greater-than column, right + <span class="muControl">break-if</span> line-done? + print-character screen, <span class="Constant">32/space</span> + column<span class="Special"> <- </span>add column, <span class="Constant">1</span> + <span class="muControl">loop</span> + <span class="Delimiter">}</span> + row<span class="Special"> <- </span>add row, <span class="Constant">1</span> + <span class="muControl">loop</span> + <span class="Delimiter">}</span> + <span class="muControl">reply</span> row/same-as-ingredient:<span class="Constant">4</span>, screen/same-as-ingredient:<span class="Constant">0</span> +] + +<span class="muScenario">scenario</span> run-updates-results [ + $close-trace <span class="Comment"># trace too long</span> + assume-screen <span class="Constant">100/width</span>, <span class="Constant">12/height</span> + <span class="Comment"># define a recipe (no indent for the 'add' line below so column numbers are more obvious)</span> + <span class="Constant">1</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[ </span> +<span class="Constant">recipe foo [</span> +<span class="Constant">z:number <- add 2, 2</span> +<span class="Constant">]</span>] + <span class="Comment"># sandbox editor contains an instruction without storing outputs</span> + <span class="Constant">2</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[foo]</span> + <span class="Constant">3</span>:address:programming-environment-data<span class="Special"> <- </span>new-programming-environment screen:address, <span class="Constant">1</span>:address:array:character, <span class="Constant">2</span>:address:array:character + <span class="Comment"># run the code in the editors</span> + assume-console [ + press F4 + ] + run [ + event-loop screen:address, console:address, <span class="Constant">3</span>:address:programming-environment-data + ] + <span class="Comment"># check that screen prints the results</span> + screen-should-contain [ + <span class="Constant"> . run (F4) .</span> + <span class="Constant"> . ┊ .</span> + <span class="Constant"> .recipe foo [ ┊━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━.</span> + <span class="Constant"> .z:number <- add 2, 2 ┊ x.</span> + <span class="Constant"> .] ┊foo .</span> + <span class="Constant"> .┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┊4 .</span> + <span class="Constant"> . ┊━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━.</span> + <span class="Constant"> . ┊ .</span> + ] + <span class="Comment"># make a change (incrementing one of the args to 'add'), then rerun</span> + assume-console [ + left-click <span class="Constant">3</span>, <span class="Constant">28</span> <span class="Comment"># one past the value of the second arg</span> + press backspace + type <span class="Constant">[3]</span> + press F4 + ] + run [ + event-loop screen:address, console:address, <span class="Constant">3</span>:address:programming-environment-data + ] + <span class="Comment"># check that screen updates the result on the right</span> + screen-should-contain [ + <span class="Constant"> . run (F4) .</span> + <span class="Constant"> . ┊ .</span> + <span class="Constant"> .recipe foo [ ┊━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━.</span> + <span class="Constant"> .z:number <- add 2, 3 ┊ x.</span> + <span class="Constant"> .] ┊foo .</span> + <span class="Constant"> .┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┊5 .</span> + <span class="Constant"> . ┊━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━.</span> + <span class="Constant"> . ┊ .</span> + ] +] + +<span class="muScenario">scenario</span> run-instruction-manages-screen-per-sandbox [ + $close-trace <span class="Comment"># trace too long</span> + assume-screen <span class="Constant">100/width</span>, <span class="Constant">20/height</span> + <span class="Comment"># left editor is empty</span> + <span class="Constant">1</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[]</span> + <span class="Comment"># right editor contains an instruction</span> + <span class="Constant">2</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[print-integer screen:address, 4]</span> + <span class="Constant">3</span>:address:programming-environment-data<span class="Special"> <- </span>new-programming-environment screen:address, <span class="Constant">1</span>:address:array:character, <span class="Constant">2</span>:address:array:character + <span class="Comment"># run the code in the editor</span> + assume-console [ + press F4 + ] + run [ + event-loop screen:address, console:address, <span class="Constant">3</span>:address:programming-environment-data + ] + <span class="Comment"># check that it prints a little toy screen</span> + screen-should-contain [ + <span class="Constant"> . run (F4) .</span> + <span class="Constant"> . ┊ .</span> +<span class="Constant"> .┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┊━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━.</span> + <span class="Constant"> . ┊ x.</span> + <span class="Constant"> . ┊print-integer screen:address, 4 .</span> + <span class="Constant"> . ┊screen: .</span> + <span class="Constant"> . ┊ .4 . .</span> + <span class="Constant"> . ┊ . . .</span> + <span class="Constant"> . ┊ . . .</span> + <span class="Constant"> . ┊ . . .</span> + <span class="Constant"> . ┊ . . .</span> + <span class="Constant"> . ┊━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━.</span> + <span class="Constant"> . ┊ .</span> + ] +] + +<span class="muRecipe">recipe</span> editor-contents [ + <span class="Constant">local-scope</span> + editor:address:editor-data<span class="Special"> <- </span><span class="Constant">next-ingredient</span> + buf:address:buffer<span class="Special"> <- </span>new-buffer <span class="Constant">80</span> + curr:address:duplex-list<span class="Special"> <- </span>get *editor, <span class="Constant">data:offset</span> + <span class="Comment"># skip § sentinel</span> + assert curr, <span class="Constant">[editor without data is illegal; must have at least a sentinel]</span> + curr<span class="Special"> <- </span>next-duplex curr + <span class="muControl">reply-unless</span> curr, <span class="Constant">0</span> + <span class="Delimiter">{</span> + <span class="muControl">break-unless</span> curr + c:character<span class="Special"> <- </span>get *curr, <span class="Constant">value:offset</span> + buffer-append buf, c + curr<span class="Special"> <- </span>next-duplex curr + <span class="muControl">loop</span> + <span class="Delimiter">}</span> + result:address:array:character<span class="Special"> <- </span>buffer-to-array buf + <span class="muControl">reply</span> result +] + +<span class="muScenario">scenario</span> editor-provides-edited-contents [ + assume-screen <span class="Constant">10/width</span>, <span class="Constant">5/height</span> + <span class="Constant">1</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[abc]</span> + <span class="Constant">2</span>:address:editor-data<span class="Special"> <- </span>new-editor <span class="Constant">1</span>:address:array:character, screen:address, <span class="Constant">0/left</span>, <span class="Constant">10/right</span> + assume-console [ + left-click <span class="Constant">1</span>, <span class="Constant">2</span> + type <span class="Constant">[def]</span> + ] + run [ + editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data + <span class="Constant">3</span>:address:array:character<span class="Special"> <- </span>editor-contents <span class="Constant">2</span>:address:editor-data + <span class="Constant">4</span>:array:character<span class="Special"> <- </span>copy *<span class="Constant">3</span>:address:array:character + ] + memory-should-contain [ + <span class="Constant">4</span>:string<span class="Special"> <- </span><span class="Constant">[abdefc]</span> + ] +] +</pre> +</body> +</html> +<!-- vim: set foldmethod=manual : --> diff --git a/html/edit/006-sandbox-edit.mu.html b/html/edit/006-sandbox-edit.mu.html new file mode 100644 index 00000000..e5c2d430 --- /dev/null +++ b/html/edit/006-sandbox-edit.mu.html @@ -0,0 +1,212 @@ +<!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/006-sandbox-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; } +.Special { color: #ff6060; } +.muRecipe { color: #ff8700; } +.Comment { color: #9090ff; } +.Constant { color: #00a0a0; } +.SalientComment { color: #00ffff; } +.Delimiter { color: #a04060; } +.muControl { color: #c0a020; } +--> +</style> + +<script type='text/javascript'> +<!-- + +--> +</script> +</head> +<body> +<pre id='vimCodeElement'> +<span class="SalientComment">## editing sandboxes after they've been created</span> + +<span class="muScenario">scenario</span> clicking-on-a-sandbox-moves-it-to-editor [ + $close-trace <span class="Comment"># trace too long</span> + assume-screen <span class="Constant">40/width</span>, <span class="Constant">10/height</span> + <span class="Comment"># basic recipe</span> + <span class="Constant">1</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[ </span> +<span class="Constant">recipe foo [</span> +<span class="Constant"> add 2, 2</span> +<span class="Constant">]</span>] + <span class="Comment"># run it</span> + <span class="Constant">2</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[foo]</span> + assume-console [ + press F4 + ] + <span class="Constant">3</span>:address:programming-environment-data<span class="Special"> <- </span>new-programming-environment screen:address, <span class="Constant">1</span>:address:array:character, <span class="Constant">2</span>:address:array:character + event-loop screen:address, console:address, <span class="Constant">3</span>:address:programming-environment-data + screen-should-contain [ + <span class="Constant"> . run (F4) .</span> + <span class="Constant"> . ┊ .</span> + <span class="Constant"> .recipe foo [ ┊━━━━━━━━━━━━━━━━━━━.</span> + <span class="Constant"> . add 2, 2 ┊ x.</span> + <span class="Constant"> .] ┊foo .</span> + <span class="Constant"> .┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┊4 .</span> + <span class="Constant"> . ┊━━━━━━━━━━━━━━━━━━━.</span> + <span class="Constant"> . ┊ .</span> + ] + <span class="Comment"># click somewhere on the sandbox</span> + assume-console [ + left-click <span class="Constant">3</span>, <span class="Constant">30</span> + ] + run [ + event-loop screen:address, console:address, <span class="Constant">3</span>:address:programming-environment-data + ] + <span class="Comment"># it pops back into editor</span> + screen-should-contain [ + <span class="Constant"> . run (F4) .</span> + <span class="Constant"> . ┊foo .</span> + <span class="Constant"> .recipe foo [ ┊━━━━━━━━━━━━━━━━━━━.</span> + <span class="Constant"> . add 2, 2 ┊ .</span> + <span class="Constant"> .] ┊ .</span> + <span class="Constant"> .┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┊ .</span> + <span class="Constant"> . ┊ .</span> + <span class="Constant"> . ┊ .</span> + ] + <span class="Comment"># cursor should be in the right place</span> + assume-console [ + type <span class="Constant">[0]</span> + ] + run [ + event-loop screen:address, console:address, <span class="Constant">3</span>:address:programming-environment-data + ] + screen-should-contain [ + <span class="Constant"> . run (F4) .</span> + <span class="Constant"> . ┊0foo .</span> + <span class="Constant"> .recipe foo [ ┊━━━━━━━━━━━━━━━━━━━.</span> + <span class="Constant"> . add 2, 2 ┊ .</span> + <span class="Constant"> .] ┊ .</span> + <span class="Constant"> .┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┊ .</span> + <span class="Constant"> . ┊ .</span> + <span class="Constant"> . ┊ .</span> + ] +] + +<span class="muRecipe">after</span> <span class="Constant"><global-touch></span> [ + <span class="Comment"># right side of screen and below sandbox editor? pop appropriate sandbox</span> + <span class="Comment"># contents back into sandbox editor provided it's empty</span> + <span class="Delimiter">{</span> + sandbox-left-margin:number<span class="Special"> <- </span>get *current-sandbox, <span class="Constant">left:offset</span> + click-column:number<span class="Special"> <- </span>get *t, <span class="Constant">column:offset</span> + on-sandbox-side?:boolean<span class="Special"> <- </span>greater-or-equal click-column, sandbox-left-margin + <span class="muControl">break-unless</span> on-sandbox-side? + first-sandbox:address:sandbox-data<span class="Special"> <- </span>get *env, <span class="Constant">sandbox:offset</span> + <span class="muControl">break-unless</span> first-sandbox + first-sandbox-begins:number<span class="Special"> <- </span>get *first-sandbox, <span class="Constant">starting-row-on-screen:offset</span> + click-row:number<span class="Special"> <- </span>get *t, <span class="Constant">row:offset</span> + below-sandbox-editor?:boolean<span class="Special"> <- </span>greater-or-equal click-row, first-sandbox-begins + <span class="muControl">break-unless</span> below-sandbox-editor? + empty-sandbox-editor?:boolean<span class="Special"> <- </span>empty-editor? current-sandbox + <span class="muControl">break-unless</span> empty-sandbox-editor? <span class="Comment"># make the user hit F4 before editing a new sandbox</span> + <span class="Comment"># identify the sandbox to edit and remove it from the sandbox list</span> + sandbox:address:sandbox-data<span class="Special"> <- </span>extract-sandbox env, click-row + text:address:array:character<span class="Special"> <- </span>get *sandbox, <span class="Constant">data:offset</span> + current-sandbox<span class="Special"> <- </span>insert-text current-sandbox, text + hide-screen screen + screen<span class="Special"> <- </span>render-sandbox-side screen, env + screen<span class="Special"> <- </span>update-cursor screen, recipes, current-sandbox, *sandbox-in-focus? + show-screen screen + <span class="muControl">loop</span> <span class="Constant">+next-event:label</span> + <span class="Delimiter">}</span> +] + +<span class="muRecipe">recipe</span> empty-editor? [ + <span class="Constant">local-scope</span> + editor:address:editor-data<span class="Special"> <- </span><span class="Constant">next-ingredient</span> + head:address:duplex-list<span class="Special"> <- </span>get *editor, <span class="Constant">data:offset</span> + first:address:duplex-list<span class="Special"> <- </span>next-duplex head + result:boolean<span class="Special"> <- </span>not first + <span class="muControl">reply</span> result +] + +<span class="muRecipe">recipe</span> extract-sandbox [ + <span class="Constant">local-scope</span> + env:address:programming-environment-data<span class="Special"> <- </span><span class="Constant">next-ingredient</span> + click-row:number<span class="Special"> <- </span><span class="Constant">next-ingredient</span> + <span class="Comment"># assert click-row >= sandbox.starting-row-on-screen</span> + sandbox:address:address:sandbox-data<span class="Special"> <- </span>get-address *env, <span class="Constant">sandbox:offset</span> + start:number<span class="Special"> <- </span>get **sandbox, <span class="Constant">starting-row-on-screen:offset</span> + clicked-on-sandboxes?:boolean<span class="Special"> <- </span>greater-or-equal click-row, start + assert clicked-on-sandboxes?, <span class="Constant">[extract-sandbox called on click to sandbox editor]</span> + <span class="Delimiter">{</span> + next-sandbox:address:sandbox-data<span class="Special"> <- </span>get **sandbox, <span class="Constant">next-sandbox:offset</span> + <span class="muControl">break-unless</span> next-sandbox + <span class="Comment"># if click-row < sandbox.next-sandbox.starting-row-on-screen, break</span> + next-start:number<span class="Special"> <- </span>get *next-sandbox, <span class="Constant">starting-row-on-screen:offset</span> + found?:boolean<span class="Special"> <- </span>lesser-than click-row, next-start + <span class="muControl">break-if</span> found? + sandbox<span class="Special"> <- </span>get-address **sandbox, <span class="Constant">next-sandbox:offset</span> + <span class="muControl">loop</span> + <span class="Delimiter">}</span> + <span class="Comment"># snip sandbox out of its list</span> + result:address:sandbox-data<span class="Special"> <- </span>copy *sandbox + *sandbox<span class="Special"> <- </span>copy next-sandbox + <span class="Comment"># position cursor in sandbox editor</span> + sandbox-in-focus?:address:boolean<span class="Special"> <- </span>get-address *env, <span class="Constant">sandbox-in-focus?:offset</span> + *sandbox-in-focus?<span class="Special"> <- </span>copy <span class="Constant">1/true</span> + <span class="muControl">reply</span> result +] + +<span class="muScenario">scenario</span> sandbox-with-print-can-be-edited [ + $close-trace <span class="Comment"># trace too long</span> + assume-screen <span class="Constant">100/width</span>, <span class="Constant">20/height</span> + <span class="Comment"># left editor is empty</span> + <span class="Constant">1</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[]</span> + <span class="Comment"># right editor contains an instruction</span> + <span class="Constant">2</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[print-integer screen:address, 4]</span> + <span class="Constant">3</span>:address:programming-environment-data<span class="Special"> <- </span>new-programming-environment screen:address, <span class="Constant">1</span>:address:array:character, <span class="Constant">2</span>:address:array:character + <span class="Comment"># run the sandbox</span> + assume-console [ + press F4 + ] + run [ + event-loop screen:address, console:address, <span class="Constant">3</span>:address:programming-environment-data + ] + screen-should-contain [ + <span class="Constant"> . run (F4) .</span> + <span class="Constant"> . ┊ .</span> +<span class="Constant"> .┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┊━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━.</span> + <span class="Constant"> . ┊ x.</span> + <span class="Constant"> . ┊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="Comment"># edit the sandbox</span> + assume-console [ + left-click <span class="Constant">3</span>, <span class="Constant">70</span> + ] + run [ + event-loop screen:address, console:address, <span class="Constant">3</span>:address:programming-environment-data + ] + screen-should-contain [ + <span class="Constant"> . run (F4) .</span> + <span class="Constant"> . ┊print-integer screen:address, 4 .</span> +<span class="Constant"> .┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┊━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━.</span> + <span class="Constant"> . ┊ .</span> + <span class="Constant"> . ┊ .</span> + ] +] +</pre> +</body> +</html> +<!-- vim: set foldmethod=manual : --> diff --git a/html/edit/007-sandbox-delete.mu.html b/html/edit/007-sandbox-delete.mu.html new file mode 100644 index 00000000..5f3cdfcf --- /dev/null +++ b/html/edit/007-sandbox-delete.mu.html @@ -0,0 +1,149 @@ +<!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/007-sandbox-delete.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; } +.Special { color: #ff6060; } +.muRecipe { color: #ff8700; } +.Comment { color: #9090ff; } +.Constant { color: #00a0a0; } +.SalientComment { color: #00ffff; } +.Delimiter { color: #a04060; } +.muControl { color: #c0a020; } +--> +</style> + +<script type='text/javascript'> +<!-- + +--> +</script> +</head> +<body> +<pre id='vimCodeElement'> +<span class="SalientComment">## deleting sandboxes</span> + +<span class="muScenario">scenario</span> deleting-sandboxes [ + $close-trace <span class="Comment"># trace too long</span> + assume-screen <span class="Constant">100/width</span>, <span class="Constant">15/height</span> + <span class="Constant">1</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[]</span> + <span class="Constant">2</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[]</span> + <span class="Constant">3</span>:address:programming-environment-data<span class="Special"> <- </span>new-programming-environment screen:address, <span class="Constant">1</span>:address:array:character, <span class="Constant">2</span>:address:array:character + <span class="Comment"># run a few commands</span> + assume-console [ + left-click <span class="Constant">1</span>, <span class="Constant">80</span> + type <span class="Constant">[divide-with-remainder 11, 3]</span> + press F4 + type <span class="Constant">[add 2, 2]</span> + press F4 + ] + run [ + event-loop screen:address, console:address, <span class="Constant">3</span>:address:programming-environment-data + ] + screen-should-contain [ + <span class="Constant"> . run (F4) .</span> + <span class="Constant"> . ┊ .</span> +<span class="Constant"> .┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┊━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━.</span> + <span class="Constant"> . ┊ x.</span> + <span class="Constant"> . ┊add 2, 2 .</span> + <span class="Constant"> . ┊4 .</span> + <span class="Constant"> . ┊━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━.</span> + <span class="Constant"> . ┊ x.</span> + <span class="Constant"> . ┊divide-with-remainder 11, 3 .</span> + <span class="Constant"> . ┊3 .</span> + <span class="Constant"> . ┊2 .</span> + <span class="Constant"> . ┊━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━.</span> + <span class="Constant"> . ┊ .</span> + ] + <span class="Comment"># delete second sandbox</span> + assume-console [ + left-click <span class="Constant">7</span>, <span class="Constant">99</span> + ] + run [ + event-loop screen:address, console:address, <span class="Constant">3</span>:address:programming-environment-data + ] + screen-should-contain [ + <span class="Constant"> . run (F4) .</span> + <span class="Constant"> . ┊ .</span> +<span class="Constant"> .┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┊━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━.</span> + <span class="Constant"> . ┊ x.</span> + <span class="Constant"> . ┊add 2, 2 .</span> + <span class="Constant"> . ┊4 .</span> + <span class="Constant"> . ┊━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━.</span> + <span class="Constant"> . ┊ .</span> + <span class="Constant"> . ┊ .</span> + ] + <span class="Comment"># delete first sandbox</span> + assume-console [ + left-click <span class="Constant">3</span>, <span class="Constant">99</span> + ] + run [ + event-loop screen:address, console:address, <span class="Constant">3</span>:address:programming-environment-data + ] + screen-should-contain [ + <span class="Constant"> . run (F4) .</span> + <span class="Constant"> . ┊ .</span> +<span class="Constant"> .┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┊━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━.</span> + <span class="Constant"> . ┊ .</span> + <span class="Constant"> . ┊ .</span> + ] +] + +<span class="muRecipe">after</span> <span class="Constant"><global-touch></span> [ + <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, env + <span class="muControl">break-unless</span> was-delete? + hide-screen screen + screen<span class="Special"> <- </span>render-sandbox-side screen, env + screen<span class="Special"> <- </span>update-cursor screen, recipes, current-sandbox, *sandbox-in-focus? + show-screen screen + <span class="muControl">loop</span> <span class="Constant">+next-event:label</span> + <span class="Delimiter">}</span> +] + +<span class="Comment"># was-deleted?:boolean <- 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, <span class="Constant">column:offset</span> + current-sandbox:address:editor-data<span class="Special"> <- </span>get *env, <span class="Constant">current-sandbox:offset</span> + right:number<span class="Special"> <- </span>get *current-sandbox, <span class="Constant">right:offset</span> + at-right?:boolean<span class="Special"> <- </span>equal click-column, right + <span class="muControl">reply-unless</span> at-right?, <span class="Constant">0/false</span> + click-row:number<span class="Special"> <- </span>get t, <span class="Constant">row:offset</span> + prev:address:address:sandbox-data<span class="Special"> <- </span>get-address *env, <span class="Constant">sandbox:offset</span> + curr:address:sandbox-data<span class="Special"> <- </span>get *env, <span class="Constant">sandbox:offset</span> + <span class="Delimiter">{</span> + <span class="muControl">break-unless</span> curr + <span class="Comment"># more sandboxes to check</span> + <span class="Delimiter">{</span> + target-row:number<span class="Special"> <- </span>get *curr, <span class="Constant">starting-row-on-screen:offset</span> + delete-curr?:boolean<span class="Special"> <- </span>equal target-row, click-row + <span class="muControl">break-unless</span> delete-curr? + <span class="Comment"># delete this sandbox, rerender and stop</span> + *prev<span class="Special"> <- </span>get *curr, <span class="Constant">next-sandbox:offset</span> + <span class="muControl">reply</span> <span class="Constant">1/true</span> + <span class="Delimiter">}</span> + prev<span class="Special"> <- </span>get-address *curr, <span class="Constant">next-sandbox:offset</span> + curr<span class="Special"> <- </span>get *curr, <span class="Constant">next-sandbox:offset</span> + <span class="muControl">loop</span> + <span class="Delimiter">}</span> + <span class="muControl">reply</span> <span class="Constant">0/false</span> +] +</pre> +</body> +</html> +<!-- vim: set foldmethod=manual : --> diff --git a/html/edit/008-sandbox-test.mu.html b/html/edit/008-sandbox-test.mu.html new file mode 100644 index 00000000..0cdd6a08 --- /dev/null +++ b/html/edit/008-sandbox-test.mu.html @@ -0,0 +1,211 @@ +<!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/008-sandbox-test.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; } +.Special { color: #ff6060; } +.muRecipe { color: #ff8700; } +.Comment { color: #9090ff; } +.Constant { color: #00a0a0; } +.SalientComment { color: #00ffff; } +.Delimiter { color: #a04060; } +.muControl { color: #c0a020; } +--> +</style> + +<script type='text/javascript'> +<!-- + +--> +</script> +</head> +<body> +<pre id='vimCodeElement'> +<span class="SalientComment">## clicking on sandbox results to 'fix' them and turn sandboxes into tests</span> + +<span class="muScenario">scenario</span> sandbox-click-on-result-toggles-color-to-green [ + $close-trace <span class="Comment"># trace too long</span> + assume-screen <span class="Constant">40/width</span>, <span class="Constant">10/height</span> + <span class="Comment"># basic recipe</span> + <span class="Constant">1</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[ </span> +<span class="Constant">recipe foo [</span> +<span class="Constant"> add 2, 2</span> +<span class="Constant">]</span>] + <span class="Comment"># run it</span> + <span class="Constant">2</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[foo]</span> + assume-console [ + press F4 + ] + <span class="Constant">3</span>:address:programming-environment-data<span class="Special"> <- </span>new-programming-environment screen:address, <span class="Constant">1</span>:address:array:character, <span class="Constant">2</span>:address:array:character + event-loop screen:address, console:address, <span class="Constant">3</span>:address:programming-environment-data + screen-should-contain [ + <span class="Constant"> . run (F4) .</span> + <span class="Constant"> . ┊ .</span> + <span class="Constant"> .recipe foo [ ┊━━━━━━━━━━━━━━━━━━━.</span> + <span class="Constant"> . add 2, 2 ┊ x.</span> + <span class="Constant"> .] ┊foo .</span> + <span class="Constant"> .┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┊4 .</span> + <span class="Constant"> . ┊━━━━━━━━━━━━━━━━━━━.</span> + <span class="Constant"> . ┊ .</span> + ] + <span class="Comment"># click on the '4' in the result</span> + assume-console [ + left-click <span class="Constant">5</span>, <span class="Constant">21</span> + ] + run [ + event-loop screen:address, console:address, <span class="Constant">3</span>:address:programming-environment-data + ] + <span class="Comment"># color toggles to green</span> + screen-should-contain-in-color <span class="Constant">2/green</span>, [ + <span class="Constant"> . .</span> + <span class="Constant"> . .</span> + <span class="Constant"> . .</span> + <span class="Constant"> . .</span> + <span class="Constant"> . .</span> + <span class="Constant"> . 4 .</span> + <span class="Constant"> . .</span> + <span class="Constant"> . .</span> + ] + <span class="Comment"># cursor should remain unmoved</span> + run [ + print-character screen:address, <span class="Constant">9251/␣/cursor</span> + ] + screen-should-contain [ + <span class="Constant"> . run (F4) .</span> + <span class="Constant"> .␣ ┊ .</span> + <span class="Constant"> .recipe foo [ ┊━━━━━━━━━━━━━━━━━━━.</span> + <span class="Constant"> . add 2, 2 ┊ x.</span> + <span class="Constant"> .] ┊foo .</span> + <span class="Constant"> .┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┊4 .</span> + <span class="Constant"> . ┊━━━━━━━━━━━━━━━━━━━.</span> + <span class="Constant"> . ┊ .</span> + ] + <span class="Comment"># now change the second arg of the 'add'</span> + <span class="Comment"># then rerun</span> + assume-console [ + left-click <span class="Constant">3</span>, <span class="Constant">11</span> <span class="Comment"># cursor to end of line</span> + press backspace + type <span class="Constant">[3]</span> + press F4 + ] + run [ + event-loop screen:address, console:address, <span class="Constant">3</span>:address:programming-environment-data + ] + <span class="Comment"># result turns red</span> + screen-should-contain-in-color <span class="Constant">1/red</span>, [ + <span class="Constant"> . .</span> + <span class="Constant"> . .</span> + <span class="Constant"> . .</span> + <span class="Constant"> . .</span> + <span class="Constant"> . .</span> + <span class="Constant"> . 5 .</span> + <span class="Constant"> . .</span> + <span class="Constant"> . .</span> + ] +] + +<span class="Comment"># clicks on sandbox responses save it as 'expected'</span> +<span class="muRecipe">after</span> <span class="Constant"><global-touch></span> [ + <span class="Comment"># right side of screen? check if it's inside the output of any sandbox</span> + <span class="Delimiter">{</span> + sandbox-left-margin:number<span class="Special"> <- </span>get *current-sandbox, <span class="Constant">left:offset</span> + click-column:number<span class="Special"> <- </span>get *t, <span class="Constant">column:offset</span> + on-sandbox-side?:boolean<span class="Special"> <- </span>greater-or-equal click-column, sandbox-left-margin + <span class="muControl">break-unless</span> on-sandbox-side? + first-sandbox:address:sandbox-data<span class="Special"> <- </span>get *env, <span class="Constant">sandbox:offset</span> + <span class="muControl">break-unless</span> first-sandbox + first-sandbox-begins:number<span class="Special"> <- </span>get *first-sandbox, <span class="Constant">starting-row-on-screen:offset</span> + click-row:number<span class="Special"> <- </span>get *t, <span class="Constant">row:offset</span> + below-sandbox-editor?:boolean<span class="Special"> <- </span>greater-or-equal click-row, first-sandbox-begins + <span class="muControl">break-unless</span> below-sandbox-editor? + <span class="Comment"># identify the sandbox whose output is being clicked on</span> + sandbox:address:sandbox-data<span class="Special"> <- </span>find-click-in-sandbox-output env, click-row + <span class="muControl">break-unless</span> sandbox + <span class="Comment"># toggle its expected-response, and save session</span> + sandbox<span class="Special"> <- </span>toggle-expected-response sandbox + save-sandboxes env + hide-screen screen + screen<span class="Special"> <- </span>render-sandbox-side screen, env, <span class="Constant">1/clear</span> + screen<span class="Special"> <- </span>update-cursor screen, recipes, current-sandbox, *sandbox-in-focus? + <span class="Comment"># no change in cursor</span> + show-screen screen + <span class="muControl">loop</span> <span class="Constant">+next-event:label</span> + <span class="Delimiter">}</span> +] + +<span class="muRecipe">recipe</span> find-click-in-sandbox-output [ + <span class="Constant">local-scope</span> + env:address:programming-environment-data<span class="Special"> <- </span><span class="Constant">next-ingredient</span> + click-row:number<span class="Special"> <- </span><span class="Constant">next-ingredient</span> + <span class="Comment"># assert click-row >= sandbox.starting-row-on-screen</span> + sandbox:address:sandbox-data<span class="Special"> <- </span>get *env, <span class="Constant">sandbox:offset</span> + start:number<span class="Special"> <- </span>get *sandbox, <span class="Constant">starting-row-on-screen:offset</span> + clicked-on-sandboxes?:boolean<span class="Special"> <- </span>greater-or-equal click-row, start + assert clicked-on-sandboxes?, <span class="Constant">[extract-sandbox called on click to sandbox editor]</span> + <span class="Comment"># while click-row < sandbox.next-sandbox.starting-row-on-screen</span> + <span class="Delimiter">{</span> + next-sandbox:address:sandbox-data<span class="Special"> <- </span>get *sandbox, <span class="Constant">next-sandbox:offset</span> + <span class="muControl">break-unless</span> next-sandbox + next-start:number<span class="Special"> <- </span>get *next-sandbox, <span class="Constant">starting-row-on-screen:offset</span> + found?:boolean<span class="Special"> <- </span>lesser-than click-row, next-start + <span class="muControl">break-if</span> found? + sandbox<span class="Special"> <- </span>copy next-sandbox + <span class="muControl">loop</span> + <span class="Delimiter">}</span> + <span class="Comment"># return sandbox if click is in its output region</span> + response-starting-row:number<span class="Special"> <- </span>get *sandbox, <span class="Constant">response-starting-row-on-screen:offset</span> + <span class="muControl">reply-unless</span> response-starting-row, <span class="Constant">0/no-click-in-sandbox-output</span> + click-in-response?:boolean<span class="Special"> <- </span>greater-or-equal click-row, response-starting-row + <span class="muControl">reply-unless</span> click-in-response?, <span class="Constant">0/no-click-in-sandbox-output</span> + <span class="muControl">reply</span> sandbox +] + +<span class="muRecipe">recipe</span> toggle-expected-response [ + <span class="Constant">local-scope</span> + sandbox:address:sandbox-data<span class="Special"> <- </span><span class="Constant">next-ingredient</span> + expected-response:address:address:array:character<span class="Special"> <- </span>get-address *sandbox, <span class="Constant">expected-response:offset</span> + <span class="Delimiter">{</span> + <span class="Comment"># if expected-response is set, reset</span> + <span class="muControl">break-unless</span> *expected-response + *expected-response<span class="Special"> <- </span>copy <span class="Constant">0</span> + <span class="muControl">reply</span> sandbox/same-as-ingredient:<span class="Constant">0</span> + <span class="Delimiter">}</span> + <span class="Comment"># if not, current response is the expected response</span> + response:address:array:character<span class="Special"> <- </span>get *sandbox, <span class="Constant">response:offset</span> + *expected-response<span class="Special"> <- </span>copy response + <span class="muControl">reply</span> sandbox/same-as-ingredient:<span class="Constant">0</span> +] + +<span class="Comment"># when rendering a sandbox, color it in red/green if expected response exists</span> +<span class="muRecipe">after</span> <span class="Constant"><render-sandbox-response></span> [ + <span class="Delimiter">{</span> + <span class="muControl">break-unless</span> sandbox-response + expected-response:address:array:character<span class="Special"> <- </span>get *sandbox, <span class="Constant">expected-response:offset</span> + <span class="muControl">break-unless</span> expected-response <span class="Comment"># fall-through to print in grey</span> + response-is-expected?:boolean<span class="Special"> <- </span>string-equal expected-response, sandbox-response + <span class="Delimiter">{</span> + <span class="muControl">break-if</span> response-is-expected?:boolean + row, screen<span class="Special"> <- </span>render-string screen, sandbox-response, left, right, <span class="Constant">1/red</span>, row + <span class="Delimiter">}</span> + <span class="Delimiter">{</span> + <span class="muControl">break-unless</span> response-is-expected?:boolean + row, screen<span class="Special"> <- </span>render-string screen, sandbox-response, left, right, <span class="Constant">2/green</span>, row + <span class="Delimiter">}</span> + <span class="muControl">jump</span> <span class="Constant">+render-sandbox-end:label</span> + <span class="Delimiter">}</span> +] +</pre> +</body> +</html> +<!-- vim: set foldmethod=manual : --> diff --git a/html/edit/009-sandbox-trace.mu.html b/html/edit/009-sandbox-trace.mu.html new file mode 100644 index 00000000..b73fbee6 --- /dev/null +++ b/html/edit/009-sandbox-trace.mu.html @@ -0,0 +1,248 @@ +<!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/009-sandbox-trace.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; } +.muData { color: #ffff00; } +.Special { color: #ff6060; } +.muRecipe { color: #ff8700; } +.Comment { color: #9090ff; } +.Constant { color: #00a0a0; } +.SalientComment { color: #00ffff; } +.Delimiter { color: #a04060; } +.muControl { color: #c0a020; } +--> +</style> + +<script type='text/javascript'> +<!-- + +--> +</script> +</head> +<body> +<pre id='vimCodeElement'> +<span class="SalientComment">## clicking on the code typed into a sandbox toggles its trace</span> + +<span class="muScenario">scenario</span> sandbox-click-on-code-toggles-app-trace [ + $close-trace <span class="Comment"># trace too long</span> + assume-screen <span class="Constant">40/width</span>, <span class="Constant">10/height</span> + <span class="Comment"># basic recipe</span> + <span class="Constant">1</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[ </span> +<span class="Constant">recipe foo [</span> +<span class="Constant"> stash [abc]</span> +]] + <span class="Comment"># run it</span> + <span class="Constant">2</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[foo]</span> + assume-console [ + press F4 + ] + <span class="Constant">3</span>:address:programming-environment-data<span class="Special"> <- </span>new-programming-environment screen:address, <span class="Constant">1</span>:address:array:character, <span class="Constant">2</span>:address:array:character + event-loop screen:address, console:address, <span class="Constant">3</span>:address:programming-environment-data + screen-should-contain [ + <span class="Constant"> . run (F4) .</span> + <span class="Constant"> . ┊ .</span> + <span class="Constant"> .recipe foo [ ┊━━━━━━━━━━━━━━━━━━━.</span> + <span class="Constant"> . stash [abc] ┊ x.</span> + <span class="Constant"> .] ┊foo .</span> +<span class="Constant"> .┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┊━━━━━━━━━━━━━━━━━━━.</span> + <span class="Constant"> . ┊ .</span> + ] + <span class="Comment"># click on the 'foo' line in the sandbox</span> + assume-console [ + left-click <span class="Constant">4</span>, <span class="Constant">21</span> + ] + run [ + event-loop screen:address, console:address, <span class="Constant">3</span>:address:programming-environment-data + print-character screen:address, <span class="Constant">9251/␣/cursor</span> + ] + <span class="Comment"># trace now printed and cursor shouldn't have budged</span> + screen-should-contain [ + <span class="Constant"> . run (F4) .</span> + <span class="Constant"> .␣ ┊ .</span> + <span class="Constant"> .recipe foo [ ┊━━━━━━━━━━━━━━━━━━━.</span> + <span class="Constant"> . stash [abc] ┊ x.</span> + <span class="Constant"> .] ┊foo .</span> + <span class="Constant"> .┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┊abc .</span> + <span class="Constant"> . ┊━━━━━━━━━━━━━━━━━━━.</span> + <span class="Constant"> . ┊ .</span> + ] + screen-should-contain-in-color <span class="Constant">245/grey</span>, [ + <span class="Constant"> . .</span> + <span class="Constant"> . ┊ .</span> + <span class="Constant"> . ┊━━━━━━━━━━━━━━━━━━━.</span> + <span class="Constant"> . ┊ x.</span> + <span class="Constant"> . ┊ .</span> + <span class="Constant"> .┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┊abc .</span> + <span class="Constant"> . ┊━━━━━━━━━━━━━━━━━━━.</span> + <span class="Constant"> . ┊ .</span> + ] + <span class="Comment"># click again on the same region</span> + assume-console [ + left-click <span class="Constant">4</span>, <span class="Constant">25</span> + ] + run [ + event-loop screen:address, console:address, <span class="Constant">3</span>:address:programming-environment-data + print-character screen:address, <span class="Constant">9251/␣/cursor</span> + ] + <span class="Comment"># trace hidden again</span> + screen-should-contain [ + <span class="Constant"> . run (F4) .</span> + <span class="Constant"> .␣ ┊ .</span> + <span class="Constant"> .recipe foo [ ┊━━━━━━━━━━━━━━━━━━━.</span> + <span class="Constant"> . stash [abc] ┊ x.</span> + <span class="Constant"> .] ┊foo .</span> +<span class="Constant"> .┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┊━━━━━━━━━━━━━━━━━━━.</span> + <span class="Constant"> . ┊ .</span> + ] +] + +<span class="muScenario">scenario</span> sandbox-shows-app-trace-and-result [ + $close-trace <span class="Comment"># trace too long</span> + assume-screen <span class="Constant">40/width</span>, <span class="Constant">10/height</span> + <span class="Comment"># basic recipe</span> + <span class="Constant">1</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[ </span> +<span class="Constant">recipe foo [</span> +<span class="Constant"> stash [abc]</span> + add <span class="Constant">2</span>, <span class="Constant">2</span> +]] + <span class="Comment"># run it</span> + <span class="Constant">2</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[foo]</span> + assume-console [ + press F4 + ] + <span class="Constant">3</span>:address:programming-environment-data<span class="Special"> <- </span>new-programming-environment screen:address, <span class="Constant">1</span>:address:array:character, <span class="Constant">2</span>:address:array:character + event-loop screen:address, console:address, <span class="Constant">3</span>:address:programming-environment-data + screen-should-contain [ + <span class="Constant"> . run (F4) .</span> + <span class="Constant"> . ┊ .</span> + <span class="Constant"> .recipe foo [ ┊━━━━━━━━━━━━━━━━━━━.</span> + <span class="Constant"> . stash [abc] ┊ x.</span> + <span class="Constant"> . add 2, 2 ┊foo .</span> + <span class="Constant"> .] ┊4 .</span> +<span class="Constant"> .┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┊━━━━━━━━━━━━━━━━━━━.</span> + <span class="Constant"> . ┊ .</span> + ] + <span class="Comment"># click on the 'foo' line in the sandbox</span> + assume-console [ + left-click <span class="Constant">4</span>, <span class="Constant">21</span> + ] + run [ + event-loop screen:address, console:address, <span class="Constant">3</span>:address:programming-environment-data + ] + <span class="Comment"># trace now printed</span> + screen-should-contain [ + <span class="Constant"> . run (F4) .</span> + <span class="Constant"> . ┊ .</span> + <span class="Constant"> .recipe foo [ ┊━━━━━━━━━━━━━━━━━━━.</span> + <span class="Constant"> . stash [abc] ┊ x.</span> + <span class="Constant"> . add 2, 2 ┊foo .</span> + <span class="Constant"> .] ┊abc .</span> + <span class="Constant"> .┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┊4 .</span> + <span class="Constant"> . ┊━━━━━━━━━━━━━━━━━━━.</span> + <span class="Constant"> . ┊ .</span> + ] +] + +<span class="muData">container</span> sandbox-data [ + trace:address:array:character + display-trace?:boolean +] + +<span class="Comment"># replaced in a later layer</span> +<span class="muRecipe">recipe!</span> update-sandbox [ + <span class="Constant">local-scope</span> + sandbox:address:sandbox-data<span class="Special"> <- </span><span class="Constant">next-ingredient</span> + data:address:array:character<span class="Special"> <- </span>get *sandbox, <span class="Constant">data:offset</span> + response:address:address:array:character<span class="Special"> <- </span>get-address *sandbox, <span class="Constant">response:offset</span> + trace:address:address:array:character<span class="Special"> <- </span>get-address *sandbox, <span class="Constant">trace:offset</span> + fake-screen:address:address:screen<span class="Special"> <- </span>get-address *sandbox, <span class="Constant">screen:offset</span> + *response, _, *fake-screen, *trace<span class="Special"> <- </span>run-interactive data +] + +<span class="Comment"># clicks on sandbox code toggle its display-trace? flag</span> +<span class="muRecipe">after</span> <span class="Constant"><global-touch></span> [ + <span class="Comment"># right side of screen? check if it's inside the code of any sandbox</span> + <span class="Delimiter">{</span> + sandbox-left-margin:number<span class="Special"> <- </span>get *current-sandbox, <span class="Constant">left:offset</span> + click-column:number<span class="Special"> <- </span>get *t, <span class="Constant">column:offset</span> + on-sandbox-side?:boolean<span class="Special"> <- </span>greater-or-equal click-column, sandbox-left-margin + <span class="muControl">break-unless</span> on-sandbox-side? + first-sandbox:address:sandbox-data<span class="Special"> <- </span>get *env, <span class="Constant">sandbox:offset</span> + <span class="muControl">break-unless</span> first-sandbox + first-sandbox-begins:number<span class="Special"> <- </span>get *first-sandbox, <span class="Constant">starting-row-on-screen:offset</span> + click-row:number<span class="Special"> <- </span>get *t, <span class="Constant">row:offset</span> + below-sandbox-editor?:boolean<span class="Special"> <- </span>greater-or-equal click-row, first-sandbox-begins + <span class="muControl">break-unless</span> below-sandbox-editor? + <span class="Comment"># identify the sandbox whose code is being clicked on</span> + sandbox:address:sandbox-data<span class="Special"> <- </span>find-click-in-sandbox-code env, click-row + <span class="muControl">break-unless</span> sandbox + <span class="Comment"># toggle its display-trace? property</span> + x:address:boolean<span class="Special"> <- </span>get-address *sandbox, <span class="Constant">display-trace?:offset</span> + *x<span class="Special"> <- </span>not *x + hide-screen screen + screen<span class="Special"> <- </span>render-sandbox-side screen, env, <span class="Constant">1/clear</span> + screen<span class="Special"> <- </span>update-cursor screen, recipes, current-sandbox, *sandbox-in-focus? + <span class="Comment"># no change in cursor</span> + show-screen screen + <span class="muControl">loop</span> <span class="Constant">+next-event:label</span> + <span class="Delimiter">}</span> +] + +<span class="muRecipe">recipe</span> find-click-in-sandbox-code [ + <span class="Constant">local-scope</span> + env:address:programming-environment-data<span class="Special"> <- </span><span class="Constant">next-ingredient</span> + click-row:number<span class="Special"> <- </span><span class="Constant">next-ingredient</span> + <span class="Comment"># assert click-row >= sandbox.starting-row-on-screen</span> + sandbox:address:sandbox-data<span class="Special"> <- </span>get *env, <span class="Constant">sandbox:offset</span> + start:number<span class="Special"> <- </span>get *sandbox, <span class="Constant">starting-row-on-screen:offset</span> + clicked-on-sandboxes?:boolean<span class="Special"> <- </span>greater-or-equal click-row, start + assert clicked-on-sandboxes?, <span class="Constant">[extract-sandbox called on click to sandbox editor]</span> + <span class="Comment"># while click-row < sandbox.next-sandbox.starting-row-on-screen</span> + <span class="Delimiter">{</span> + next-sandbox:address:sandbox-data<span class="Special"> <- </span>get *sandbox, <span class="Constant">next-sandbox:offset</span> + <span class="muControl">break-unless</span> next-sandbox + next-start:number<span class="Special"> <- </span>get *next-sandbox, <span class="Constant">starting-row-on-screen:offset</span> + found?:boolean<span class="Special"> <- </span>lesser-than click-row, next-start + <span class="muControl">break-if</span> found? + sandbox<span class="Special"> <- </span>copy next-sandbox + <span class="muControl">loop</span> + <span class="Delimiter">}</span> + <span class="Comment"># return sandbox if click is in its code region</span> + code-ending-row:number<span class="Special"> <- </span>get *sandbox, <span class="Constant">code-ending-row-on-screen:offset</span> + click-above-response?:boolean<span class="Special"> <- </span>lesser-than click-row, code-ending-row + start:number<span class="Special"> <- </span>get *sandbox, <span class="Constant">starting-row-on-screen:offset</span> + click-below-menu?:boolean<span class="Special"> <- </span>greater-than click-row, start + click-on-sandbox-code?:boolean<span class="Special"> <- </span>and click-above-response?, click-below-menu? + <span class="Delimiter">{</span> + <span class="muControl">break-if</span> click-on-sandbox-code? + <span class="muControl">reply</span> <span class="Constant">0/no-click-in-sandbox-output</span> + <span class="Delimiter">}</span> + <span class="muControl">reply</span> sandbox +] + +<span class="Comment"># when rendering a sandbox, dump its trace before response/warning if display-trace? property is set</span> +<span class="muRecipe">after</span> <span class="Constant"><render-sandbox-results></span> [ + <span class="Delimiter">{</span> + display-trace?:boolean<span class="Special"> <- </span>get *sandbox, <span class="Constant">display-trace?:offset</span> + <span class="muControl">break-unless</span> display-trace? + sandbox-trace:address:array:character<span class="Special"> <- </span>get *sandbox, <span class="Constant">trace:offset</span> + <span class="muControl">break-unless</span> sandbox-trace <span class="Comment"># nothing to print; move on</span> + row, screen<span class="Special"> <- </span>render-string, screen, sandbox-trace, left, right, <span class="Constant">245/grey</span>, row + <span class="Delimiter">}</span> +] +</pre> +</body> +</html> +<!-- vim: set foldmethod=manual : --> diff --git a/html/edit/010-warnings.mu.html b/html/edit/010-warnings.mu.html new file mode 100644 index 00000000..ca9008b7 --- /dev/null +++ b/html/edit/010-warnings.mu.html @@ -0,0 +1,428 @@ +<!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/010-warnings.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; } +.muRecipe { color: #ff8700; } +.muData { color: #ffff00; } +.Special { color: #ff6060; } +.muScenario { color: #00af00; } +.Comment { color: #9090ff; } +.Constant { color: #00a0a0; } +.SalientComment { color: #00ffff; } +.Delimiter { color: #a04060; } +.muControl { color: #c0a020; } +--> +</style> + +<script type='text/javascript'> +<!-- + +--> +</script> +</head> +<body> +<pre id='vimCodeElement'> +<span class="SalientComment">## handling malformed programs</span> + +<span class="muData">container</span> programming-environment-data [ + recipe-warnings:address:array:character +] + +<span class="Comment"># copy code from recipe editor, persist, load into mu, save any warnings</span> +<span class="muRecipe">recipe!</span> update-recipes [ + <span class="Constant">local-scope</span> + env:address:programming-environment-data<span class="Special"> <- </span><span class="Constant">next-ingredient</span> + screen:address<span class="Special"> <- </span><span class="Constant">next-ingredient</span> + recipes:address:editor-data<span class="Special"> <- </span>get *env, <span class="Constant">recipes:offset</span> + in:address:array:character<span class="Special"> <- </span>editor-contents recipes + save <span class="Constant">[recipes.mu]</span>, in + recipe-warnings:address:address:array:character<span class="Special"> <- </span>get-address *env, <span class="Constant">recipe-warnings:offset</span> + *recipe-warnings<span class="Special"> <- </span>reload in + <span class="Comment"># if recipe editor has errors, stop</span> + <span class="Delimiter">{</span> + <span class="muControl">break-unless</span> *recipe-warnings + status:address:array:character<span class="Special"> <- </span>new <span class="Constant">[errors found]</span> + update-status screen, status, <span class="Constant">1/red</span> + <span class="muControl">reply</span> <span class="Constant">1/errors-found</span>, env/same-as-ingredient:<span class="Constant">0</span>, screen/same-as-ingredient:<span class="Constant">1</span> + <span class="Delimiter">}</span> + <span class="muControl">reply</span> <span class="Constant">0/no-errors-found</span>, env/same-as-ingredient:<span class="Constant">0</span>, screen/same-as-ingredient:<span class="Constant">1</span> +] + +<span class="muRecipe">before</span> <span class="Constant"><render-components-end></span> [ + trace <span class="Constant">11</span>, <span class="Constant">[app]</span>, <span class="Constant">[render status]</span> + recipe-warnings:address:array:character<span class="Special"> <- </span>get *env, <span class="Constant">recipe-warnings:offset</span> + <span class="Delimiter">{</span> + <span class="muControl">break-unless</span> recipe-warnings + status:address:array:character<span class="Special"> <- </span>new <span class="Constant">[errors found]</span> + update-status screen, status, <span class="Constant">1/red</span> + <span class="Delimiter">}</span> +] + +<span class="muRecipe">before</span> <span class="Constant"><render-recipe-components-end></span> [ + <span class="Delimiter">{</span> + recipe-warnings:address:array:character<span class="Special"> <- </span>get *env, <span class="Constant">recipe-warnings:offset</span> + <span class="muControl">break-unless</span> recipe-warnings + row, screen<span class="Special"> <- </span>render-string screen, recipe-warnings, left, right, <span class="Constant">1/red</span>, row + <span class="Delimiter">}</span> +] + +<span class="muData">container</span> sandbox-data [ + warnings:address:array:character +] + +<span class="muRecipe">recipe!</span> update-sandbox [ + <span class="Constant">local-scope</span> + sandbox:address:sandbox-data<span class="Special"> <- </span><span class="Constant">next-ingredient</span> + data:address:array:character<span class="Special"> <- </span>get *sandbox, <span class="Constant">data:offset</span> + response:address:address:array:character<span class="Special"> <- </span>get-address *sandbox, <span class="Constant">response:offset</span> + warnings:address:address:array:character<span class="Special"> <- </span>get-address *sandbox, <span class="Constant">warnings:offset</span> + trace:address:address:array:character<span class="Special"> <- </span>get-address *sandbox, <span class="Constant">trace:offset</span> + fake-screen:address:address:screen<span class="Special"> <- </span>get-address *sandbox, <span class="Constant">screen:offset</span> + *response, *warnings, *fake-screen, *trace, completed?:boolean<span class="Special"> <- </span>run-interactive data + <span class="Delimiter">{</span> + <span class="muControl">break-if</span> *warnings + <span class="muControl">break-if</span> completed?:boolean + *warnings<span class="Special"> <- </span>new <span class="Constant">[took too long!</span> +<span class="Constant">]</span> + <span class="Delimiter">}</span> +] + +<span class="muRecipe">after</span> <span class="Constant"><render-sandbox-results></span> [ + <span class="Delimiter">{</span> + sandbox-warnings:address:array:character<span class="Special"> <- </span>get *sandbox, <span class="Constant">warnings:offset</span> + <span class="muControl">break-unless</span> sandbox-warnings + *response-starting-row<span class="Special"> <- </span>copy <span class="Constant">0</span> <span class="Comment"># no response</span> + row, screen<span class="Special"> <- </span>render-string screen, sandbox-warnings, left, right, <span class="Constant">1/red</span>, row + <span class="muControl">jump</span> <span class="Constant">+render-sandbox-end:label</span> + <span class="Delimiter">}</span> +] + +<span class="muScenario">scenario</span> run-shows-warnings-in-get [ + $close-trace <span class="Comment"># trace too long</span> + assume-screen <span class="Constant">100/width</span>, <span class="Constant">15/height</span> + <span class="Constant">1</span>:address:array:character<span class="Special"> <- </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>] + <span class="Constant">2</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[foo]</span> + <span class="Constant">3</span>:address:programming-environment-data<span class="Special"> <- </span>new-programming-environment screen:address, <span class="Constant">1</span>:address:array:character, <span class="Constant">2</span>:address:array:character + assume-console [ + press F4 + ] + run [ + event-loop screen:address, console:address, <span class="Constant">3</span>:address:programming-environment-data + ] + screen-should-contain [ + <span class="Constant"> . errors found run (F4) .</span> + <span class="Constant"> . ┊foo .</span> + <span class="Constant"> .recipe foo [ ┊━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━.</span> + <span class="Constant"> . get 123:number, foo:offset ┊ .</span> + <span class="Constant"> .] ┊ .</span> + <span class="Constant"> .unknown element foo in container number ┊ .</span> + <span class="Constant"> .┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┊ .</span> + <span class="Constant"> . ┊ .</span> + ] + screen-should-contain-in-color <span class="Constant">1/red</span>, [ + <span class="Constant"> . errors found .</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 [ + $close-trace <span class="Comment"># trace too long</span> + assume-screen <span class="Constant">100/width</span>, <span class="Constant">15/height</span> + <span class="Constant">1</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[ </span> +<span class="Constant">recipe foo [</span> +<span class="Constant"> x <- copy 0</span> +<span class="Constant">]</span>] + <span class="Constant">2</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[foo]</span> + <span class="Constant">3</span>:address:programming-environment-data<span class="Special"> <- </span>new-programming-environment screen:address, <span class="Constant">1</span>:address:array:character, <span class="Constant">2</span>:address:array:character + assume-console [ + press F4 + ] + run [ + event-loop screen:address, console:address, <span class="Constant">3</span>:address:programming-environment-data + ] + screen-should-contain [ + <span class="Constant"> . errors found run (F4) .</span> + <span class="Constant"> . ┊foo .</span> + <span class="Constant"> .recipe foo [ ┊━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━.</span> + <span class="Constant"> . x <- copy 0 ┊ .</span> + <span class="Constant"> .] ┊ .</span> + <span class="Constant"> .missing type in 'x <- copy 0' ┊ .</span> + <span class="Constant"> .┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┊ .</span> + <span class="Constant"> . ┊ .</span> + ] +] + +<span class="muScenario">scenario</span> run-shows-unbalanced-bracket-warnings [ + $close-trace <span class="Comment"># trace too long</span> + assume-screen <span class="Constant">100/width</span>, <span class="Constant">15/height</span> + <span class="Comment"># recipe is incomplete (unbalanced '[')</span> + <span class="Constant">1</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[ </span> +<span class="Constant">recipe foo «</span> +<span class="Constant"> x <- copy 0</span> +<span class="Constant">]</span> + string-replace <span class="Constant">1</span>:address:array:character, <span class="Constant">171/«</span>, <span class="Constant">91</span> <span class="Comment"># '['</span> + <span class="Constant">2</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[foo]</span> + <span class="Constant">3</span>:address:programming-environment-data<span class="Special"> <- </span>new-programming-environment screen:address, <span class="Constant">1</span>:address:array:character, <span class="Constant">2</span>:address:array:character + assume-console [ + press F4 + ] + run [ + event-loop screen:address, console:address, <span class="Constant">3</span>:address:programming-environment-data + ] + screen-should-contain [ + <span class="Constant"> . errors found run (F4) .</span> + <span class="Constant"> . ┊foo .</span> + <span class="Constant"> .recipe foo \\\[ ┊━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━.</span> + <span class="Constant"> . x <- copy 0 ┊ .</span> + <span class="Constant"> . ┊ .</span> + <span class="Constant"> .9: unbalanced '\\\[' for recipe ┊ .</span> + <span class="Constant"> .┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┊ .</span> + <span class="Constant"> . ┊ .</span> + ] +] + +<span class="muScenario">scenario</span> run-shows-get-on-non-container-warnings [ + $close-trace <span class="Comment"># trace too long</span> + assume-screen <span class="Constant">100/width</span>, <span class="Constant">15/height</span> + <span class="Constant">1</span>:address:array:character<span class="Special"> <- </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>] + <span class="Constant">2</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[foo]</span> + <span class="Constant">3</span>:address:programming-environment-data<span class="Special"> <- </span>new-programming-environment screen:address, <span class="Constant">1</span>:address:array:character, <span class="Constant">2</span>:address:array:character + assume-console [ + press F4 + ] + run [ + event-loop screen:address, console:address, <span class="Constant">3</span>:address:programming-environment-data + ] + screen-should-contain [ + <span class="Constant"> . run (F4) .</span> + <span class="Constant"> . ┊ .</span> + <span class="Constant"> .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: first ingredient of 'get' should be a conta↩.</span> + <span class="Constant"> .┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┊iner, but got x:address:point .</span> + <span class="Constant"> . ┊━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━.</span> + <span class="Constant"> . ┊ .</span> + ] +] + +<span class="muScenario">scenario</span> run-shows-non-literal-get-argument-warnings [ + $close-trace <span class="Comment"># trace too long</span> + assume-screen <span class="Constant">100/width</span>, <span class="Constant">15/height</span> + <span class="Constant">1</span>:address:array:character<span class="Special"> <- </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, x:number</span> +<span class="Constant">]</span>] + <span class="Constant">2</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[foo]</span> + <span class="Constant">3</span>:address:programming-environment-data<span class="Special"> <- </span>new-programming-environment screen:address, <span class="Constant">1</span>:address:array:character, <span class="Constant">2</span>:address:array:character + assume-console [ + press F4 + ] + run [ + event-loop screen:address, console:address, <span class="Constant">3</span>:address:programming-environment-data + ] + screen-should-contain [ + <span class="Constant"> . errors found run (F4) .</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, 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="muScenario">scenario</span> run-shows-warnings-everytime [ + $close-trace <span class="Comment"># trace too long</span> + <span class="Comment"># try to run a file with an error</span> + assume-screen <span class="Constant">100/width</span>, <span class="Constant">15/height</span> + <span class="Constant">1</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[ </span> +<span class="Constant">recipe foo [</span> +<span class="Constant"> x:number <- copy y:number</span> +<span class="Constant">]</span>] + <span class="Constant">2</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[foo]</span> + <span class="Constant">3</span>:address:programming-environment-data<span class="Special"> <- </span>new-programming-environment screen:address, <span class="Constant">1</span>:address:array:character, <span class="Constant">2</span>:address:array:character + assume-console [ + press F4 + ] + run [ + event-loop screen:address, console:address, <span class="Constant">3</span>:address:programming-environment-data + ] + screen-should-contain [ + <span class="Constant"> . errors found run (F4) .</span> + <span class="Constant"> . ┊foo .</span> + <span class="Constant"> .recipe foo [ ┊━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━.</span> + <span class="Constant"> . x:number <- copy y:number ┊ .</span> + <span class="Constant"> .] ┊ .</span> + <span class="Constant"> .use before set: y in foo ┊ .</span> + <span class="Constant"> .┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┊ .</span> + <span class="Constant"> . ┊ .</span> + ] + <span class="Comment"># rerun the file, check for the same error</span> + assume-console [ + press F4 + ] + run [ + event-loop screen:address, console:address, <span class="Constant">3</span>:address:programming-environment-data + ] + screen-should-contain [ + <span class="Constant"> . errors found run (F4) .</span> + <span class="Constant"> . ┊foo .</span> + <span class="Constant"> .recipe foo [ ┊━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━.</span> + <span class="Constant"> . x:number <- copy y:number ┊ .</span> + <span class="Constant"> .] ┊ .</span> + <span class="Constant"> .use before set: y in foo ┊ .</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</span> + assume-screen <span class="Constant">100/width</span>, <span class="Constant">10/height</span> + <span class="Comment"># left editor is empty</span> + <span class="Constant">1</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[]</span> + <span class="Comment"># right editor contains an illegal instruction</span> + <span class="Constant">2</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[get 1234:number, foo:offset]</span> + <span class="Constant">3</span>:address:programming-environment-data<span class="Special"> <- </span>new-programming-environment screen:address, <span class="Constant">1</span>:address:array:character, <span class="Constant">2</span>:address:array:character + <span class="Comment"># run the code in the editors</span> + assume-console [ + press F4 + ] + run [ + event-loop screen:address, console:address, <span class="Constant">3</span>:address:programming-environment-data + ] + <span class="Comment"># check that screen prints error message in red</span> + screen-should-contain [ + <span class="Constant"> . run (F4) .</span> + <span class="Constant"> . ┊ .</span> +<span class="Constant"> .┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┊━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━.</span> + <span class="Constant"> . ┊ x.</span> + <span class="Constant"> . ┊get 1234:number, foo:offset .</span> + <span class="Constant"> . ┊unknown element foo in container number .</span> + <span class="Constant"> . ┊━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━.</span> + <span class="Constant"> . ┊ .</span> + ] + screen-should-contain-in-color <span class="Constant">7/white</span>, [ + <span class="Constant"> . .</span> + <span class="Constant"> . .</span> + <span class="Constant"> . .</span> + <span class="Constant"> . .</span> + <span class="Constant"> . get 1234:number, foo:offset .</span> + <span class="Constant"> . .</span> + <span class="Constant"> . .</span> + <span class="Constant"> . .</span> + ] + screen-should-contain-in-color <span class="Constant">1/red</span>, [ + <span class="Constant"> . .</span> + <span class="Constant"> . .</span> + <span class="Constant"> . .</span> + <span class="Constant"> . .</span> + <span class="Constant"> . .</span> + <span class="Constant"> . unknown element foo in container number .</span> + <span class="Constant"> . .</span> + ] + screen-should-contain-in-color <span class="Constant">245/grey</span>, [ + <span class="Constant"> . .</span> + <span class="Constant"> . ┊ .</span> +<span class="Constant"> .┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┊━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━.</span> + <span class="Constant"> . ┊ x.</span> + <span class="Constant"> . ┊ .</span> + <span class="Constant"> . ┊ .</span> + <span class="Constant"> . ┊━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━.</span> + <span class="Constant"> . ┊ .</span> + ] +] + +<span class="muScenario">scenario</span> run-instruction-and-print-warnings-only-once [ + $close-trace <span class="Comment"># trace too long</span> + assume-screen <span class="Constant">100/width</span>, <span class="Constant">10/height</span> + <span class="Comment"># left editor is empty</span> + <span class="Constant">1</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[]</span> + <span class="Comment"># right editor contains an illegal instruction</span> + <span class="Constant">2</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[get 1234:number, foo:offset]</span> + <span class="Constant">3</span>:address:programming-environment-data<span class="Special"> <- </span>new-programming-environment screen:address, <span class="Constant">1</span>:address:array:character, <span class="Constant">2</span>:address:array:character + <span class="Comment"># run the code in the editors multiple times</span> + assume-console [ + press F4 + press F4 + ] + run [ + event-loop screen:address, console:address, <span class="Constant">3</span>:address:programming-environment-data + ] + <span class="Comment"># check that screen prints error message just once</span> + screen-should-contain [ + <span class="Constant"> . run (F4) .</span> + <span class="Constant"> . ┊ .</span> +<span class="Constant"> .┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┊━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━.</span> + <span class="Constant"> . ┊ x.</span> + <span class="Constant"> . ┊get 1234:number, foo:offset .</span> + <span class="Constant"> . ┊unknown element foo in container number .</span> + <span class="Constant"> . ┊━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━.</span> + <span class="Constant"> . ┊ .</span> + ] +] + +<span class="muScenario">scenario</span> sandbox-can-handle-infinite-loop [ + $close-trace <span class="Comment"># trace too long</span> + assume-screen <span class="Constant">100/width</span>, <span class="Constant">20/height</span> + <span class="Comment"># left editor is empty</span> + <span class="Constant">1</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[recipe foo [</span> +<span class="Constant"> {</span> +<span class="Constant"> loop</span> +<span class="Constant"> }</span> +<span class="Constant">]</span>] + <span class="Comment"># right editor contains an instruction</span> + <span class="Constant">2</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[foo]</span> + <span class="Constant">3</span>:address:programming-environment-data<span class="Special"> <- </span>new-programming-environment screen:address, <span class="Constant">1</span>:address:array:character, <span class="Constant">2</span>:address:array:character + <span class="Comment"># run the sandbox</span> + assume-console [ + press F4 + ] + run [ + event-loop screen:address, console:address, <span class="Constant">3</span>:address:programming-environment-data + ] + screen-should-contain [ + <span class="Constant"> . run (F4) .</span> + <span class="Constant"> .recipe foo [ ┊ .</span> + <span class="Constant"> . { ┊━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━.</span> + <span class="Constant"> . loop ┊ x.</span> + <span class="Constant"> . } ┊foo .</span> + <span class="Constant"> .] ┊took too long! .</span> +<span class="Constant"> .┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┊━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━.</span> + <span class="Constant"> . ┊ .</span> + ] +] +</pre> +</body> +</html> +<!-- vim: set foldmethod=manual : --> diff --git a/html/edit/011-editor-undo.mu.html b/html/edit/011-editor-undo.mu.html new file mode 100644 index 00000000..37417b7f --- /dev/null +++ b/html/edit/011-editor-undo.mu.html @@ -0,0 +1,2095 @@ +<!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/011-editor-undo.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; } +.muRecipe { color: #ff8700; } +.muData { color: #ffff00; } +.Special { color: #ff6060; } +.muScenario { color: #00af00; } +.Comment { color: #9090ff; } +.Constant { color: #00a0a0; } +.SalientComment { color: #00ffff; } +.Delimiter { color: #a04060; } +.muControl { color: #c0a020; } +--> +</style> + +<script type='text/javascript'> +<!-- + +--> +</script> +</head> +<body> +<pre id='vimCodeElement'> +<span class="SalientComment">## undo/redo</span> + +<span class="Comment"># for every undoable event, create a type of *operation* that contains all the</span> +<span class="Comment"># information needed to reverse it</span> +<span class="muData">exclusive-container</span> operation [ + typing:insert-operation + move:move-operation + delete:delete-operation +] + +<span class="muData">container</span> insert-operation [ + before-row:number + before-column:number + before-top-of-screen:address:duplex-list:character + after-row:number + after-column:number + after-top-of-screen:address:duplex-list:character + <span class="Comment"># inserted text is from 'insert-from' until 'insert-until'; list doesn't have to terminate</span> + insert-from:address:duplex-list:character + insert-until:address:duplex-list:character + tag:number <span class="Comment"># event causing this operation; might be used to coalesce runs of similar events</span> + <span class="Comment"># 0: no coalesce (enter+indent)</span> + <span class="Comment"># 1: regular alphanumeric characters</span> +] + +<span class="muData">container</span> move-operation [ + before-row:number + before-column:number + before-top-of-screen:address:duplex-list:character + after-row:number + after-column:number + after-top-of-screen:address:duplex-list:character + tag:number <span class="Comment"># event causing this operation; might be used to coalesce runs of similar events</span> + <span class="Comment"># 0: no coalesce (touch events, etc)</span> + <span class="Comment"># 1: left arrow</span> + <span class="Comment"># 2: right arrow</span> + <span class="Comment"># 3: up arrow</span> + <span class="Comment"># 4: down arrow</span> +] + +<span class="muData">container</span> delete-operation [ + before-row:number + before-column:number + before-top-of-screen:address:duplex-list:character + after-row:number + after-column:number + after-top-of-screen:address:duplex-list:character + deleted-text:address:duplex-list:character + delete-from:address:duplex-list:character + delete-until:address:duplex-list:character + tag:number <span class="Comment"># event causing this operation; might be used to coalesce runs of similar events</span> + <span class="Comment"># 0: no coalesce (ctrl-k, ctrl-u)</span> + <span class="Comment"># 1: backspace</span> + <span class="Comment"># 2: delete</span> +] + +<span class="Comment"># every editor accumulates a list of operations to undo/redo</span> +<span class="muData">container</span> editor-data [ + undo:address:list:address:operation + redo:address:list:address:operation +] + +<span class="Comment"># ctrl-z - undo operation</span> +<span class="muRecipe">after</span> <span class="Constant"><handle-special-character></span> [ + <span class="Delimiter">{</span> + undo?:boolean<span class="Special"> <- </span>equal *c, <span class="Constant">26/ctrl-z</span> + <span class="muControl">break-unless</span> undo? + undo:address:address:list<span class="Special"> <- </span>get-address *editor, <span class="Constant">undo:offset</span> + <span class="muControl">break-unless</span> *undo + op:address:operation<span class="Special"> <- </span>first *undo + *undo<span class="Special"> <- </span>rest *undo + redo:address:address:list<span class="Special"> <- </span>get-address *editor, <span class="Constant">redo:offset</span> + *redo<span class="Special"> <- </span>push op, *redo +<span class="Constant"> <handle-undo></span> + <span class="muControl">reply</span> screen/same-as-ingredient:<span class="Constant">0</span>, editor/same-as-ingredient:<span class="Constant">1</span>, <span class="Constant">1/go-render</span> + <span class="Delimiter">}</span> +] + +<span class="Comment"># ctrl-y - redo operation</span> +<span class="muRecipe">after</span> <span class="Constant"><handle-special-character></span> [ + <span class="Delimiter">{</span> + redo?:boolean<span class="Special"> <- </span>equal *c, <span class="Constant">25/ctrl-y</span> + <span class="muControl">break-unless</span> redo? + redo:address:address:list<span class="Special"> <- </span>get-address *editor, <span class="Constant">redo:offset</span> + <span class="muControl">break-unless</span> *redo + op:address:operation<span class="Special"> <- </span>first *redo + *redo<span class="Special"> <- </span>rest *redo + undo:address:address:list<span class="Special"> <- </span>get-address *editor, <span class="Constant">undo:offset</span> + *undo<span class="Special"> <- </span>push op, *undo +<span class="Constant"> <handle-redo></span> + <span class="muControl">reply</span> screen/same-as-ingredient:<span class="Constant">0</span>, editor/same-as-ingredient:<span class="Constant">1</span>, <span class="Constant">1/go-render</span> + <span class="Delimiter">}</span> +] + +<span class="Comment"># undo typing</span> + +<span class="muScenario">scenario</span> editor-can-undo-typing [ + <span class="Comment"># create an editor and type a character</span> + assume-screen <span class="Constant">10/width</span>, <span class="Constant">5/height</span> + <span class="Constant">1</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[]</span> + <span class="Constant">2</span>:address:editor-data<span class="Special"> <- </span>new-editor <span class="Constant">1</span>:address:array:character, screen:address, <span class="Constant">0/left</span>, <span class="Constant">10/right</span> + editor-render screen, <span class="Constant">2</span>:address:editor-data + assume-console [ + type <span class="Constant">[0]</span> + ] + editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data + <span class="Comment"># undo</span> + assume-console [ + press ctrl-z + ] + run [ + editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data + ] + <span class="Comment"># character should be gone</span> + screen-should-contain [ + <span class="Constant"> . .</span> + <span class="Constant"> . .</span> +<span class="Constant"> .┈┈┈┈┈┈┈┈┈┈.</span> + <span class="Constant"> . .</span> + ] + <span class="Comment"># cursor should be in the right place</span> + assume-console [ + type <span class="Constant">[1]</span> + ] + run [ + editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data + ] + screen-should-contain [ + <span class="Constant"> . .</span> + <span class="Constant"> .1 .</span> +<span class="Constant"> .┈┈┈┈┈┈┈┈┈┈.</span> + <span class="Constant"> . .</span> + ] +] + +<span class="Comment"># save operation to undo</span> +<span class="muRecipe">after</span> <span class="Constant"><insert-character-begin></span> [ + top-before:address:duplex-list<span class="Special"> <- </span>get *editor, <span class="Constant">top-of-screen:offset</span> + cursor-before:address:duplex-list<span class="Special"> <- </span>copy *before-cursor +] +<span class="muRecipe">before</span> <span class="Constant"><insert-character-end></span> [ + top-after:address:duplex-list<span class="Special"> <- </span>get *editor, <span class="Constant">top-of-screen:offset</span> + undo:address:address:list<span class="Special"> <- </span>get-address *editor, <span class="Constant">undo:offset</span> + <span class="Delimiter">{</span> + <span class="Comment"># if previous operation was an insert, coalesce this operation with it</span> + <span class="muControl">break-unless</span> *undo + op:address:operation<span class="Special"> <- </span>first *undo + typing:address:insert-operation<span class="Special"> <- </span>maybe-convert *op, <span class="Constant">typing:variant</span> + <span class="muControl">break-unless</span> typing + previous-coalesce-tag:number<span class="Special"> <- </span>get *typing, <span class="Constant">tag:offset</span> + <span class="muControl">break-unless</span> previous-coalesce-tag + insert-until:address:address:duplex-list<span class="Special"> <- </span>get-address *typing, <span class="Constant">insert-until:offset</span> + *insert-until<span class="Special"> <- </span>next-duplex *before-cursor + after-row:address:number<span class="Special"> <- </span>get-address *typing, <span class="Constant">after-row:offset</span> + *after-row<span class="Special"> <- </span>copy *cursor-row + after-column:address:number<span class="Special"> <- </span>get-address *typing, <span class="Constant">after-column:offset</span> + *after-column<span class="Special"> <- </span>copy *cursor-column + after-top:address:number<span class="Special"> <- </span>get-address *typing, <span class="Constant">after-top-of-screen:offset</span> + *after-top<span class="Special"> <- </span>get *editor, <span class="Constant">top-of-screen:offset</span> + <span class="muControl">break</span> <span class="Constant">+done-adding-insert-operation:label</span> + <span class="Delimiter">}</span> + <span class="Comment"># if not, create a new operation</span> + insert-from:address:duplex-list<span class="Special"> <- </span>next-duplex cursor-before + insert-to:address:duplex-list<span class="Special"> <- </span>next-duplex insert-from + op:address:operation<span class="Special"> <- </span>new <span class="Constant">operation:type</span> + *op<span class="Special"> <- </span>merge <span class="Constant">0/insert-operation</span>, save-row/<span class="muRecipe">before</span>, save-column/<span class="muRecipe">before</span>, top-before, *cursor-row/<span class="muRecipe">after</span>, *cursor-column/<span class="muRecipe">after</span>, top-after, insert-from, insert-to, <span class="Constant">1/coalesce</span> + editor<span class="Special"> <- </span>add-operation editor, op +<span class="Constant"> +done-adding-insert-operation</span> +] + +<span class="Comment"># enter operations never coalesce with typing before or after</span> +<span class="muRecipe">after</span> <span class="Constant"><insert-enter-begin></span> [ + cursor-row-before:number<span class="Special"> <- </span>copy *cursor-row + cursor-column-before:number<span class="Special"> <- </span>copy *cursor-column + top-before:address:duplex-list<span class="Special"> <- </span>get *editor, <span class="Constant">top-of-screen:offset</span> + cursor-before:address:duplex-list<span class="Special"> <- </span>copy *before-cursor +] +<span class="muRecipe">before</span> <span class="Constant"><insert-enter-end></span> [ + top-after:address:duplex-list<span class="Special"> <- </span>get *editor, <span class="Constant">top-of-screen:offset</span> + <span class="Comment"># never coalesce</span> + insert-from:address:duplex-list<span class="Special"> <- </span>next-duplex cursor-before + insert-to:address:duplex-list<span class="Special"> <- </span>next-duplex *before-cursor + op:address:operation<span class="Special"> <- </span>new <span class="Constant">operation:type</span> + *op<span class="Special"> <- </span>merge <span class="Constant">0/insert-operation</span>, cursor-row-before, cursor-column-before, top-before, *cursor-row/<span class="muRecipe">after</span>, *cursor-column/<span class="muRecipe">after</span>, top-after, insert-from, insert-to, <span class="Constant">0/never-coalesce</span> + editor<span class="Special"> <- </span>add-operation editor, op +] + +<span class="Comment"># Everytime you add a new operation to the undo stack, be sure to clear the</span> +<span class="Comment"># redo stack, because it's now obsolete.</span> +<span class="Comment"># Beware: since we're counting cursor moves as operations, this means just</span> +<span class="Comment"># moving the cursor can lose work on the undo stack.</span> +<span class="muRecipe">recipe</span> add-operation [ + <span class="Constant">local-scope</span> + editor:address:editor-data<span class="Special"> <- </span><span class="Constant">next-ingredient</span> + op:address:operation<span class="Special"> <- </span><span class="Constant">next-ingredient</span> + undo:address:address:list:address:operation<span class="Special"> <- </span>get-address *editor, <span class="Constant">undo:offset</span> + *undo<span class="Special"> <- </span>push op *undo + redo:address:address:list:address:operation<span class="Special"> <- </span>get-address *editor, <span class="Constant">redo:offset</span> + *redo<span class="Special"> <- </span>copy <span class="Constant">0</span> + <span class="muControl">reply</span> editor/same-as-ingredient:<span class="Constant">0</span> +] + +<span class="muRecipe">after</span> <span class="Constant"><handle-undo></span> [ + <span class="Delimiter">{</span> + typing:address:insert-operation<span class="Special"> <- </span>maybe-convert *op, <span class="Constant">typing:variant</span> + <span class="muControl">break-unless</span> typing + start:address:duplex-list<span class="Special"> <- </span>get *typing, <span class="Constant">insert-from:offset</span> + end:address:duplex-list<span class="Special"> <- </span>get *typing, <span class="Constant">insert-until:offset</span> + <span class="Comment"># assert cursor-row/cursor-column/top-of-screen match after-row/after-column/after-top-of-screen</span> + *before-cursor<span class="Special"> <- </span>prev-duplex start + remove-duplex-between *before-cursor, end + *cursor-row<span class="Special"> <- </span>get *typing, <span class="Constant">before-row:offset</span> + *cursor-column<span class="Special"> <- </span>get *typing, <span class="Constant">before-column:offset</span> + top:address:address:duplex-list<span class="Special"> <- </span>get *editor, <span class="Constant">top-of-screen:offset</span> + *top<span class="Special"> <- </span>get *typing, <span class="Constant">before-top-of-screen:offset</span> + <span class="Delimiter">}</span> +] + +<span class="muScenario">scenario</span> editor-can-undo-typing-multiple [ + <span class="Comment"># create an editor and type multiple characters</span> + assume-screen <span class="Constant">10/width</span>, <span class="Constant">5/height</span> + <span class="Constant">1</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[]</span> + <span class="Constant">2</span>:address:editor-data<span class="Special"> <- </span>new-editor <span class="Constant">1</span>:address:array:character, screen:address, <span class="Constant">0/left</span>, <span class="Constant">10/right</span> + editor-render screen, <span class="Constant">2</span>:address:editor-data + assume-console [ + type <span class="Constant">[012]</span> + ] + editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data + <span class="Comment"># undo</span> + assume-console [ + press ctrl-z + ] + run [ + editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data + ] + <span class="Comment"># all characters must be gone</span> + screen-should-contain [ + <span class="Constant"> . .</span> + <span class="Constant"> . .</span> +<span class="Constant"> .┈┈┈┈┈┈┈┈┈┈.</span> + <span class="Constant"> . .</span> + ] +] + +<span class="muScenario">scenario</span> editor-can-undo-typing-multiple-2 [ + <span class="Comment"># create an editor with some text</span> + assume-screen <span class="Constant">10/width</span>, <span class="Constant">5/height</span> + <span class="Constant">1</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[a]</span> + <span class="Constant">2</span>:address:editor-data<span class="Special"> <- </span>new-editor <span class="Constant">1</span>:address:array:character, screen:address, <span class="Constant">0/left</span>, <span class="Constant">10/right</span> + editor-render screen, <span class="Constant">2</span>:address:editor-data + <span class="Comment"># type some characters</span> + assume-console [ + type <span class="Constant">[012]</span> + ] + editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data + screen-should-contain [ + <span class="Constant"> . .</span> + <span class="Constant"> .012a .</span> +<span class="Constant"> .┈┈┈┈┈┈┈┈┈┈.</span> + <span class="Constant"> . .</span> + ] + <span class="Comment"># undo</span> + assume-console [ + press ctrl-z + ] + run [ + editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data + ] + <span class="Comment"># back to original text</span> + screen-should-contain [ + <span class="Constant"> . .</span> + <span class="Constant"> .a .</span> +<span class="Constant"> .┈┈┈┈┈┈┈┈┈┈.</span> + <span class="Constant"> . .</span> + ] + <span class="Comment"># cursor should be in the right place</span> + assume-console [ + type <span class="Constant">[3]</span> + ] + run [ + editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data + ] + screen-should-contain [ + <span class="Constant"> . .</span> + <span class="Constant"> .3a .</span> +<span class="Constant"> .┈┈┈┈┈┈┈┈┈┈.</span> + <span class="Constant"> . .</span> + ] +] + +<span class="muScenario">scenario</span> editor-can-undo-typing-enter [ + <span class="Comment"># create an editor with some text</span> + assume-screen <span class="Constant">10/width</span>, <span class="Constant">5/height</span> + <span class="Constant">1</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[ abc]</span> + <span class="Constant">2</span>:address:editor-data<span class="Special"> <- </span>new-editor <span class="Constant">1</span>:address:array:character, screen:address, <span class="Constant">0/left</span>, <span class="Constant">10/right</span> + editor-render screen, <span class="Constant">2</span>:address:editor-data + <span class="Comment"># new line</span> + assume-console [ + left-click <span class="Constant">1</span>, <span class="Constant">8</span> + press enter + ] + editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data + screen-should-contain [ + <span class="Constant"> . .</span> + <span class="Constant"> . abc .</span> + <span class="Constant"> . .</span> +<span class="Constant"> .┈┈┈┈┈┈┈┈┈┈.</span> + <span class="Constant"> . .</span> + ] + <span class="Comment"># line is indented</span> + <span class="Constant">3</span>:number<span class="Special"> <- </span>get *<span class="Constant">2</span>:address:editor-data, <span class="Constant">cursor-row:offset</span> + <span class="Constant">4</span>:number<span class="Special"> <- </span>get *<span class="Constant">2</span>:address:editor-data, <span class="Constant">cursor-column:offset</span> + memory-should-contain [ + <span class="Constant">3</span><span class="Special"> <- </span><span class="Constant">2</span> + <span class="Constant">4</span><span class="Special"> <- </span><span class="Constant">2</span> + ] + <span class="Comment"># undo</span> + assume-console [ + press ctrl-z + ] + run [ + editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data + ] + <span class="Constant">3</span>:number<span class="Special"> <- </span>get *<span class="Constant">2</span>:address:editor-data, <span class="Constant">cursor-row:offset</span> + <span class="Constant">4</span>:number<span class="Special"> <- </span>get *<span class="Constant">2</span>:address:editor-data, <span class="Constant">cursor-column:offset</span> + memory-should-contain [ + <span class="Constant">3</span><span class="Special"> <- </span><span class="Constant">1</span> + <span class="Constant">4</span><span class="Special"> <- </span><span class="Constant">5</span> + ] + <span class="Comment"># back to original text</span> + screen-should-contain [ + <span class="Constant"> . .</span> + <span class="Constant"> . abc .</span> +<span class="Constant"> .┈┈┈┈┈┈┈┈┈┈.</span> + <span class="Constant"> . .</span> + ] + <span class="Comment"># cursor should be at end of line</span> + assume-console [ + type <span class="Constant">[1]</span> + ] + run [ + editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data + ] + screen-should-contain [ + <span class="Constant"> . .</span> + <span class="Constant"> . abc1 .</span> +<span class="Constant"> .┈┈┈┈┈┈┈┈┈┈.</span> + <span class="Constant"> . .</span> + ] +] + +<span class="Comment"># redo typing</span> + +<span class="muScenario">scenario</span> editor-redo-typing [ + <span class="Comment"># create an editor, type something, undo</span> + assume-screen <span class="Constant">10/width</span>, <span class="Constant">5/height</span> + <span class="Constant">1</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[a]</span> + <span class="Constant">2</span>:address:editor-data<span class="Special"> <- </span>new-editor <span class="Constant">1</span>:address:array:character, screen:address, <span class="Constant">0/left</span>, <span class="Constant">10/right</span> + editor-render screen, <span class="Constant">2</span>:address:editor-data + assume-console [ + type <span class="Constant">[012]</span> + press ctrl-z + ] + editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data + screen-should-contain [ + <span class="Constant"> . .</span> + <span class="Constant"> .a .</span> +<span class="Constant"> .┈┈┈┈┈┈┈┈┈┈.</span> + <span class="Constant"> . .</span> + ] + <span class="Comment"># redo</span> + assume-console [ + press ctrl-y + ] + run [ + editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data + ] + <span class="Comment"># all characters must be back</span> + screen-should-contain [ + <span class="Constant"> . .</span> + <span class="Constant"> .012a .</span> +<span class="Constant"> .┈┈┈┈┈┈┈┈┈┈.</span> + <span class="Constant"> . .</span> + ] + <span class="Comment"># cursor should be in the right place</span> + assume-console [ + type <span class="Constant">[3]</span> + ] + run [ + editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data + ] + screen-should-contain [ + <span class="Constant"> . .</span> + <span class="Constant"> .0123a .</span> +<span class="Constant"> .┈┈┈┈┈┈┈┈┈┈.</span> + <span class="Constant"> . .</span> + ] +] + +<span class="muRecipe">after</span> <span class="Constant"><handle-redo></span> [ + <span class="Delimiter">{</span> + typing:address:insert-operation<span class="Special"> <- </span>maybe-convert *op, <span class="Constant">typing:variant</span> + <span class="muControl">break-unless</span> typing + insert-from:address:duplex-list<span class="Special"> <- </span>get *typing, <span class="Constant">insert-from:offset</span> <span class="Comment"># ignore insert-to because it's already been spliced away</span> + <span class="Comment"># assert insert-to matches next-duplex(*before-cursor)</span> + insert-duplex-range *before-cursor, insert-from + <span class="Comment"># assert cursor-row/cursor-column/top-of-screen match after-row/after-column/after-top-of-screen</span> + *cursor-row<span class="Special"> <- </span>get *typing, <span class="Constant">after-row:offset</span> + *cursor-column<span class="Special"> <- </span>get *typing, <span class="Constant">after-column:offset</span> + top:address:address:duplex-list<span class="Special"> <- </span>get *editor, <span class="Constant">top-of-screen:offset</span> + *top<span class="Special"> <- </span>get *typing, <span class="Constant">after-top-of-screen:offset</span> + <span class="Delimiter">}</span> +] + +<span class="muScenario">scenario</span> editor-redo-typing-empty [ + <span class="Comment"># create an editor, type something, undo</span> + assume-screen <span class="Constant">10/width</span>, <span class="Constant">5/height</span> + <span class="Constant">1</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[]</span> + <span class="Constant">2</span>:address:editor-data<span class="Special"> <- </span>new-editor <span class="Constant">1</span>:address:array:character, screen:address, <span class="Constant">0/left</span>, <span class="Constant">10/right</span> + editor-render screen, <span class="Constant">2</span>:address:editor-data + assume-console [ + type <span class="Constant">[012]</span> + press ctrl-z + ] + editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data + screen-should-contain [ + <span class="Constant"> . .</span> + <span class="Constant"> . .</span> +<span class="Constant"> .┈┈┈┈┈┈┈┈┈┈.</span> + <span class="Constant"> . .</span> + ] + <span class="Comment"># redo</span> + assume-console [ + press ctrl-y + ] + run [ + editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data + ] + <span class="Comment"># all characters must be back</span> + screen-should-contain [ + <span class="Constant"> . .</span> + <span class="Constant"> .012 .</span> +<span class="Constant"> .┈┈┈┈┈┈┈┈┈┈.</span> + <span class="Constant"> . .</span> + ] + <span class="Comment"># cursor should be in the right place</span> + assume-console [ + type <span class="Constant">[3]</span> + ] + run [ + editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data + ] + screen-should-contain [ + <span class="Constant"> . .</span> + <span class="Constant"> .0123 .</span> +<span class="Constant"> .┈┈┈┈┈┈┈┈┈┈.</span> + <span class="Constant"> . .</span> + ] +] + +<span class="muScenario">scenario</span> editor-work-clears-redo-stack [ + <span class="Comment"># create an editor with some text, do some work, undo</span> + assume-screen <span class="Constant">10/width</span>, <span class="Constant">5/height</span> + <span class="Constant">1</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[abc</span> +<span class="Constant">def</span> +<span class="Constant">ghi]</span> + <span class="Constant">2</span>:address:editor-data<span class="Special"> <- </span>new-editor <span class="Constant">1</span>:address:array:character, screen:address, <span class="Constant">0/left</span>, <span class="Constant">10/right</span> + editor-render screen, <span class="Constant">2</span>:address:editor-data + assume-console [ + type <span class="Constant">[1]</span> + press ctrl-z + ] + editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data + <span class="Comment"># do some more work</span> + assume-console [ + type <span class="Constant">[0]</span> + ] + editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data + screen-should-contain [ + <span class="Constant"> . .</span> + <span class="Constant"> .0abc .</span> + <span class="Constant"> .def .</span> + <span class="Constant"> .ghi .</span> +<span class="Constant"> .┈┈┈┈┈┈┈┈┈┈.</span> + ] + <span class="Comment"># redo</span> + assume-console [ + press ctrl-y + ] + run [ + editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data + ] + <span class="Comment"># nothing should happen</span> + screen-should-contain [ + <span class="Constant"> . .</span> + <span class="Constant"> .0abc .</span> + <span class="Constant"> .def .</span> + <span class="Constant"> .ghi .</span> +<span class="Constant"> .┈┈┈┈┈┈┈┈┈┈.</span> + ] +] + +<span class="muScenario">scenario</span> editor-can-redo-typing-and-enter-and-tab [ + <span class="Comment"># create an editor</span> + assume-screen <span class="Constant">10/width</span>, <span class="Constant">5/height</span> + <span class="Constant">1</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[]</span> + <span class="Constant">2</span>:address:editor-data<span class="Special"> <- </span>new-editor <span class="Constant">1</span>:address:array:character, screen:address, <span class="Constant">0/left</span>, <span class="Constant">10/right</span> + editor-render screen, <span class="Constant">2</span>:address:editor-data + <span class="Comment"># insert some text and tabs, hit enter, some more text and tabs</span> + assume-console [ + press tab + type <span class="Constant">[ab]</span> + press tab + type <span class="Constant">[cd]</span> + press enter + press tab + type <span class="Constant">[efg]</span> + ] + editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data + screen-should-contain [ + <span class="Constant"> . .</span> + <span class="Constant"> . ab cd .</span> + <span class="Constant"> . efg .</span> +<span class="Constant"> .┈┈┈┈┈┈┈┈┈┈.</span> + <span class="Constant"> . .</span> + ] + <span class="Constant">3</span>:number<span class="Special"> <- </span>get *<span class="Constant">2</span>:address:editor-data, <span class="Constant">cursor-row:offset</span> + <span class="Constant">4</span>:number<span class="Special"> <- </span>get *<span class="Constant">2</span>:address:editor-data, <span class="Constant">cursor-column:offset</span> + memory-should-contain [ + <span class="Constant">3</span><span class="Special"> <- </span><span class="Constant">2</span> + <span class="Constant">4</span><span class="Special"> <- </span><span class="Constant">7</span> + ] + <span class="Comment"># undo</span> + assume-console [ + press ctrl-z + ] + run [ + editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data + ] + <span class="Comment"># typing in second line deleted, but not indent</span> + <span class="Constant">3</span>:number<span class="Special"> <- </span>get *<span class="Constant">2</span>:address:editor-data, <span class="Constant">cursor-row:offset</span> + <span class="Constant">4</span>:number<span class="Special"> <- </span>get *<span class="Constant">2</span>:address:editor-data, <span class="Constant">cursor-column:offset</span> + memory-should-contain [ + <span class="Constant">3</span><span class="Special"> <- </span><span class="Constant">2</span> + <span class="Constant">4</span><span class="Special"> <- </span><span class="Constant">2</span> + ] + screen-should-contain [ + <span class="Constant"> . .</span> + <span class="Constant"> . ab cd .</span> + <span class="Constant"> . .</span> +<span class="Constant"> .┈┈┈┈┈┈┈┈┈┈.</span> + <span class="Constant"> . .</span> + ] + <span class="Comment"># undo again</span> + assume-console [ + press ctrl-z + ] + run [ + editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data + ] + <span class="Comment"># indent and newline deleted</span> + <span class="Constant">3</span>:number<span class="Special"> <- </span>get *<span class="Constant">2</span>:address:editor-data, <span class="Constant">cursor-row:offset</span> + <span class="Constant">4</span>:number<span class="Special"> <- </span>get *<span class="Constant">2</span>:address:editor-data, <span class="Constant">cursor-column:offset</span> + memory-should-contain [ + <span class="Constant">3</span><span class="Special"> <- </span><span class="Constant">1</span> + <span class="Constant">4</span><span class="Special"> <- </span><span class="Constant">8</span> + ] + screen-should-contain [ + <span class="Constant"> . .</span> + <span class="Constant"> . ab cd .</span> +<span class="Constant"> .┈┈┈┈┈┈┈┈┈┈.</span> + <span class="Constant"> . .</span> + ] + <span class="Comment"># undo again</span> + assume-console [ + press ctrl-z + ] + run [ + editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data + ] + <span class="Comment"># empty screen</span> + <span class="Constant">3</span>:number<span class="Special"> <- </span>get *<span class="Constant">2</span>:address:editor-data, <span class="Constant">cursor-row:offset</span> + <span class="Constant">4</span>:number<span class="Special"> <- </span>get *<span class="Constant">2</span>:address:editor-data, <span class="Constant">cursor-column:offset</span> + memory-should-contain [ + <span class="Constant">3</span><span class="Special"> <- </span><span class="Constant">1</span> + <span class="Constant">4</span><span class="Special"> <- </span><span class="Constant">0</span> + ] + screen-should-contain [ + <span class="Constant"> . .</span> + <span class="Constant"> . .</span> +<span class="Constant"> .┈┈┈┈┈┈┈┈┈┈.</span> + <span class="Constant"> . .</span> + ] + <span class="Comment"># redo</span> + assume-console [ + press ctrl-y + ] + run [ + editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data + ] + <span class="Comment"># first line inserted</span> + <span class="Constant">3</span>:number<span class="Special"> <- </span>get *<span class="Constant">2</span>:address:editor-data, <span class="Constant">cursor-row:offset</span> + <span class="Constant">4</span>:number<span class="Special"> <- </span>get *<span class="Constant">2</span>:address:editor-data, <span class="Constant">cursor-column:offset</span> + memory-should-contain [ + <span class="Constant">3</span><span class="Special"> <- </span><span class="Constant">1</span> + <span class="Constant">4</span><span class="Special"> <- </span><span class="Constant">8</span> + ] + screen-should-contain [ + <span class="Constant"> . .</span> + <span class="Constant"> . ab cd .</span> +<span class="Constant"> .┈┈┈┈┈┈┈┈┈┈.</span> + <span class="Constant"> . .</span> + ] + <span class="Comment"># redo again</span> + assume-console [ + press ctrl-y + ] + run [ + editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data + ] + <span class="Comment"># newline and indent inserted</span> + <span class="Constant">3</span>:number<span class="Special"> <- </span>get *<span class="Constant">2</span>:address:editor-data, <span class="Constant">cursor-row:offset</span> + <span class="Constant">4</span>:number<span class="Special"> <- </span>get *<span class="Constant">2</span>:address:editor-data, <span class="Constant">cursor-column:offset</span> + memory-should-contain [ + <span class="Constant">3</span><span class="Special"> <- </span><span class="Constant">2</span> + <span class="Constant">4</span><span class="Special"> <- </span><span class="Constant">2</span> + ] + screen-should-contain [ + <span class="Constant"> . .</span> + <span class="Constant"> . ab cd .</span> + <span class="Constant"> . .</span> +<span class="Constant"> .┈┈┈┈┈┈┈┈┈┈.</span> + <span class="Constant"> . .</span> + ] + <span class="Comment"># redo again</span> + assume-console [ + press ctrl-y + ] + run [ + editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data + ] + <span class="Comment"># indent and newline deleted</span> + <span class="Constant">3</span>:number<span class="Special"> <- </span>get *<span class="Constant">2</span>:address:editor-data, <span class="Constant">cursor-row:offset</span> + <span class="Constant">4</span>:number<span class="Special"> <- </span>get *<span class="Constant">2</span>:address:editor-data, <span class="Constant">cursor-column:offset</span> + memory-should-contain [ + <span class="Constant">3</span><span class="Special"> <- </span><span class="Constant">2</span> + <span class="Constant">4</span><span class="Special"> <- </span><span class="Constant">7</span> + ] + screen-should-contain [ + <span class="Constant"> . .</span> + <span class="Constant"> . ab cd .</span> + <span class="Constant"> . efg .</span> +<span class="Constant"> .┈┈┈┈┈┈┈┈┈┈.</span> + <span class="Constant"> . .</span> + ] +] + +<span class="Comment"># undo cursor movement and scroll</span> + +<span class="muScenario">scenario</span> editor-can-undo-touch [ + <span class="Comment"># create an editor with some text</span> + assume-screen <span class="Constant">10/width</span>, <span class="Constant">5/height</span> + <span class="Constant">1</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[abc</span> +<span class="Constant">def</span> +<span class="Constant">ghi]</span> + <span class="Constant">2</span>:address:editor-data<span class="Special"> <- </span>new-editor <span class="Constant">1</span>:address:array:character, screen:address, <span class="Constant">0/left</span>, <span class="Constant">10/right</span> + editor-render screen, <span class="Constant">2</span>:address:editor-data + <span class="Comment"># move the cursor</span> + assume-console [ + left-click <span class="Constant">3</span>, <span class="Constant">1</span> + ] + editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data + <span class="Comment"># undo</span> + assume-console [ + press ctrl-z + ] + run [ + editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data + <span class="Constant">3</span>:number<span class="Special"> <- </span>get *<span class="Constant">2</span>:address:editor-data, <span class="Constant">cursor-row:offset</span> + <span class="Constant">4</span>:number<span class="Special"> <- </span>get *<span class="Constant">2</span>:address:editor-data, <span class="Constant">cursor-column:offset</span> + ] + <span class="Comment"># click undone</span> + memory-should-contain [ + <span class="Constant">3</span><span class="Special"> <- </span><span class="Constant">1</span> + <span class="Constant">4</span><span class="Special"> <- </span><span class="Constant">0</span> + ] + <span class="Comment"># cursor should be in the right place</span> + assume-console [ + type <span class="Constant">[1]</span> + ] + run [ + editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data + ] + screen-should-contain [ + <span class="Constant"> . .</span> + <span class="Constant"> .1abc .</span> + <span class="Constant"> .def .</span> + <span class="Constant"> .ghi .</span> +<span class="Constant"> .┈┈┈┈┈┈┈┈┈┈.</span> + ] +] + +<span class="muRecipe">after</span> <span class="Constant"><move-cursor-begin></span> [ + before-cursor-row:number<span class="Special"> <- </span>get *editor, <span class="Constant">cursor-row:offset</span> + before-cursor-column:number<span class="Special"> <- </span>get *editor, <span class="Constant">cursor-column:offset</span> + before-top-of-screen:address:duplex-list<span class="Special"> <- </span>get *editor, <span class="Constant">top-of-screen:offset</span> +] +<span class="muRecipe">before</span> <span class="Constant"><move-cursor-end></span> [ + after-cursor-row:number<span class="Special"> <- </span>get *editor, <span class="Constant">cursor-row:offset</span> + after-cursor-column:number<span class="Special"> <- </span>get *editor, <span class="Constant">cursor-column:offset</span> + after-top-of-screen:address:duplex-list<span class="Special"> <- </span>get *editor, <span class="Constant">top-of-screen:offset</span> + <span class="Delimiter">{</span> + <span class="muControl">break-unless</span> undo-coalesce-tag + <span class="Comment"># if previous operation was also a move, and also had the same coalesce</span> + <span class="Comment"># tag, coalesce with it</span> + undo:address:address:list<span class="Special"> <- </span>get-address *editor, <span class="Constant">undo:offset</span> + <span class="muControl">break-unless</span> *undo + op:address:operation<span class="Special"> <- </span>first *undo + move:address:move-operation<span class="Special"> <- </span>maybe-convert *op, <span class="Constant">move:variant</span> + <span class="muControl">break-unless</span> move + previous-coalesce-tag:number<span class="Special"> <- </span>get *move, <span class="Constant">tag:offset</span> + coalesce?:boolean<span class="Special"> <- </span>equal undo-coalesce-tag, previous-coalesce-tag + <span class="muControl">break-unless</span> coalesce? + after-row:address:number<span class="Special"> <- </span>get-address *move, <span class="Constant">after-row:offset</span> + *after-row<span class="Special"> <- </span>copy after-cursor-row + after-column:address:number<span class="Special"> <- </span>get-address *move, <span class="Constant">after-column:offset</span> + *after-column<span class="Special"> <- </span>copy after-cursor-column + after-top:address:number<span class="Special"> <- </span>get-address *move, <span class="Constant">after-top-of-screen:offset</span> + *after-top<span class="Special"> <- </span>get *editor, <span class="Constant">top-of-screen:offset</span> + <span class="muControl">break</span> <span class="Constant">+done-adding-move-operation:label</span> + <span class="Delimiter">}</span> + op:address:operation<span class="Special"> <- </span>new <span class="Constant">operation:type</span> + *op<span class="Special"> <- </span>merge <span class="Constant">1/move-operation</span>, before-cursor-row, before-cursor-column, before-top-of-screen, after-cursor-row, after-cursor-column, after-top-of-screen, undo-coalesce-tag + editor<span class="Special"> <- </span>add-operation editor, op +<span class="Constant"> +done-adding-move-operation</span> +] + +<span class="muRecipe">after</span> <span class="Constant"><handle-undo></span> [ + <span class="Delimiter">{</span> + move:address:move-operation<span class="Special"> <- </span>maybe-convert *op, <span class="Constant">move:variant</span> + <span class="muControl">break-unless</span> move + <span class="Comment"># assert cursor-row/cursor-column/top-of-screen match after-row/after-column/after-top-of-screen</span> + top:address:address:duplex-list<span class="Special"> <- </span>get-address *editor, <span class="Constant">top-of-screen:offset</span> + *cursor-row<span class="Special"> <- </span>get *move, <span class="Constant">before-row:offset</span> + *cursor-column<span class="Special"> <- </span>get *move, <span class="Constant">before-column:offset</span> + *top<span class="Special"> <- </span>get *move, <span class="Constant">before-top-of-screen:offset</span> + <span class="Delimiter">}</span> +] + +<span class="muScenario">scenario</span> editor-can-undo-scroll [ + <span class="Comment"># screen has 1 line for menu + 3 lines</span> + assume-screen <span class="Constant">5/width</span>, <span class="Constant">4/height</span> + <span class="Comment"># editor contains a wrapped line</span> + <span class="Constant">1</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[a</span> +<span class="Constant">b</span> +<span class="Constant">cdefgh]</span> + <span class="Constant">2</span>:address:editor-data<span class="Special"> <- </span>new-editor <span class="Constant">1</span>:address:array:character, screen:address, <span class="Constant">0/left</span>, <span class="Constant">5/right</span> + <span class="Comment"># position cursor at end of screen and try to move right</span> + assume-console [ + left-click <span class="Constant">3</span>, <span class="Constant">3</span> + press right-arrow + ] + editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data + <span class="Constant">3</span>:number<span class="Special"> <- </span>get *<span class="Constant">2</span>:address:editor-data, <span class="Constant">cursor-row:offset</span> + <span class="Constant">4</span>:number<span class="Special"> <- </span>get *<span class="Constant">2</span>:address:editor-data, <span class="Constant">cursor-column:offset</span> + <span class="Comment"># screen scrolls</span> + screen-should-contain [ + <span class="Constant"> . .</span> + <span class="Constant"> .b .</span> +<span class="Constant"> .cdef↩.</span> + <span class="Constant"> .gh .</span> + ] + memory-should-contain [ + <span class="Constant">3</span><span class="Special"> <- </span><span class="Constant">3</span> + <span class="Constant">4</span><span class="Special"> <- </span><span class="Constant">0</span> + ] + <span class="Comment"># undo</span> + assume-console [ + press ctrl-z + ] + run [ + editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data + <span class="Constant">3</span>:number<span class="Special"> <- </span>get *<span class="Constant">2</span>:address:editor-data, <span class="Constant">cursor-row:offset</span> + <span class="Constant">4</span>:number<span class="Special"> <- </span>get *<span class="Constant">2</span>:address:editor-data, <span class="Constant">cursor-column:offset</span> + ] + <span class="Comment"># cursor moved back</span> + memory-should-contain [ + <span class="Constant">3</span><span class="Special"> <- </span><span class="Constant">3</span> + <span class="Constant">4</span><span class="Special"> <- </span><span class="Constant">3</span> + ] + <span class="Comment"># scroll undone</span> + screen-should-contain [ + <span class="Constant"> . .</span> + <span class="Constant"> .a .</span> + <span class="Constant"> .b .</span> +<span class="Constant"> .cdef↩.</span> + ] + <span class="Comment"># cursor should be in the right place</span> + assume-console [ + type <span class="Constant">[1]</span> + ] + run [ + editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data + ] + screen-should-contain [ + <span class="Constant"> . .</span> + <span class="Constant"> .b .</span> +<span class="Constant"> .cde1↩.</span> + <span class="Constant"> .fgh .</span> + ] +] + +<span class="muScenario">scenario</span> editor-can-undo-left-arrow [ + <span class="Comment"># create an editor with some text</span> + assume-screen <span class="Constant">10/width</span>, <span class="Constant">5/height</span> + <span class="Constant">1</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[abc</span> +<span class="Constant">def</span> +<span class="Constant">ghi]</span> + <span class="Constant">2</span>:address:editor-data<span class="Special"> <- </span>new-editor <span class="Constant">1</span>:address:array:character, screen:address, <span class="Constant">0/left</span>, <span class="Constant">10/right</span> + editor-render screen, <span class="Constant">2</span>:address:editor-data + <span class="Comment"># move the cursor</span> + assume-console [ + left-click <span class="Constant">3</span>, <span class="Constant">1</span> + press left-arrow + ] + editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data + <span class="Comment"># undo</span> + assume-console [ + press ctrl-z + ] + run [ + editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data + <span class="Constant">3</span>:number<span class="Special"> <- </span>get *<span class="Constant">2</span>:address:editor-data, <span class="Constant">cursor-row:offset</span> + <span class="Constant">4</span>:number<span class="Special"> <- </span>get *<span class="Constant">2</span>:address:editor-data, <span class="Constant">cursor-column:offset</span> + ] + <span class="Comment"># cursor moves back</span> + memory-should-contain [ + <span class="Constant">3</span><span class="Special"> <- </span><span class="Constant">3</span> + <span class="Constant">4</span><span class="Special"> <- </span><span class="Constant">1</span> + ] + <span class="Comment"># cursor should be in the right place</span> + assume-console [ + type <span class="Constant">[1]</span> + ] + run [ + editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data + ] + screen-should-contain [ + <span class="Constant"> . .</span> + <span class="Constant"> .abc .</span> + <span class="Constant"> .def .</span> + <span class="Constant"> .g1hi .</span> +<span class="Constant"> .┈┈┈┈┈┈┈┈┈┈.</span> + ] +] + +<span class="muScenario">scenario</span> editor-can-undo-up-arrow [ + <span class="Comment"># create an editor with some text</span> + assume-screen <span class="Constant">10/width</span>, <span class="Constant">5/height</span> + <span class="Constant">1</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[abc</span> +<span class="Constant">def</span> +<span class="Constant">ghi]</span> + <span class="Constant">2</span>:address:editor-data<span class="Special"> <- </span>new-editor <span class="Constant">1</span>:address:array:character, screen:address, <span class="Constant">0/left</span>, <span class="Constant">10/right</span> + editor-render screen, <span class="Constant">2</span>:address:editor-data + <span class="Comment"># move the cursor</span> + assume-console [ + left-click <span class="Constant">3</span>, <span class="Constant">1</span> + press up-arrow + ] + editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data + <span class="Constant">3</span>:number<span class="Special"> <- </span>get *<span class="Constant">2</span>:address:editor-data, <span class="Constant">cursor-row:offset</span> + <span class="Constant">4</span>:number<span class="Special"> <- </span>get *<span class="Constant">2</span>:address:editor-data, <span class="Constant">cursor-column:offset</span> + memory-should-contain [ + <span class="Constant">3</span><span class="Special"> <- </span><span class="Constant">2</span> + <span class="Constant">4</span><span class="Special"> <- </span><span class="Constant">1</span> + ] + <span class="Comment"># undo</span> + assume-console [ + press ctrl-z + ] + run [ + editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data + <span class="Constant">3</span>:number<span class="Special"> <- </span>get *<span class="Constant">2</span>:address:editor-data, <span class="Constant">cursor-row:offset</span> + <span class="Constant">4</span>:number<span class="Special"> <- </span>get *<span class="Constant">2</span>:address:editor-data, <span class="Constant">cursor-column:offset</span> + ] + <span class="Comment"># cursor moves back</span> + memory-should-contain [ + <span class="Constant">3</span><span class="Special"> <- </span><span class="Constant">3</span> + <span class="Constant">4</span><span class="Special"> <- </span><span class="Constant">1</span> + ] + <span class="Comment"># cursor should be in the right place</span> + assume-console [ + type <span class="Constant">[1]</span> + ] + run [ + editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data + ] + screen-should-contain [ + <span class="Constant"> . .</span> + <span class="Constant"> .abc .</span> + <span class="Constant"> .def .</span> + <span class="Constant"> .g1hi .</span> +<span class="Constant"> .┈┈┈┈┈┈┈┈┈┈.</span> + ] +] + +<span class="muScenario">scenario</span> editor-can-undo-down-arrow [ + <span class="Comment"># create an editor with some text</span> + assume-screen <span class="Constant">10/width</span>, <span class="Constant">5/height</span> + <span class="Constant">1</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[abc</span> +<span class="Constant">def</span> +<span class="Constant">ghi]</span> + <span class="Constant">2</span>:address:editor-data<span class="Special"> <- </span>new-editor <span class="Constant">1</span>:address:array:character, screen:address, <span class="Constant">0/left</span>, <span class="Constant">10/right</span> + editor-render screen, <span class="Constant">2</span>:address:editor-data + <span class="Comment"># move the cursor</span> + assume-console [ + left-click <span class="Constant">2</span>, <span class="Constant">1</span> + press down-arrow + ] + editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data + <span class="Comment"># undo</span> + assume-console [ + press ctrl-z + ] + run [ + editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data + <span class="Constant">3</span>:number<span class="Special"> <- </span>get *<span class="Constant">2</span>:address:editor-data, <span class="Constant">cursor-row:offset</span> + <span class="Constant">4</span>:number<span class="Special"> <- </span>get *<span class="Constant">2</span>:address:editor-data, <span class="Constant">cursor-column:offset</span> + ] + <span class="Comment"># cursor moves back</span> + memory-should-contain [ + <span class="Constant">3</span><span class="Special"> <- </span><span class="Constant">2</span> + <span class="Constant">4</span><span class="Special"> <- </span><span class="Constant">1</span> + ] + <span class="Comment"># cursor should be in the right place</span> + assume-console [ + type <span class="Constant">[1]</span> + ] + run [ + editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data + ] + screen-should-contain [ + <span class="Constant"> . .</span> + <span class="Constant"> .abc .</span> + <span class="Constant"> .d1ef .</span> + <span class="Constant"> .ghi .</span> +<span class="Constant"> .┈┈┈┈┈┈┈┈┈┈.</span> + ] +] + +<span class="muScenario">scenario</span> editor-can-undo-ctrl-f [ + <span class="Comment"># create an editor with multiple pages of text</span> + assume-screen <span class="Constant">10/width</span>, <span class="Constant">5/height</span> + <span class="Constant">1</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[a</span> +<span class="Constant">b</span> +<span class="Constant">c</span> +<span class="Constant">d</span> +<span class="Constant">e</span> +<span class="Constant">f]</span> + <span class="Constant">2</span>:address:editor-data<span class="Special"> <- </span>new-editor <span class="Constant">1</span>:address:array:character, screen:address, <span class="Constant">0/left</span>, <span class="Constant">10/right</span> + editor-render screen, <span class="Constant">2</span>:address:editor-data + <span class="Comment"># scroll the page</span> + assume-console [ + press ctrl-f + ] + editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data + <span class="Comment"># undo</span> + assume-console [ + press ctrl-z + ] + run [ + editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data + <span class="Constant">3</span>:number<span class="Special"> <- </span>get *<span class="Constant">2</span>:address:editor-data, <span class="Constant">cursor-row:offset</span> + <span class="Constant">4</span>:number<span class="Special"> <- </span>get *<span class="Constant">2</span>:address:editor-data, <span class="Constant">cursor-column:offset</span> + ] + <span class="Comment"># screen should again show page 1</span> + screen-should-contain [ + <span class="Constant"> . .</span> + <span class="Constant"> .a .</span> + <span class="Constant"> .b .</span> + <span class="Constant"> .c .</span> + <span class="Constant"> .d .</span> + ] +] + +<span class="muScenario">scenario</span> editor-can-undo-page-down [ + <span class="Comment"># create an editor with multiple pages of text</span> + assume-screen <span class="Constant">10/width</span>, <span class="Constant">5/height</span> + <span class="Constant">1</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[a</span> +<span class="Constant">b</span> +<span class="Constant">c</span> +<span class="Constant">d</span> +<span class="Constant">e</span> +<span class="Constant">f]</span> + <span class="Constant">2</span>:address:editor-data<span class="Special"> <- </span>new-editor <span class="Constant">1</span>:address:array:character, screen:address, <span class="Constant">0/left</span>, <span class="Constant">10/right</span> + editor-render screen, <span class="Constant">2</span>:address:editor-data + <span class="Comment"># scroll the page</span> + assume-console [ + press page-down + ] + editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data + <span class="Comment"># undo</span> + assume-console [ + press ctrl-z + ] + run [ + editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data + <span class="Constant">3</span>:number<span class="Special"> <- </span>get *<span class="Constant">2</span>:address:editor-data, <span class="Constant">cursor-row:offset</span> + <span class="Constant">4</span>:number<span class="Special"> <- </span>get *<span class="Constant">2</span>:address:editor-data, <span class="Constant">cursor-column:offset</span> + ] + <span class="Comment"># screen should again show page 1</span> + screen-should-contain [ + <span class="Constant"> . .</span> + <span class="Constant"> .a .</span> + <span class="Constant"> .b .</span> + <span class="Constant"> .c .</span> + <span class="Constant"> .d .</span> + ] +] + +<span class="muScenario">scenario</span> editor-can-undo-ctrl-b [ + <span class="Comment"># create an editor with multiple pages of text</span> + assume-screen <span class="Constant">10/width</span>, <span class="Constant">5/height</span> + <span class="Constant">1</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[a</span> +<span class="Constant">b</span> +<span class="Constant">c</span> +<span class="Constant">d</span> +<span class="Constant">e</span> +<span class="Constant">f]</span> + <span class="Constant">2</span>:address:editor-data<span class="Special"> <- </span>new-editor <span class="Constant">1</span>:address:array:character, screen:address, <span class="Constant">0/left</span>, <span class="Constant">10/right</span> + editor-render screen, <span class="Constant">2</span>:address:editor-data + <span class="Comment"># scroll the page down and up</span> + assume-console [ + press page-down + press ctrl-b + ] + editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data + <span class="Comment"># undo</span> + assume-console [ + press ctrl-z + ] + run [ + editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data + <span class="Constant">3</span>:number<span class="Special"> <- </span>get *<span class="Constant">2</span>:address:editor-data, <span class="Constant">cursor-row:offset</span> + <span class="Constant">4</span>:number<span class="Special"> <- </span>get *<span class="Constant">2</span>:address:editor-data, <span class="Constant">cursor-column:offset</span> + ] + <span class="Comment"># screen should again show page 2</span> + screen-should-contain [ + <span class="Constant"> . .</span> + <span class="Constant"> .d .</span> + <span class="Constant"> .e .</span> + <span class="Constant"> .f .</span> +<span class="Constant"> .┈┈┈┈┈┈┈┈┈┈.</span> + ] +] + +<span class="muScenario">scenario</span> editor-can-undo-page-up [ + <span class="Comment"># create an editor with multiple pages of text</span> + assume-screen <span class="Constant">10/width</span>, <span class="Constant">5/height</span> + <span class="Constant">1</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[a</span> +<span class="Constant">b</span> +<span class="Constant">c</span> +<span class="Constant">d</span> +<span class="Constant">e</span> +<span class="Constant">f]</span> + <span class="Constant">2</span>:address:editor-data<span class="Special"> <- </span>new-editor <span class="Constant">1</span>:address:array:character, screen:address, <span class="Constant">0/left</span>, <span class="Constant">10/right</span> + editor-render screen, <span class="Constant">2</span>:address:editor-data + <span class="Comment"># scroll the page down and up</span> + assume-console [ + press page-down + press page-up + ] + editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data + <span class="Comment"># undo</span> + assume-console [ + press ctrl-z + ] + run [ + editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data + <span class="Constant">3</span>:number<span class="Special"> <- </span>get *<span class="Constant">2</span>:address:editor-data, <span class="Constant">cursor-row:offset</span> + <span class="Constant">4</span>:number<span class="Special"> <- </span>get *<span class="Constant">2</span>:address:editor-data, <span class="Constant">cursor-column:offset</span> + ] + <span class="Comment"># screen should again show page 2</span> + screen-should-contain [ + <span class="Constant"> . .</span> + <span class="Constant"> .d .</span> + <span class="Constant"> .e .</span> + <span class="Constant"> .f .</span> +<span class="Constant"> .┈┈┈┈┈┈┈┈┈┈.</span> + ] +] + +<span class="muScenario">scenario</span> editor-can-undo-ctrl-a [ + <span class="Comment"># create an editor with some text</span> + assume-screen <span class="Constant">10/width</span>, <span class="Constant">5/height</span> + <span class="Constant">1</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[abc</span> +<span class="Constant">def</span> +<span class="Constant">ghi]</span> + <span class="Constant">2</span>:address:editor-data<span class="Special"> <- </span>new-editor <span class="Constant">1</span>:address:array:character, screen:address, <span class="Constant">0/left</span>, <span class="Constant">10/right</span> + editor-render screen, <span class="Constant">2</span>:address:editor-data + <span class="Comment"># move the cursor, then to start of line</span> + assume-console [ + left-click <span class="Constant">2</span>, <span class="Constant">1</span> + press ctrl-a + ] + editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data + <span class="Comment"># undo</span> + assume-console [ + press ctrl-z + ] + run [ + editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data + <span class="Constant">3</span>:number<span class="Special"> <- </span>get *<span class="Constant">2</span>:address:editor-data, <span class="Constant">cursor-row:offset</span> + <span class="Constant">4</span>:number<span class="Special"> <- </span>get *<span class="Constant">2</span>:address:editor-data, <span class="Constant">cursor-column:offset</span> + ] + <span class="Comment"># cursor moves back</span> + memory-should-contain [ + <span class="Constant">3</span><span class="Special"> <- </span><span class="Constant">2</span> + <span class="Constant">4</span><span class="Special"> <- </span><span class="Constant">1</span> + ] + <span class="Comment"># cursor should be in the right place</span> + assume-console [ + type <span class="Constant">[1]</span> + ] + run [ + editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data + ] + screen-should-contain [ + <span class="Constant"> . .</span> + <span class="Constant"> .abc .</span> + <span class="Constant"> .d1ef .</span> + <span class="Constant"> .ghi .</span> +<span class="Constant"> .┈┈┈┈┈┈┈┈┈┈.</span> + ] +] + +<span class="muScenario">scenario</span> editor-can-undo-home [ + <span class="Comment"># create an editor with some text</span> + assume-screen <span class="Constant">10/width</span>, <span class="Constant">5/height</span> + <span class="Constant">1</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[abc</span> +<span class="Constant">def</span> +<span class="Constant">ghi]</span> + <span class="Constant">2</span>:address:editor-data<span class="Special"> <- </span>new-editor <span class="Constant">1</span>:address:array:character, screen:address, <span class="Constant">0/left</span>, <span class="Constant">10/right</span> + editor-render screen, <span class="Constant">2</span>:address:editor-data + <span class="Comment"># move the cursor, then to start of line</span> + assume-console [ + left-click <span class="Constant">2</span>, <span class="Constant">1</span> + press home + ] + editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data + <span class="Comment"># undo</span> + assume-console [ + press ctrl-z + ] + run [ + editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data + <span class="Constant">3</span>:number<span class="Special"> <- </span>get *<span class="Constant">2</span>:address:editor-data, <span class="Constant">cursor-row:offset</span> + <span class="Constant">4</span>:number<span class="Special"> <- </span>get *<span class="Constant">2</span>:address:editor-data, <span class="Constant">cursor-column:offset</span> + ] + <span class="Comment"># cursor moves back</span> + memory-should-contain [ + <span class="Constant">3</span><span class="Special"> <- </span><span class="Constant">2</span> + <span class="Constant">4</span><span class="Special"> <- </span><span class="Constant">1</span> + ] + <span class="Comment"># cursor should be in the right place</span> + assume-console [ + type <span class="Constant">[1]</span> + ] + run [ + editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data + ] + screen-should-contain [ + <span class="Constant"> . .</span> + <span class="Constant"> .abc .</span> + <span class="Constant"> .d1ef .</span> + <span class="Constant"> .ghi .</span> +<span class="Constant"> .┈┈┈┈┈┈┈┈┈┈.</span> + ] +] + +<span class="muScenario">scenario</span> editor-can-undo-ctrl-e [ + <span class="Comment"># create an editor with some text</span> + assume-screen <span class="Constant">10/width</span>, <span class="Constant">5/height</span> + <span class="Constant">1</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[abc</span> +<span class="Constant">def</span> +<span class="Constant">ghi]</span> + <span class="Constant">2</span>:address:editor-data<span class="Special"> <- </span>new-editor <span class="Constant">1</span>:address:array:character, screen:address, <span class="Constant">0/left</span>, <span class="Constant">10/right</span> + editor-render screen, <span class="Constant">2</span>:address:editor-data + <span class="Comment"># move the cursor, then to start of line</span> + assume-console [ + left-click <span class="Constant">2</span>, <span class="Constant">1</span> + press ctrl-e + ] + editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data + <span class="Comment"># undo</span> + assume-console [ + press ctrl-z + ] + run [ + editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data + <span class="Constant">3</span>:number<span class="Special"> <- </span>get *<span class="Constant">2</span>:address:editor-data, <span class="Constant">cursor-row:offset</span> + <span class="Constant">4</span>:number<span class="Special"> <- </span>get *<span class="Constant">2</span>:address:editor-data, <span class="Constant">cursor-column:offset</span> + ] + <span class="Comment"># cursor moves back</span> + memory-should-contain [ + <span class="Constant">3</span><span class="Special"> <- </span><span class="Constant">2</span> + <span class="Constant">4</span><span class="Special"> <- </span><span class="Constant">1</span> + ] + <span class="Comment"># cursor should be in the right place</span> + assume-console [ + type <span class="Constant">[1]</span> + ] + run [ + editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data + ] + screen-should-contain [ + <span class="Constant"> . .</span> + <span class="Constant"> .abc .</span> + <span class="Constant"> .d1ef .</span> + <span class="Constant"> .ghi .</span> +<span class="Constant"> .┈┈┈┈┈┈┈┈┈┈.</span> + ] +] + +<span class="muScenario">scenario</span> editor-can-undo-end [ + <span class="Comment"># create an editor with some text</span> + assume-screen <span class="Constant">10/width</span>, <span class="Constant">5/height</span> + <span class="Constant">1</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[abc</span> +<span class="Constant">def</span> +<span class="Constant">ghi]</span> + <span class="Constant">2</span>:address:editor-data<span class="Special"> <- </span>new-editor <span class="Constant">1</span>:address:array:character, screen:address, <span class="Constant">0/left</span>, <span class="Constant">10/right</span> + editor-render screen, <span class="Constant">2</span>:address:editor-data + <span class="Comment"># move the cursor, then to start of line</span> + assume-console [ + left-click <span class="Constant">2</span>, <span class="Constant">1</span> + press end + ] + editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data + <span class="Comment"># undo</span> + assume-console [ + press ctrl-z + ] + run [ + editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data + <span class="Constant">3</span>:number<span class="Special"> <- </span>get *<span class="Constant">2</span>:address:editor-data, <span class="Constant">cursor-row:offset</span> + <span class="Constant">4</span>:number<span class="Special"> <- </span>get *<span class="Constant">2</span>:address:editor-data, <span class="Constant">cursor-column:offset</span> + ] + <span class="Comment"># cursor moves back</span> + memory-should-contain [ + <span class="Constant">3</span><span class="Special"> <- </span><span class="Constant">2</span> + <span class="Constant">4</span><span class="Special"> <- </span><span class="Constant">1</span> + ] + <span class="Comment"># cursor should be in the right place</span> + assume-console [ + type <span class="Constant">[1]</span> + ] + run [ + editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data + ] + screen-should-contain [ + <span class="Constant"> . .</span> + <span class="Constant"> .abc .</span> + <span class="Constant"> .d1ef .</span> + <span class="Constant"> .ghi .</span> +<span class="Constant"> .┈┈┈┈┈┈┈┈┈┈.</span> + ] +] + +<span class="muScenario">scenario</span> editor-separates-undo-insert-from-undo-cursor-move [ + <span class="Comment"># create an editor, type some text, move the cursor, type some more text</span> + assume-screen <span class="Constant">10/width</span>, <span class="Constant">5/height</span> + <span class="Constant">1</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[]</span> + <span class="Constant">2</span>:address:editor-data<span class="Special"> <- </span>new-editor <span class="Constant">1</span>:address:array:character, screen:address, <span class="Constant">0/left</span>, <span class="Constant">10/right</span> + editor-render screen, <span class="Constant">2</span>:address:editor-data + assume-console [ + type <span class="Constant">[abc]</span> + left-click <span class="Constant">1</span>, <span class="Constant">1</span> + type <span class="Constant">[d]</span> + ] + editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data + <span class="Constant">3</span>:number<span class="Special"> <- </span>get *<span class="Constant">2</span>:address:editor-data, <span class="Constant">cursor-row:offset</span> + <span class="Constant">4</span>:number<span class="Special"> <- </span>get *<span class="Constant">2</span>:address:editor-data, <span class="Constant">cursor-column:offset</span> + screen-should-contain [ + <span class="Constant"> . .</span> + <span class="Constant"> .adbc .</span> +<span class="Constant"> .┈┈┈┈┈┈┈┈┈┈.</span> + <span class="Constant"> . .</span> + ] + memory-should-contain [ + <span class="Constant">3</span><span class="Special"> <- </span><span class="Constant">1</span> + <span class="Constant">4</span><span class="Special"> <- </span><span class="Constant">2</span> + ] + <span class="Comment"># undo</span> + assume-console [ + press ctrl-z + ] + run [ + editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data + <span class="Constant">3</span>:number<span class="Special"> <- </span>get *<span class="Constant">2</span>:address:editor-data, <span class="Constant">cursor-row:offset</span> + <span class="Constant">4</span>:number<span class="Special"> <- </span>get *<span class="Constant">2</span>:address:editor-data, <span class="Constant">cursor-column:offset</span> + ] + <span class="Comment"># last letter typed is deleted</span> + screen-should-contain [ + <span class="Constant"> . .</span> + <span class="Constant"> .abc .</span> +<span class="Constant"> .┈┈┈┈┈┈┈┈┈┈.</span> + <span class="Constant"> . .</span> + ] + memory-should-contain [ + <span class="Constant">3</span><span class="Special"> <- </span><span class="Constant">1</span> + <span class="Constant">4</span><span class="Special"> <- </span><span class="Constant">1</span> + ] + <span class="Comment"># undo again</span> + assume-console [ + press ctrl-z + ] + run [ + editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data + <span class="Constant">3</span>:number<span class="Special"> <- </span>get *<span class="Constant">2</span>:address:editor-data, <span class="Constant">cursor-row:offset</span> + <span class="Constant">4</span>:number<span class="Special"> <- </span>get *<span class="Constant">2</span>:address:editor-data, <span class="Constant">cursor-column:offset</span> + ] + <span class="Comment"># no change to screen; cursor moves</span> + screen-should-contain [ + <span class="Constant"> . .</span> + <span class="Constant"> .abc .</span> +<span class="Constant"> .┈┈┈┈┈┈┈┈┈┈.</span> + <span class="Constant"> . .</span> + ] + memory-should-contain [ + <span class="Constant">3</span><span class="Special"> <- </span><span class="Constant">1</span> + <span class="Constant">4</span><span class="Special"> <- </span><span class="Constant">3</span> + ] + <span class="Comment"># undo again</span> + assume-console [ + press ctrl-z + ] + run [ + editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data + <span class="Constant">3</span>:number<span class="Special"> <- </span>get *<span class="Constant">2</span>:address:editor-data, <span class="Constant">cursor-row:offset</span> + <span class="Constant">4</span>:number<span class="Special"> <- </span>get *<span class="Constant">2</span>:address:editor-data, <span class="Constant">cursor-column:offset</span> + ] + <span class="Comment"># screen empty</span> + screen-should-contain [ + <span class="Constant"> . .</span> + <span class="Constant"> . .</span> +<span class="Constant"> .┈┈┈┈┈┈┈┈┈┈.</span> + <span class="Constant"> . .</span> + ] + memory-should-contain [ + <span class="Constant">3</span><span class="Special"> <- </span><span class="Constant">1</span> + <span class="Constant">4</span><span class="Special"> <- </span><span class="Constant">0</span> + ] + <span class="Comment"># redo</span> + assume-console [ + press ctrl-y + ] + run [ + editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data + <span class="Constant">3</span>:number<span class="Special"> <- </span>get *<span class="Constant">2</span>:address:editor-data, <span class="Constant">cursor-row:offset</span> + <span class="Constant">4</span>:number<span class="Special"> <- </span>get *<span class="Constant">2</span>:address:editor-data, <span class="Constant">cursor-column:offset</span> + ] + <span class="Comment"># first insert</span> + screen-should-contain [ + <span class="Constant"> . .</span> + <span class="Constant"> .abc .</span> +<span class="Constant"> .┈┈┈┈┈┈┈┈┈┈.</span> + <span class="Constant"> . .</span> + ] + memory-should-contain [ + <span class="Constant">3</span><span class="Special"> <- </span><span class="Constant">1</span> + <span class="Constant">4</span><span class="Special"> <- </span><span class="Constant">3</span> + ] + <span class="Comment"># redo again</span> + assume-console [ + press ctrl-y + ] + run [ + editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data + <span class="Constant">3</span>:number<span class="Special"> <- </span>get *<span class="Constant">2</span>:address:editor-data, <span class="Constant">cursor-row:offset</span> + <span class="Constant">4</span>:number<span class="Special"> <- </span>get *<span class="Constant">2</span>:address:editor-data, <span class="Constant">cursor-column:offset</span> + ] + <span class="Comment"># cursor moves</span> + screen-should-contain [ + <span class="Constant"> . .</span> + <span class="Constant"> .abc .</span> +<span class="Constant"> .┈┈┈┈┈┈┈┈┈┈.</span> + <span class="Constant"> . .</span> + ] + memory-should-contain [ + <span class="Constant">3</span><span class="Special"> <- </span><span class="Constant">1</span> + <span class="Constant">4</span><span class="Special"> <- </span><span class="Constant">1</span> + ] + <span class="Comment"># redo again</span> + assume-console [ + press ctrl-y + ] + run [ + editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data + <span class="Constant">3</span>:number<span class="Special"> <- </span>get *<span class="Constant">2</span>:address:editor-data, <span class="Constant">cursor-row:offset</span> + <span class="Constant">4</span>:number<span class="Special"> <- </span>get *<span class="Constant">2</span>:address:editor-data, <span class="Constant">cursor-column:offset</span> + ] + <span class="Comment"># second insert</span> + screen-should-contain [ + <span class="Constant"> . .</span> + <span class="Constant"> .adbc .</span> +<span class="Constant"> .┈┈┈┈┈┈┈┈┈┈.</span> + <span class="Constant"> . .</span> + ] + memory-should-contain [ + <span class="Constant">3</span><span class="Special"> <- </span><span class="Constant">1</span> + <span class="Constant">4</span><span class="Special"> <- </span><span class="Constant">2</span> + ] +] + +<span class="muScenario">scenario</span> editor-can-undo-multiple-arrows-in-the-same-direction [ + <span class="Comment"># create an editor with some text</span> + assume-screen <span class="Constant">10/width</span>, <span class="Constant">5/height</span> + <span class="Constant">1</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[abc</span> +<span class="Constant">def</span> +<span class="Constant">ghi]</span> + <span class="Constant">2</span>:address:editor-data<span class="Special"> <- </span>new-editor <span class="Constant">1</span>:address:array:character, screen:address, <span class="Constant">0/left</span>, <span class="Constant">10/right</span> + editor-render screen, <span class="Constant">2</span>:address:editor-data + <span class="Comment"># move the cursor</span> + assume-console [ + left-click <span class="Constant">2</span>, <span class="Constant">1</span> + press right-arrow + press right-arrow + press up-arrow + ] + editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data + <span class="Constant">3</span>:number<span class="Special"> <- </span>get *<span class="Constant">2</span>:address:editor-data, <span class="Constant">cursor-row:offset</span> + <span class="Constant">4</span>:number<span class="Special"> <- </span>get *<span class="Constant">2</span>:address:editor-data, <span class="Constant">cursor-column:offset</span> + memory-should-contain [ + <span class="Constant">3</span><span class="Special"> <- </span><span class="Constant">1</span> + <span class="Constant">4</span><span class="Special"> <- </span><span class="Constant">3</span> + ] + <span class="Comment"># undo</span> + assume-console [ + press ctrl-z + ] + run [ + editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data + <span class="Constant">3</span>:number<span class="Special"> <- </span>get *<span class="Constant">2</span>:address:editor-data, <span class="Constant">cursor-row:offset</span> + <span class="Constant">4</span>:number<span class="Special"> <- </span>get *<span class="Constant">2</span>:address:editor-data, <span class="Constant">cursor-column:offset</span> + ] + <span class="Comment"># up-arrow is undone</span> + memory-should-contain [ + <span class="Constant">3</span><span class="Special"> <- </span><span class="Constant">2</span> + <span class="Constant">4</span><span class="Special"> <- </span><span class="Constant">3</span> + ] + <span class="Comment"># undo again</span> + assume-console [ + press ctrl-z + ] + run [ + editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data + <span class="Constant">3</span>:number<span class="Special"> <- </span>get *<span class="Constant">2</span>:address:editor-data, <span class="Constant">cursor-row:offset</span> + <span class="Constant">4</span>:number<span class="Special"> <- </span>get *<span class="Constant">2</span>:address:editor-data, <span class="Constant">cursor-column:offset</span> + ] + <span class="Comment"># both right-arrows are undone</span> + memory-should-contain [ + <span class="Constant">3</span><span class="Special"> <- </span><span class="Constant">2</span> + <span class="Constant">4</span><span class="Special"> <- </span><span class="Constant">1</span> + ] +] + +<span class="Comment"># redo cursor movement and scroll</span> + +<span class="muScenario">scenario</span> editor-redo-touch [ + <span class="Comment"># create an editor with some text, click on a character, undo</span> + assume-screen <span class="Constant">10/width</span>, <span class="Constant">5/height</span> + <span class="Constant">1</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[abc</span> +<span class="Constant">def</span> +<span class="Constant">ghi]</span> + <span class="Constant">2</span>:address:editor-data<span class="Special"> <- </span>new-editor <span class="Constant">1</span>:address:array:character, screen:address, <span class="Constant">0/left</span>, <span class="Constant">10/right</span> + editor-render screen, <span class="Constant">2</span>:address:editor-data + assume-console [ + left-click <span class="Constant">3</span>, <span class="Constant">1</span> + press ctrl-z + ] + editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data + <span class="Comment"># redo</span> + assume-console [ + press ctrl-y + ] + run [ + editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data + <span class="Constant">3</span>:number<span class="Special"> <- </span>get *<span class="Constant">2</span>:address:editor-data, <span class="Constant">cursor-row:offset</span> + <span class="Constant">4</span>:number<span class="Special"> <- </span>get *<span class="Constant">2</span>:address:editor-data, <span class="Constant">cursor-column:offset</span> + ] + <span class="Comment"># cursor moves to left-click</span> + memory-should-contain [ + <span class="Constant">3</span><span class="Special"> <- </span><span class="Constant">3</span> + <span class="Constant">4</span><span class="Special"> <- </span><span class="Constant">1</span> + ] + <span class="Comment"># cursor should be in the right place</span> + assume-console [ + type <span class="Constant">[1]</span> + ] + run [ + editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data + ] + screen-should-contain [ + <span class="Constant"> . .</span> + <span class="Constant"> .abc .</span> + <span class="Constant"> .def .</span> + <span class="Constant"> .g1hi .</span> +<span class="Constant"> .┈┈┈┈┈┈┈┈┈┈.</span> + ] +] + +<span class="muRecipe">after</span> <span class="Constant"><handle-redo></span> [ + <span class="Delimiter">{</span> + move:address:move-operation<span class="Special"> <- </span>maybe-convert *op, <span class="Constant">move:variant</span> + <span class="muControl">break-unless</span> move + <span class="Comment"># assert cursor-row/cursor-column/top-of-screen match after-row/after-column/after-top-of-screen</span> + *cursor-row<span class="Special"> <- </span>get *move, <span class="Constant">after-row:offset</span> + *cursor-column<span class="Special"> <- </span>get *move, <span class="Constant">after-column:offset</span> + top:address:address:duplex-list<span class="Special"> <- </span>get *editor, <span class="Constant">top-of-screen:offset</span> + *top<span class="Special"> <- </span>get *move, <span class="Constant">after-top-of-screen:offset</span> + <span class="Delimiter">}</span> +] + +<span class="Comment"># undo backspace</span> + +<span class="muScenario">scenario</span> editor-can-undo-and-redo-backspace [ + <span class="Comment"># create an editor</span> + assume-screen <span class="Constant">10/width</span>, <span class="Constant">5/height</span> + <span class="Constant">1</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[]</span> + <span class="Constant">2</span>:address:editor-data<span class="Special"> <- </span>new-editor <span class="Constant">1</span>:address:array:character, screen:address, <span class="Constant">0/left</span>, <span class="Constant">10/right</span> + editor-render screen, <span class="Constant">2</span>:address:editor-data + <span class="Comment"># insert some text and hit backspace</span> + assume-console [ + type <span class="Constant">[abc]</span> + press backspace + press backspace + ] + editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data + screen-should-contain [ + <span class="Constant"> . .</span> + <span class="Constant"> .a .</span> +<span class="Constant"> .┈┈┈┈┈┈┈┈┈┈.</span> + <span class="Constant"> . .</span> + ] + <span class="Constant">3</span>:number<span class="Special"> <- </span>get *<span class="Constant">2</span>:address:editor-data, <span class="Constant">cursor-row:offset</span> + <span class="Constant">4</span>:number<span class="Special"> <- </span>get *<span class="Constant">2</span>:address:editor-data, <span class="Constant">cursor-column:offset</span> + memory-should-contain [ + <span class="Constant">3</span><span class="Special"> <- </span><span class="Constant">1</span> + <span class="Constant">4</span><span class="Special"> <- </span><span class="Constant">1</span> + ] + <span class="Comment"># undo</span> + assume-console [ + press ctrl-z + ] + run [ + editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data + ] + <span class="Constant">3</span>:number<span class="Special"> <- </span>get *<span class="Constant">2</span>:address:editor-data, <span class="Constant">cursor-row:offset</span> + <span class="Constant">4</span>:number<span class="Special"> <- </span>get *<span class="Constant">2</span>:address:editor-data, <span class="Constant">cursor-column:offset</span> + memory-should-contain [ + <span class="Constant">3</span><span class="Special"> <- </span><span class="Constant">1</span> + <span class="Constant">4</span><span class="Special"> <- </span><span class="Constant">3</span> + ] + screen-should-contain [ + <span class="Constant"> . .</span> + <span class="Constant"> .abc .</span> +<span class="Constant"> .┈┈┈┈┈┈┈┈┈┈.</span> + <span class="Constant"> . .</span> + ] + <span class="Comment"># redo</span> + assume-console [ + press ctrl-y + ] + run [ + editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data + ] + <span class="Constant">3</span>:number<span class="Special"> <- </span>get *<span class="Constant">2</span>:address:editor-data, <span class="Constant">cursor-row:offset</span> + <span class="Constant">4</span>:number<span class="Special"> <- </span>get *<span class="Constant">2</span>:address:editor-data, <span class="Constant">cursor-column:offset</span> + memory-should-contain [ + <span class="Constant">3</span><span class="Special"> <- </span><span class="Constant">1</span> + <span class="Constant">4</span><span class="Special"> <- </span><span class="Constant">1</span> + ] + screen-should-contain [ + <span class="Constant"> . .</span> + <span class="Constant"> .a .</span> +<span class="Constant"> .┈┈┈┈┈┈┈┈┈┈.</span> + <span class="Constant"> . .</span> + ] +] + +<span class="Comment"># save operation to undo</span> +<span class="muRecipe">after</span> <span class="Constant"><backspace-character-begin></span> [ + top-before:address:duplex-list<span class="Special"> <- </span>get *editor, <span class="Constant">top-of-screen:offset</span> +] +<span class="muRecipe">before</span> <span class="Constant"><backspace-character-end></span> [ + <span class="Delimiter">{</span> + <span class="muControl">break-unless</span> backspaced-cell <span class="Comment"># backspace failed; don't add an undo operation</span> + top-after:address:duplex-list<span class="Special"> <- </span>get *editor, <span class="Constant">top-of-screen:offset</span> + undo:address:address:list<span class="Special"> <- </span>get-address *editor, <span class="Constant">undo:offset</span> + <span class="Delimiter">{</span> + <span class="Comment"># if previous operation was an insert, coalesce this operation with it</span> + <span class="muControl">break-unless</span> *undo + op:address:operation<span class="Special"> <- </span>first *undo + deletion:address:delete-operation<span class="Special"> <- </span>maybe-convert *op, <span class="Constant">delete:variant</span> + <span class="muControl">break-unless</span> deletion + previous-coalesce-tag:number<span class="Special"> <- </span>get *deletion, <span class="Constant">tag:offset</span> + coalesce?:boolean<span class="Special"> <- </span>equal previous-coalesce-tag, <span class="Constant">1/coalesce-backspace</span> + <span class="muControl">break-unless</span> coalesce? + delete-from:address:address:duplex-list<span class="Special"> <- </span>get-address *deletion, <span class="Constant">delete-from:offset</span> + *delete-from<span class="Special"> <- </span>copy *before-cursor + backspaced-so-far:address:address:duplex-list<span class="Special"> <- </span>get-address *deletion, <span class="Constant">deleted-text:offset</span> + insert-duplex-range backspaced-cell, *backspaced-so-far + *backspaced-so-far<span class="Special"> <- </span>copy backspaced-cell + after-row:address:number<span class="Special"> <- </span>get-address *deletion, <span class="Constant">after-row:offset</span> + *after-row<span class="Special"> <- </span>copy *cursor-row + after-column:address:number<span class="Special"> <- </span>get-address *deletion, <span class="Constant">after-column:offset</span> + *after-column<span class="Special"> <- </span>copy *cursor-column + after-top:address:number<span class="Special"> <- </span>get-address *deletion, <span class="Constant">after-top-of-screen:offset</span> + *after-top<span class="Special"> <- </span>get *editor, <span class="Constant">top-of-screen:offset</span> + <span class="muControl">break</span> <span class="Constant">+done-adding-backspace-operation:label</span> + <span class="Delimiter">}</span> + <span class="Comment"># if not, create a new operation</span> + op:address:operation<span class="Special"> <- </span>new <span class="Constant">operation:type</span> + deleted-until:address:duplex-list<span class="Special"> <- </span>next-duplex *before-cursor + *op<span class="Special"> <- </span>merge <span class="Constant">2/delete-operation</span>, save-row/<span class="muRecipe">before</span>, save-column/<span class="muRecipe">before</span>, top-before, *cursor-row/<span class="muRecipe">after</span>, *cursor-column/<span class="muRecipe">after</span>, top-after, backspaced-cell/deleted, *before-cursor/delete-from, deleted-until, <span class="Constant">1/coalesce-backspace</span> + editor<span class="Special"> <- </span>add-operation editor, op +<span class="Constant"> +done-adding-backspace-operation</span> + <span class="Delimiter">}</span> +] + +<span class="muRecipe">after</span> <span class="Constant"><handle-undo></span> [ + <span class="Delimiter">{</span> + deletion:address:delete-operation<span class="Special"> <- </span>maybe-convert *op, <span class="Constant">delete:variant</span> + <span class="muControl">break-unless</span> deletion + start2:address:address:duplex-list<span class="Special"> <- </span>get-address *editor, <span class="Constant">data:offset</span> + anchor:address:duplex-list<span class="Special"> <- </span>get *deletion, <span class="Constant">delete-from:offset</span> + <span class="muControl">break-unless</span> anchor + deleted:address:duplex-list<span class="Special"> <- </span>get *deletion, <span class="Constant">deleted-text:offset</span> + old-cursor:address:duplex-list<span class="Special"> <- </span>last-duplex deleted + insert-duplex-range anchor, deleted + <span class="Comment"># assert cursor-row/cursor-column/top-of-screen match after-row/after-column/after-top-of-screen</span> + *before-cursor<span class="Special"> <- </span>copy old-cursor + *cursor-row<span class="Special"> <- </span>get *deletion, <span class="Constant">before-row:offset</span> + *cursor-column<span class="Special"> <- </span>get *deletion, <span class="Constant">before-column:offset</span> + top:address:address:duplex-list<span class="Special"> <- </span>get *editor, <span class="Constant">top-of-screen:offset</span> + *top<span class="Special"> <- </span>get *deletion, <span class="Constant">before-top-of-screen:offset</span> + <span class="Delimiter">}</span> +] + +<span class="muRecipe">after</span> <span class="Constant"><handle-redo></span> [ + <span class="Delimiter">{</span> + deletion:address:delete-operation<span class="Special"> <- </span>maybe-convert *op, <span class="Constant">delete:variant</span> + <span class="muControl">break-unless</span> deletion + start:address:duplex-list<span class="Special"> <- </span>get *deletion, <span class="Constant">delete-from:offset</span> + end:address:duplex-list<span class="Special"> <- </span>get *deletion, <span class="Constant">delete-until:offset</span> + remove-duplex-between start, end + <span class="Comment"># assert cursor-row/cursor-column/top-of-screen match after-row/after-column/after-top-of-screen</span> + *cursor-row<span class="Special"> <- </span>get *deletion, <span class="Constant">after-row:offset</span> + *cursor-column<span class="Special"> <- </span>get *deletion, <span class="Constant">after-column:offset</span> + top:address:address:duplex-list<span class="Special"> <- </span>get *editor, <span class="Constant">top-of-screen:offset</span> + *top<span class="Special"> <- </span>get *deletion, <span class="Constant">after-top-of-screen:offset</span> + <span class="Delimiter">}</span> +] + +<span class="Comment"># undo delete</span> + +<span class="muScenario">scenario</span> editor-can-undo-and-redo-delete [ + <span class="Comment"># create an editor</span> + assume-screen <span class="Constant">10/width</span>, <span class="Constant">5/height</span> + <span class="Constant">1</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[]</span> + <span class="Constant">2</span>:address:editor-data<span class="Special"> <- </span>new-editor <span class="Constant">1</span>:address:array:character, screen:address, <span class="Constant">0/left</span>, <span class="Constant">10/right</span> + editor-render screen, <span class="Constant">2</span>:address:editor-data + <span class="Comment"># insert some text and hit delete and backspace a few times</span> + assume-console [ + type <span class="Constant">[abcdef]</span> + left-click <span class="Constant">1</span>, <span class="Constant">2</span> + press delete + press backspace + press delete + press delete + ] + editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data + screen-should-contain [ + <span class="Constant"> . .</span> + <span class="Constant"> .af .</span> +<span class="Constant"> .┈┈┈┈┈┈┈┈┈┈.</span> + <span class="Constant"> . .</span> + ] + <span class="Constant">3</span>:number<span class="Special"> <- </span>get *<span class="Constant">2</span>:address:editor-data, <span class="Constant">cursor-row:offset</span> + <span class="Constant">4</span>:number<span class="Special"> <- </span>get *<span class="Constant">2</span>:address:editor-data, <span class="Constant">cursor-column:offset</span> + memory-should-contain [ + <span class="Constant">3</span><span class="Special"> <- </span><span class="Constant">1</span> + <span class="Constant">4</span><span class="Special"> <- </span><span class="Constant">1</span> + ] + <span class="Comment"># undo deletes</span> + assume-console [ + press ctrl-z + ] + run [ + editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data + ] + <span class="Constant">3</span>:number<span class="Special"> <- </span>get *<span class="Constant">2</span>:address:editor-data, <span class="Constant">cursor-row:offset</span> + <span class="Constant">4</span>:number<span class="Special"> <- </span>get *<span class="Constant">2</span>:address:editor-data, <span class="Constant">cursor-column:offset</span> + memory-should-contain [ + <span class="Constant">3</span><span class="Special"> <- </span><span class="Constant">1</span> + <span class="Constant">4</span><span class="Special"> <- </span><span class="Constant">1</span> + ] + screen-should-contain [ + <span class="Constant"> . .</span> + <span class="Constant"> .adef .</span> +<span class="Constant"> .┈┈┈┈┈┈┈┈┈┈.</span> + <span class="Constant"> . .</span> + ] + <span class="Comment"># undo backspace</span> + assume-console [ + press ctrl-z + ] + run [ + editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data + ] + <span class="Constant">3</span>:number<span class="Special"> <- </span>get *<span class="Constant">2</span>:address:editor-data, <span class="Constant">cursor-row:offset</span> + <span class="Constant">4</span>:number<span class="Special"> <- </span>get *<span class="Constant">2</span>:address:editor-data, <span class="Constant">cursor-column:offset</span> + memory-should-contain [ + <span class="Constant">3</span><span class="Special"> <- </span><span class="Constant">1</span> + <span class="Constant">4</span><span class="Special"> <- </span><span class="Constant">2</span> + ] + screen-should-contain [ + <span class="Constant"> . .</span> + <span class="Constant"> .abdef .</span> +<span class="Constant"> .┈┈┈┈┈┈┈┈┈┈.</span> + <span class="Constant"> . .</span> + ] + <span class="Comment"># undo first delete</span> + assume-console [ + press ctrl-z + ] + run [ + editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data + ] + <span class="Constant">3</span>:number<span class="Special"> <- </span>get *<span class="Constant">2</span>:address:editor-data, <span class="Constant">cursor-row:offset</span> + <span class="Constant">4</span>:number<span class="Special"> <- </span>get *<span class="Constant">2</span>:address:editor-data, <span class="Constant">cursor-column:offset</span> + memory-should-contain [ + <span class="Constant">3</span><span class="Special"> <- </span><span class="Constant">1</span> + <span class="Constant">4</span><span class="Special"> <- </span><span class="Constant">2</span> + ] + screen-should-contain [ + <span class="Constant"> . .</span> + <span class="Constant"> .abcdef .</span> +<span class="Constant"> .┈┈┈┈┈┈┈┈┈┈.</span> + <span class="Constant"> . .</span> + ] + <span class="Comment"># redo first delete</span> + assume-console [ + press ctrl-y + ] + run [ + editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data + ] + <span class="Comment"># first line inserted</span> + <span class="Constant">3</span>:number<span class="Special"> <- </span>get *<span class="Constant">2</span>:address:editor-data, <span class="Constant">cursor-row:offset</span> + <span class="Constant">4</span>:number<span class="Special"> <- </span>get *<span class="Constant">2</span>:address:editor-data, <span class="Constant">cursor-column:offset</span> + memory-should-contain [ + <span class="Constant">3</span><span class="Special"> <- </span><span class="Constant">1</span> + <span class="Constant">4</span><span class="Special"> <- </span><span class="Constant">2</span> + ] + screen-should-contain [ + <span class="Constant"> . .</span> + <span class="Constant"> .abdef .</span> +<span class="Constant"> .┈┈┈┈┈┈┈┈┈┈.</span> + <span class="Constant"> . .</span> + ] + <span class="Comment"># redo backspace</span> + assume-console [ + press ctrl-y + ] + run [ + editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data + ] + <span class="Comment"># first line inserted</span> + <span class="Constant">3</span>:number<span class="Special"> <- </span>get *<span class="Constant">2</span>:address:editor-data, <span class="Constant">cursor-row:offset</span> + <span class="Constant">4</span>:number<span class="Special"> <- </span>get *<span class="Constant">2</span>:address:editor-data, <span class="Constant">cursor-column:offset</span> + memory-should-contain [ + <span class="Constant">3</span><span class="Special"> <- </span><span class="Constant">1</span> + <span class="Constant">4</span><span class="Special"> <- </span><span class="Constant">1</span> + ] + screen-should-contain [ + <span class="Constant"> . .</span> + <span class="Constant"> .adef .</span> +<span class="Constant"> .┈┈┈┈┈┈┈┈┈┈.</span> + <span class="Constant"> . .</span> + ] + <span class="Comment"># redo deletes</span> + assume-console [ + press ctrl-y + ] + run [ + editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data + ] + <span class="Comment"># first line inserted</span> + <span class="Constant">3</span>:number<span class="Special"> <- </span>get *<span class="Constant">2</span>:address:editor-data, <span class="Constant">cursor-row:offset</span> + <span class="Constant">4</span>:number<span class="Special"> <- </span>get *<span class="Constant">2</span>:address:editor-data, <span class="Constant">cursor-column:offset</span> + memory-should-contain [ + <span class="Constant">3</span><span class="Special"> <- </span><span class="Constant">1</span> + <span class="Constant">4</span><span class="Special"> <- </span><span class="Constant">1</span> + ] + screen-should-contain [ + <span class="Constant"> . .</span> + <span class="Constant"> .af .</span> +<span class="Constant"> .┈┈┈┈┈┈┈┈┈┈.</span> + <span class="Constant"> . .</span> + ] +] + +<span class="muRecipe">after</span> <span class="Constant"><delete-character-begin></span> [ + top-before:address:duplex-list<span class="Special"> <- </span>get *editor, <span class="Constant">top-of-screen:offset</span> +] +<span class="muRecipe">before</span> <span class="Constant"><delete-character-end></span> [ + <span class="Delimiter">{</span> + <span class="muControl">break-unless</span> deleted-cell <span class="Comment"># delete failed; don't add an undo operation</span> + top-after:address:duplex-list<span class="Special"> <- </span>get *editor, <span class="Constant">top-of-screen:offset</span> + undo:address:address:list<span class="Special"> <- </span>get-address *editor, <span class="Constant">undo:offset</span> + <span class="Delimiter">{</span> + <span class="Comment"># if previous operation was an insert, coalesce this operation with it</span> + <span class="muControl">break-unless</span> *undo + op:address:operation<span class="Special"> <- </span>first *undo + deletion:address:delete-operation<span class="Special"> <- </span>maybe-convert *op, <span class="Constant">delete:variant</span> + <span class="muControl">break-unless</span> deletion + previous-coalesce-tag:number<span class="Special"> <- </span>get *deletion, <span class="Constant">tag:offset</span> + coalesce?:boolean<span class="Special"> <- </span>equal previous-coalesce-tag, <span class="Constant">2/coalesce-delete</span> + <span class="muControl">break-unless</span> coalesce? + delete-until:address:address:duplex-list<span class="Special"> <- </span>get-address *deletion, <span class="Constant">delete-until:offset</span> + *delete-until<span class="Special"> <- </span>next-duplex *before-cursor + deleted-so-far:address:address:duplex-list<span class="Special"> <- </span>get-address *deletion, <span class="Constant">deleted-text:offset</span> + *deleted-so-far<span class="Special"> <- </span>append-duplex *deleted-so-far, deleted-cell + after-row:address:number<span class="Special"> <- </span>get-address *deletion, <span class="Constant">after-row:offset</span> + *after-row<span class="Special"> <- </span>copy *cursor-row + after-column:address:number<span class="Special"> <- </span>get-address *deletion, <span class="Constant">after-column:offset</span> + *after-column<span class="Special"> <- </span>copy *cursor-column + after-top:address:number<span class="Special"> <- </span>get-address *deletion, <span class="Constant">after-top-of-screen:offset</span> + *after-top<span class="Special"> <- </span>get *editor, <span class="Constant">top-of-screen:offset</span> + <span class="muControl">break</span> <span class="Constant">+done-adding-delete-operation:label</span> + <span class="Delimiter">}</span> + <span class="Comment"># if not, create a new operation</span> + op:address:operation<span class="Special"> <- </span>new <span class="Constant">operation:type</span> + deleted-until:address:duplex-list<span class="Special"> <- </span>next-duplex *before-cursor + *op<span class="Special"> <- </span>merge <span class="Constant">2/delete-operation</span>, save-row/<span class="muRecipe">before</span>, save-column/<span class="muRecipe">before</span>, top-before, *cursor-row/<span class="muRecipe">after</span>, *cursor-column/<span class="muRecipe">after</span>, top-after, deleted-cell/deleted, *before-cursor/delete-from, deleted-until, <span class="Constant">2/coalesce-delete</span> + editor<span class="Special"> <- </span>add-operation editor, op +<span class="Constant"> +done-adding-delete-operation</span> + <span class="Delimiter">}</span> +] + +<span class="Comment"># undo ctrl-k</span> + +<span class="muScenario">scenario</span> editor-can-undo-and-redo-ctrl-k [ + <span class="Comment"># create an editor</span> + assume-screen <span class="Constant">10/width</span>, <span class="Constant">5/height</span> + <span class="Constant">1</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[abc</span> +<span class="Constant">def]</span> + <span class="Constant">2</span>:address:editor-data<span class="Special"> <- </span>new-editor <span class="Constant">1</span>:address:array:character, screen:address, <span class="Constant">0/left</span>, <span class="Constant">10/right</span> + editor-render screen, <span class="Constant">2</span>:address:editor-data + <span class="Comment"># insert some text and hit delete and backspace a few times</span> + assume-console [ + left-click <span class="Constant">1</span>, <span class="Constant">1</span> + press ctrl-k + ] + editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data + screen-should-contain [ + <span class="Constant"> . .</span> + <span class="Constant"> .a .</span> + <span class="Constant"> .def .</span> +<span class="Constant"> .┈┈┈┈┈┈┈┈┈┈.</span> + <span class="Constant"> . .</span> + ] + <span class="Constant">3</span>:number<span class="Special"> <- </span>get *<span class="Constant">2</span>:address:editor-data, <span class="Constant">cursor-row:offset</span> + <span class="Constant">4</span>:number<span class="Special"> <- </span>get *<span class="Constant">2</span>:address:editor-data, <span class="Constant">cursor-column:offset</span> + memory-should-contain [ + <span class="Constant">3</span><span class="Special"> <- </span><span class="Constant">1</span> + <span class="Constant">4</span><span class="Special"> <- </span><span class="Constant">1</span> + ] + <span class="Comment"># undo</span> + assume-console [ + press ctrl-z + ] + run [ + editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data + ] + screen-should-contain [ + <span class="Constant"> . .</span> + <span class="Constant"> .abc .</span> + <span class="Constant"> .def .</span> +<span class="Constant"> .┈┈┈┈┈┈┈┈┈┈.</span> + <span class="Constant"> . .</span> + ] + <span class="Constant">3</span>:number<span class="Special"> <- </span>get *<span class="Constant">2</span>:address:editor-data, <span class="Constant">cursor-row:offset</span> + <span class="Constant">4</span>:number<span class="Special"> <- </span>get *<span class="Constant">2</span>:address:editor-data, <span class="Constant">cursor-column:offset</span> + memory-should-contain [ + <span class="Constant">3</span><span class="Special"> <- </span><span class="Constant">1</span> + <span class="Constant">4</span><span class="Special"> <- </span><span class="Constant">1</span> + ] + <span class="Comment"># redo</span> + assume-console [ + press ctrl-y + ] + run [ + editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data + ] + <span class="Comment"># first line inserted</span> + screen-should-contain [ + <span class="Constant"> . .</span> + <span class="Constant"> .a .</span> + <span class="Constant"> .def .</span> +<span class="Constant"> .┈┈┈┈┈┈┈┈┈┈.</span> + <span class="Constant"> . .</span> + ] + <span class="Constant">3</span>:number<span class="Special"> <- </span>get *<span class="Constant">2</span>:address:editor-data, <span class="Constant">cursor-row:offset</span> + <span class="Constant">4</span>:number<span class="Special"> <- </span>get *<span class="Constant">2</span>:address:editor-data, <span class="Constant">cursor-column:offset</span> + memory-should-contain [ + <span class="Constant">3</span><span class="Special"> <- </span><span class="Constant">1</span> + <span class="Constant">4</span><span class="Special"> <- </span><span class="Constant">1</span> + ] + <span class="Comment"># cursor should be in the right place</span> + assume-console [ + type <span class="Constant">[1]</span> + ] + run [ + editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data + ] + screen-should-contain [ + <span class="Constant"> . .</span> + <span class="Constant"> .a1 .</span> + <span class="Constant"> .def .</span> +<span class="Constant"> .┈┈┈┈┈┈┈┈┈┈.</span> + <span class="Constant"> . .</span> + ] +] + +<span class="muRecipe">after</span> <span class="Constant"><delete-to-end-of-line-begin></span> [ + top-before:address:duplex-list<span class="Special"> <- </span>get *editor, <span class="Constant">top-of-screen:offset</span> +] +<span class="muRecipe">before</span> <span class="Constant"><delete-to-end-of-line-end></span> [ + <span class="Delimiter">{</span> + <span class="muControl">break-unless</span> deleted-cells <span class="Comment"># delete failed; don't add an undo operation</span> + top-after:address:duplex-list<span class="Special"> <- </span>get *editor, <span class="Constant">top-of-screen:offset</span> + undo:address:address:list<span class="Special"> <- </span>get-address *editor, <span class="Constant">undo:offset</span> + op:address:operation<span class="Special"> <- </span>new <span class="Constant">operation:type</span> + deleted-until:address:duplex-list<span class="Special"> <- </span>next-duplex *before-cursor + *op<span class="Special"> <- </span>merge <span class="Constant">2/delete-operation</span>, save-row/<span class="muRecipe">before</span>, save-column/<span class="muRecipe">before</span>, top-before, *cursor-row/<span class="muRecipe">after</span>, *cursor-column/<span class="muRecipe">after</span>, top-after, deleted-cells/deleted, *before-cursor/delete-from, deleted-until, <span class="Constant">0/never-coalesce</span> + editor<span class="Special"> <- </span>add-operation editor, op +<span class="Constant"> +done-adding-delete-operation</span> + <span class="Delimiter">}</span> +] + +<span class="Comment"># undo ctrl-u</span> + +<span class="muScenario">scenario</span> editor-can-undo-and-redo-ctrl-u [ + <span class="Comment"># create an editor</span> + assume-screen <span class="Constant">10/width</span>, <span class="Constant">5/height</span> + <span class="Constant">1</span>:address:array:character<span class="Special"> <- </span>new <span class="Constant">[abc</span> +<span class="Constant">def]</span> + <span class="Constant">2</span>:address:editor-data<span class="Special"> <- </span>new-editor <span class="Constant">1</span>:address:array:character, screen:address, <span class="Constant">0/left</span>, <span class="Constant">10/right</span> + editor-render screen, <span class="Constant">2</span>:address:editor-data + <span class="Comment"># insert some text and hit delete and backspace a few times</span> + assume-console [ + left-click <span class="Constant">1</span>, <span class="Constant">2</span> + press ctrl-u + ] + editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data + screen-should-contain [ + <span class="Constant"> . .</span> + <span class="Constant"> .c .</span> + <span class="Constant"> .def .</span> +<span class="Constant"> .┈┈┈┈┈┈┈┈┈┈.</span> + <span class="Constant"> . .</span> + ] + <span class="Constant">3</span>:number<span class="Special"> <- </span>get *<span class="Constant">2</span>:address:editor-data, <span class="Constant">cursor-row:offset</span> + <span class="Constant">4</span>:number<span class="Special"> <- </span>get *<span class="Constant">2</span>:address:editor-data, <span class="Constant">cursor-column:offset</span> + memory-should-contain [ + <span class="Constant">3</span><span class="Special"> <- </span><span class="Constant">1</span> + <span class="Constant">4</span><span class="Special"> <- </span><span class="Constant">0</span> + ] + <span class="Comment"># undo</span> + assume-console [ + press ctrl-z + ] + run [ + editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data + ] + screen-should-contain [ + <span class="Constant"> . .</span> + <span class="Constant"> .abc .</span> + <span class="Constant"> .def .</span> +<span class="Constant"> .┈┈┈┈┈┈┈┈┈┈.</span> + <span class="Constant"> . .</span> + ] + <span class="Constant">3</span>:number<span class="Special"> <- </span>get *<span class="Constant">2</span>:address:editor-data, <span class="Constant">cursor-row:offset</span> + <span class="Constant">4</span>:number<span class="Special"> <- </span>get *<span class="Constant">2</span>:address:editor-data, <span class="Constant">cursor-column:offset</span> + memory-should-contain [ + <span class="Constant">3</span><span class="Special"> <- </span><span class="Constant">1</span> + <span class="Constant">4</span><span class="Special"> <- </span><span class="Constant">2</span> + ] + <span class="Comment"># redo</span> + assume-console [ + press ctrl-y + ] + run [ + editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data + ] + <span class="Comment"># first line inserted</span> + screen-should-contain [ + <span class="Constant"> . .</span> + <span class="Constant"> .c .</span> + <span class="Constant"> .def .</span> +<span class="Constant"> .┈┈┈┈┈┈┈┈┈┈.</span> + <span class="Constant"> . .</span> + ] + <span class="Constant">3</span>:number<span class="Special"> <- </span>get *<span class="Constant">2</span>:address:editor-data, <span class="Constant">cursor-row:offset</span> + <span class="Constant">4</span>:number<span class="Special"> <- </span>get *<span class="Constant">2</span>:address:editor-data, <span class="Constant">cursor-column:offset</span> + memory-should-contain [ + <span class="Constant">3</span><span class="Special"> <- </span><span class="Constant">1</span> + <span class="Constant">4</span><span class="Special"> <- </span><span class="Constant">0</span> + ] + <span class="Comment"># cursor should be in the right place</span> + assume-console [ + type <span class="Constant">[1]</span> + ] + run [ + editor-event-loop screen:address, console:address, <span class="Constant">2</span>:address:editor-data + ] + screen-should-contain [ + <span class="Constant"> . .</span> + <span class="Constant"> .1c .</span> + <span class="Constant"> .def .</span> +<span class="Constant"> .┈┈┈┈┈┈┈┈┈┈.</span> + <span class="Constant"> . .</span> + ] +] + +<span class="muRecipe">after</span> <span class="Constant"><delete-to-start-of-line-begin></span> [ + top-before:address:duplex-list<span class="Special"> <- </span>get *editor, <span class="Constant">top-of-screen:offset</span> +] +<span class="muRecipe">before</span> <span class="Constant"><delete-to-start-of-line-end></span> [ + <span class="Delimiter">{</span> + <span class="muControl">break-unless</span> deleted-cells <span class="Comment"># delete failed; don't add an undo operation</span> + top-after:address:duplex-list<span class="Special"> <- </span>get *editor, <span class="Constant">top-of-screen:offset</span> + undo:address:address:list<span class="Special"> <- </span>get-address *editor, <span class="Constant">undo:offset</span> + op:address:operation<span class="Special"> <- </span>new <span class="Constant">operation:type</span> + deleted-until:address:duplex-list<span class="Special"> <- </span>next-duplex *before-cursor + *op<span class="Special"> <- </span>merge <span class="Constant">2/delete-operation</span>, save-row/<span class="muRecipe">before</span>, save-column/<span class="muRecipe">before</span>, top-before, *cursor-row/<span class="muRecipe">after</span>, *cursor-column/<span class="muRecipe">after</span>, top-after, deleted-cells/deleted, *before-cursor/delete-from, deleted-until, <span class="Constant">0/never-coalesce</span> + editor<span class="Special"> <- </span>add-operation editor, op +<span class="Constant"> +done-adding-delete-operation</span> + <span class="Delimiter">}</span> +] + +<span class="Comment"># todo:</span> +<span class="Comment"># operations for recipe side and each sandbox-data</span> +<span class="Comment"># undo delete sandbox as a separate primitive on the status bar</span> +</pre> +</body> +</html> +<!-- vim: set foldmethod=manual : --> diff --git a/html/factorial.mu.html b/html/factorial.mu.html index 30cf628b..d3837c22 100644 --- a/html/factorial.mu.html +++ b/html/factorial.mu.html @@ -13,10 +13,13 @@ 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; } -.Special { color: #ff6060; } +.muRecipe { color: #ff8700; } +.muScenario { color: #00af00; } .Comment { color: #9090ff; } -.Underlined { color: #c000c0; text-decoration: underline; } -.Identifier { color: #804000; } +.Constant { color: #00a0a0; } +.Special { color: #ff6060; } +.Delimiter { color: #a04060; } +.muControl { color: #c0a020; } --> </style> @@ -30,36 +33,36 @@ body { font-family: monospace; color: #eeeeee; background-color: #080808; } <pre id='vimCodeElement'> <span class="Comment"># example program: compute the factorial of 5</span> -recipe main [ - <span class="Underlined">local</span>-scope - x:number<span class="Special"> <- </span>factorial 5 - $<span class="Identifier">print</span> [result: ], x, [ -] +<span class="muRecipe">recipe</span> main [ + <span class="Constant">local-scope</span> + x:number<span class="Special"> <- </span>factorial <span class="Constant">5</span> + $print <span class="Constant">[result: ]</span>, x, <span class="Constant">[ </span> +<span class="Constant">]</span> ] -recipe factorial [ - <span class="Underlined">local</span>-scope - n:number<span class="Special"> <- </span>next-ingredient - { +<span class="muRecipe">recipe</span> factorial [ + <span class="Constant">local-scope</span> + n:number<span class="Special"> <- </span><span class="Constant">next-ingredient</span> + <span class="Delimiter">{</span> <span class="Comment"># if n=0 return 1</span> - zero?:boolean<span class="Special"> <- </span>equal n, 0 - break-unless zero? - reply 1 - } + zero?:boolean<span class="Special"> <- </span>equal n, <span class="Constant">0</span> + <span class="muControl">break-unless</span> zero? + <span class="muControl">reply</span> <span class="Constant">1</span> + <span class="Delimiter">}</span> <span class="Comment"># return n * factorial(n-1)</span> - x:number<span class="Special"> <- </span>subtract n, 1 + x:number<span class="Special"> <- </span>subtract n, <span class="Constant">1</span> subresult:number<span class="Special"> <- </span>factorial x result:number<span class="Special"> <- </span>multiply subresult, n - reply result + <span class="muControl">reply</span> result ] <span class="Comment"># unit test</span> -scenario factorial-test [ +<span class="muScenario">scenario</span> factorial-test [ run [ - 1:number<span class="Special"> <- </span>factorial 5 + <span class="Constant">1</span>:number<span class="Special"> <- </span>factorial <span class="Constant">5</span> ] memory-should-contain [ - 1<span class="Special"> <- </span>120 + <span class="Constant">1</span><span class="Special"> <- </span><span class="Constant">120</span> ] ] </pre> diff --git a/html/fork.mu.html b/html/fork.mu.html index b75cceac..09d02860 100644 --- a/html/fork.mu.html +++ b/html/fork.mu.html @@ -13,8 +13,11 @@ 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; } +.muRecipe { color: #ff8700; } .Comment { color: #9090ff; } -.Identifier { color: #804000; } +.Constant { color: #00a0a0; } +.Delimiter { color: #a04060; } +.muControl { color: #c0a020; } --> </style> @@ -28,19 +31,19 @@ body { font-family: monospace; color: #eeeeee; background-color: #080808; } <pre id='vimCodeElement'> <span class="Comment"># example program: running multiple routines</span> -recipe main [ - start-running thread2:recipe - { - $<span class="Identifier">print</span> 34 - loop - } +<span class="muRecipe">recipe</span> main [ + start-running <span class="Constant">thread2:recipe</span> + <span class="Delimiter">{</span> + $print <span class="Constant">34</span> + <span class="muControl">loop</span> + <span class="Delimiter">}</span> ] -recipe thread2 [ - { - $<span class="Identifier">print</span> 35 - loop - } +<span class="muRecipe">recipe</span> thread2 [ + <span class="Delimiter">{</span> + $print <span class="Constant">35</span> + <span class="muControl">loop</span> + <span class="Delimiter">}</span> ] </pre> </body> diff --git a/html/global.mu.html b/html/global.mu.html index f94b215c..6e2c0491 100644 --- a/html/global.mu.html +++ b/html/global.mu.html @@ -13,9 +13,10 @@ 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; } +.muRecipe { color: #ff8700; } .Comment { color: #9090ff; } +.Constant { color: #00a0a0; } .Special { color: #ff6060; } -.Identifier { color: #804000; } --> </style> @@ -29,17 +30,17 @@ body { font-family: monospace; color: #eeeeee; background-color: #080808; } <pre id='vimCodeElement'> <span class="Comment"># example program: creating and using global variables</span> -recipe main [ +<span class="muRecipe">recipe</span> main [ <span class="Comment"># allocate 5 locations for globals</span> - global-space:address:<span class="Identifier">array</span>:location<span class="Special"> <- </span><span class="Identifier">new</span> location:<span class="Identifier">type</span>, 5 + <span class="Constant">global-space</span>:address:array:location<span class="Special"> <- </span>new <span class="Constant">location:type</span>, <span class="Constant">5</span> <span class="Comment"># read to globals by using /space:global</span> - 1:number/space:global<span class="Special"> <- </span><span class="Identifier">copy</span> 3 + <span class="Special">1:number/space:global</span><span class="Special"> <- </span>copy <span class="Constant">3</span> foo ] -recipe foo [ +<span class="muRecipe">recipe</span> foo [ <span class="Comment"># ditto for writing to globals</span> - $<span class="Identifier">print</span> 1:number/space:global + $print <span class="Special">1:number/space:global</span> ] </pre> </body> diff --git a/html/screen.mu.html b/html/screen.mu.html index 72156547..6efea923 100644 --- a/html/screen.mu.html +++ b/html/screen.mu.html @@ -13,9 +13,10 @@ 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; } +.muRecipe { color: #ff8700; } .Comment { color: #9090ff; } +.Constant { color: #00a0a0; } .Special { color: #ff6060; } -.Identifier { color: #804000; } --> </style> @@ -28,30 +29,30 @@ body { font-family: monospace; color: #eeeeee; background-color: #080808; } <body> <pre id='vimCodeElement'> <span class="Comment"># example program: managing the display using 'screen' objects</span> -# +<span class="Comment">#</span> <span class="Comment"># The zero screen below means 'use the real screen'. Tests can also use fake</span> <span class="Comment"># screens.</span> -recipe main [ +<span class="muRecipe">recipe</span> main [ open-console - <span class="Identifier">print</span>-character 0/screen, 97/a, 2/red - 1:number/<span class="Special">raw</span>, 2:number/<span class="Special">raw <- </span>cursor-position 0/screen - wait-for-event 0/console - clear-screen 0/screen - move-cursor 0/screen, 0/row, 4/column - <span class="Identifier">print</span>-character 0/screen, 98/b - wait-for-event 0/console - move-cursor 0/screen, 0/row, 0/column - clear-line 0/screen - wait-for-event 0/console - cursor-down 0/screen - wait-for-event 0/console - cursor-right 0/screen - wait-for-event 0/console - cursor-left 0/screen - wait-for-event 0/console - cursor-up 0/screen - wait-for-event 0/console + print-character <span class="Constant">0/screen</span>, <span class="Constant">97/a</span>, <span class="Constant">2/red</span> + <span class="Constant">1</span>:number/<span class="Special">raw</span>, <span class="Constant">2</span>:number/<span class="Special">raw <- </span>cursor-position <span class="Constant">0/screen</span> + wait-for-event <span class="Constant">0/console</span> + clear-screen <span class="Constant">0/screen</span> + move-cursor <span class="Constant">0/screen</span>, <span class="Constant">0/row</span>, <span class="Constant">4/column</span> + print-character <span class="Constant">0/screen</span>, <span class="Constant">98/b</span> + wait-for-event <span class="Constant">0/console</span> + move-cursor <span class="Constant">0/screen</span>, <span class="Constant">0/row</span>, <span class="Constant">0/column</span> + clear-line <span class="Constant">0/screen</span> + wait-for-event <span class="Constant">0/console</span> + cursor-down <span class="Constant">0/screen</span> + wait-for-event <span class="Constant">0/console</span> + cursor-right <span class="Constant">0/screen</span> + wait-for-event <span class="Constant">0/console</span> + cursor-left <span class="Constant">0/screen</span> + wait-for-event <span class="Constant">0/console</span> + cursor-up <span class="Constant">0/screen</span> + wait-for-event <span class="Constant">0/console</span> close-console ] </pre> diff --git a/html/tangle.mu.html b/html/tangle.mu.html index aae321e8..e3dba023 100644 --- a/html/tangle.mu.html +++ b/html/tangle.mu.html @@ -13,10 +13,12 @@ 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; } -.Special { color: #ff6060; } +.muRecipe { color: #ff8700; } .Comment { color: #9090ff; } -.Underlined { color: #c000c0; text-decoration: underline; } -.Identifier { color: #804000; } +.Constant { color: #00a0a0; } +.Special { color: #ff6060; } +.Delimiter { color: #a04060; } +.muControl { color: #c0a020; } --> </style> @@ -29,40 +31,40 @@ body { font-family: monospace; color: #eeeeee; background-color: #080808; } <body> <pre id='vimCodeElement'> <span class="Comment"># example program: constructing recipes out of order</span> -# +<span class="Comment">#</span> <span class="Comment"># We construct a factorial function with separate base and recursive cases.</span> <span class="Comment"># Compare factorial.mu.</span> -# +<span class="Comment">#</span> <span class="Comment"># This isn't a very tasteful example, just a simple demonstration of</span> <span class="Comment"># possibilities.</span> -recipe factorial [ - <span class="Underlined">local</span>-scope - n:number<span class="Special"> <- </span>next-ingredient - { - +base-case - } - +recursive-case +<span class="muRecipe">recipe</span> factorial [ + <span class="Constant">local-scope</span> + n:number<span class="Special"> <- </span><span class="Constant">next-ingredient</span> + <span class="Delimiter">{</span> +<span class="Constant"> +base-case</span> + <span class="Delimiter">}</span> +<span class="Constant"> +recursive-case</span> ] -after +base-case [ +<span class="muRecipe">after</span> +base-case [ <span class="Comment"># if n=0 return 1</span> - zero?:boolean<span class="Special"> <- </span>equal n, 0 - break-unless zero? - reply 1 + zero?:boolean<span class="Special"> <- </span>equal n, <span class="Constant">0</span> + <span class="muControl">break-unless</span> zero? + <span class="muControl">reply</span> <span class="Constant">1</span> ] -after +recursive-case [ +<span class="muRecipe">after</span> +recursive-case [ <span class="Comment"># return n * factorial(n - 1)</span> - x:number<span class="Special"> <- </span>subtract n, 1 + x:number<span class="Special"> <- </span>subtract n, <span class="Constant">1</span> subresult:number<span class="Special"> <- </span>factorial x result:number<span class="Special"> <- </span>multiply subresult, n - reply result + <span class="muControl">reply</span> result ] -recipe main [ - 1:number<span class="Special"> <- </span>factorial 5 - $<span class="Identifier">print</span> [result: ], 1:number, [ +<span class="muRecipe">recipe</span> main [ + <span class="Constant">1</span>:number<span class="Special"> <- </span>factorial <span class="Constant">5</span> + $print <span class="Constant">[result: ]</span>, <span class="Constant">1</span>:number, [ ] ] </pre> diff --git a/html/x.mu.html b/html/x.mu.html index aa8162bc..7ff0e1aa 100644 --- a/html/x.mu.html +++ b/html/x.mu.html @@ -13,9 +13,10 @@ 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; } +.muRecipe { color: #ff8700; } .Comment { color: #9090ff; } +.Constant { color: #00a0a0; } .Special { color: #ff6060; } -.Identifier { color: #804000; } --> </style> @@ -29,11 +30,11 @@ body { font-family: monospace; color: #eeeeee; background-color: #080808; } <pre id='vimCodeElement'> <span class="Comment"># example program: add two numbers</span> -recipe main [ - 11:number<span class="Special"> <- </span><span class="Identifier">copy</span> 1 - 12:number<span class="Special"> <- </span><span class="Identifier">copy</span> 3 - 13:number<span class="Special"> <- </span>add 11:number, 12:number - $dump-memory +<span class="muRecipe">recipe</span> main [ + <span class="Constant">11</span>:number<span class="Special"> <- </span>copy <span class="Constant">1</span> + <span class="Constant">12</span>:number<span class="Special"> <- </span>copy <span class="Constant">3</span> + <span class="Constant">13</span>:number<span class="Special"> <- </span>add <span class="Constant">11</span>:number, <span class="Constant">12</span>:number +<span class="Constant"> $dump-memory</span> ] </pre> </body> |