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