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 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
243 {
244 ¦ break-if screen
245 ¦ clear-display-from row, left, left, right
246 ¦ return
247 }
248 screen <- move-cursor screen, row, left
249 screen-height:num <- screen-height screen
250 {
251 ¦ at-bottom-of-screen?:bool <- greater-or-equal row, screen-height
252 ¦ break-if at-bottom-of-screen?
253 ¦ screen <- move-cursor screen, row, left
254 ¦ clear-line-until screen, right
255 ¦ row <- add row, 1
256 ¦ loop
257 }
258 ]
259
260 scenario editor-prints-multiple-lines [
261 local-scope
262 assume-screen 5/width, 5/height
263 s:text <- new [abc
264 def]
265 e:&:editor <- new-editor s, 0/left, 5/right
266 run [
267 ¦ render screen, e
268 ]
269 screen-should-contain [
270 ¦ . .
271 ¦ .abc .
272 ¦ .def .
273 ¦ . .
274 ]
275 ]
276
277 scenario editor-handles-offsets [
278 local-scope
279 assume-screen 5/width, 5/height
280 e:&:editor <- new-editor [abc], 1/left, 5/right
281 run [
282 ¦ render screen, e
283 ]
284 screen-should-contain [
285 ¦ . .
286 ¦ . abc .
287 ¦ . .
288 ]
289 ]
290
291 scenario editor-prints-multiple-lines-at-offset [
292 local-scope
293 assume-screen 5/width, 5/height
294 s:text <- new [abc
295 def]
296 e:&:editor <- new-editor s, 1/left, 5/right
297 run [
298 ¦ render screen, e
299 ]
300 screen-should-contain [
301 ¦ . .
302 ¦ . abc .
303 ¦ . def .
304 ¦ . .
305 ]
306 ]
307
308 scenario editor-wraps-long-lines [
309 local-scope
310 assume-screen 5/width, 5/height
311 e:&:editor <- new-editor [abc def], 0/left, 5/right
312 run [
313 ¦ render screen, e
314 ]
315 screen-should-contain [
316 ¦ . .
317 ¦ .abc ↩.
318 ¦ .def .
319 ¦ . .
320 ]
321 screen-should-contain-in-color 245/grey [
322 ¦ . .
323 ¦ . ↩.
324 ¦ . .
325 ¦ . .
326 ]
327 ]
328
329 scenario editor-wraps-barely-long-lines [
330 local-scope
331 assume-screen 5/width, 5/height
332 e:&:editor <- new-editor [abcde], 0/left, 5/right
333 run [
334 ¦ render screen, e
335 ]
336
337
338 screen-should-contain [
339 ¦ . .
340 ¦ .abcd↩.
341 ¦ .e .
342 ¦ . .
343 ]
344 screen-should-contain-in-color 245/grey [
345 ¦ . .
346 ¦ . ↩.
347 ¦ . .
348 ¦ . .
349 ]
350 ]
351
352 scenario editor-with-empty-text [
353 local-scope
354 assume-screen 5/width, 5/height
355 e:&:editor <- new-editor [], 0/left, 5/right
356 run [
357 ¦ render screen, e
358 ¦ 3:num/raw <- get *e, cursor-row:offset
359 ¦ 4:num/raw <- get *e, cursor-column:offset
360 ]
361 screen-should-contain [
362 ¦ . .
363 ¦ . .
364 ¦ . .
365 ]
366 memory-should-contain [
367 ¦ 3 <- 1
368 ¦ 4 <- 0
369 ]
370 ]
371
372
373
374 scenario render-colors-comments [
375 local-scope
376 assume-screen 5/width, 5/height
377 s:text <- new [abc
378 # de
379 f]
380 e:&:editor <- new-editor s, 0/left, 5/right
381 run [
382 ¦ render screen, e
383 ]
384 screen-should-contain [
385 ¦ . .
386 ¦ .abc .
387 ¦ .# de .
388 ¦ .f .
389 ¦ . .
390 ]
391 screen-should-contain-in-color 12/lightblue, [
392 ¦ . .
393 ¦ . .
394 ¦ .# de .
395 ¦ . .
396 ¦ . .
397 ]
398 screen-should-contain-in-color 7/white, [
399 ¦ . .
400 ¦ .abc .
401 ¦ . .
402 ¦ .f .
403 ¦ . .
404 ]
405 ]
406
407 after <character-c-received> [
408 color <- get-color color, c
409 ]
410
411
412 def get-color color:num, c:char -> color:num [
413 local-scope
414 load-ingredients
415 color-is-white?:bool <- equal color, 7/white
416
417 {
418 ¦ break-unless color-is-white?
419 ¦ starting-comment?:bool <- equal c, 35/#
420 ¦ break-unless starting-comment?
421 ¦ trace 90, [app], [switch color back to blue]
422 ¦ return 12/lightblue
423 }
424
425 {
426 ¦ color-is-blue?:bool <- equal color, 12/lightblue
427 ¦ break-unless color-is-blue?
428 ¦ ending-comment?:bool <- equal c, 10/newline
429 ¦ break-unless ending-comment?
430 ¦ trace 90, [app], [switch color back to white]
431 ¦ return 7/white
432 }
433
434 {
435 ¦ break-unless color-is-white?
436 ¦ starting-assignment?:bool <- equal c, 60/<
437 ¦ break-unless starting-assignment?
438 ¦ return 1/red
439 }
440
441 {
442 ¦ color-is-red?:bool <- equal color, 1/red
443 ¦ break-unless color-is-red?
444 ¦ ending-assignment?:bool <- equal c, 32/space
445 ¦ break-unless ending-assignment?
446 ¦ return 7/white
447 }
448
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 ]