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 ]