https://github.com/akkartik/mu/blob/main/501draw-text.mu
  1 # some primitives for moving the cursor without making assumptions about
  2 # raster order
  3 fn move-cursor-left screen: (addr screen) {
  4   var cursor-x/eax: int <- copy 0
  5   var cursor-y/ecx: int <- copy 0
  6   cursor-x, cursor-y <- cursor-position screen
  7   compare cursor-x, 0
  8   {
  9     break-if->
 10     return
 11   }
 12   cursor-x <- decrement
 13   set-cursor-position screen, cursor-x, cursor-y
 14 }
 15 
 16 fn move-cursor-right screen: (addr screen) {
 17   var _width/eax: int <- copy 0
 18   var dummy/ecx: int <- copy 0
 19   _width, dummy <- screen-size screen
 20   var limit/edx: int <- copy _width
 21   limit <- decrement
 22   var cursor-x/eax: int <- copy 0
 23   var cursor-y/ecx: int <- copy 0
 24   cursor-x, cursor-y <- cursor-position screen
 25   compare cursor-x, limit
 26   {
 27     break-if-<
 28     return
 29   }
 30   cursor-x <- increment
 31   set-cursor-position screen, cursor-x, cursor-y
 32 }
 33 
 34 fn move-cursor-up screen: (addr screen) {
 35   var cursor-x/eax: int <- copy 0
 36   var cursor-y/ecx: int <- copy 0
 37   cursor-x, cursor-y <- cursor-position screen
 38   compare cursor-y, 0
 39   {
 40     break-if->
 41     return
 42   }
 43   cursor-y <- decrement
 44   set-cursor-position screen, cursor-x, cursor-y
 45 }
 46 
 47 fn move-cursor-down screen: (addr screen) {
 48   var dummy/eax: int <- copy 0
 49   var _height/ecx: int <- copy 0
 50   dummy, _height <- screen-size screen
 51   var limit/edx: int <- copy _height
 52   limit <- decrement
 53   var cursor-x/eax: int <- copy 0
 54   var cursor-y/ecx: int <- copy 0
 55   cursor-x, cursor-y <- cursor-position screen
 56   compare cursor-y, limit
 57   {
 58     break-if-<
 59     return
 60   }
 61   cursor-y <- increment
 62   set-cursor-position screen, cursor-x, cursor-y
 63 }
 64 
 65 fn move-cursor-to-left-margin-of-next-line screen: (addr screen) {
 66   var dummy/eax: int <- copy 0
 67   var _height/ecx: int <- copy 0
 68   dummy, _height <- screen-size screen
 69   var limit/edx: int <- copy _height
 70   limit <- decrement
 71   var cursor-x/eax: int <- copy 0
 72   var cursor-y/ecx: int <- copy 0
 73   cursor-x, cursor-y <- cursor-position screen
 74   compare cursor-y, limit
 75   {
 76     break-if-<
 77     return
 78   }
 79   cursor-y <- increment
 80   cursor-x <- copy 0
 81   set-cursor-position screen, cursor-x, cursor-y
 82 }
 83 
 84 fn draw-code-point-at-cursor screen: (addr screen), c: code-point, color: int, background-color: int {
 85   var cursor-x/eax: int <- copy 0
 86   var cursor-y/ecx: int <- copy 0
 87   cursor-x, cursor-y <- cursor-position screen
 88   var dummy/eax: int <- draw-code-point screen, c, cursor-x, cursor-y, color, background-color
 89 }
 90 
 91 fn draw-code-point-at-cursor-over-full-screen screen: (addr screen), c: code-point, color: int, background-color: int {
 92   var cursor-x/eax: int <- copy 0
 93   var cursor-y/ecx: int <- copy 0
 94   cursor-x, cursor-y <- cursor-position screen
 95   var _offset/eax: int <- draw-code-point screen, c, cursor-x, cursor-y, color, background-color
 96   var offset/edx: int <- copy _offset
 97   var width/eax: int <- copy 0
 98   var dummy/ecx: int <- copy 0
 99   width, dummy <- screen-size screen
100   move-cursor-rightward-and-downward screen, 0 width
101   offset <- decrement
102   compare offset, 0
103   {
104     break-if-=
105     # should never move downward here
106     move-cursor-rightward-and-downward screen, 0 width
107   }
108 }
109 
110 # draw a single line of text from x, y to xmax
111 # return the next 'x' coordinate
112 # if there isn't enough space, truncate
113 fn draw-text-rightward screen: (addr screen), text: (addr array byte), x: int, xmax: int, y: int, color: int, background-color: int -> _/eax: int {
114   var stream-storage: (stream byte 0x400/print-buffer-size)
115   var stream/esi: (addr stream byte) <- address stream-storage
116   write stream, text
117   var xcurr/eax: int <- draw-stream-rightward screen, stream, x, xmax, y, color, background-color
118   return xcurr
119 }
120 
121 # draw a single-line stream from x, y to xmax
122 # return the next 'x' coordinate
123 # if there isn't enough space, truncate
124 fn draw-stream-rightward screen: (addr screen), stream: (addr stream byte), x: int, xmax: int, y: int, color: int, background-color: int -> _/eax: int {
125   var xcurr/ecx: int <- copy x
126   {
127     var g/eax: grapheme <- read-grapheme stream
128     compare g, 0xffffffff/end-of-file
129     break-if-=
130     var c/eax: code-point <- to-code-point g
131     var offset/eax: int <- draw-code-point screen, c, xcurr, y, color, background-color
132     xcurr <- add offset
133     loop
134   }
135   set-cursor-position screen, xcurr, y
136   return xcurr
137 }
138 
139 fn draw-text-rightward-over-full-screen screen: (addr screen), text: (addr array byte), x: int, y: int, color: int, background-color: int -> _/eax: int {
140   var width/eax: int <- copy 0
141   var height/ecx: int <- copy 0
142   width, height <- screen-size screen
143   var result/eax: int <- draw-text-rightward screen, text, x, width, y, color, background-color
144   return result
145 }
146 
147 fn draw-text-rightward-from-cursor screen: (addr screen), text: (addr array byte), xmax: int, color: int, background-color: int {
148   var cursor-x/eax: int <- copy 0
149   var cursor-y/ecx: int <- copy 0
150   cursor-x, cursor-y <- cursor-position screen
151   cursor-x <- draw-text-rightward screen, text, cursor-x, xmax, cursor-y, color, background-color
152   set-cursor-position screen, cursor-x, cursor-y
153 }
154 
155 fn draw-text-rightward-from-cursor-over-full-screen screen: (addr screen), text: (addr array byte), color: int, background-color: int {
156   var width/eax: int <- copy 0
157   var height/ecx: int <- copy 0
158   width, height <- screen-size screen
159   draw-text-rightward-from-cursor screen, text, width, color, background-color
160 }
161 
162 fn render-code-point screen: (addr screen), c: code-point, xmin: int, ymin: int, xmax: int, ymax: int, x: int, y: int, color: int, background-color: int -> _/eax: int, _/ecx: int {
163   var x/ecx: int <- copy x
164   compare c, 0xa/newline
165   {
166     break-if-!=
167     # minimum effort to clear cursor
168     var dummy/eax: int <- draw-code-point screen, 0x20/space, x, y, color, background-color
169     x <- copy xmin
170     increment y
171     return x, y
172   }
173   var offset/eax: int <- draw-code-point screen, c, x, y, color, background-color
174   x <- add offset
175   compare x, xmax
176   {
177     break-if-<
178     x <- copy xmin
179     increment y
180   }
181   return x, y
182 }
183 
184 # draw text in the rectangle from (xmin, ymin) to (xmax, ymax), starting from (x, y), wrapping as necessary
185 # return the next (x, y) coordinate in raster order where drawing stopped
186 # that way the caller can draw more if given the same min and max bounding-box.
187 # if there isn't enough space, truncate
188 fn draw-text-wrapping-right-then-down screen: (addr screen), _text: (addr array byte), xmin: int, ymin: int, xmax: int, ymax: int, _x: int, _y: int, color: int, background-color: int -> _/eax: int, _/ecx: int {
189   var stream-storage: (stream byte 0x200/print-buffer-size)
190   var stream/edi: (addr stream byte) <- address stream-storage
191   var text/esi: (addr array byte) <- copy _text
192   var len/eax: int <- length text
193   compare len, 0x200/print-buffer-size
194   {
195     break-if-<
196     write stream, "ERROR: stream too small in draw-text-wrapping-right-then-down"
197   }
198   compare len, 0x200/print-buffer-size
199   {
200     break-if->=
201     write stream, text
202   }
203   var x/eax: int <- copy _x
204   var y/ecx: int <- copy _y
205   x, y <- draw-stream-wrapping-right-then-down screen, stream, xmin, ymin, xmax, ymax, x, y, color, background-color
206   return x, y
207 }
208 
209 # draw a stream in the rectangle from (xmin, ymin) to (xmax, ymax), starting from (x, y), wrapping as necessary
210 # return the next (x, y) coordinate in raster order where drawing stopped
211 # that way the caller can draw more if given the same min and max bounding-box.
212 # if there isn't enough space, truncate
213 fn draw-stream-wrapping-right-then-down screen: (addr screen), stream: (addr stream byte), xmin: int, ymin: int, xmax: int, ymax: int, x: int, y: int, color: int, background-color: int -> _/eax: int, _/ecx: int {
214   var xcurr/ecx: int <- copy x
215   var ycurr/edx: int <- copy y
216   var c/ebx: code-point <- copy 0
217   var next-c/esi: code-point <- copy 0
218   $draw-stream-wrapping-right-then-down:loop: {
219     # read c from either next-c or stream
220     $draw-stream-wrapping-right-then-down:read-base: {
221       compare next-c, 0
222       {
223         break-if-=
224         c <- copy next-c
225         next-c <- copy 0
226         break $draw-stream-wrapping-right-then-down:read-base
227       }
228       var g/eax: grapheme <- read-grapheme stream
229       var _c/eax: code-point <- to-code-point g
230       c <- copy _c
231     }
232     compare c, 0xffffffff/end-of-file
233     break-if-=
234     compare c, 0xa/newline
235     {
236       break-if-!=
237       # minimum effort to clear cursor
238       var dummy/eax: int <- draw-code-point screen, 0x20/space, xcurr, ycurr, color, background-color
239       xcurr <- copy xmin
240       ycurr <- increment
241       loop $draw-stream-wrapping-right-then-down:loop
242     }
243     var offset/eax: int <- draw-code-point screen, c, xcurr, ycurr, color, background-color
244     # overlay a combining character if necessary
245     $draw-stream-wrapping-right-then-down:read-combiner: {
246       var done?/eax: boolean <- stream-empty? stream
247       compare done?, 0/false
248       break-if-!=
249       # read a character
250       var g/eax: grapheme <- read-grapheme stream
251       var c/eax: code-point <- to-code-point g
252       # if not a combining character, save for next iteration and loop
253       {
254         var combining-code-point?/eax: boolean <- combining-code-point? c
255         compare combining-code-point?, 0/false
256       }
257       {
258         break-if-!=
259         next-c <- copy c
260         break $draw-stream-wrapping-right-then-down:read-combiner
261       }
262       # otherwise overlay it without saving its width
263       # This means strange results if a base and its combiner have different
264       # widths. We'll always follow the base width.
265       var dummy/eax: int <- overlay-code-point screen, c, xcurr, ycurr, color, background-color
266     }
267     xcurr <- add offset
268     compare xcurr, xmax
269     {
270       break-if-<
271       xcurr <- copy xmin
272       ycurr <- increment
273     }
274     loop
275   }
276   set-cursor-position screen, xcurr, ycurr
277   return xcurr, ycurr
278 }
279 
280 fn draw-stream-wrapping-right-then-down-from-cursor screen: (addr screen), stream: (addr stream byte), xmin: int, ymin: int, xmax: int, ymax: int, color: int, background-color: int {
281   var cursor-x/eax: int <- copy 0
282   var cursor-y/ecx: int <- copy 0
283   cursor-x, cursor-y <- cursor-position screen
284   var end-x/edx: int <- copy cursor-x
285   end-x <- increment
286   compare end-x, xmax
287   {
288     break-if-<
289     cursor-x <- copy xmin
290     cursor-y <- increment
291   }
292   cursor-x, cursor-y <- draw-stream-wrapping-right-then-down screen, stream, xmin, ymin, xmax, ymax, cursor-x, cursor-y, color, background-color
293 }
294 
295 fn draw-stream-wrapping-right-then-down-from-cursor-over-full-screen screen: (addr screen), stream: (addr stream byte), color: int, background-color: int {
296   var width/eax: int <- copy 0
297   var height/ecx: int <- copy 0
298   width, height <- screen-size screen
299   draw-stream-wrapping-right-then-down-from-cursor screen, stream, 0/xmin, 0/ymin, width, height, color, background-color
300 }
301 
302 fn move-cursor-rightward-and-downward screen: (addr screen), xmin: int, xmax: int {
303   var cursor-x/eax: int <- copy 0
304   var cursor-y/ecx: int <- copy 0
305   cursor-x, cursor-y <- cursor-position screen
306   cursor-x <- increment
307   compare cursor-x, xmax
308   {
309     break-if-<
310     cursor-x <- copy xmin
311     cursor-y <- increment
312   }
313   set-cursor-position screen, cursor-x, cursor-y
314 }
315 
316 fn draw-text-wrapping-right-then-down-over-full-screen screen: (addr screen), text: (addr array byte), x: int, y: int, color: int, background-color: int -> _/eax: int, _/ecx: int {
317   var x2/eax: int <- copy 0
318   var y2/ecx: int <- copy 0
319   x2, y2 <- screen-size screen  # width, height
320   x2, y2 <- draw-text-wrapping-right-then-down screen, text, 0/xmin, 0/ymin, x2, y2, x, y, color, background-color
321   return x2, y2  # cursor-x, cursor-y
322 }
323 
324 fn draw-text-wrapping-right-then-down-from-cursor screen: (addr screen), text: (addr array byte), xmin: int, ymin: int, xmax: int, ymax: int, color: int, background-color: int {
325   var cursor-x/eax: int <- copy 0
326   var cursor-y/ecx: int <- copy 0
327   cursor-x, cursor-y <- cursor-position screen
328   var end-x/edx: int <- copy cursor-x
329   end-x <- increment
330   compare end-x, xmax
331   {
332     break-if-<
333     cursor-x <- copy xmin
334     cursor-y <- increment
335   }
336   cursor-x, cursor-y <- draw-text-wrapping-right-then-down screen, text, xmin, ymin, xmax, ymax, cursor-x, cursor-y, color, background-color
337 }
338 
339 fn draw-text-wrapping-right-then-down-from-cursor-over-full-screen screen: (addr screen), text: (addr array byte), color: int, background-color: int {
340   var width/eax: int <- copy 0
341   var height/ecx: int <- copy 0
342   width, height <- screen-size screen
343   draw-text-wrapping-right-then-down-from-cursor screen, text, 0/xmin, 0/ymin, width, height, color, background-color
344 }
345 
346 fn draw-int32-hex-wrapping-right-then-down screen: (addr screen), n: int, xmin: int, ymin: int, xmax: int, ymax: int, x: int, y: int, color: int, background-color: int -> _/eax: int, _/ecx: int {
347   var stream-storage: (stream byte 0x100)
348   var stream/esi: (addr stream byte) <- address stream-storage
349   write-int32-hex stream, n
350   var xcurr/edx: int <- copy x
351   var ycurr/ecx: int <- copy y
352   {
353     var g/eax: grapheme <- read-grapheme stream
354     compare g, 0xffffffff/end-of-file
355     break-if-=
356     var c/eax: code-point <- to-code-point g
357     var offset/eax: int <- draw-code-point screen, c, xcurr, ycurr, color, background-color
358     xcurr <- add offset
359     compare xcurr, xmax
360     {
361       break-if-<
362       xcurr <- copy xmin
363       ycurr <- increment
364     }
365     loop
366   }
367   set-cursor-position screen, xcurr, ycurr
368   return xcurr, ycurr
369 }
370 
371 fn draw-int32-hex-wrapping-right-then-down-over-full-screen screen: (addr screen), n: int, x: int, y: int, color: int, background-color: int -> _/eax: int, _/ecx: int {
372   var x2/eax: int <- copy 0
373   var y2/ecx: int <- copy 0
374   x2, y2 <- screen-size screen  # width, height
375   x2, y2 <- draw-int32-hex-wrapping-right-then-down screen, n, 0/xmin, 0/ymin, x2, y2, x, y, color, background-color
376   return x2, y2  # cursor-x, cursor-y
377 }
378 
379 fn draw-int32-hex-wrapping-right-then-down-from-cursor screen: (addr screen), n: int, xmin: int, ymin: int, xmax: int, ymax: int, color: int, background-color: int {
380   var cursor-x/eax: int <- copy 0
381   var cursor-y/ecx: int <- copy 0
382   cursor-x, cursor-y <- cursor-position screen
383   var end-x/edx: int <- copy cursor-x
384   end-x <- increment
385   compare end-x, xmax
386   {
387     break-if-<
388     cursor-x <- copy xmin
389     cursor-y <- increment
390   }
391   cursor-x, cursor-y <- draw-int32-hex-wrapping-right-then-down screen, n, xmin, ymin, xmax, ymax, cursor-x, cursor-y, color, background-color
392 }
393 
394 fn draw-int32-hex-wrapping-right-then-down-from-cursor-over-full-screen screen: (addr screen), n: int, color: int, background-color: int {
395   var width/eax: int <- copy 0
396   var height/ecx: int <- copy 0
397   width, height <- screen-size screen
398   draw-int32-hex-wrapping-right-then-down-from-cursor screen, n, 0/xmin, 0/ymin, width, height, color, background-color
399 }
400 
401 fn draw-int32-decimal-wrapping-right-then-down screen: (addr screen), n: int, xmin: int, ymin: int, xmax: int, ymax: int, x: int, y: int, color: int, background-color: int -> _/eax: int, _/ecx: int {
402   var stream-storage: (stream byte 0x100)
403   var stream/esi: (addr stream byte) <- address stream-storage
404   write-int32-decimal stream, n
405   var xcurr/edx: int <- copy x
406   var ycurr/ecx: int <- copy y
407   {
408     var g/eax: grapheme <- read-grapheme stream
409     compare g, 0xffffffff/end-of-file
410     break-if-=
411     var c/eax: code-point <- to-code-point g
412     var offset/eax: int <- draw-code-point screen, c, xcurr, ycurr, color, background-color
413     xcurr <- add offset
414     compare xcurr, xmax
415     {
416       break-if-<
417       xcurr <- copy xmin
418       ycurr <- increment
419     }
420     loop
421   }
422   set-cursor-position screen, xcurr, ycurr
423   return xcurr, ycurr
424 }
425 
426 fn draw-int32-decimal-wrapping-right-then-down-over-full-screen screen: (addr screen), n: int, x: int, y: int, color: int, background-color: int -> _/eax: int, _/ecx: int {
427   var x2/eax: int <- copy 0
428   var y2/ecx: int <- copy 0
429   x2, y2 <- screen-size screen  # width, height
430   x2, y2 <- draw-int32-decimal-wrapping-right-then-down screen, n, 0/xmin, 0/ymin, x2, y2, x, y, color, background-color
431   return x2, y2  # cursor-x, cursor-y
432 }
433 
434 fn draw-int32-decimal-wrapping-right-then-down-from-cursor screen: (addr screen), n: int, xmin: int, ymin: int, xmax: int, ymax: int, color: int, background-color: int {
435   var cursor-x/eax: int <- copy 0
436   var cursor-y/ecx: int <- copy 0
437   cursor-x, cursor-y <- cursor-position screen
438   var end-x/edx: int <- copy cursor-x
439   end-x <- increment
440   compare end-x, xmax
441   {
442     break-if-<
443     cursor-x <- copy xmin
444     cursor-y <- increment
445   }
446   cursor-x, cursor-y <- draw-int32-decimal-wrapping-right-then-down screen, n, xmin, ymin, xmax, ymax, cursor-x, cursor-y, color, background-color
447 }
448 
449 fn draw-int32-decimal-wrapping-right-then-down-from-cursor-over-full-screen screen: (addr screen), n: int, color: int, background-color: int {
450   var width/eax: int <- copy 0
451   var height/ecx: int <- copy 0
452   width, height <- screen-size screen
453   draw-int32-decimal-wrapping-right-then-down-from-cursor screen, n, 0/xmin, 0/ymin, width, height, color, background-color
454 }
455 
456 ## Text direction: down then right
457 
458 # draw a single line of text vertically from x, y to ymax
459 # return the next 'y' coordinate
460 # if there isn't enough space, truncate
461 fn draw-text-downward screen: (addr screen), text: (addr array byte), x: int, y: int, ymax: int, color: int, background-color: int -> _/eax: int {
462   var stream-storage: (stream byte 0x100)
463   var stream/esi: (addr stream byte) <- address stream-storage
464   write stream, text
465   var ycurr/eax: int <- draw-stream-downward screen, stream, x, y, ymax, color, background-color
466   return ycurr
467 }
468 
469 # draw a single-line stream vertically from x, y to ymax
470 # return the next 'y' coordinate
471 # if there isn't enough space, truncate
472 # TODO: should we track horizontal width?
473 fn draw-stream-downward screen: (addr screen), stream: (addr stream byte), x: int, y: int, ymax: int, color: int, background-color: int -> _/eax: int {
474   var ycurr/ecx: int <- copy y
475   {
476     var g/eax: grapheme <- read-grapheme stream
477     compare g, 0xffffffff/end-of-file
478     break-if-=
479     var c/eax: code-point <- to-code-point g
480     var dummy/eax: int <- draw-code-point screen, c, x, ycurr, color, background-color
481     ycurr <- increment
482     loop
483   }
484   set-cursor-position screen, x, ycurr
485   return ycurr
486 }
487 
488 fn draw-text-downward-from-cursor screen: (addr screen), text: (addr array byte), ymax: int, color: int, background-color: int {
489   var cursor-x/eax: int <- copy 0
490   var cursor-y/ecx: int <- copy 0
491   cursor-x, cursor-y <- cursor-position screen
492   var result/eax: int <- draw-text-downward screen, text, cursor-x, cursor-y, ymax, color, background-color
493 }
494 
495 # draw text down and right in the rectangle from (xmin, ymin) to (xmax, ymax), starting from (x, y), wrapping as necessary
496 # return the next (x, y) coordinate in raster order where drawing stopped
497 # that way the caller can draw more if given the same min and max bounding-box.
498 # if there isn't enough space, truncate
499 fn draw-text-wrapping-down-then-right screen: (addr screen), text: (addr array byte), xmin: int, ymin: int, xmax: int, ymax: int, _x: int, _y: int, color: int, background-color: int -> _/eax: int, _/ecx: int {
500   var stream-storage: (stream byte 0x100)
501   var stream/esi: (addr stream byte) <- address stream-storage
502   write stream, text
503   var x/eax: int <- copy _x
504   var y/ecx: int <- copy _y
505   x, y <- draw-stream-wrapping-down-then-right screen, stream, xmin, ymin, xmax, ymax, x, y, color, background-color
506   return x, y
507 }
508 
509 # draw a stream down and right in the rectangle from (xmin, ymin) to (xmax, ymax), starting from (x, y), wrapping as necessary
510 # return the next (x, y) coordinate in raster order where drawing stopped
511 # that way the caller can draw more if given the same min and max bounding-box.
512 # if there isn't enough space, truncate
513 # TODO: should we track horizontal width? just always offset by 2 for now
514 fn draw-stream-wrapping-down-then-right screen: (addr screen), stream: (addr stream byte), xmin: int, ymin: int, xmax: int, ymax: int, x: int, y: int, color: int, background-color: int -> _/eax: int, _/ecx: int {
515   var xcurr/edx: int <- copy x
516   var ycurr/ecx: int <- copy y
517   {
518     var g/eax: grapheme <- read-grapheme stream
519     compare g, 0xffffffff/end-of-file
520     break-if-=
521     var c/eax: code-point <- to-code-point g
522     var offset/eax: int <- draw-code-point screen, c, xcurr, ycurr, color, background-color
523     ycurr <- increment
524     compare ycurr, ymax
525     {
526       break-if-<
527       xcurr <- add 2
528       ycurr <- copy ymin
529     }
530     loop
531   }
532   set-cursor-position screen, xcurr, ycurr
533   return xcurr, ycurr
534 }
535 
536 fn draw-text-wrapping-down-then-right-over-full-screen screen: (addr screen), text: (addr array byte), x: int, y: int, color: int, background-color: int -> _/eax: int, _/ecx: int {
537   var x2/eax: int <- copy 0
538   var y2/ecx: int <- copy 0
539   x2, y2 <- screen-size screen  # width, height
540   x2, y2 <- draw-text-wrapping-down-then-right screen, text, 0/xmin, 0/ymin, x2, y2, x, y, color, background-color
541   return x2, y2  # cursor-x, cursor-y
542 }
543 
544 fn draw-text-wrapping-down-then-right-from-cursor screen: (addr screen), text: (addr array byte), xmin: int, ymin: int, xmax: int, ymax: int, color: int, background-color: int {
545   var cursor-x/eax: int <- copy 0
546   var cursor-y/ecx: int <- copy 0
547   cursor-x, cursor-y <- cursor-position screen
548   var end-y/edx: int <- copy cursor-y
549   end-y <- increment
550   compare end-y, ymax
551   {
552     break-if-<
553     cursor-x <- increment
554     cursor-y <- copy ymin
555   }
556   cursor-x, cursor-y <- draw-text-wrapping-down-then-right screen, text, xmin, ymin, xmax, ymax, cursor-x, cursor-y, color, background-color
557 }
558 
559 fn draw-text-wrapping-down-then-right-from-cursor-over-full-screen screen: (addr screen), text: (addr array byte), color: int, background-color: int {
560   var width/eax: int <- copy 0
561   var height/ecx: int <- copy 0
562   width, height <- screen-size screen
563   draw-text-wrapping-down-then-right-from-cursor screen, text, 0/xmin, 0/ymin, width, height, color, background-color
564 }