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