https://github.com/akkartik/mu/blob/master/edit/005-sandbox.mu
1
2
3
4
5
6
7
8
9
10 def! main [
11 local-scope
12 open-console
13 clear-screen null/screen
14 env:&:environment <- new-programming-environment null/filesystem, null/screen
15 env <- restore-sandboxes env, null/filesystem
16 render-all null/screen, env, render
17 event-loop null/screen, null/console, env, null/filesystem
18 ]
19
20 container environment [
21 sandbox:&:sandbox
22 render-from:num
23 number-of-sandboxes:num
24 ]
25
26 after <programming-environment-initialization> [
27 *result <- put *result, render-from:offset, -1
28 ]
29
30 container sandbox [
31 data:text
32 response:text
33
34
35 starting-row-on-screen:num
36 code-ending-row-on-screen:num
37 screen:&:screen
38 next-sandbox:&:sandbox
39 ]
40
41 scenario run-and-show-results [
42 local-scope
43 trace-until 100/app
44 assume-screen 100/width, 15/height
45
46 assume-resources [
47 ]
48
49 env:&:environment <- new-programming-environment resources, screen, [divide-with-remainder 11, 3]
50 render-all screen, env, render
51
52 assume-console [
53 press F4
54 ]
55 run [
56 event-loop screen, console, env, resources
57 ]
58
59 screen-should-contain [
60 . run (F4) .
61 . ╎ .
62 .╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╎─────────────────────────────────────────────────.
63 . ╎0 edit copy to recipe delete .
64 . ╎divide-with-remainder 11, 3 .
65 . ╎3 .
66 . ╎2 .
67 . ╎─────────────────────────────────────────────────.
68 . ╎ .
69 ]
70 screen-should-contain-in-color 7/white, [
71 . .
72 . .
73 . .
74 . .
75 . divide-with-remainder 11, 3 .
76 . .
77 . .
78 . .
79 . .
80 ]
81 screen-should-contain-in-color 245/grey, [
82 . .
83 . ╎ .
84 .╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╎─────────────────────────────────────────────────.
85 . ╎ .
86 . ╎ .
87 . ╎3 .
88 . ╎2 .
89 . ╎─────────────────────────────────────────────────.
90 . ╎ .
91 ]
92
93 screen-should-contain-in-color 232/black, [
94 . .
95 . .
96 . .
97 . 0 edit copy to recipe delete .
98 ]
99
100 assume-console [
101 left-click 1, 80
102 type [add 2, 2]
103 press F4
104 ]
105 run [
106 event-loop screen, console, env, resources
107 ]
108
109 screen-should-contain [
110 . run (F4) .
111 . ╎ .
112 .╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╎─────────────────────────────────────────────────.
113 . ╎0 edit copy to recipe delete .
114 . ╎add 2, 2 .
115 . ╎4 .
116 . ╎─────────────────────────────────────────────────.
117 . ╎1 edit copy to recipe delete .
118 . ╎divide-with-remainder 11, 3 .
119 . ╎3 .
120 . ╎2 .
121 . ╎─────────────────────────────────────────────────.
122 . ╎ .
123 ]
124 ]
125
126 after <global-keypress> [
127
128 {
129 do-run?:bool <- equal k, 65532/F4
130 break-unless do-run?
131 screen <- update-status screen, [running... ], 245/grey
132 <begin-run-sandboxes-on-F4>
133 error?:bool <- run-sandboxes env, resources, screen
134
135 <end-run-sandboxes-on-F4>
136 screen <- render-sandbox-side screen, env, render
137 {
138 break-if error?
139 screen <- update-status screen, [ ], 245/grey
140 }
141 screen <- update-cursor screen, recipes, current-sandbox, sandbox-in-focus?, env
142 loop +next-event
143 }
144 ]
145
146 def run-sandboxes env:&:environment, resources:&:resources, screen:&:screen -> errors-found?:bool, env:&:environment, resources:&:resources, screen:&:screen [
147 local-scope
148 load-inputs
149 errors-found?:bool <- update-recipes env, resources, screen
150 jump-if errors-found?, +return
151
152 <begin-run-sandboxes>
153 current-sandbox:&:editor <- get *env, current-sandbox:offset
154 {
155 sandbox-contents:text <- editor-contents current-sandbox
156 break-unless sandbox-contents
157
158
159 new-sandbox:&:sandbox <- new sandbox:type
160 *new-sandbox <- put *new-sandbox, data:offset, sandbox-contents
161
162 dest:&:sandbox <- get *env, sandbox:offset
163 *new-sandbox <- put *new-sandbox, next-sandbox:offset, dest
164 *env <- put *env, sandbox:offset, new-sandbox
165
166 sandbox-count:num <- get *env, number-of-sandboxes:offset
167 sandbox-count <- add sandbox-count, 1
168 *env <- put *env, number-of-sandboxes:offset, sandbox-count
169
170
171 save-sandboxes env, resources
172
173 init:&:duplex-list:char <- push 167/§, null
174 *current-sandbox <- put *current-sandbox, data:offset, init
175 *current-sandbox <- put *current-sandbox, top-of-screen:offset, init
176 }
177
178 curr:&:sandbox <- get *env, sandbox:offset
179 idx:num <- copy 0
180 {
181 break-unless curr
182 curr <- update-sandbox curr, env, idx
183 curr <- get *curr, next-sandbox:offset
184 idx <- add idx, 1
185 loop
186 }
187 <end-run-sandboxes>
188 +return
189 {
190 break-if resources
191 $system [./snapshot_lesson]
192 }
193 ]
194
195
196
197 def update-recipes env:&:environment, resources:&:resources, screen:&:screen -> errors-found?:bool, env:&:environment, resources:&:resources, screen:&:screen [
198 local-scope
199 load-inputs
200 recipes:&:editor <- get *env, recipes:offset
201 in:text <- editor-contents recipes
202 resources <- dump resources, [lesson/recipes.mu], in
203 reload in
204 errors-found? <- copy false
205 ]
206
207
208 def update-sandbox sandbox:&:sandbox, env:&:environment, idx:num -> sandbox:&:sandbox, env:&:environment [
209 local-scope
210 load-inputs
211 data:text <- get *sandbox, data:offset
212 response:text, _, fake-screen:&:screen <- run-sandboxed data
213 *sandbox <- put *sandbox, response:offset, response
214 *sandbox <- put *sandbox, screen:offset, fake-screen
215 ]
216
217 def update-status screen:&:screen, msg:text, color:num -> screen:&:screen [
218 local-scope
219 load-inputs
220 screen <- move-cursor screen, 0, 2
221 screen <- print screen, msg, color, 238/grey/background
222 ]
223
224 def save-sandboxes env:&:environment, resources:&:resources -> resources:&:resources [
225 local-scope
226 load-inputs
227 trace 11, [app], [save sandboxes]
228 current-sandbox:&:editor <- get *env, current-sandbox:offset
229
230 $system [rm lesson/[0-9]* >/dev/null 2>/dev/null]
231 curr:&:sandbox <- get *env, sandbox:offset
232 idx:num <- copy 0
233 {
234 break-unless curr
235 resources <- save-sandbox resources, curr, idx
236 idx <- add idx, 1
237 curr <- get *curr, next-sandbox:offset
238 loop
239 }
240 ]
241
242 def save-sandbox resources:&:resources, sandbox:&:sandbox, sandbox-index:num -> resources:&:resources [
243 local-scope
244 load-inputs
245 data:text <- get *sandbox, data:offset
246 filename:text <- append [lesson/], sandbox-index
247 resources <- dump resources, filename, data
248 <end-save-sandbox>
249 ]
250
251 def! render-sandbox-side screen:&:screen, env:&:environment, render-editor:render-recipe -> screen:&:screen, env:&:environment [
252 local-scope
253 load-inputs
254 trace 11, [app], [render sandbox side]
255 old-top-idx:num <- save-top-idx screen
256 current-sandbox:&:editor <- get *env, current-sandbox:offset
257 row:num, column:num <- copy 1, 0
258 left:num <- get *current-sandbox, left:offset
259 right:num <- get *current-sandbox, right:offset
260
261 render-from:num <- get *env, render-from:offset
262 {
263 render-current-sandbox?:bool <- equal render-from, -1
264 break-unless render-current-sandbox?
265 row, column, screen, current-sandbox <- call render-editor, screen, current-sandbox
266 }
267
268 draw-horizontal screen, row, left, right
269 sandbox:&:sandbox <- get *env, sandbox:offset
270 row, screen <- render-sandboxes screen, sandbox, left, right, row, render-from
271 clear-rest-of-screen screen, row, left, right
272
273 assert-no-scroll screen, old-top-idx
274 ]
275
276 def render-sandboxes screen:&:screen, sandbox:&:sandbox, left:num, right:num, row:num, render-from:num, idx:num -> row:num, screen:&:screen, sandbox:&:sandbox [
277 local-scope
278 load-inputs
279 return-unless sandbox
280 screen-height:num <- screen-height screen
281 hidden?:bool <- lesser-than idx, render-from
282 {
283 break-if hidden?
284
285 row <- add row, 1
286 at-bottom?:bool <- greater-or-equal row, screen-height
287 return-if at-bottom?
288 screen <- move-cursor screen, row, left
289 screen <- render-sandbox-menu screen, idx, left, right
290
291 *sandbox <- put *sandbox, starting-row-on-screen:offset, row
292
293 row <- add row, 1
294 screen <- move-cursor screen, row, left
295 sandbox-data:text <- get *sandbox, data:offset
296 row, screen <- render-code screen, sandbox-data, left, right, row
297 *sandbox <- put *sandbox, code-ending-row-on-screen:offset, row
298
299 sandbox-response:text <- get *sandbox, response:offset
300 <render-sandbox-results>
301 {
302 sandbox-screen:&:screen <- get *sandbox, screen:offset
303 empty-screen?:bool <- fake-screen-is-empty? sandbox-screen
304 break-if empty-screen?
305 row, screen <- render-screen screen, sandbox-screen, left, right, row
306 }
307 {
308 break-unless empty-screen?
309 <render-sandbox-response>
310 row, screen <- render-text screen, sandbox-response, left, right, 245/grey, row
311 }
312 +render-sandbox-end
313 at-bottom?:bool <- greater-or-equal row, screen-height
314 return-if at-bottom?
315
316 draw-horizontal screen, row, left, right
317 }
318
319 {
320 break-unless hidden?
321 *sandbox <- put *sandbox, starting-row-on-screen:offset, 0
322 *sandbox <- put *sandbox, code-ending-row-on-screen:offset, 0
323 <end-render-sandbox-reset-hidden>
324 }
325
326 next-sandbox:&:sandbox <- get *sandbox, next-sandbox:offset
327 next-idx:num <- add idx, 1
328 row, screen <- render-sandboxes screen, next-sandbox, left, right, row, render-from, next-idx
329 ]
330
331 def render-sandbox-menu screen:&:screen, sandbox-index:num, left:num, right:num -> screen:&:screen [
332 local-scope
333 load-inputs
334 move-cursor-to-column screen, left
335 edit-button-left:num, edit-button-right:num, copy-button-left:num, copy-button-right:num, recipe-button-left:num, recipe-button-right:num, delete-button-left:num <- sandbox-menu-columns left, right
336 print screen, sandbox-index, 232/dark-grey, 245/grey
337 start-buttons:num <- subtract edit-button-left, 1
338 clear-line-until screen, start-buttons, 245/grey
339 print screen, [edit], 232/black, 25/background-blue
340 clear-line-until screen, edit-button-right, 25/background-blue
341 print screen, [copy], 232/black, 58/background-green
342 clear-line-until screen, copy-button-right, 58/background-green
343 print screen, [to recipe], 232/black, 94/background-orange
344 clear-line-until screen, recipe-button-right, 94/background-orange
345 print screen, [delete], 232/black, 52/background-red
346 clear-line-until screen, right, 52/background-red
347 ]
348
349 scenario skip-rendering-sandbox-menu-past-bottom-row [
350 trace-until 100/app
351 assume-screen 100/width, 6/height
352
353 assume-resources [
354 [lesson/0] <- [|add 2, 2|]
355 [lesson/1] <- [|add 1, 1|]
356 ]
357
358 env:&:environment <- new-programming-environment resources, screen, []
359 env <- restore-sandboxes env, resources
360 run [
361 render-all screen, env, render
362 ]
363 screen-should-contain [
364 . run (F4) .
365 . ╎ .
366 .╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╎─────────────────────────────────────────────────.
367 . ╎0 edit copy to recipe delete .
368 . ╎add 2, 2 .
369 . ╎─────────────────────────────────────────────────.
370 ]
371 ]
372
373
374
375
376 def sandbox-menu-columns left:num, right:num -> edit-button-left:num, edit-button-right:num, copy-button-left:num, copy-button-right:num, recipe-button-left:num, recipe-button-right:num, delete-button-left:num [
377 local-scope
378 load-inputs
379 start-buttons:num <- add left, 4/space-for-sandbox-index
380 buttons-space:num <- subtract right, start-buttons
381 button-width:num <- divide-with-remainder buttons-space, 4
382 buttons-wide-enough?:bool <- greater-or-equal button-width, 10
383 assert buttons-wide-enough?, [sandbox must be at least 40 or so characters wide]
384 edit-button-left:num <- copy start-buttons
385 copy-button-left:num <- add start-buttons, button-width
386 edit-button-right:num <- subtract copy-button-left, 1
387 recipe-button-left:num <- add copy-button-left, button-width
388 copy-button-right:num <- subtract recipe-button-left, 1
389 delete-button-left:num <- subtract right, button-width, -2
390 recipe-button-right:num <- subtract delete-button-left, 1
391 ]
392
393
394
395
396 def render-text screen:&:screen, s:text, left:num, right:num, color:num, row:num -> row:num, screen:&:screen [
397 local-scope
398 load-inputs
399 return-unless s
400 column:num <- copy left
401 screen <- move-cursor screen, row, column
402 screen-height:num <- screen-height screen
403 i:num <- copy 0
404 len:num <- length *s
405 {
406 +next-character
407 done?:bool <- greater-or-equal i, len
408 break-if done?
409 done? <- greater-or-equal row, screen-height
410 break-if done?
411 c:char <- index *s, i
412 {
413
414 newline?:bool <- equal c, 10/newline
415 break-unless newline?
416
417 {
418 done?:bool <- greater-than column, right
419 break-if done?
420 space:char <- copy 32/space
421 print screen, space
422 column <- add column, 1
423 loop
424 }
425 row <- add row, 1
426 column <- copy left
427 screen <- move-cursor screen, row, column
428 i <- add i, 1
429 loop +next-character
430 }
431 {
432
433 at-right?:bool <- equal column, right
434 break-unless at-right?
435
436 wrap-icon:char <- copy 8617/loop-back-to-left
437 print screen, wrap-icon, 245/grey
438 column <- copy left
439 row <- add row, 1
440 screen <- move-cursor screen, row, column
441
442 loop +next-character
443 }
444 i <- add i, 1
445 print screen, c, color
446 column <- add column, 1
447 loop
448 }
449 was-at-left?:bool <- equal column, left
450 clear-line-until screen, right
451 {
452 break-if was-at-left?
453 row <- add row, 1
454 }
455 move-cursor screen, row, left
456 ]
457
458 scenario render-text-wraps-barely-long-lines [
459 local-scope
460 assume-screen 5/width, 5/height
461 run [
462 render-text screen, [abcde], 0/left, 4/right, 7/white, 1/row
463 ]
464 screen-should-contain [
465 . .
466 .abcd↩.
467 .e .
468 . .
469 ]
470 ]
471
472
473 def restore-sandboxes env:&:environment, resources:&:resources -> env:&:environment [
474 local-scope
475 load-inputs
476
477 idx:num <- copy 0
478 curr:&:sandbox <- copy null
479 prev:&:sandbox <- copy null
480 {
481 filename:text <- append [lesson/], idx
482 contents:text <- slurp resources, filename
483 break-unless contents
484
485
486 curr <- new sandbox:type
487 *curr <- put *curr, data:offset, contents
488 <end-restore-sandbox>
489 {
490 break-if idx
491 *env <- put *env, sandbox:offset, curr
492 }
493 {
494 break-unless idx
495 *prev <- put *prev, next-sandbox:offset, curr
496 }
497 idx <- add idx, 1
498 prev <- copy curr
499 loop
500 }
501
502 *env <- put *env, number-of-sandboxes:offset, idx
503 ]
504
505
506
507 def render-screen screen:&:screen, sandbox-screen:&:screen, left:num, right:num, row:num -> row:num, screen:&:screen [
508 local-scope
509 load-inputs
510 return-unless sandbox-screen
511
512 row <- render-text screen, [screen:], left, right, 245/grey, row
513 screen <- move-cursor screen, row, left
514
515 column:num <- copy left
516 s-width:num <- screen-width sandbox-screen
517 s-height:num <- screen-height sandbox-screen
518 buf:&:@:screen-cell <- get *sandbox-screen, data:offset
519 stop-printing:num <- add left, s-width, 3
520 max-column:num <- min stop-printing, right
521 i:num <- copy 0
522 len:num <- length *buf
523 screen-height:num <- screen-height screen
524 {
525 done?:bool <- greater-or-equal i, len
526 break-if done?
527 done? <- greater-or-equal row, screen-height
528 break-if done?
529 column <- copy left
530 screen <- move-cursor screen, row, column
531
532 space:char <- copy 32/space
533 print screen, space, 245/grey
534 print screen, space, 245/grey
535 full-stop:char <- copy 46/period
536 print screen, full-stop, 245/grey
537 column <- add left, 3
538 {
539
540 row-done?:bool <- greater-or-equal column, max-column
541 break-if row-done?
542 curr:screen-cell <- index *buf, i
543 c:char <- get curr, contents:offset
544 color:num <- get curr, color:offset
545 {
546
547 white?:bool <- equal color, 7/white
548 break-unless white?
549 color <- copy 245/grey
550 }
551 print screen, c, color
552 column <- add column, 1
553 i <- add i, 1
554 loop
555 }
556
557 print screen, full-stop, 245/grey
558 column <- add column, 1
559 {
560
561 line-done?:bool <- greater-than column, right
562 break-if line-done?
563 print screen, space
564 column <- add column, 1
565 loop
566 }
567 row <- add row, 1
568 loop
569 }
570 ]
571
572 scenario run-updates-results [
573 local-scope
574 trace-until 100/app
575 assume-screen 100/width, 12/height
576
577 assume-resources [
578 [lesson/recipes.mu] <- [
579 ||
580 |recipe foo [|
581 | local-scope|
582 | z:num <- add 2, 2|
583 | reply z|
584 |]|
585 ]
586 ]
587
588 env:&:environment <- new-programming-environment resources, screen, [foo]
589 render-all screen, env, render
590 $clear-trace
591
592 assume-console [
593 press F4
594 ]
595 event-loop screen, console, env, resources
596 screen-should-contain [
597 . run (F4) .
598 . ╎ .
599 .recipe foo [ ╎─────────────────────────────────────────────────.
600 . local-scope ╎0 edit copy to recipe delete .
601 . z:num <- add 2, 2 ╎foo .
602 . reply z ╎4 .
603 .] ╎─────────────────────────────────────────────────.
604 . ╎ .
605 .╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╎ .
606 . ╎ .
607 ]
608
609 trace-should-contain [
610 app: save sandboxes
611 ]
612
613 trace-should-not-contain [
614 app: render recipes
615 ]
616
617 $clear-trace
618 assume-console [
619 left-click 4, 28
620 press backspace
621 type [3]
622 press F4
623 ]
624 run [
625 event-loop screen, console, env, resources
626 ]
627
628 screen-should-contain [
629 . run (F4) .
630 . ╎ .
631 .recipe foo [ ╎─────────────────────────────────────────────────.
632 . local-scope ╎0 edit copy to recipe delete .
633 . z:num <- add 2, 3 ╎foo .
634 . reply z ╎5 .
635 .] ╎─────────────────────────────────────────────────.
636 . ╎ .
637 .╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╎ .
638 . ╎ .
639 ]
640
641 trace-should-not-contain [
642 app: save sandboxes
643 ]
644 ]
645
646 scenario run-instruction-manages-screen-per-sandbox [
647 local-scope
648 trace-until 100/app
649 assume-screen 100/width, 20/height
650
651 assume-resources [
652 ]
653
654 env:&:environment <- new-programming-environment resources, screen, [print screen, 4]
655 render-all screen, env, render
656
657 assume-console [
658 press F4
659 ]
660 run [
661 event-loop screen, console, env, resources
662 ]
663
664 screen-should-contain [
665 . run (F4) .
666 . ╎ .
667 .╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╎─────────────────────────────────────────────────.
668 . ╎0 edit copy to recipe delete .
669 . ╎print screen, 4 .
670 . ╎screen: .
671 . ╎ .4 . .
672 . ╎ . . .
673 . ╎ . . .
674 . ╎ . . .
675 . ╎ . . .
676 . ╎─────────────────────────────────────────────────.
677 . ╎ .
678 ]
679 ]
680
681 def editor-contents editor:&:editor -> result:text [
682 local-scope
683 load-inputs
684 buf:&:buffer:char <- new-buffer 80
685 curr:&:duplex-list:char <- get *editor, data:offset
686
687 assert curr, [editor without data is illegal; must have at least a sentinel]
688 curr <- next curr
689 return-unless curr, null
690 {
691 break-unless curr
692 c:char <- get *curr, value:offset
693 buf <- append buf, c
694 curr <- next curr
695 loop
696 }
697 result <- buffer-to-array buf
698 ]
699
700 scenario editor-provides-edited-contents [
701 local-scope
702 assume-screen 10/width, 5/height
703 e:&:editor <- new-editor [abc], 0/left, 10/right
704 assume-console [
705 left-click 1, 2
706 type [def]
707 ]
708 run [
709 editor-event-loop screen, console, e
710 s:text <- editor-contents e
711 1:@:char/raw <- copy *s
712 ]
713 memory-should-contain [
714 1:array:character <- [abdefc]
715 ]
716 ]
717
718
719
720 scenario scrolling-down-past-bottom-of-recipe-editor [
721 local-scope
722 trace-until 100/app
723 assume-screen 100/width, 10/height
724 assume-resources [
725 ]
726 env:&:environment <- new-programming-environment resources, screen, []
727 render-all screen, env, render
728 assume-console [
729 press enter
730 press down-arrow
731 ]
732 event-loop screen, console, env, resources
733
734 screen-should-contain [
735 . run (F4) .
736 . ╎ .
737 . ╎─────────────────────────────────────────────────.
738 .╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╎ .
739 . ╎ .
740 ]
741 ]
742
743 scenario cursor-down-in-recipe-editor [
744 local-scope
745 trace-until 100/app
746 assume-screen 100/width, 10/height
747 assume-resources [
748 ]
749 env:&:environment <- new-programming-environment resources, screen, []
750 render-all screen, env, render
751 assume-console [
752 press enter
753 press up-arrow
754 press down-arrow
755 ]
756 event-loop screen, console, env, resources
757 cursor:char <- copy 9251/␣
758 print screen, cursor
759
760 screen-should-contain [
761 . run (F4) .
762 . ╎ .
763 .␣ ╎─────────────────────────────────────────────────.
764 .╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╎ .
765 . ╎ .
766 ]
767 ]
768
769 scenario scrolling-down-past-bottom-of-recipe-editor-2 [
770 local-scope
771 trace-until 100/app
772 assume-screen 100/width, 10/height
773 assume-resources [
774 ]
775 env:&:environment <- new-programming-environment resources, screen, []
776 render-all screen, env, render
777 assume-console [
778
779 press enter
780
781 press up-arrow
782
783 press page-down
784 ]
785 event-loop screen, console, env, resources
786
787 screen-should-contain [
788 . run (F4) .
789 . ╎ .
790 . ╎─────────────────────────────────────────────────.
791 .╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╎ .
792 . ╎ .
793 ]
794 ]
795
796 scenario scrolling-down-past-bottom-of-recipe-editor-3 [
797 local-scope
798 trace-until 100/app
799 assume-screen 100/width, 10/height
800 assume-resources [
801 ]
802 env:&:environment <- new-programming-environment resources, screen, [ab
803 cd]
804 render-all screen, env, render
805 assume-console [
806
807 press enter
808
809 press ctrl-n
810
811 press down-arrow
812 ]
813 event-loop screen, console, env, resources
814 cursor:char <- copy 9251/␣
815 print screen, cursor
816
817 screen-should-contain [
818 . run (F4) .
819 . ╎ab .
820 . ╎␣d .
821 .╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╎─────────────────────────────────────────────────.
822 . ╎ .
823 ]
824 ]
825
826
827
828 scenario scrolling-down-past-bottom-of-sandbox-editor [
829 local-scope
830 trace-until 100/app
831 assume-screen 100/width, 10/height
832
833 assume-resources [
834 ]
835 env:&:environment <- new-programming-environment resources, screen, [add 2, 2]
836 render-all screen, env, render
837 assume-console [
838
839 press F4
840 ]
841 event-loop screen, console, env, resources
842 screen-should-contain [
843 . run (F4) .
844 . ╎ .
845 .╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╎─────────────────────────────────────────────────.
846 . ╎0 edit copy to recipe delete .
847 . ╎add 2, 2 .
848 ]
849
850 assume-console [
851 press ctrl-n
852 press page-down
853 ]
854 run [
855 event-loop screen, console, env, resources
856 cursor:char <- copy 9251/␣
857 print screen, cursor
858 ]
859
860
861 screen-should-contain [
862 . run (F4) .
863 . ╎─────────────────────────────────────────────────.
864 .╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╎␣ edit copy to recipe delete .
865 . ╎add 2, 2 .
866 . ╎4 .
867 ]
868
869 assume-console [
870 press page-up
871 ]
872 run [
873 event-loop screen, console, env, resources
874 cursor:char <- copy 9251/␣
875 print screen, cursor
876 ]
877
878 screen-should-contain [
879 . run (F4) .
880 . ╎␣ .
881 .╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╎─────────────────────────────────────────────────.
882 . ╎0 edit copy to recipe delete .
883 . ╎add 2, 2 .
884 ]
885 ]
886
887
888 after <global-keypress> [
889 {
890 break-unless sandbox-in-focus?
891 page-down?:bool <- equal k, 65518/page-down
892 break-unless page-down?
893 sandbox:&:sandbox <- get *env, sandbox:offset
894 break-unless sandbox
895
896 {
897 render-from:num <- get *env, render-from:offset
898 number-of-sandboxes:num <- get *env, number-of-sandboxes:offset
899 max:num <- subtract number-of-sandboxes, 1
900 at-end?:bool <- greater-or-equal render-from, max
901 loop-if at-end?, +next-event
902 render-from <- add render-from, 1
903 *env <- put *env, render-from:offset, render-from
904 }
905 screen <- render-sandbox-side screen, env, render
906 screen <- update-cursor screen, recipes, current-sandbox, sandbox-in-focus?, env
907 loop +next-event
908 }
909 ]
910
911
912 after <update-cursor-special-cases> [
913 {
914 break-unless sandbox-in-focus?
915 render-from:num <- get *env, render-from:offset
916 scrolling?:bool <- greater-or-equal render-from, 0
917 break-unless scrolling?
918 cursor-column:num <- get *current-sandbox, left:offset
919 screen <- move-cursor screen, 2/row, cursor-column
920 return
921 }
922 ]
923
924
925 after <global-keypress> [
926 {
927 break-unless sandbox-in-focus?
928 page-up?:bool <- equal k, 65519/page-up
929 break-unless page-up?
930 render-from:num <- get *env, render-from:offset
931 at-beginning?:bool <- equal render-from, -1
932 break-if at-beginning?
933 render-from <- subtract render-from, 1
934 *env <- put *env, render-from:offset, render-from
935 screen <- render-sandbox-side screen, env, render
936 screen <- update-cursor screen, recipes, current-sandbox, sandbox-in-focus?, env
937 loop +next-event
938 }
939 ]
940
941
942
943 def previous-sandbox env:&:environment, in:&:sandbox -> out:&:sandbox [
944 local-scope
945 load-inputs
946 curr:&:sandbox <- get *env, sandbox:offset
947 return-unless curr, null
948 next:&:sandbox <- get *curr, next-sandbox:offset
949 {
950 return-unless next, null
951 found?:bool <- equal next, in
952 break-if found?
953 curr <- copy next
954 next <- get *curr, next-sandbox:offset
955 loop
956 }
957 return curr
958 ]
959
960 scenario scrolling-through-multiple-sandboxes [
961 local-scope
962 trace-until 100/app
963 assume-screen 100/width, 10/height
964
965 assume-resources [
966 ]
967 env:&:environment <- new-programming-environment resources, screen, []
968 render-all screen, env, render
969
970 assume-console [
971 press ctrl-n
972 type [add 2, 2]
973 press F4
974 type [add 1, 1]
975 press F4
976 ]
977 event-loop screen, console, env, resources
978 cursor:char <- copy 9251/␣
979 print screen, cursor
980 screen-should-contain [
981 . run (F4) .
982 . ╎␣ .
983 .╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╎─────────────────────────────────────────────────.
984 . ╎0 edit copy to recipe delete .
985 . ╎add 1, 1 .
986 . ╎2 .
987 . ╎─────────────────────────────────────────────────.
988 . ╎1 edit copy to recipe delete .
989 . ╎add 2, 2 .
990 . ╎4 .
991 ]
992
993 assume-console [
994 press page-down
995 ]
996 run [
997 event-loop screen, console, env, resources
998 cursor:char <- copy 9251/␣
999 print screen, cursor
1000 ]
1001
1002
1003 screen-should-contain [
1004 . run (F4) .
1005 . ╎─────────────────────────────────────────────────.
1006 .╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╎␣ edit copy to recipe delete .
1007 . ╎add 1, 1 .
1008 . ╎2 .
1009 . ╎─────────────────────────────────────────────────.
1010 . ╎1 edit copy to recipe delete .
1011 . ╎add 2, 2 .
1012 . ╎4 .
1013 ]
1014
1015 assume-console [
1016 press page-down
1017 ]
1018 run [
1019 event-loop screen, console, env, resources
1020 ]
1021
1022 screen-should-contain [
1023 . run (F4) .
1024 . ╎─────────────────────────────────────────────────.
1025 .╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╎1 edit copy to recipe delete .
1026 . ╎add 2, 2 .
1027 . ╎4 .
1028 . ╎─────────────────────────────────────────────────.
1029 . ╎ .
1030 ]
1031
1032 assume-console [
1033 press page-down
1034 ]
1035 run [
1036 event-loop screen, console, env, resources
1037 ]
1038
1039 screen-should-contain [
1040 . run (F4) .
1041 . ╎─────────────────────────────────────────────────.
1042 .╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╎1 edit copy to recipe delete .
1043 . ╎add 2, 2 .
1044 . ╎4 .
1045 . ╎─────────────────────────────────────────────────.
1046 . ╎ .
1047 ]
1048
1049 assume-console [
1050 press page-up
1051 ]
1052 run [
1053 event-loop screen, console, env, resources
1054 ]
1055
1056 screen-should-contain [
1057 . run (F4) .
1058 . ╎─────────────────────────────────────────────────.
1059 .╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╎0 edit copy to recipe delete .
1060 . ╎add 1, 1 .
1061 . ╎2 .
1062 . ╎─────────────────────────────────────────────────.
1063 . ╎1 edit copy to recipe delete .
1064 . ╎add 2, 2 .
1065 . ╎4 .
1066 ]
1067
1068 assume-console [
1069 press page-up
1070 ]
1071 run [
1072 event-loop screen, console, env, resources
1073 cursor:char <- copy 9251/␣
1074 print screen, cursor
1075 ]
1076
1077 screen-should-contain [
1078 . run (F4) .
1079 . ╎␣ .
1080 .╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╎─────────────────────────────────────────────────.
1081 . ╎0 edit copy to recipe delete .
1082 . ╎add 1, 1 .
1083 . ╎2 .
1084 . ╎─────────────────────────────────────────────────.
1085 . ╎1 edit copy to recipe delete .
1086 . ╎add 2, 2 .
1087 . ╎4 .
1088 ]
1089
1090 assume-console [
1091 press page-up
1092 ]
1093 run [
1094 event-loop screen, console, env, resources
1095 cursor:char <- copy 9251/␣
1096 print screen, cursor
1097 ]
1098
1099 screen-should-contain [
1100 . run (F4) .
1101 . ╎␣ .
1102 .╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╎─────────────────────────────────────────────────.
1103 . ╎0 edit copy to recipe delete .
1104 . ╎add 1, 1 .
1105 . ╎2 .
1106 . ╎─────────────────────────────────────────────────.
1107 . ╎1 edit copy to recipe delete .
1108 . ╎add 2, 2 .
1109 . ╎4 .
1110 ]
1111 ]
1112
1113 scenario scrolling-manages-sandbox-index-correctly [
1114 local-scope
1115 trace-until 100/app
1116 assume-screen 100/width, 10/height
1117
1118 assume-resources [
1119 ]
1120 env:&:environment <- new-programming-environment resources, screen, []
1121 render-all screen, env, render
1122
1123 assume-console [
1124 press ctrl-n
1125 type [add 1, 1]
1126 press F4
1127 ]
1128 event-loop screen, console, env, resources
1129 screen-should-contain [
1130 . run (F4) .
1131 . ╎ .
1132 .╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╎─────────────────────────────────────────────────.
1133 . ╎0 edit copy to recipe delete .
1134 . ╎add 1, 1 .
1135 . ╎2 .
1136 . ╎─────────────────────────────────────────────────.
1137 . ╎ .
1138 ]
1139
1140 assume-console [
1141 press page-down
1142 ]
1143 run [
1144 event-loop screen, console, env, resources
1145 ]
1146
1147
1148 screen-should-contain [
1149 . run (F4) .
1150 . ╎─────────────────────────────────────────────────.
1151 .╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╎0 edit copy to recipe delete .
1152 . ╎add 1, 1 .
1153 . ╎2 .
1154 . ╎─────────────────────────────────────────────────.
1155 . ╎ .
1156 ]
1157
1158 assume-console [
1159 press page-up
1160 ]
1161 run [
1162 event-loop screen, console, env, resources
1163 ]
1164
1165 screen-should-contain [
1166 . run (F4) .
1167 . ╎ .
1168 .╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╎─────────────────────────────────────────────────.
1169 . ╎0 edit copy to recipe delete .
1170 . ╎add 1, 1 .
1171 . ╎2 .
1172 . ╎─────────────────────────────────────────────────.
1173 . ╎ .
1174 ]
1175
1176 assume-console [
1177 press page-down
1178 ]
1179 run [
1180 event-loop screen, console, env, resources
1181 ]
1182
1183
1184 screen-should-contain [
1185 . run (F4) .
1186 . ╎─────────────────────────────────────────────────.
1187 .╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╎0 edit copy to recipe delete .
1188 . ╎add 1, 1 .
1189 . ╎2 .
1190 . ╎─────────────────────────────────────────────────.
1191 . ╎ .
1192 ]
1193 ]