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