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