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