1
2
3
4
5 def main text:text [
6 local-scope
7 load-ingredients
8 open-console
9 clear-screen 0/screen
10 e:&:editor <- new-editor text, 0/left, 5/right
11 render 0/screen, e
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 color:num <- copy 7/white
135 row:num <- copy 1/top
136 column:num <- copy left
137 cursor-row:num <- get *editor, cursor-row:offset
138 cursor-column:num <- get *editor, cursor-column:offset
139 before-cursor:&:duplex-list:char <- get *editor, before-cursor:offset
140 screen <- move-cursor screen, row, column
141 {
142 ¦ +next-character
143 ¦ break-unless curr
144 ¦ off-screen?:bool <- greater-or-equal row, screen-height
145 ¦ break-if off-screen?
146 ¦
147 ¦
148 ¦
149 ¦ {
150 ¦ ¦ at-cursor-row?:bool <- equal row, cursor-row
151 ¦ ¦ break-unless at-cursor-row?
152 ¦ ¦ at-cursor?:bool <- equal column, cursor-column
153 ¦ ¦ break-unless at-cursor?
154 ¦ ¦ before-cursor <- copy prev
155 ¦ }
156 ¦ c:char <- get *curr, value:offset
157 ¦ <character-c-received>
158 ¦ {
159 ¦ ¦
160 ¦ ¦ newline?:bool <- equal c, 10/newline
161 ¦ ¦ break-unless newline?
162 ¦ ¦
163 ¦ ¦ {
164 ¦ ¦ ¦ at-cursor-row?:bool <- equal row, cursor-row
165 ¦ ¦ ¦ break-unless at-cursor-row?
166 ¦ ¦ ¦ left-of-cursor?:bool <- lesser-than column, cursor-column
167 ¦ ¦ ¦ break-unless left-of-cursor?
168 ¦ ¦ ¦ cursor-column <- copy column
169 ¦ ¦ ¦ before-cursor <- prev curr
170 ¦ ¦ }
171 ¦ ¦
172 ¦ ¦ clear-line-until screen, right
173 ¦ ¦
174 ¦ ¦ row <- add row, 1
175 ¦ ¦ column <- copy left
176 ¦ ¦ screen <- move-cursor screen, row, column
177 ¦ ¦ curr <- next curr
178 ¦ ¦ prev <- next prev
179 ¦ ¦ loop +next-character
180 ¦ }
181 ¦ {
182 ¦ ¦
183 ¦ ¦
184 ¦ ¦ at-right?:bool <- equal column, right
185 ¦ ¦ break-unless at-right?
186 ¦ ¦
187 ¦ ¦ wrap-icon:char <- copy 8617/loop-back-to-left
188 ¦ ¦ print screen, wrap-icon, 245/grey
189 ¦ ¦ column <- copy left
190 ¦ ¦ row <- add row, 1
191 ¦ ¦ screen <- move-cursor screen, row, column
192 ¦ ¦
193 ¦ ¦ loop +next-character
194 ¦ }
195 ¦ print screen, c, color
196 ¦ curr <- next curr
197 ¦ prev <- next prev
198 ¦ column <- add column, 1
199 ¦ loop
200 }
201
202 *editor <- put *editor, bottom-of-screen:offset, curr
203
204 {
205 ¦ at-cursor-row?:bool <- equal row, cursor-row
206 ¦ cursor-outside-line?:bool <- lesser-or-equal column, cursor-column
207 ¦ before-cursor-on-same-line?:bool <- and at-cursor-row?, cursor-outside-line?
208 ¦ above-cursor-row?:bool <- lesser-than row, cursor-row
209 ¦ before-cursor?:bool <- or before-cursor-on-same-line?, above-cursor-row?
210 ¦ break-unless before-cursor?
211 ¦ cursor-row <- copy row
212 ¦ cursor-column <- copy column
213 ¦ before-cursor <- copy prev
214 }
215 *editor <- put *editor, bottom:offset, row
216 *editor <- put *editor, cursor-row:offset, cursor-row
217 *editor <- put *editor, cursor-column:offset, cursor-column
218 *editor <- put *editor, before-cursor:offset, before-cursor
219 return row, column
220 ]
221
222 def clear-screen-from screen:&:screen, row:num, column:num, left:num, right:num -> screen:&:screen [
223 local-scope
224 load-ingredients
225
226 {
227 ¦ break-if screen
228 ¦ clear-display-from row, column, left, right
229 ¦ return
230 }
231
232 screen <- move-cursor screen, row, column
233 clear-line-until screen, right
234 clear-rest-of-screen screen, row, left, right
235 ]
236
237 def clear-rest-of-screen screen:&:screen, row:num, left:num, right:num -> screen:&:screen [
238 local-scope
239 load-ingredients
240 row <- add row, 1
241
242 {
243 ¦ break-if screen
244 ¦ clear-display-from row, left, left, right
245 ¦ return
246 }
247 screen <- move-cursor screen, row, left
248 screen-height:num <- screen-height screen
249 {
250 ¦ at-bottom-of-screen?:bool <- greater-or-equal row, screen-height
251 ¦ break-if at-bottom-of-screen?
252 ¦ screen <- move-cursor screen, row, left
253 ¦ clear-line-until screen, right
254 ¦ row <- add row, 1
255 ¦ loop
256 }
257 ]
258
259 scenario editor-prints-multiple-lines [
260 local-scope
261 assume-screen 5/width, 5/height
262 s:text <- new [abc
263 def]
264 e:&:editor <- new-editor s, 0/left, 5/right
265 run [
266 ¦ render screen, e
267 ]
268 screen-should-contain [
269 ¦ . .
270 ¦ .abc .
271 ¦ .def .
272 ¦ . .
273 ]
274 ]
275
276 scenario editor-handles-offsets [
277 local-scope
278 assume-screen 5/width, 5/height
279 e:&:editor <- new-editor [abc], 1/left, 5/right
280 run [
281 ¦ render screen, e
282 ]
283 screen-should-contain [
284 ¦ . .
285 ¦ . abc .
286 ¦ . .
287 ]
288 ]
289
290 scenario editor-prints-multiple-lines-at-offset [
291 local-scope
292 assume-screen 5/width, 5/height
293 s:text <- new [abc
294 def]
295 e:&:editor <- new-editor s, 1/left, 5/right
296 run [
297 ¦ render screen, e
298 ]
299 screen-should-contain [
300 ¦ . .
301 ¦ . abc .
302 ¦ . def .
303 ¦ . .
304 ]
305 ]
306
307 scenario editor-wraps-long-lines [
308 local-scope
309 assume-screen 5/width, 5/height
310 e:&:editor <- new-editor [abc def], 0/left, 5/right
311 run [
312 ¦ render screen, e
313 ]
314 screen-should-contain [
315 ¦ . .
316 ¦ .abc ↩.
317 ¦ .def .
318 ¦ . .
319 ]
320 screen-should-contain-in-color 245/grey [
321 ¦ . .
322 ¦ . ↩.
323 ¦ . .
324 ¦ . .
325 ]
326 ]
327
328 scenario editor-wraps-barely-long-lines [
329 local-scope
330 assume-screen 5/width, 5/height
331 e:&:editor <- new-editor [abcde], 0/left, 5/right
332 run [
333 ¦ render screen, e
334 ]
335
336
337 screen-should-contain [
338 ¦ . .
339 ¦ .abcd↩.
340 ¦ .e .
341 ¦ . .
342 ]
343 screen-should-contain-in-color 245/grey [
344 ¦ . .
345 ¦ . ↩.
346 ¦ . .
347 ¦ . .
348 ]
349 ]
350
351 scenario editor-with-empty-text [
352 local-scope
353 assume-screen 5/width, 5/height
354 e:&:editor <- new-editor [], 0/left, 5/right
355 run [
356 ¦ render screen, e
357 ¦ 3:num/raw <- get *e, cursor-row:offset
358 ¦ 4:num/raw <- get *e, cursor-column:offset
359 ]
360 screen-should-contain [
361 ¦ . .
362 ¦ . .
363 ¦ . .
364 ]
365 memory-should-contain [
366 ¦ 3 <- 1
367 ¦ 4 <- 0
368 ]
369 ]
370
371
372
373 scenario render-colors-comments [
374 local-scope
375 assume-screen 5/width, 5/height
376 s:text <- new [abc
377 # de
378 f]
379 e:&:editor <- new-editor s, 0/left, 5/right
380 run [
381 ¦ render screen, e
382 ]
383 screen-should-contain [
384 ¦ . .
385 ¦ .abc .
386 ¦ .# de .
387 ¦ .f .
388 ¦ . .
389 ]
390 screen-should-contain-in-color 12/lightblue, [
391 ¦ . .
392 ¦ . .
393 ¦ .# de .
394 ¦ . .
395 ¦ . .
396 ]
397 screen-should-contain-in-color 7/white, [
398 ¦ . .
399 ¦ .abc .
400 ¦ . .
401 ¦ .f .
402 ¦ . .
403 ]
404 ]
405
406 after <character-c-received> [
407 color <- get-color color, c
408 ]
409
410
411 def get-color color:num, c:char -> color:num [
412 local-scope
413 load-ingredients
414 color-is-white?:bool <- equal color, 7/white
415
416 {
417 ¦ break-unless color-is-white?
418 ¦ starting-comment?:bool <- equal c, 35/#
419 ¦ break-unless starting-comment?
420 ¦ trace 90, [app], [switch color back to blue]
421 ¦ return 12/lightblue
422 }
423
424 {
425 ¦ color-is-blue?:bool <- equal color, 12/lightblue
426 ¦ break-unless color-is-blue?
427 ¦ ending-comment?:bool <- equal c, 10/newline
428 ¦ break-unless ending-comment?
429 ¦ trace 90, [app], [switch color back to white]
430 ¦ return 7/white
431 }
432
433 {
434 ¦ break-unless color-is-white?
435 ¦ starting-assignment?:bool <- equal c, 60/<
436 ¦ break-unless starting-assignment?
437 ¦ return 1/red
438 }
439
440 {
441 ¦ color-is-red?:bool <- equal color, 1/red
442 ¦ break-unless color-is-red?
443 ¦ ending-assignment?:bool <- equal c, 32/space
444 ¦ break-unless ending-assignment?
445 ¦ return 7/white
446 }
447
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 ]