1
2
3
4
5 def! main text:text [
6 local-scope
7 load-ingredients
8 open-console
9 editor:&:editor <- new-editor text, 5/left, 45/right
10 editor-event-loop 0/screen, 0/console, editor
11 close-console
12 ]
13
14 def editor-event-loop screen:&:screen, console:&:console, editor:&:editor -> screen:&:screen, console:&:console, editor:&:editor [
15 local-scope
16 load-ingredients
17 {
18 ¦
19 ¦ +next-event
20 ¦ cursor-row:num <- get *editor, cursor-row:offset
21 ¦ cursor-column:num <- get *editor, cursor-column:offset
22 ¦ screen <- move-cursor screen, cursor-row, cursor-column
23 ¦ e:event, found?:bool, quit?:bool, console <- read-event console
24 ¦ loop-unless found?
25 ¦ break-if quit?
26 ¦ trace 10, [app], [next-event]
27 ¦
28 ¦ t:touch-event, is-touch?:bool <- maybe-convert e, touch:variant
29 ¦ {
30 ¦ ¦ break-unless is-touch?
31 ¦ ¦ move-cursor-in-editor screen, editor, t
32 ¦ ¦ loop +next-event
33 ¦ }
34 ¦
35 ¦ {
36 ¦ ¦ break-if is-touch?
37 ¦ ¦ go-render?:bool <- handle-keyboard-event screen, editor, e
38 ¦ ¦ {
39 ¦ ¦ ¦ break-unless go-render?
40 ¦ ¦ ¦ screen <- editor-render screen, editor
41 ¦ ¦ }
42 ¦ }
43 ¦ loop
44 }
45 ]
46
47
48 def move-cursor-in-editor screen:&:screen, editor:&:editor, t:touch-event -> in-focus?:bool, editor:&:editor [
49 local-scope
50 load-ingredients
51 return-unless editor, 0/false
52 click-row:num <- get t, row:offset
53 return-unless click-row, 0/false
54 click-column:num <- get t, column:offset
55 left:num <- get *editor, left:offset
56 too-far-left?:bool <- lesser-than click-column, left
57 return-if too-far-left?, 0/false
58 right:num <- get *editor, right:offset
59 too-far-right?:bool <- greater-than click-column, right
60 return-if too-far-right?, 0/false
61
62 <move-cursor-begin>
63 editor <- snap-cursor screen, editor, click-row, click-column
64 undo-coalesce-tag:num <- copy 0/never
65 <move-cursor-end>
66
67 return 1/true
68 ]
69
70
71
72
73 def snap-cursor screen:&:screen, editor:&:editor, target-row:num, target-column:num -> editor:&:editor [
74 local-scope
75 load-ingredients
76 return-unless editor
77 left:num <- get *editor, left:offset
78 right:num <- get *editor, right:offset
79 screen-height:num <- screen-height screen
80
81 curr:&:duplex-list:char <- get *editor, top-of-screen:offset
82 prev:&:duplex-list:char <- copy curr
83 curr <- next curr
84 row:num <- copy 1/top
85 column:num <- copy left
86 *editor <- put *editor, cursor-row:offset, target-row
87 cursor-row:num <- copy target-row
88 *editor <- put *editor, cursor-column:offset, target-column
89 cursor-column:num <- copy target-column
90 before-cursor:&:duplex-list:char <- get *editor, before-cursor:offset
91 {
92 ¦ +next-character
93 ¦ break-unless curr
94 ¦ off-screen?:bool <- greater-or-equal row, screen-height
95 ¦ break-if off-screen?
96 ¦
97 ¦
98 ¦
99 ¦ {
100 ¦ ¦ at-cursor-row?:bool <- equal row, cursor-row
101 ¦ ¦ break-unless at-cursor-row?
102 ¦ ¦ at-cursor?:bool <- equal column, cursor-column
103 ¦ ¦ break-unless at-cursor?
104 ¦ ¦ before-cursor <- copy prev
105 ¦ ¦ *editor <- put *editor, before-cursor:offset, before-cursor
106 ¦ }
107 ¦ c:char <- get *curr, value:offset
108 ¦ {
109 ¦ ¦
110 ¦ ¦ newline?:bool <- equal c, 10/newline
111 ¦ ¦ break-unless newline?
112 ¦ ¦
113 ¦ ¦ {
114 ¦ ¦ ¦ at-cursor-row?:bool <- equal row, cursor-row
115 ¦ ¦ ¦ break-unless at-cursor-row?
116 ¦ ¦ ¦ left-of-cursor?:bool <- lesser-than column, cursor-column
117 ¦ ¦ ¦ break-unless left-of-cursor?
118 ¦ ¦ ¦ cursor-column <- copy column
119 ¦ ¦ ¦ *editor <- put *editor, cursor-column:offset, cursor-column
120 ¦ ¦ ¦ before-cursor <- copy prev
121 ¦ ¦ ¦ *editor <- put *editor, before-cursor:offset, before-cursor
122 ¦ ¦ }
123 ¦ ¦
124 ¦ ¦ row <- add row, 1
125 ¦ ¦ column <- copy left
126 ¦ ¦ curr <- next curr
127 ¦ ¦ prev <- next prev
128 ¦ ¦ loop +next-character
129 ¦ }
130 ¦ {
131 ¦ ¦
132 ¦ ¦
133 ¦ ¦ at-right?:bool <- equal column, right
134 ¦ ¦ break-unless at-right?
135 ¦ ¦ column <- copy left
136 ¦ ¦ row <- add row, 1
137 ¦ ¦
138 ¦ ¦ loop +next-character
139 ¦ }
140 ¦ curr <- next curr
141 ¦ prev <- next prev
142 ¦ column <- add column, 1
143 ¦ loop
144 }
145
146 {
147 ¦ at-cursor-row?:bool <- equal row, cursor-row
148 ¦ cursor-outside-line?:bool <- lesser-or-equal column, cursor-column
149 ¦ before-cursor-on-same-line?:bool <- and at-cursor-row?, cursor-outside-line?
150 ¦ above-cursor-row?:bool <- lesser-than row, cursor-row
151 ¦ before-cursor?:bool <- or before-cursor-on-same-line?, above-cursor-row?
152 ¦ break-unless before-cursor?
153 ¦ cursor-row <- copy row
154 ¦ *editor <- put *editor, cursor-row:offset, cursor-row
155 ¦ cursor-column <- copy column
156 ¦ *editor <- put *editor, cursor-column:offset, cursor-column
157 ¦ before-cursor <- copy prev
158 ¦ *editor <- put *editor, before-cursor:offset, before-cursor
159 }
160 ]
161
162
163
164 def handle-keyboard-event screen:&:screen, editor:&:editor, e:event -> go-render?:bool, screen:&:screen, editor:&:editor [
165 local-scope
166 load-ingredients
167 return-unless editor, 0/don't-render
168 screen-width:num <- screen-width screen
169 screen-height:num <- screen-height screen
170 left:num <- get *editor, left:offset
171 right:num <- get *editor, right:offset
172 before-cursor:&:duplex-list:char <- get *editor, before-cursor:offset
173 cursor-row:num <- get *editor, cursor-row:offset
174 cursor-column:num <- get *editor, cursor-column:offset
175 save-row:num <- copy cursor-row
176 save-column:num <- copy cursor-column
177
178 {
179 ¦ c:char, is-unicode?:bool <- maybe-convert e, text:variant
180 ¦ break-unless is-unicode?
181 ¦ trace 10, [app], [handle-keyboard-event: special character]
182 ¦
183 ¦ <handle-special-character>
184 ¦
185 ¦ regular-character?:bool <- greater-or-equal c, 32/space
186 ¦ return-unless regular-character?, 0/don't-render
187 ¦
188 ¦ <insert-character-begin>
189 ¦ go-render? <- insert-at-cursor editor, c, screen
190 ¦ <insert-character-end>
191 ¦ return
192 }
193
194 k:num, is-keycode?:bool <- maybe-convert e:event, keycode:variant
195 assert is-keycode?, [event was of unknown type; neither keyboard nor mouse]
196
197 <handle-special-key>
198 return 1/go-render
199 ]
200
201 def insert-at-cursor editor:&:editor, c:char, screen:&:screen -> go-render?:bool, editor:&:editor, screen:&:screen [
202 local-scope
203 load-ingredients
204 before-cursor:&:duplex-list:char <- get *editor, before-cursor:offset
205 insert c, before-cursor
206 before-cursor <- next before-cursor
207 *editor <- put *editor, before-cursor:offset, before-cursor
208 cursor-row:num <- get *editor, cursor-row:offset
209 cursor-column:num <- get *editor, cursor-column:offset
210 left:num <- get *editor, left:offset
211 right:num <- get *editor, right:offset
212 save-row:num <- copy cursor-row
213 save-column:num <- copy cursor-column
214 screen-width:num <- screen-width screen
215 screen-height:num <- screen-height screen
216
217 <insert-character-special-case>
218
219 cursor-column <- add cursor-column, 1
220 *editor <- put *editor, cursor-column:offset, cursor-column
221 next:&:duplex-list:char <- next before-cursor
222 {
223 ¦
224 ¦ at-end?:bool <- equal next, 0/null
225 ¦ break-unless at-end?
226 ¦ bottom:num <- subtract screen-height, 1
227 ¦ at-bottom?:bool <- equal save-row, bottom
228 ¦ at-right?:bool <- equal save-column, right
229 ¦ overflow?:bool <- and at-bottom?, at-right?
230 ¦ break-if overflow?
231 ¦ move-cursor screen, save-row, save-column
232 ¦ print screen, c
233 ¦ return 0/don't-render
234 }
235 {
236 ¦
237 ¦ break-unless next
238 ¦ at-right?:bool <- greater-or-equal cursor-column, screen-width
239 ¦ break-if at-right?
240 ¦ curr:&:duplex-list:char <- copy before-cursor
241 ¦ move-cursor screen, save-row, save-column
242 ¦ curr-column:num <- copy save-column
243 ¦ {
244 ¦ ¦
245 ¦ ¦ at-right?:bool <- greater-than curr-column, right
246 ¦ ¦ return-if at-right?, 1/go-render
247 ¦ ¦ break-unless curr
248 ¦ ¦
249 ¦ ¦ currc:char <- get *curr, value:offset
250 ¦ ¦ at-newline?:bool <- equal currc, 10/newline
251 ¦ ¦ break-if at-newline?
252 ¦ ¦ print screen, currc
253 ¦ ¦ curr-column <- add curr-column, 1
254 ¦ ¦ curr <- next curr
255 ¦ ¦ loop
256 ¦ }
257 ¦ return 0/don't-render
258 }
259 return 1/go-render
260 ]
261
262
263 def editor-render screen:&:screen, editor:&:editor -> screen:&:screen, editor:&:editor [
264 local-scope
265 load-ingredients
266 left:num <- get *editor, left:offset
267 right:num <- get *editor, right:offset
268 row:num, column:num <- render screen, editor
269 clear-line-until screen, right
270 row <- add row, 1
271 draw-horizontal screen, row, left, right, 9480/horizontal-dotted
272 row <- add row, 1
273 clear-screen-from screen, row, left, left, right
274 ]
275
276 scenario editor-handles-empty-event-queue [
277 local-scope
278 assume-screen 10/width, 5/height
279 e:&:editor <- new-editor [abc], 0/left, 10/right
280 editor-render screen, e
281 assume-console []
282 run [
283 ¦ editor-event-loop screen, console, e
284 ]
285 screen-should-contain [
286 ¦ . .
287 ¦ .abc .
288 ¦ .╌╌╌╌╌╌╌╌╌╌.
289 ¦ . .
290 ]
291 ]
292
293 scenario editor-handles-mouse-clicks [
294 local-scope
295 assume-screen 10/width, 5/height
296 e:&:editor <- new-editor [abc], 0/left, 10/right
297 editor-render screen, e
298 $clear-trace
299 assume-console [
300 ¦ left-click 1, 1
301 ]
302 run [
303 ¦ editor-event-loop screen, console, e
304 ¦ 3:num/raw <- get *e, cursor-row:offset
305 ¦ 4:num/raw <- get *e, cursor-column:offset
306 ]
307 screen-should-contain [
308 ¦ . .
309 ¦ .abc .
310 ¦ .╌╌╌╌╌╌╌╌╌╌.
311 ¦ . .
312 ]
313 memory-should-contain [
314 ¦ 3 <- 1
315 ¦ 4 <- 1
316 ]
317 check-trace-count-for-label 0, [print-character]
318 ]
319
320 scenario editor-handles-mouse-clicks-outside-text [
321 local-scope
322 assume-screen 10/width, 5/height
323 e:&:editor <- new-editor [abc], 0/left, 10/right
324 $clear-trace
325 assume-console [
326 ¦ left-click 1, 7
327 ]
328 run [
329 ¦ editor-event-loop screen, console, e
330 ¦ 3:num/raw <- get *e, cursor-row:offset
331 ¦ 4:num/raw <- get *e, cursor-column:offset
332 ]
333 memory-should-contain [
334 ¦ 3 <- 1
335 ¦ 4 <- 3
336 ]
337 check-trace-count-for-label 0, [print-character]
338 ]
339
340 scenario editor-handles-mouse-clicks-outside-text-2 [
341 local-scope
342 assume-screen 10/width, 5/height
343 s:text <- new [abc
344 def]
345 e:&:editor <- new-editor s, 0/left, 10/right
346 $clear-trace
347 assume-console [
348 ¦ left-click 1, 7
349 ]
350 run [
351 ¦ editor-event-loop screen, console, e
352 ¦ 3:num/raw <- get *e, cursor-row:offset
353 ¦ 4:num/raw <- get *e, cursor-column:offset
354 ]
355 memory-should-contain [
356 ¦ 3 <- 1
357 ¦ 4 <- 3
358 ]
359 check-trace-count-for-label 0, [print-character]
360 ]
361
362 scenario editor-handles-mouse-clicks-outside-text-3 [
363 local-scope
364 assume-screen 10/width, 5/height
365 s:text <- new [abc
366 def]
367 e:&:editor <- new-editor s, 0/left, 10/right
368 $clear-trace
369 assume-console [
370 ¦ left-click 3, 7
371 ]
372 run [
373 ¦ editor-event-loop screen, console, e
374 ¦ 3:num/raw <- get *e, cursor-row:offset
375 ¦ 4:num/raw <- get *e, cursor-column:offset
376 ]
377 memory-should-contain [
378 ¦ 3 <- 2
379 ¦ 4 <- 3
380 ]
381 check-trace-count-for-label 0, [print-character]
382 ]
383
384 scenario editor-handles-mouse-clicks-outside-column [
385 local-scope
386 assume-screen 10/width, 5/height
387
388 e:&:editor <- new-editor [abc], 0/left, 5/right
389 editor-render screen, e
390 $clear-trace
391 assume-console [
392 ¦
393 ¦ left-click 3, 8
394 ]
395 run [
396 ¦ editor-event-loop screen, console, e
397 ¦ 3:num/raw <- get *e, cursor-row:offset
398 ¦ 4:num/raw <- get *e, cursor-column:offset
399 ]
400 screen-should-contain [
401 ¦ . .
402 ¦ .abc .
403 ¦ .╌╌╌╌╌ .
404 ¦ . .
405 ]
406 memory-should-contain [
407 ¦ 3 <- 1
408 ¦ 4 <- 0
409 ]
410 check-trace-count-for-label 0, [print-character]
411 ]
412
413 scenario editor-handles-mouse-clicks-in-menu-area [
414 local-scope
415 assume-screen 10/width, 5/height
416 e:&:editor <- new-editor [abc], 0/left, 5/right
417 editor-render screen, e
418 $clear-trace
419 assume-console [
420 ¦
421 ¦ left-click 0, 3
422 ]
423 run [
424 ¦ editor-event-loop screen, console, e
425 ¦ 3:num/raw <- get *e, cursor-row:offset
426 ¦ 4:num/raw <- get *e, cursor-column:offset
427 ]
428
429 memory-should-contain [
430 ¦ 3 <- 1
431 ¦ 4 <- 0
432 ]
433 ]
434
435 scenario editor-inserts-characters-into-empty-editor [
436 local-scope
437 assume-screen 10/width, 5/height
438 e:&:editor <- new-editor [], 0/left, 5/right
439 editor-render screen, e
440 $clear-trace
441 assume-console [
442 ¦ type [abc]
443 ]
444 run [
445 ¦ editor-event-loop screen, console, e
446 ]
447 screen-should-contain [
448 ¦ . .
449 ¦ .abc .
450 ¦ .╌╌╌╌╌ .
451 ¦ . .
452 ]
453 check-trace-count-for-label 3, [print-character]
454 ]
455
456 scenario editor-inserts-characters-at-cursor [
457 local-scope
458 assume-screen 10/width, 5/height
459 e:&:editor <- new-editor [abc], 0/left, 10/right
460 editor-render screen, e
461 $clear-trace
462
463 assume-console [
464 ¦ type [0]
465 ¦ left-click 1, 2
466 ¦ type [d]
467 ]
468 run [
469 ¦ editor-event-loop screen, console, e
470 ]
471 screen-should-contain [
472 ¦ . .
473 ¦ .0adbc .
474 ¦ .╌╌╌╌╌╌╌╌╌╌.
475 ¦ . .
476 ]
477 check-trace-count-for-label 7, [print-character]
478 ]
479
480 scenario editor-inserts-characters-at-cursor-2 [
481 local-scope
482 assume-screen 10/width, 5/height
483 e:&:editor <- new-editor [abc], 0/left, 10/right
484 editor-render screen, e
485 $clear-trace
486 assume-console [
487 ¦ left-click 1, 5
488 ¦ type [d]
489 ]
490 run [
491 ¦ editor-event-loop screen, console, e
492 ]
493 screen-should-contain [
494 ¦ . .
495 ¦ .abcd .
496 ¦ .╌╌╌╌╌╌╌╌╌╌.
497 ¦ . .
498 ]
499 check-trace-count-for-label 1, [print-character]
500 ]
501
502 scenario editor-inserts-characters-at-cursor-5 [
503 local-scope
504 assume-screen 10/width, 5/height
505 s:text <- new [abc
506 d]
507 e:&:editor <- new-editor s, 0/left, 10/right
508 editor-render screen, e
509 $clear-trace
510 assume-console [
511 ¦ left-click 1, 5
512 ¦ type [e]
513 ]
514 run [
515 ¦ editor-event-loop screen, console, e
516 ]
517 screen-should-contain [
518 ¦ . .
519 ¦ .abce .
520 ¦ .d .
521 ¦ .╌╌╌╌╌╌╌╌╌╌.
522 ¦ . .
523 ]
524 check-trace-count-for-label 1, [print-character]
525 ]
526
527 scenario editor-inserts-characters-at-cursor-3 [
528 local-scope
529 assume-screen 10/width, 5/height
530 e:&:editor <- new-editor [abc], 0/left, 10/right
531 editor-render screen, e
532 $clear-trace
533 assume-console [
534 ¦ left-click 3, 5
535 ¦ type [d]
536 ]
537 run [
538 ¦ editor-event-loop screen, console, e
539 ]
540 screen-should-contain [
541 ¦ . .
542 ¦ .abcd .
543 ¦ .╌╌╌╌╌╌╌╌╌╌.
544 ¦ . .
545 ]
546 check-trace-count-for-label 1, [print-character]
547 ]
548
549 scenario editor-inserts-characters-at-cursor-4 [
550 local-scope
551 assume-screen 10/width, 5/height
552 s:text <- new [abc
553 d]
554 e:&:editor <- new-editor s, 0/left, 10/right
555 editor-render screen, e
556 $clear-trace
557 assume-console [
558 ¦ left-click 3, 5
559 ¦ type [e]
560 ]
561 run [
562 ¦ editor-event-loop screen, console, e
563 ]
564 screen-should-contain [
565 ¦ . .
566 ¦ .abc .
567 ¦ .de .
568 ¦ .╌╌╌╌╌╌╌╌╌╌.
569 ¦ . .
570 ]
571 check-trace-count-for-label 1, [print-character]
572 ]
573
574 scenario editor-inserts-characters-at-cursor-6 [
575 local-scope
576 assume-screen 10/width, 5/height
577 s:text <- new [abc
578 d]
579 e:&:editor <- new-editor s, 0/left, 10/right
580 editor-render screen, e
581 $clear-trace
582 assume-console [
583 ¦ left-click 3, 5
584 ¦ type [ef]
585 ]
586 run [
587 ¦ editor-event-loop screen, console, e
588 ]
589 screen-should-contain [
590 ¦ . .
591 ¦ .abc .
592 ¦ .def .
593 ¦ .╌╌╌╌╌╌╌╌╌╌.
594 ¦ . .
595 ]
596 check-trace-count-for-label 2, [print-character]
597 ]
598
599 scenario editor-moves-cursor-after-inserting-characters [
600 local-scope
601 assume-screen 10/width, 5/height
602 e:&:editor <- new-editor [ab], 0/left, 5/right
603 editor-render screen, e
604 assume-console [
605 ¦ type [01]
606 ]
607 run [
608 ¦ editor-event-loop screen, console, e
609 ]
610 screen-should-contain [
611 ¦ . .
612 ¦ .01ab .
613 ¦ .╌╌╌╌╌ .
614 ¦ . .
615 ]
616 ]
617
618
619
620 scenario editor-wraps-line-on-insert [
621 local-scope
622 assume-screen 5/width, 5/height
623 e:&:editor <- new-editor [abc], 0/left, 5/right
624 editor-render screen, e
625
626 assume-console [
627 ¦ type [e]
628 ]
629 run [
630 ¦ editor-event-loop screen, console, e
631 ]
632
633 screen-should-contain [
634 ¦ . .
635 ¦ .eabc .
636 ¦ .╌╌╌╌╌.
637 ¦ . .
638 ¦ . .
639 ]
640
641 assume-console [
642 ¦ type [f]
643 ]
644 run [
645 ¦ editor-event-loop screen, console, e
646 ]
647
648 screen-should-contain [
649 ¦ . .
650 ¦ .efab↩.
651 ¦ .c .
652 ¦ .╌╌╌╌╌.
653 ¦ . .
654 ]
655 ]
656
657 scenario editor-wraps-line-on-insert-2 [
658 local-scope
659
660 assume-screen 10/width, 5/height
661 s:text <- new [abcdefg
662 defg]
663 e:&:editor <- new-editor s, 0/left, 5/right
664 editor-render screen, e
665
666 assume-console [
667 ¦ left-click 3, 0
668 ¦ type [abc]
669 ]
670 run [
671 ¦ editor-event-loop screen, console, e
672 ¦ 3:num/raw <- get *e, cursor-row:offset
673 ¦ 4:num/raw <- get *e, cursor-column:offset
674 ]
675
676 memory-should-contain [
677 ¦ 3 <- 3
678 ¦ 4 <- 3
679 ]
680
681 screen-should-contain [
682 ¦ . .
683 ¦ .abcd↩ .
684 ¦ .efg .
685 ¦ .abcd↩ .
686 ¦ .efg .
687 ]
688 ]
689
690 after <insert-character-special-case> [
691
692 {
693 ¦
694 ¦
695 ¦
696 ¦ wrap-column:num <- copy right
697 ¦ before-wrap-column:num <- subtract wrap-column, 1
698 ¦ at-wrap?:bool <- greater-or-equal cursor-column, wrap-column
699 ¦ just-before-wrap?:bool <- greater-or-equal cursor-column, before-wrap-column
700 ¦ next:&:duplex-list:char <- next before-cursor
701 ¦
702 ¦ at-end-of-line?:bool <- equal next, 0
703 ¦ {
704 ¦ ¦ break-if at-end-of-line?
705 ¦ ¦ next-character:char <- get *next, value:offset
706 ¦ ¦ at-end-of-line? <- equal next-character, 10/newline
707 ¦ }
708 ¦
709 ¦ move-cursor-to-next-line?:bool <- copy 0/false
710 ¦ {
711 ¦ ¦ break-if at-end-of-line?
712 ¦ ¦ move-cursor-to-next-line? <- copy just-before-wrap?
713 ¦ ¦
714 ¦ ¦
715 ¦ ¦ potential-new-cursor-column:num <- copy left
716 ¦ }
717 ¦ {
718 ¦ ¦ break-unless at-end-of-line?
719 ¦ ¦ move-cursor-to-next-line? <- copy at-wrap?
720 ¦ ¦
721 ¦ ¦
722 ¦ ¦
723 ¦ ¦ potential-new-cursor-column:num <- add left, 1/make-room-for-wrap-indicator
724 ¦ }
725 ¦ break-unless move-cursor-to-next-line?
726 ¦ cursor-column <- copy potential-new-cursor-column
727 ¦ *editor <- put *editor, cursor-column:offset, cursor-column
728 ¦ cursor-row <- add cursor-row, 1
729 ¦ *editor <- put *editor, cursor-row:offset, cursor-row
730 ¦
731 ¦ {
732 ¦ ¦ below-screen?:bool <- greater-or-equal cursor-row, screen-height
733 ¦ ¦ break-unless below-screen?
734 ¦ ¦ <scroll-down>
735 ¦ }
736 ¦ return 1/go-render
737 }
738 ]
739
740 scenario editor-wraps-cursor-after-inserting-characters-in-middle-of-line [
741 local-scope
742 assume-screen 10/width, 5/height
743 e:&:editor <- new-editor [abcde], 0/left, 5/right
744 assume-console [
745 ¦ left-click 1, 3
746 ¦ type [f]
747 ]
748 run [
749 ¦ editor-event-loop screen, console, e
750 ¦ 3:num/raw <- get *e, cursor-row:offset
751 ¦ 4:num/raw <- get *e, cursor-column:offset
752 ]
753 screen-should-contain [
754 ¦ . .
755 ¦ .abcf↩ .
756 ¦ .de .
757 ¦ .╌╌╌╌╌ .
758 ¦ . .
759 ]
760 memory-should-contain [
761 ¦ 3 <- 2
762 ¦ 4 <- 0
763 ]
764 ]
765
766 scenario editor-wraps-cursor-after-inserting-characters-at-end-of-line [
767 local-scope
768 assume-screen 10/width, 5/height
769
770 s:text <- new [abc
771 xyz]
772 e:&:editor <- new-editor s, 0/left, 5/right
773 editor-render screen, e
774 screen-should-contain [
775 ¦ . .
776 ¦ .abc .
777 ¦ .xyz .
778 ¦ .╌╌╌╌╌ .
779 ¦ . .
780 ]
781 assume-console [
782 ¦ left-click 1, 4
783 ¦ type [de]
784 ]
785 run [
786 ¦ editor-event-loop screen, console, e
787 ]
788 screen-should-contain [
789 ¦ . .
790 ¦ .abcd↩ .
791 ¦ .e .
792 ¦ .xyz .
793 ¦ .╌╌╌╌╌ .
794 ]
795 ]
796
797 scenario editor-wraps-cursor-to-left-margin [
798 local-scope
799 assume-screen 10/width, 5/height
800 e:&:editor <- new-editor [abcde], 2/left, 7/right
801 assume-console [
802 ¦ left-click 1, 5
803 ¦ type [01]
804 ]
805 run [
806 ¦ editor-event-loop screen, console, e
807 ¦ 3:num/raw <- get *e, cursor-row:offset
808 ¦ 4:num/raw <- get *e, cursor-column:offset
809 ]
810 screen-should-contain [
811 ¦ . .
812 ¦ . abc0↩ .
813 ¦ . 1de .
814 ¦ . ╌╌╌╌╌ .
815 ¦ . .
816 ]
817 memory-should-contain [
818 ¦ 3 <- 2
819 ¦ 4 <- 3
820 ]
821 ]
822
823
824
825 container editor [
826 indent?:bool
827 ]
828
829 after <editor-initialization> [
830 *result <- put *result, indent?:offset, 1/true
831 ]
832
833 scenario editor-moves-cursor-down-after-inserting-newline [
834 local-scope
835 assume-screen 10/width, 5/height
836 e:&:editor <- new-editor [abc], 0/left, 10/right
837 assume-console [
838 ¦ type [0
839 1]
840 ]
841 run [
842 ¦ editor-event-loop screen, console, e
843 ]
844 screen-should-contain [
845 ¦ . .
846 ¦ .0 .
847 ¦ .1abc .
848 ¦ .╌╌╌╌╌╌╌╌╌╌.
849 ¦ . .
850 ]
851 ]
852
853 after <handle-special-character> [
854 {
855 ¦ newline?:bool <- equal c, 10/newline
856 ¦ break-unless newline?
857 ¦ <insert-enter-begin>
858 ¦ insert-new-line-and-indent editor, screen
859 ¦ <insert-enter-end>
860 ¦ return 1/go-render
861 }
862 ]
863
864 def insert-new-line-and-indent editor:&:editor, screen:&:screen -> editor:&:editor, screen:&:screen [
865 local-scope
866 load-ingredients
867 cursor-row:num <- get *editor, cursor-row:offset
868 cursor-column:num <- get *editor, cursor-column:offset
869 before-cursor:&:duplex-list:char <- get *editor, before-cursor:offset
870 left:num <- get *editor, left:offset
871 right:num <- get *editor, right:offset
872 screen-height:num <- screen-height screen
873
874 insert 10/newline, before-cursor
875 before-cursor <- next before-cursor
876 *editor <- put *editor, before-cursor:offset, before-cursor
877 cursor-row <- add cursor-row, 1
878 *editor <- put *editor, cursor-row:offset, cursor-row
879 cursor-column <- copy left
880 *editor <- put *editor, cursor-column:offset, cursor-column
881
882 {
883 ¦ below-screen?:bool <- greater-or-equal cursor-row, screen-height
884 ¦ break-unless below-screen?
885 ¦ <scroll-down>
886 ¦ cursor-row <- subtract cursor-row, 1
887 ¦ *editor <- put *editor, cursor-row:offset, cursor-row
888 }
889
890 indent?:bool <- get *editor, indent?:offset
891 return-unless indent?
892 d:&:duplex-list:char <- get *editor, data:offset
893 end-of-previous-line:&:duplex-list:char <- prev before-cursor
894 indent:num <- line-indent end-of-previous-line, d
895 i:num <- copy 0
896 {
897 ¦ indent-done?:bool <- greater-or-equal i, indent
898 ¦ break-if indent-done?
899 ¦ insert-at-cursor editor, 32/space, screen
900 ¦ i <- add i, 1
901 ¦ loop
902 }
903 ]
904
905
906
907 def line-indent curr:&:duplex-list:char, start:&:duplex-list:char -> result:num [
908 local-scope
909 load-ingredients
910 result:num <- copy 0
911 return-unless curr
912 at-start?:bool <- equal curr, start
913 return-if at-start?
914 {
915 ¦ curr <- prev curr
916 ¦ break-unless curr
917 ¦ at-start?:bool <- equal curr, start
918 ¦ break-if at-start?
919 ¦ c:char <- get *curr, value:offset
920 ¦ at-newline?:bool <- equal c, 10/newline
921 ¦ break-if at-newline?
922 ¦
923 ¦ is-space?:bool <- equal c, 32/space
924 ¦ {
925 ¦ ¦ break-unless is-space?
926 ¦ ¦ result <- add result, 1
927 ¦ }
928 ¦
929 ¦ {
930 ¦ ¦ break-if is-space?
931 ¦ ¦ result <- copy 0
932 ¦ }
933 ¦ loop
934 }
935 ]
936
937 scenario editor-moves-cursor-down-after-inserting-newline-2 [
938 local-scope
939 assume-screen 10/width, 5/height
940 e:&:editor <- new-editor [abc], 1/left, 10/right
941 assume-console [
942 ¦ type [0
943 1]
944 ]
945 run [
946 ¦ editor-event-loop screen, console, e
947 ]
948 screen-should-contain [
949 ¦ . .
950 ¦ . 0 .
951 ¦ . 1abc .
952 ¦ . ╌╌╌╌╌╌╌╌╌.
953 ¦ . .
954 ]
955 ]
956
957 scenario editor-clears-previous-line-completely-after-inserting-newline [
958 local-scope
959 assume-screen 10/width, 5/height
960 e:&:editor <- new-editor [abcde], 0/left, 5/right
961 editor-render screen, e
962 screen-should-contain [
963 ¦ . .
964 ¦ .abcd↩ .
965 ¦ .e .
966 ¦ .╌╌╌╌╌ .
967 ¦ . .
968 ]
969 assume-console [
970 ¦ press enter
971 ]
972 run [
973 ¦ editor-event-loop screen, console, e
974 ]
975
976 screen-should-contain [
977 ¦ . .
978 ¦ . .
979 ¦ .abcd↩ .
980 ¦ .e .
981 ¦ .╌╌╌╌╌ .
982 ]
983 ]
984
985 scenario editor-inserts-indent-after-newline [
986 local-scope
987 assume-screen 10/width, 10/height
988 s:text <- new [ab
989 cd
990 ef]
991 e:&:editor <- new-editor s, 0/left, 10/right
992
993 assume-console [
994 ¦ left-click 2, 8
995 ¦ type [
996 ]
997 ]
998 run [
999 ¦ editor-event-loop screen, console, e
1000 ¦ 3:num/raw <- get *e, cursor-row:offset
1001 ¦ 4:num/raw <- get *e, cursor-column:offset
1002 ]
1003
1004 memory-should-contain [
1005 ¦ 3 <- 3
1006 ¦ 4 <- 2
1007 ]
1008 ]
1009
1010 scenario editor-skips-indent-around-paste [
1011 local-scope
1012 assume-screen 10/width, 10/height
1013 s:text <- new [ab
1014 cd
1015 ef]
1016 e:&:editor <- new-editor s, 0/left, 10/right
1017
1018 assume-console [
1019 ¦ left-click 2, 8
1020 ¦ press 65507
1021 ¦ press enter
1022 ¦ press 65506
1023 ]
1024 run [
1025 ¦ editor-event-loop screen, console, e
1026 ¦ 3:num/raw <- get *e, cursor-row:offset
1027 ¦ 4:num/raw <- get *e, cursor-column:offset
1028 ]
1029
1030 memory-should-contain [
1031 ¦ 3 <- 3
1032 ¦ 4 <- 0
1033 ]
1034 ]
1035
1036 after <handle-special-key> [
1037 {
1038 ¦ paste-start?:bool <- equal k, 65507/paste-start
1039 ¦ break-unless paste-start?
1040 ¦ *editor <- put *editor, indent?:offset, 0/false
1041 ¦ return 1/go-render
1042 }
1043 ]
1044
1045 after <handle-special-key> [
1046 {
1047 ¦ paste-end?:bool <- equal k, 65506/paste-end
1048 ¦ break-unless paste-end?
1049 ¦ *editor <- put *editor, indent?:offset, 1/true
1050 ¦ return 1/go-render
1051 }
1052 ]
1053
1054
1055
1056 def draw-horizontal screen:&:screen, row:num, x:num, right:num -> screen:&:screen [
1057 local-scope
1058 load-ingredients
1059 style:char, style-found?:bool <- next-ingredient
1060 {
1061 ¦ break-if style-found?
1062 ¦ style <- copy 9472/horizontal
1063 }
1064 color:num, color-found?:bool <- next-ingredient
1065 {
1066 ¦
1067 ¦ break-if color-found?
1068 ¦ color <- copy 245/grey
1069 }
1070 bg-color:num, bg-color-found?:bool <- next-ingredient
1071 {
1072 ¦ break-if bg-color-found?
1073 ¦ bg-color <- copy 0/black
1074 }
1075 screen <- move-cursor screen, row, x
1076 {
1077 ¦ continue?:bool <- lesser-or-equal x, right
1078 ¦ break-unless continue?
1079 ¦ print screen, style, color, bg-color
1080 ¦ x <- add x, 1
1081 ¦ loop
1082 }
1083 ]