https://github.com/akkartik/mu/blob/master/apps/browse/paginated-screen.mu
  1 # If a screen is too wide, split it up into a fixed size of pages.
  2 # We take control of drawing and moving the cursor, and delegate everything else.
  3 # Never scroll; use the 'done-drawing?' method instead.
  4 #
  5 # Example usage:
  6 #   initialize-paginated-screen
  7 #   on each frame
  8 #     start-drawing
  9 #     while !done-drawing
 10 #       add-grapheme ...
 11 
 12 type paginated-screen {
 13   screen: (handle screen)
 14   nrows: int  # const
 15   ncols: int  # const
 16   page-width: int
 17   top-margin: int
 18   left-margin: int
 19   # page bounds
 20   toprow: int
 21   botrow: int  # (inclusive)
 22   leftcol: int
 23   rightcol: int  # (exclusive)
 24   # current cursor position
 25   row: int
 26   col: int
 27 }
 28 
 29 fn initialize-paginated-screen _self: (addr paginated-screen), page-width: int, top-margin: int, left-margin: int {
 30   var self/esi: (addr paginated-screen) <- copy _self
 31   var screen-ah/eax: (addr handle screen) <- get self, screen
 32   var _screen-addr/eax: (addr screen) <- lookup *screen-ah
 33   var screen-addr/edi: (addr screen) <- copy _screen-addr
 34   var nrows/eax: int <- copy 0
 35   var ncols/ecx: int <- copy 0
 36   nrows, ncols <- screen-size screen-addr
 37   var dest/edx: (addr int) <- copy 0
 38   # self->nrows = nrows
 39   dest <- get self, nrows
 40   copy-to *dest, nrows
 41   # self->ncols = ncols
 42   dest <- get self, ncols
 43   copy-to *dest, ncols
 44   # self->page-width = page-width
 45   {
 46     var tmp/eax: int <- copy page-width
 47     dest <- get self, page-width
 48     copy-to *dest, tmp
 49   }
 50   # self->top-margin = top-margin
 51   {
 52     var tmp/eax: int <- copy top-margin
 53     dest <- get self, top-margin
 54     copy-to *dest, tmp
 55   }
 56   # self->left-margin = left-margin
 57   {
 58     var tmp/eax: int <- copy left-margin
 59     dest <- get self, left-margin
 60     copy-to *dest, tmp
 61   }
 62   # self->toprow = 1 + top-margin
 63   {
 64     var tmp/eax: int <- copy top-margin
 65     dest <- get self, toprow
 66     copy-to *dest, 1
 67     add-to *dest, tmp
 68   }
 69   # self->botrow = nrows
 70   {
 71     dest <- get self, botrow
 72     copy-to *dest, nrows
 73   }
 74   #
 75   start-drawing self
 76 }
 77 
 78 fn start-drawing _self: (addr paginated-screen) {
 79   var self/esi: (addr paginated-screen) <- copy _self
 80   clear-paginated-screen self
 81   var tmp/eax: (addr int) <- copy 0
 82   var tmp2/ecx: int <- copy 0
 83   # self->leftcol = 1 + left-margin
 84   tmp <- get self, left-margin
 85   tmp2 <- copy *tmp
 86   tmp <- get self, leftcol
 87   copy-to *tmp, 1
 88   add-to *tmp, tmp2
 89 #?   print-string-to-real-screen "start: left column: "
 90 #?   print-int32-hex-to-real-screen *tmp
 91   # self->rightcol = min(ncols+1, self->leftcol + page-width)
 92   # . tmp2 = self->leftcol + page-width
 93   tmp <- get self, page-width
 94   tmp2 <- copy *tmp
 95   tmp <- get self, leftcol
 96   tmp2 <- add *tmp
 97   # . if (tmp2 > ncols+1) tmp2 = ncols+1
 98   {
 99     tmp <- get self, ncols
100     compare tmp2, *tmp
101     break-if-<=
102     tmp2 <- copy *tmp
103     tmp2 <- increment
104   }
105   # . self->rightcol = tmp2
106   tmp <- get self, rightcol
107   copy-to *tmp, tmp2
108 #?   print-string-to-real-screen "; right column: "
109 #?   print-int32-hex-to-real-screen *tmp
110 #?   print-string-to-real-screen "\n"
111   # self->row = self->toprow
112   tmp <- get self, toprow
113   tmp2 <- copy *tmp
114   tmp <- get self, row
115   copy-to *tmp, tmp2
116   # self->col = self->leftcol
117   tmp <- get self, leftcol
118   tmp2 <- copy *tmp
119   tmp <- get self, col
120   copy-to *tmp, tmp2
121   #
122   reposition-cursor self
123 }
124 
125 fn done-drawing? _self: (addr paginated-screen) -> result/eax: boolean {
126 $done-drawing?:body: {
127   # if (self->leftcol == left-margin + 1) return false
128   var self/esi: (addr paginated-screen) <- copy _self
129   var tmp/eax: (addr int) <- get self, left-margin
130   var first-col/ecx: int <- copy *tmp
131   first-col <- increment
132   tmp <- get self, leftcol
133   $done-drawing:first-page?: {
134     compare first-col, *tmp
135     break-if-!=
136     result <- copy 0
137     break $done-drawing?:body
138   }
139   # return self->rightcol > self->ncols + 1
140   tmp <- get self, ncols
141   var max/ecx: int <- copy *tmp
142   max <- increment
143   tmp <- get self, rightcol
144 #?   print-string-to-real-screen "done-drawing? "
145 #?   print-int32-hex-to-real-screen *tmp
146 #?   print-string-to-real-screen " vs "
147 #?   print-int32-hex-to-real-screen max
148 #?   print-string-to-real-screen "\n"
149   compare *tmp, max
150   {
151     break-if->
152     result <- copy 0  # false
153     break $done-drawing?:body
154   }
155   {
156     break-if-<=
157     result <- copy 1  # true
158   }
159 }
160 }
161 
162 fn add-grapheme _self: (addr paginated-screen), c: grapheme {
163 #?   print-string-to-real-screen "add-grapheme: "
164 #?   print-grapheme-to-real-screen c
165 #?   print-string-to-real-screen "\n"
166 $add-grapheme:body: {
167   var self/esi: (addr paginated-screen) <- copy _self
168   {
169     compare c, 0xa  # newline
170     break-if-!=
171     next-line self
172     reposition-cursor self
173     break $add-grapheme:body
174   }
175   # print c
176   var screen-ah/eax: (addr handle screen) <- get self, screen
177   var screen-addr/eax: (addr screen) <- lookup *screen-ah
178   print-grapheme screen-addr, c
179   # self->col++
180   var tmp/eax: (addr int) <- get self, col
181   increment *tmp
182   # if (self->col > self->rightcol) next-line(self)
183   var tmp2/ecx: int <- copy *tmp
184   tmp <- get self, rightcol
185   compare tmp2, *tmp
186   {
187     break-if-<
188     next-line self
189     reposition-cursor self
190   }
191 }
192 }
193 
194 ## tests
195 
196 fn test-print-grapheme-on-paginated-screen {
197   var pg-on-stack: paginated-screen
198   var pg/eax: (addr paginated-screen) <- address pg-on-stack
199   initialize-fake-paginated-screen pg, 3, 0xa, 0xa, 0, 0
200   start-drawing pg
201   {
202     var c/ecx: grapheme <- copy 0x61   # 'a'
203     add-grapheme pg, c
204     var done?/eax: boolean <- done-drawing? pg
205     var done/eax: int <- copy done?
206     check-ints-equal done, 0, "F - test-print-grapheme-on-paginated-screen/done"
207   }
208   var screen-ah/eax: (addr handle screen) <- get pg, screen
209   var screen-addr/eax: (addr screen) <- lookup *screen-ah
210   check-screen-row screen-addr, 1, "a", "F - test-print-grapheme-on-paginated-screen"
211 }
212 
213 fn test-print-single-page {
214   var pg-on-stack: paginated-screen
215   var pg/eax: (addr paginated-screen) <- address pg-on-stack
216   initialize-fake-paginated-screen pg, 2, 4, 2, 0, 0  # 2 rows, 4 columns, 2 pages * 2 columns each
217   start-drawing pg
218   # pages at columns [1, 3), [3, 5)
219   {
220     var c/ecx: grapheme <- copy 0x61   # 'a'
221     add-grapheme pg, c
222     var done?/eax: boolean <- done-drawing? pg
223     var done/eax: int <- copy done?
224     check-ints-equal done, 0, "F - test-print-single-page/done-1"
225   }
226   {
227     var c/ecx: grapheme <- copy 0x62   # 'b'
228     add-grapheme pg, c
229     var done?/eax: boolean <- done-drawing? pg
230     var done/eax: int <- copy done?
231     check-ints-equal done, 0, "F - test-print-single-page/done-2"
232   }
233   {
234     var c/ecx: grapheme <- copy 0x63   # 'c'
235     add-grapheme pg, c
236     var done?/eax: boolean <- done-drawing? pg
237     var done/eax: int <- copy done?
238     check-ints-equal done, 0, "F - test-print-single-page/done-3"
239   }
240   {
241     var c/ecx: grapheme <- copy 0x64   # 'd'
242     add-grapheme pg, c
243     var done?/eax: boolean <- done-drawing? pg
244     var done/eax: int <- copy done?
245     check-ints-equal done, 0, "F - test-print-single-page/done-4"
246   }
247   var screen-ah/eax: (addr handle screen) <- get pg, screen
248   var screen-addr/eax: (addr screen) <- lookup *screen-ah
249   check-screen-row screen-addr, 1, "ab  ", "F - test-print-single-page/row1"
250   check-screen-row screen-addr, 2, "cd  ", "F - test-print-single-page/row2"
251   # currently it's hard-coded that we avoid printing to the bottom-most row of the screen
252 }
253 
254 fn test-print-single-page-narrower-than-page-width {
255   var pg-on-stack: paginated-screen
256   var pg/eax: (addr paginated-screen) <- address pg-on-stack
257   initialize-fake-paginated-screen pg, 2, 4, 5, 0, 0  # 2 rows, 4 columns, 5-column pages
258   start-drawing pg
259   {
260     var c/ecx: grapheme <- copy 0x61   # 'a'
261     add-grapheme pg, c
262     var done?/eax: boolean <- done-drawing? pg
263     var done/eax: int <- copy done?
264     check-ints-equal done, 0, "F - test-print-single-page-narrower-than-page-width/done-1"
265   }
266   {
267     var c/ecx: grapheme <- copy 0x62   # 'b'
268     add-grapheme pg, c
269     var done?/eax: boolean <- done-drawing? pg
270     var done/eax: int <- copy done?
271     check-ints-equal done, 0, "F - test-print-single-page-narrower-than-page-width/done-2"
272   }
273   {
274     var c/ecx: grapheme <- copy 0x63   # 'c'
275     add-grapheme pg, c
276     var done?/eax: boolean <- done-drawing? pg
277     var done/eax: int <- copy done?
278     check-ints-equal done, 0, "F - test-print-single-page-narrower-than-page-width/done-3"
279   }
280   {
281     var c/ecx: grapheme <- copy 0x64   # 'd'
282     add-grapheme pg, c
283     var done?/eax: boolean <- done-drawing? pg
284     var done/eax: int <- copy done?
285     check-ints-equal done, 0, "F - test-print-single-page-narrower-than-page-width/done-4"
286   }
287   {
288     var c/ecx: grapheme <- copy 0x65   # 'e'
289     add-grapheme pg, c
290     var done?/eax: boolean <- done-drawing? pg
291     var done/eax: int <- copy done?
292     check-ints-equal done, 0, "F - test-print-single-page-narrower-than-page-width/done-5"
293   }
294   var screen-ah/eax: (addr handle screen) <- get pg, screen
295   var screen-addr/eax: (addr screen) <- lookup *screen-ah
296   check-screen-row screen-addr, 1, "abcd", "F - test-print-single-page-narrower-than-page-width/row1"
297   check-screen-row screen-addr, 2, "e   ", "F - test-print-single-page-narrower-than-page-width/row2"
298   # currently it's hard-coded that we avoid printing to the bottom-most row of the screen
299 }
300 
301 fn test-print-single-page-narrower-than-page-width-with-margin {
302   var pg-on-stack: paginated-screen
303   var pg/eax: (addr paginated-screen) <- address pg-on-stack
304   initialize-fake-paginated-screen pg, 2, 4, 5, 0, 1  # 2 rows, 4 columns, 5-column pages, left margin
305   start-drawing pg
306   {
307     var c/ecx: grapheme <- copy 0x61   # 'a'
308     add-grapheme pg, c
309     var done?/eax: boolean <- done-drawing? pg
310     var done/eax: int <- copy done?
311     check-ints-equal done, 0, "F - test-print-single-page-narrower-than-page-width-with-margin/done-1"
312   }
313   {
314     var c/ecx: grapheme <- copy 0x62   # 'b'
315     add-grapheme pg, c
316     var done?/eax: boolean <- done-drawing? pg
317     var done/eax: int <- copy done?
318     check-ints-equal done, 0, "F - test-print-single-page-narrower-than-page-width-with-margin/done-2"
319   }
320   {
321     var c/ecx: grapheme <- copy 0x63   # 'c'
322     add-grapheme pg, c
323     var done?/eax: boolean <- done-drawing? pg
324     var done/eax: int <- copy done?
325     check-ints-equal done, 0, "F - test-print-single-page-narrower-than-page-width-with-margin/done-3"
326   }
327   {
328     var c/ecx: grapheme <- copy 0x64   # 'd'
329     add-grapheme pg, c
330     var done?/eax: boolean <- done-drawing? pg
331     var done/eax: int <- copy done?
332     check-ints-equal done, 0, "F - test-print-single-page-narrower-than-page-width-with-margin/done-4"
333   }
334   {
335     var c/ecx: grapheme <- copy 0x65   # 'e'
336     add-grapheme pg, c
337     var done?/eax: boolean <- done-drawing? pg
338     var done/eax: int <- copy done?
339     check-ints-equal done, 0, "F - test-print-single-page-narrower-than-page-width-with-margin/done-5"
340   }
341   var screen-ah/eax: (addr handle screen) <- get pg, screen
342   var screen-addr/eax: (addr screen) <- lookup *screen-ah
343   check-screen-row screen-addr, 1, " abc", "F - test-print-single-page-narrower-than-page-width-with-margin/row1"
344   check-screen-row screen-addr, 2, " de ", "F - test-print-single-page-narrower-than-page-width-with-margin/row2"
345   # currently it's hard-coded that we avoid printing to the bottom-most row of the screen
346 }
347 
348 fn test-print-multiple-pages {
349   var pg-on-stack: paginated-screen
350   var pg/eax: (addr paginated-screen) <- address pg-on-stack
351   initialize-fake-paginated-screen pg, 2, 2, 1, 0, 0  # 2 rows, 2 columns, 2 pages * 1 column each
352   start-drawing pg
353   {
354     var c/ecx: grapheme <- copy 0x61   # 'a'
355     add-grapheme pg, c
356     var done?/eax: boolean <- done-drawing? pg
357     var done/eax: int <- copy done?
358     check-ints-equal done, 0, "F - test-print-multiple-pages/done-1"
359   }
360   {
361     var c/ecx: grapheme <- copy 0x62   # 'b'
362     add-grapheme pg, c
363     var done?/eax: boolean <- done-drawing? pg
364     var done/eax: int <- copy done?
365     check-ints-equal done, 0, "F - test-print-multiple-pages/done-2"
366   }
367   {
368     var c/ecx: grapheme <- copy 0x63   # 'c'
369     add-grapheme pg, c
370     var done?/eax: boolean <- done-drawing? pg
371     var done/eax: int <- copy done?
372     check-ints-equal done, 0, "F - test-print-multiple-pages/done-3"
373   }
374   {
375     var c/ecx: grapheme <- copy 0x64   # 'd'
376     add-grapheme pg, c
377     var done?/eax: boolean <- done-drawing? pg
378     var done/eax: int <- copy done?
379     check-ints-equal done, 1, "F - test-print-multiple-pages/done-4"
380   }
381   var screen-ah/eax: (addr handle screen) <- get pg, screen
382   var screen-addr/eax: (addr screen) <- lookup *screen-ah
383   check-screen-row screen-addr, 1, "ac", "F - test-print-multiple-pages/row1"
384   check-screen-row screen-addr, 2, "bd", "F - test-print-multiple-pages/row2"
385   # currently it's hard-coded that we avoid printing to the bottom-most row of the screen
386 }
387 
388 fn test-print-multiple-pages-2 {
389   var pg-on-stack: paginated-screen
390   var pg/eax: (addr paginated-screen) <- address pg-on-stack
391   initialize-fake-paginated-screen pg, 2, 4, 2, 0, 0  # 2 rows, 4 columns, 2 pages * 2 columns each
392   start-drawing pg
393   {
394     var c/ecx: grapheme <- copy 0x61   # 'a'
395     add-grapheme pg, c
396     var done?/eax: boolean <- done-drawing? pg
397     var done/eax: int <- copy done?
398     check-ints-equal done, 0, "F - test-print-multiple-pages-2/done-1"
399   }
400   {
401     var c/ecx: grapheme <- copy 0x62   # 'b'
402     add-grapheme pg, c
403     var done?/eax: boolean <- done-drawing? pg
404     var done/eax: int <- copy done?
405     check-ints-equal done, 0, "F - test-print-multiple-pages-2/done-2"
406   }
407   {
408     var c/ecx: grapheme <- copy 0x63   # 'c'
409     add-grapheme pg, c
410     var done?/eax: boolean <- done-drawing? pg
411     var done/eax: int <- copy done?
412     check-ints-equal done, 0, "F - test-print-multiple-pages-2/done-3"
413   }
414   {
415     var c/ecx: grapheme <- copy 0x64   # 'd'
416     add-grapheme pg, c
417     var done?/eax: boolean <- done-drawing? pg
418     var done/eax: int <- copy done?
419     check-ints-equal done, 0, "F - test-print-multiple-pages-2/done-4"
420   }
421   {
422     var c/ecx: grapheme <- copy 0x65   # 'e'
423     add-grapheme pg, c
424     var done?/eax: boolean <- done-drawing? pg
425     var done/eax: int <- copy done?
426     check-ints-equal done, 0, "F - test-print-multiple-pages-2/done-5"
427   }
428   {
429     var c/ecx: grapheme <- copy 0x66   # 'f'
430     add-grapheme pg, c
431     var done?/eax: boolean <- done-drawing? pg
432     var done/eax: int <- copy done?
433     check-ints-equal done, 0, "F - test-print-multiple-pages-2/done-6"
434   }
435   {
436     var c/ecx: grapheme <- copy 0x67   # 'g'
437     add-grapheme pg, c
438     var done?/eax: boolean <- done-drawing? pg
439     var done/eax: int <- copy done?
440     check-ints-equal done, 0, "F - test-print-multiple-pages-2/done-7"
441   }
442   {
443     var c/ecx: grapheme <- copy 0x68   # 'h'
444     add-grapheme pg, c
445     var done?/eax: boolean <- done-drawing? pg
446     var done/eax: int <- copy done?
447     check-ints-equal done, 1, "F - test-print-multiple-pages-2/done-8"
448   }
449   var screen-ah/eax: (addr handle screen) <- get pg, screen
450   var screen-addr/eax: (addr screen) <- lookup *screen-ah
451   check-screen-row screen-addr, 1, "abef", "F - test-print-multiple-pages-2/row1"
452   check-screen-row screen-addr, 2, "cdgh", "F - test-print-multiple-pages-2/row2"
453   # currently it's hard-coded that we avoid printing to the bottom-most row of the screen
454 }
455 
456 fn test-print-multiple-pages-with-margins {
457   var pg-on-stack: paginated-screen
458   var pg/eax: (addr paginated-screen) <- address pg-on-stack
459   initialize-fake-paginated-screen pg, 3, 6, 2, 1, 1  # 3 rows, 5 columns, 2 pages * 2 columns each
460   start-drawing pg
461   {
462     var c/ecx: grapheme <- copy 0x61   # 'a'
463     add-grapheme pg, c
464     var done?/eax: boolean <- done-drawing? pg
465     var done/eax: int <- copy done?
466     check-ints-equal done, 0, "F - test-print-multiple-pages-with-margins/grapheme-1"
467   }
468   {
469     var c/ecx: grapheme <- copy 0x62   # 'b'
470     add-grapheme pg, c
471     var done?/eax: boolean <- done-drawing? pg
472     var done/eax: int <- copy done?
473     check-ints-equal done, 0, "F - test-print-multiple-pages-with-margins/grapheme-2"
474   }
475   {
476     var c/ecx: grapheme <- copy 0x63   # 'c'
477     add-grapheme pg, c
478     var done?/eax: boolean <- done-drawing? pg
479     var done/eax: int <- copy done?
480     check-ints-equal done, 0, "F - test-print-multiple-pages-with-margins/grapheme-3"
481   }
482   {
483     var c/ecx: grapheme <- copy 0x64   # 'd'
484     add-grapheme pg, c
485     var done?/eax: boolean <- done-drawing? pg
486     var done/eax: int <- copy done?
487     check-ints-equal done, 0, "F - test-print-multiple-pages-with-margins/grapheme-4"
488   }
489   {
490     var c/ecx: grapheme <- copy 0x65   # 'e'
491     add-grapheme pg, c
492     var done?/eax: boolean <- done-drawing? pg
493     var done/eax: int <- copy done?
494     check-ints-equal done, 0, "F - test-print-multiple-pages-with-margins/grapheme-5"
495   }
496   {
497     var c/ecx: grapheme <- copy 0x66   # 'f'
498     add-grapheme pg, c
499     var done?/eax: boolean <- done-drawing? pg
500     var done/eax: int <- copy done?
501     check-ints-equal done, 0, "F - test-print-multiple-pages-with-margins/grapheme-6"
502   }
503   {
504     var c/ecx: grapheme <- copy 0x67   # 'g'
505     add-grapheme pg, c
506     var done?/eax: boolean <- done-drawing? pg
507     var done/eax: int <- copy done?
508     check-ints-equal done, 0, "F - test-print-multiple-pages-with-margins/grapheme-7"
509   }
510   {
511     var c/ecx: grapheme <- copy 0x68   # 'h'
512     add-grapheme pg, c
513     var done?/eax: boolean <- done-drawing? pg
514     var done/eax: int <- copy done?
515     check-ints-equal done, 1, "F - test-print-multiple-pages-with-margins/grapheme-8"
516   }
517   var screen-ah/eax: (addr handle screen) <- get pg, screen
518   var screen-addr/eax: (addr screen) <- lookup *screen-ah
519   check-screen-row screen-addr, 1, "      ", "F - test-print-multiple-pages-with-margins/row1"
520   check-screen-row screen-addr, 2, " ab ef", "F - test-print-multiple-pages-with-margins/row2"
521   check-screen-row screen-addr, 3, " cd gh", "F - test-print-multiple-pages-with-margins/row3"
522   # currently it's hard-coded that we avoid printing to the bottom-most row of the screen
523 }
524 
525 fn initialize-fake-paginated-screen _self: (addr paginated-screen), nrows: int, ncols: int, page-width: int, top-margin: int, left-margin: int {
526   var self/esi: (addr paginated-screen) <- copy _self
527   var screen-ah/eax: (addr handle screen) <- get self, screen
528   allocate screen-ah
529   var screen-addr/eax: (addr screen) <- lookup *screen-ah
530   initialize-screen screen-addr, nrows, ncols
531   initialize-paginated-screen self, page-width, top-margin, left-margin
532 }
533 
534 ## simple delegates
535 
536 fn reposition-cursor _self: (addr paginated-screen) {
537   var self/esi: (addr paginated-screen) <- copy _self
538   var r/ecx: (addr int) <- get self, row
539   var c/edx: (addr int) <- get self, col
540 #?   print-string-to-real-screen "reposition cursor: "
541 #?   print-int32-hex-to-real-screen *r
542 #?   print-string-to-real-screen ", "
543 #?   print-int32-hex-to-real-screen *c
544 #?   print-string-to-real-screen "\n"
545   var screen-ah/eax: (addr handle screen) <- get self, screen
546   var screen-addr/eax: (addr screen) <- lookup *screen-ah
547   move-cursor screen-addr, *r *c
548 }
549 
550 fn clear-paginated-screen _self: (addr paginated-screen) {
551   var self/esi: (addr paginated-screen) <- copy _self
552   var screen-ah/eax: (addr handle screen) <- get self, screen
553   var screen-addr/eax: (addr screen) <- lookup *screen-ah
554   clear-screen screen-addr
555 }
556 
557 fn start-color-on-paginated-screen _self: (addr paginated-screen), fg: int, bg: int {
558   var self/esi: (addr paginated-screen) <- copy _self
559   var screen-ah/eax: (addr handle screen) <- get self, screen
560   var screen-addr/eax: (addr screen) <- lookup *screen-ah
561   start-color screen-addr, fg, bg
562 }
563 
564 fn start-bold-on-paginated-screen _self: (addr paginated-screen) {
565   var self/esi: (addr paginated-screen) <- copy _self
566   var screen-ah/eax: (addr handle screen) <- get self, screen
567   var screen-addr/eax: (addr screen) <- lookup *screen-ah
568   start-bold screen-addr
569 }
570 
571 fn start-underline-on-paginated-screen _self: (addr paginated-screen) {
572   var self/esi: (addr paginated-screen) <- copy _self
573   var screen-ah/eax: (addr handle screen) <- get self, screen
574   var screen-addr/eax: (addr screen) <- lookup *screen-ah
575   start-underline screen-addr
576 }
577 
578 fn start-reverse-video-on-paginated-screen _self: (addr paginated-screen) {
579   var self/esi: (addr paginated-screen) <- copy _self
580   var screen-ah/eax: (addr handle screen) <- get self, screen
581   var screen-addr/eax: (addr screen) <- lookup *screen-ah
582   start-reverse-video screen-addr
583 }
584 
585 fn start-blinking-on-paginated-screen _self: (addr paginated-screen) {
586   var self/esi: (addr paginated-screen) <- copy _self
587   var screen-ah/eax: (addr handle screen) <- get self, screen
588   var screen-addr/eax: (addr screen) <- lookup *screen-ah
589   start-blinking screen-addr
590 }
591 
592 fn reset-formatting-on-paginated-screen _self: (addr paginated-screen) {
593   var self/esi: (addr paginated-screen) <- copy _self
594   var screen-ah/eax: (addr handle screen) <- get self, screen
595   var screen-addr/eax: (addr screen) <- lookup *screen-ah
596   reset-formatting screen-addr
597 }
598 
599 ## helpers
600 
601 fn next-line _self: (addr paginated-screen) {
602 #?   print-string-to-real-screen "next-line\n"
603   var self/esi: (addr paginated-screen) <- copy _self
604   var tmp/eax: (addr int) <- copy 0
605   var tmp2/ecx: int <- copy 0
606   # self->col = self->leftcol
607   tmp <- get self, leftcol
608   tmp2 <- copy *tmp
609   tmp <- get self, col
610   copy-to *tmp, tmp2
611   # self->row++
612   tmp <- get self, row
613   increment *tmp
614 #?   print-string-to-real-screen "next-line: row: "
615 #?   print-int32-hex-to-real-screen *tmp
616 #?   print-string-to-real-screen "\n"
617   # if (self->row > self->botrow) next-page(self)
618   tmp2 <- copy *tmp
619   tmp <- get self, botrow
620   compare tmp2, *tmp
621   {
622     break-if-<=
623     next-page self
624   }
625 }
626 
627 fn next-page _self: (addr paginated-screen) {
628 #?   print-string-to-real-screen "next-page\n"
629   var self/esi: (addr paginated-screen) <- copy _self
630   var tmp/eax: (addr int) <- copy 0
631   var tmp2/ecx: int <- copy 0
632 #?   # temporary: stop
633 #?   tmp <- get self, ncols
634 #?   tmp2 <- copy *tmp
635 #?   tmp <- get self, rightcol
636 #?   copy-to *tmp, tmp2
637   # real: multiple pages
638   # self->leftcol = self->rightcol + left-margin
639   tmp <- get self, rightcol
640   tmp2 <- copy *tmp
641   tmp <- get self, left-margin
642   tmp2 <- add *tmp
643   tmp <- get self, leftcol
644   copy-to *tmp, tmp2
645 #?   print-string-to-real-screen "left: "
646 #?   print-int32-hex-to-real-screen tmp2
647 #?   print-string-to-real-screen "\n"
648   # self->rightcol = self->leftcol + page-width
649   tmp <- get self, page-width
650   tmp2 <- copy *tmp
651   tmp <- get self, leftcol
652   tmp2 <- add *tmp
653   tmp <- get self, rightcol
654   copy-to *tmp, tmp2
655 #?   print-string-to-real-screen "right: "
656 #?   print-int32-hex-to-real-screen tmp2
657 #?   print-string-to-real-screen "\n"
658   # self->row = self->toprow
659   tmp <- get self, toprow
660   tmp2 <- copy *tmp
661   tmp <- get self, row
662   copy-to *tmp, tmp2
663   # self->col = self->leftcol
664   tmp <- get self, leftcol
665   tmp2 <- copy *tmp
666   tmp <- get self, col
667   copy-to *tmp, tmp2
668 }