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