1
2
3
4
5 def! main text:text [
6 local-scope
7 load-ingredients
8 open-console
9 hide-screen 0/screen
10 new-editor text, 0/left, 5/right
11 show-screen 0/screen
12 wait-for-event 0/console
13 close-console
14 ]
15
16 scenario editor-renders-text-to-screen [
17 local-scope
18 assume-screen 10/width, 5/height
19 e:&:editor <- new-editor [abc], 0/left, 10/right
20 run [
21 render screen, e
22 ]
23 screen-should-contain [
24
25 . .
26 .abc .
27 . .
28 ]
29 ]
30
31 container editor [
32
33 data:&:duplex-list:char
34 top-of-screen:&:duplex-list:char
35 bottom-of-screen:&:duplex-list:char
36
37 before-cursor:&:duplex-list:char
38
39
40
41 left:num
42 right:num
43 bottom:num
44
45 cursor-row:num
46 cursor-column:num
47 ]
48
49
50
51 def new-editor s:text, left:num, right:num -> result:&:editor [
52 local-scope
53 load-ingredients
54
55 right <- subtract right, 1
56 result <- new editor:type
57
58 *result <- put *result, left:offset, left
59 *result <- put *result, right:offset, right
60
61 *result <- put *result, cursor-row:offset, 1/top
62 *result <- put *result, cursor-column:offset, left
63
64 init:&:duplex-list:char <- push 167/§, 0/tail
65 *result <- put *result, data:offset, init
66 *result <- put *result, top-of-screen:offset, init
67 *result <- put *result, before-cursor:offset, init
68 result <- insert-text result, s
69 <editor-initialization>
70 ]
71
72 def insert-text editor:&:editor, text:text -> editor:&:editor [
73 local-scope
74 load-ingredients
75
76 return-unless text
77 len:num <- length *text
78 return-unless len
79 idx:num <- copy 0
80
81 curr:&:duplex-list:char <- get *editor, data:offset
82 {
83 done?:bool <- greater-or-equal idx, len
84 break-if done?
85 c:char <- index *text, idx
86 insert c, curr
87
88 curr <- next curr
89 idx <- add idx, 1
90 loop
91 }
92 ]
93
94 scenario editor-initializes-without-data [
95 local-scope
96 assume-screen 5/width, 3/height
97 run [
98 e:&:editor <- new-editor 0/data, 2/left, 5/right
99 2:editor/raw <- copy *e
100 ]
101 memory-should-contain [
102
103
104 4 <- 0
105
106 6 <- 2
107 7 <- 4
108 8 <- 0
109 9 <- 1
110 10 <- 2
111 ]
112 screen-should-contain [
113 . .
114 . .
115 . .
116 ]
117 ]
118
119
120
121
122 def render screen:&:screen, editor:&:editor -> last-row:num, last-column:num, screen:&:screen, editor:&:editor [
123 local-scope
124 load-ingredients
125 return-unless editor, 1/top, 0/left
126 left:num <- get *editor, left:offset
127 screen-height:num <- screen-height screen
128 right:num <- get *editor, right:offset
129
130 curr:&:duplex-list:char <- get *editor, top-of-screen:offset
131 prev:&:duplex-list:char <- copy curr
132 curr <- next curr
133
134 +render-loop-initialization
135 color:num <- copy 7/white
136 row:num <- copy 1/top
137 column:num <- copy left
138 cursor-row:num <- get *editor, cursor-row:offset
139 cursor-column:num <- get *editor, cursor-column:offset
140 before-cursor:&:duplex-list:char <- get *editor, before-cursor:offset
141 screen <- move-cursor screen, row, column
142 {
143 +next-character
144 break-unless curr
145 off-screen?:bool <- greater-or-equal row, screen-height
146 break-if off-screen?
147
148
149
150 {
151 at-cursor-row?:bool <- equal row, cursor-row
152 break-unless at-cursor-row?
153 at-cursor?:bool <- equal column, cursor-column
154 break-unless at-cursor?
155 before-cursor <- copy prev
156 }
157 c:char <- get *curr, value:offset
158 <character-c-received>
159 {
160
161 newline?:bool <- equal c, 10/newline
162 break-unless newline?
163
164 {
165 at-cursor-row?:bool <- equal row, cursor-row
166 break-unless at-cursor-row?
167 left-of-cursor?:bool <- lesser-than column, cursor-column
168 break-unless left-of-cursor?
169 cursor-column <- copy column
170 before-cursor <- prev curr
171 }
172
173 clear-line-until screen, right
174
175 row <- add row, 1
176 column <- copy left
177 screen <- move-cursor screen, row, column
178 curr <- next curr
179 prev <- next prev
180 loop +next-character
181 }
182 {
183
184
185 at-right?:bool <- equal column, right
186 break-unless at-right?
187
188 wrap-icon:char <- copy 8617/loop-back-to-left
189 print screen, wrap-icon, 245/grey
190 column <- copy left
191 row <- add row, 1
192 screen <- move-cursor screen, row, column
193
194 loop +next-character
195 }
196 print screen, c, color
197 curr <- next curr
198 prev <- next prev
199 column <- add column, 1
200 loop
201 }
202
203 *editor <- put *editor, bottom-of-screen:offset, curr
204
205 {
206 at-cursor-row?:bool <- equal row, cursor-row
207 cursor-outside-line?:bool <- lesser-or-equal column, cursor-column
208 before-cursor-on-same-line?:bool <- and at-cursor-row?, cursor-outside-line?
209 above-cursor-row?:bool <- lesser-than row, cursor-row
210 before-cursor?:bool <- or before-cursor-on-same-line?, above-cursor-row?
211 break-unless before-cursor?
212 cursor-row <- copy row
213 cursor-column <- copy column
214 before-cursor <- copy prev
215 }
216 *editor <- put *editor, bottom:offset, row
217 *editor <- put *editor, cursor-row:offset, cursor-row
218 *editor <- put *editor, cursor-column:offset, cursor-column
219 *editor <- put *editor, before-cursor:offset, before-cursor
220 return row, column
221 ]
222
223 def clear-screen-from screen:&:screen, row:num, column:num, left:num, right:num -> screen:&:screen [
224 local-scope
225 load-ingredients
226
227 {
228 break-if screen
229 clear-display-from row, column, left, right
230 return
231 }
232
233 screen <- move-cursor screen, row, column
234 clear-line-until screen, right
235 clear-rest-of-screen screen, row, left, right
236 ]
237
238 def clear-rest-of-screen screen:&:screen, row:num, left:num, right:num -> screen:&:screen [
239 local-scope
240 load-ingredients
241 row <- add row, 1
242 screen <- move-cursor screen, row, left
243 screen-height:num <- screen-height screen
244 {
245 at-bottom-of-screen?:bool <- greater-or-equal row, screen-height
246 break-if at-bottom-of-screen?
247 screen <- move-cursor screen, row, left
248 clear-line-until screen, right
249 row <- add row, 1
250 loop
251 }
252 ]
253
254 scenario editor-prints-multiple-lines [
255 local-scope
256 assume-screen 5/width, 5/height
257 s:text <- new [abc
258 def]
259 e:&:editor <- new-editor s, 0/left, 5/right
260 run [
261 render screen, e
262 ]
263 screen-should-contain [
264 . .
265 .abc .
266 .def .
267 . .
268 ]
269 ]
270
271 scenario editor-handles-offsets [
272 local-scope
273 assume-screen 5/width, 5/height
274 e:&:editor <- new-editor [abc], 1/left, 5/right
275 run [
276 render screen, e
277 ]
278 screen-should-contain [
279 . .
280 . abc .
281 . .
282 ]
283 ]
284
285 scenario editor-prints-multiple-lines-at-offset [
286 local-scope
287 assume-screen 5/width, 5/height
288 s:text <- new [abc
289 def]
290 e:&:editor <- new-editor s, 1/left, 5/right
291 run [
292 render screen, e
293 ]
294 screen-should-contain [
295 . .
296 . abc .
297 . def .
298 . .
299 ]
300 ]
301
302 scenario editor-wraps-long-lines [
303 local-scope
304 assume-screen 5/width, 5/height
305 e:&:editor <- new-editor [abc def], 0/left, 5/right
306 run [
307 render screen, e
308 ]
309 screen-should-contain [
310 . .
311 .abc ↩.
312 .def .
313 . .
314 ]
315 screen-should-contain-in-color 245/grey [
316 . .
317 . ↩.
318 . .
319 . .
320 ]
321 ]
322
323 scenario editor-wraps-barely-long-lines [
324 local-scope
325 assume-screen 5/width, 5/height
326 e:&:editor <- new-editor [abcde], 0/left, 5/right
327 run [
328 render screen, e
329 ]
330
331
332 screen-should-contain [
333 . .
334 .abcd↩.
335 .e .
336 . .
337 ]
338 screen-should-contain-in-color 245/grey [
339 . .
340 . ↩.
341 . .
342 . .
343 ]
344 ]
345
346 scenario editor-with-empty-text [
347 local-scope
348 assume-screen 5/width, 5/height
349 e:&:editor <- new-editor [], 0/left, 5/right
350 run [
351 render screen, e
352 3:num/raw <- get *e, cursor-row:offset
353 4:num/raw <- get *e, cursor-column:offset
354 ]
355 screen-should-contain [
356 . .
357 . .
358 . .
359 ]
360 memory-should-contain [
361 3 <- 1
362 4 <- 0
363 ]
364 ]
365
366
367
368 scenario render-colors-comments [
369 local-scope
370 assume-screen 5/width, 5/height
371 s:text <- new [abc
372 # de
373 f]
374 e:&:editor <- new-editor s, 0/left, 5/right
375 run [
376 render screen, e
377 ]
378 screen-should-contain [
379 . .
380 .abc .
381 .# de .
382 .f .
383 . .
384 ]
385 screen-should-contain-in-color 12/lightblue, [
386 . .
387 . .
388 .# de .
389 . .
390 . .
391 ]
392 screen-should-contain-in-color 7/white, [
393 . .
394 .abc .
395 . .
396 .f .
397 . .
398 ]
399 ]
400
401 after <character-c-received> [
402 color <- get-color color, c
403 ]
404
405
406 def get-color color:num, c:char -> color:num [
407 local-scope
408 load-ingredients
409 color-is-white?:bool <- equal color, 7/white
410
411 {
412 break-unless color-is-white?
413 starting-comment?:bool <- equal c, 35/#
414 break-unless starting-comment?
415 trace 90, [app], [switch color back to blue]
416 color <- copy 12/lightblue
417 jump +exit
418 }
419
420 {
421 color-is-blue?:bool <- equal color, 12/lightblue
422 break-unless color-is-blue?
423 ending-comment?:bool <- equal c, 10/newline
424 break-unless ending-comment?
425 trace 90, [app], [switch color back to white]
426 color <- copy 7/white
427 jump +exit
428 }
429
430 {
431 break-unless color-is-white?
432 starting-assignment?:bool <- equal c, 60/<
433 break-unless starting-assignment?
434 color <- copy 1/red
435 jump +exit
436 }
437
438 {
439 color-is-red?:bool <- equal color, 1/red
440 break-unless color-is-red?
441 ending-assignment?:bool <- equal c, 32/space
442 break-unless ending-assignment?
443 color <- copy 7/white
444 jump +exit
445 }
446
447 +exit
448 return color
449 ]
450
451 scenario render-colors-assignment [
452 local-scope
453 assume-screen 8/width, 5/height
454 s:text <- new [abc
455 d <- e
456 f]
457 e:&:editor <- new-editor s, 0/left, 8/right
458 run [
459 render screen, e
460 ]
461 screen-should-contain [
462 . .
463 .abc .
464 .d <- e .
465 .f .
466 . .
467 ]
468 screen-should-contain-in-color 1/red, [
469 . .
470 . .
471 . <- .
472 . .
473 . .
474 ]
475 ]