https://github.com/akkartik/mu/blob/main/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) -> _/eax: boolean {
126   # if (self->leftcol == left-margin + 1) return false
127   var self/esi: (addr paginated-screen) <- copy _self
128   var tmp/eax: (addr int) <- get self, left-margin
129   var first-col/ecx: int <- copy *tmp
130   first-col <- increment
131   tmp <- get self, leftcol
132   $done-drawing:first-page?: {
133     compare first-col, *tmp
134     break-if-!=
135     return 0  # false
136   }
137   # return self->rightcol > self->ncols + 1
138   tmp <- get self, ncols
139   var max/ecx: int <- copy *tmp
140   max <- increment
141   tmp <- get self, rightcol
142 #?   print-string-to-real-screen "done-drawing? "
143 #?   print-int32-hex-to-real-screen *tmp
144 #?   print-string-to-real-screen " vs "
145 #?   print-int32-hex-to-real-screen max
146 #?   print-string-to-real-screen "\n"
147   compare *tmp, max
148   {
149     break-if->
150     return 0  # false
151   }
152   return 1  # true
153 }
154 
155 fn add-grapheme _self: (addr paginated-screen), c: grapheme {
156 #?   print-string-to-real-screen "add-grapheme: "
157 #?   print-grapheme-to-real-screen c
158 #?   print-string-to-real-screen "\n"
159 $add-grapheme:body: {
160   var self/esi: (addr paginated-screen) <- copy _self
161   {
162     compare c, 0xa  # newline
163     break-if-!=
164     next-line self
165     reposition-cursor self
166     break $add-grapheme:body
167   }
168   # print c
169   var screen-ah/eax: (addr handle screen) <- get self, screen
170   var screen-addr/eax: (addr screen) <- lookup *screen-ah
171   print-grapheme screen-addr, c
172   # self->col++
173   var tmp/eax: (addr int) <- get self, col
174   increment *tmp
175   # if (self->col > self->rightcol) next-line(self)
176   var tmp2/ecx: int <- copy *tmp
177   tmp <- get self, rightcol
178   compare tmp2, *tmp
179   {
180     break-if-<
181     next-line self
182     reposition-cursor self
183   }
184 }
185 }
186 
187 ## tests
188 
189 fn test-print-grapheme-on-paginated-screen {
190   var pg-on-stack: paginated-screen
191   var pg/eax: (addr paginated-screen) <- address pg-on-stack
192   initialize-fake-paginated-screen pg, 3, 0xa, 0xa, 0, 0
193   start-drawing pg
194   {
195     var c/ecx: grapheme <- copy 0x61   # 'a'
196     add-grapheme pg, c
197     var done?/eax: boolean <- done-drawing? pg
198     var done/eax: int <- copy done?
199     check-ints-equal done, 0, "F - test-print-grapheme-on-paginated-screen/done"
200   }
201   var screen-ah/eax: (addr handle screen) <- get pg, screen
202   var screen-addr/eax: (addr screen) <- lookup *screen-ah
203   check-screen-row screen-addr, 1, "a", "F - test-print-grapheme-on-paginated-screen"
204 }
205 
206 fn test-print-single-page {
207   var pg-on-stack: paginated-screen
208   var pg/eax: (addr paginated-screen) <- address pg-on-stack
209   initialize-fake-paginated-screen pg, 2, 4, 2, 0, 0  # 2 rows, 4 columns, 2 pages * 2 columns each
210   start-drawing pg
211   # pages at columns [1, 3), [3, 5)
212   {
213     var c/ecx: grapheme <- copy 0x61   # 'a'
214     add-grapheme pg, c
215     var done?/eax: boolean <- done-drawing? pg
216     var done/eax: int <- copy done?
217     check-ints-equal done, 0, "F - test-print-single-page/done-1"
218   }
219   {
220     var c/ecx: grapheme <- copy 0x62   # 'b'
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-2"
225   }
226   {
227     var c/ecx: grapheme <- copy 0x63   # 'c'
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-3"
232   }
233   {
234     var c/ecx: grapheme <- copy 0x64   # 'd'
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-4"
239   }
240   var screen-ah/eax: (addr handle screen) <- get pg, screen
241   var screen-addr/eax: (addr screen) <- lookup *screen-ah
242   check-screen-row screen-addr, 1, "ab  ", "F - test-print-single-page/row1"
243   check-screen-row screen-addr, 2, "cd  ", "F - test-print-single-page/row2"
244   # currently it's hard-coded that we avoid printing to the bottom-most row of the screen
245 }
246 
247 fn test-print-single-page-narrower-than-page-width {
248   var pg-on-stack: paginated-screen
249   var pg/eax: (addr paginated-screen) <- address pg-on-stack
250   initialize-fake-paginated-screen pg, 2, 4, 5, 0, 0  # 2 rows, 4 columns, 5-column pages
251   start-drawing pg
252   {
253     var c/ecx: grapheme <- copy 0x61   # 'a'
254     add-grapheme pg, c
255     var done?/eax: boolean <- done-drawing? pg
256     var done/eax: int <- copy done?
257     check-ints-equal done, 0, "F - test-print-single-page-narrower-than-page-width/done-1"
258   }
259   {
260     var c/ecx: grapheme <- copy 0x62   # 'b'
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-2"
265   }
266   {
267     var c/ecx: grapheme <- copy 0x63   # 'c'
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-3"
272   }
273   {
274     var c/ecx: grapheme <- copy 0x64   # 'd'
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-4"
279   }
280   {
281     var c/ecx: grapheme <- copy 0x65   # 'e'
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-5"
286   }
287   var screen-ah/eax: (addr handle screen) <- get pg, screen
288   var screen-addr/eax: (addr screen) <- lookup *screen-ah
289   check-screen-row screen-addr, 1, "abcd", "F - test-print-single-page-narrower-than-page-width/row1"
290   check-screen-row screen-addr, 2, "e   ", "F - test-print-single-page-narrower-than-page-width/row2"
291   # currently it's hard-coded that we avoid printing to the bottom-most row of the screen
292 }
293 
294 fn test-print-single-page-narrower-than-page-width-with-margin {
295   var pg-on-stack: paginated-screen
296   var pg/eax: (addr paginated-screen) <- address pg-on-stack
297   initialize-fake-paginated-screen pg, 2, 4, 5, 0, 1  # 2 rows, 4 columns, 5-column pages, left margin
298   start-drawing pg
299   {
300     var c/ecx: grapheme <- copy 0x61   # 'a'
301     add-grapheme pg, c
302     var done?/eax: boolean <- done-drawing? pg
303     var done/eax: int <- copy done?
304     check-ints-equal done, 0, "F - test-print-single-page-narrower-than-page-width-with-margin/done-1"
305   }
306   {
307     var c/ecx: grapheme <- copy 0x62   # 'b'
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-2"
312   }
313   {
314     var c/ecx: grapheme <- copy 0x63   # 'c'
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-3"
319   }
320   {
321     var c/ecx: grapheme <- copy 0x64   # 'd'
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-4"
326   }
327   {
328     var c/ecx: grapheme <- copy 0x65   # 'e'
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-5"
333   }
334   var screen-ah/eax: (addr handle screen) <- get pg, screen
335   var screen-addr/eax: (addr screen) <- lookup *screen-ah
336   check-screen-row screen-addr, 1, " abc", "F - test-print-single-page-narrower-than-page-width-with-margin/row1"
337   check-screen-row screen-addr, 2, " de ", "F - test-print-single-page-narrower-than-page-width-with-margin/row2"
338   # currently it's hard-coded that we avoid printing to the bottom-most row of the screen
339 }
340 
341 fn test-print-multiple-pages {
342   var pg-on-stack: paginated-screen
343   var pg/eax: (addr paginated-screen) <- address pg-on-stack
344   initialize-fake-paginated-screen pg, 2, 2, 1, 0, 0  # 2 rows, 2 columns, 2 pages * 1 column each
345   start-drawing pg
346   {
347     var c/ecx: grapheme <- copy 0x61   # 'a'
348     add-grapheme pg, c
349     var done?/eax: boolean <- done-drawing? pg
350     var done/eax: int <- copy done?
351     check-ints-equal done, 0, "F - test-print-multiple-pages/done-1"
352   }
353   {
354     var c/ecx: grapheme <- copy 0x62   # 'b'
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-2"
359   }
360   {
361     var c/ecx: grapheme <- copy 0x63   # 'c'
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-3"
366   }
367   {
368     var c/ecx: grapheme <- copy 0x64   # 'd'
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, 1, "F - test-print-multiple-pages/done-4"
373   }
374   var screen-ah/eax: (addr handle screen) <- get pg, screen
375   var screen-addr/eax: (addr screen) <- lookup *screen-ah
376   check-screen-row screen-addr, 1, "ac", "F - test-print-multiple-pages/row1"
377   check-screen-row screen-addr, 2, "bd", "F - test-print-multiple-pages/row2"
378   # currently it's hard-coded that we avoid printing to the bottom-most row of the screen
379 }
380 
381 fn test-print-multiple-pages-2 {
382   var pg-on-stack: paginated-screen
383   var pg/eax: (addr paginated-screen) <- address pg-on-stack
384   initialize-fake-paginated-screen pg, 2, 4, 2, 0, 0  # 2 rows, 4 columns, 2 pages * 2 columns each
385   start-drawing pg
386   {
387     var c/ecx: grapheme <- copy 0x61   # 'a'
388     add-grapheme pg, c
389     var done?/eax: boolean <- done-drawing? pg
390     var done/eax: int <- copy done?
391     check-ints-equal done, 0, "F - test-print-multiple-pages-2/done-1"
392   }
393   {
394     var c/ecx: grapheme <- copy 0x62   # 'b'
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-2"
399   }
400   {
401     var c/ecx: grapheme <- copy 0x63   # 'c'
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-3"
406   }
407   {
408     var c/ecx: grapheme <- copy 0x64   # 'd'
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-4"
413   }
414   {
415     var c/ecx: grapheme <- copy 0x65   # 'e'
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-5"
420   }
421   {
422     var c/ecx: grapheme <- copy 0x66   # 'f'
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-6"
427   }
428   {
429     var c/ecx: grapheme <- copy 0x67   # 'g'
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-7"
434   }
435   {
436     var c/ecx: grapheme <- copy 0x68   # 'h'
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, 1, "F - test-print-multiple-pages-2/done-8"
441   }
442   var screen-ah/eax: (addr handle screen) <- get pg, screen
443   var screen-addr/eax: (addr screen) <- lookup *screen-ah
444   check-screen-row screen-addr, 1, "abef", "F - test-print-multiple-pages-2/row1"
445   check-screen-row screen-addr, 2, "cdgh", "F - test-print-multiple-pages-2/row2"
446   # currently it's hard-coded that we avoid printing to the bottom-most row of the screen
447 }
448 
449 fn test-print-multiple-pages-with-margins {
450   var pg-on-stack: paginated-screen
451   var pg/eax: (addr paginated-screen) <- address pg-on-stack
452   initialize-fake-paginated-screen pg, 3, 6, 2, 1, 1  # 3 rows, 5 columns, 2 pages * 2 columns each
453   start-drawing pg
454   {
455     var c/ecx: grapheme <- copy 0x61   # 'a'
456     add-grapheme pg, c
457     var done?/eax: boolean <- done-drawing? pg
458     var done/eax: int <- copy done?
459     check-ints-equal done, 0, "F - test-print-multiple-pages-with-margins/grapheme-1"
460   }
461   {
462     var c/ecx: grapheme <- copy 0x62   # 'b'
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-2"
467   }
468   {
469     var c/ecx: grapheme <- copy 0x63   # 'c'
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-3"
474   }
475   {
476     var c/ecx: grapheme <- copy 0x64   # 'd'
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-4"
481   }
482   {
483     var c/ecx: grapheme <- copy 0x65   # 'e'
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-5"
488   }
489   {
490     var c/ecx: grapheme <- copy 0x66   # 'f'
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-6"
495   }
496   {
497     var c/ecx: grapheme <- copy 0x67   # 'g'
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-7"
502   }
503   {
504     var c/ecx: grapheme <- copy 0x68   # 'h'
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, 1, "F - test-print-multiple-pages-with-margins/grapheme-8"
509   }
510   var screen-ah/eax: (addr handle screen) <- get pg, screen
511   var screen-addr/eax: (addr screen) <- lookup *screen-ah
512   check-screen-row screen-addr, 1, "      ", "F - test-print-multiple-pages-with-margins/row1"
513   check-screen-row screen-addr, 2, " ab ef", "F - test-print-multiple-pages-with-margins/row2"
514   check-screen-row screen-addr, 3, " cd gh", "F - test-print-multiple-pages-with-margins/row3"
515   # currently it's hard-coded that we avoid printing to the bottom-most row of the screen
516 }
517 
518 fn initialize-fake-paginated-screen _self: (addr paginated-screen), nrows: int, ncols: int, page-width: int, top-margin: int, left-margin: int {
519   var self/esi: (addr paginated-screen) <- copy _self
520   var screen-ah/eax: (addr handle screen) <- get self, screen
521   allocate screen-ah
522   var screen-addr/eax: (addr screen) <- lookup *screen-ah
523   initialize-screen screen-addr, nrows, ncols
524   initialize-paginated-screen self, page-width, top-margin, left-margin
525 }
526 
527 ## simple delegates
528 
529 fn reposition-cursor _self: (addr paginated-screen) {
530   var self/esi: (addr paginated-screen) <- copy _self
531   var r/ecx: (addr int) <- get self, row
532   var c/edx: (addr int) <- get self, col
533 #?   print-string-to-real-screen "reposition cursor: "
534 #?   print-int32-hex-to-real-screen *r
535 #?   print-string-to-real-screen ", "
536 #?   print-int32-hex-to-real-screen *c
537 #?   print-string-to-real-screen "\n"
538   var screen-ah/eax: (addr handle screen) <- get self, screen
539   var screen-addr/eax: (addr screen) <- lookup *screen-ah
540   move-cursor screen-addr, *r *c
541 }
542 
543 fn clear-paginated-screen _self: (addr paginated-screen) {
544   var self/esi: (addr paginated-screen) <- copy _self
545   var screen-ah/eax: (addr handle screen) <- get self, screen
546   var screen-addr/eax: (addr screen) <- lookup *screen-ah
547   clear-screen screen-addr
548 }
549 
550 fn start-color-on-paginated-screen _self: (addr paginated-screen), fg: int, bg: int {
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   start-color screen-addr, fg, bg
555 }
556 
557 fn start-bold-on-paginated-screen _self: (addr paginated-screen) {
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-bold screen-addr
562 }
563 
564 fn start-underline-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-underline screen-addr
569 }
570 
571 fn start-reverse-video-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-reverse-video screen-addr
576 }
577 
578 fn start-blinking-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-blinking screen-addr
583 }
584 
585 fn reset-formatting-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   reset-formatting screen-addr
590 }
591 
592 ## helpers
593 
594 fn next-line _self: (addr paginated-screen) {
595 #?   print-string-to-real-screen "next-line\n"
596   var self/esi: (addr paginated-screen) <- copy _self
597   var tmp/eax: (addr int) <- copy 0
598   var tmp2/ecx: int <- copy 0
599   # self->col = self->leftcol
600   tmp <- get self, leftcol
601   tmp2 <- copy *tmp
602   tmp <- get self, col
603   copy-to *tmp, tmp2
604   # self->row++
605   tmp <- get self, row
606   increment *tmp
607 #?   print-string-to-real-screen "next-line: row: "
608 #?   print-int32-hex-to-real-screen *tmp
609 #?   print-string-to-real-screen "\n"
610   # if (self->row > self->botrow) next-page(self)
611   tmp2 <- copy *tmp
612   tmp <- get self, botrow
613   compare tmp2, *tmp
614   {
615     break-if-<=
616     next-page self
617   }
618 }
619 
620 fn next-page _self: (addr paginated-screen) {
621 #?   print-string-to-real-screen "next-page\n"
622   var self/esi: (addr paginated-screen) <- copy _self
623   var tmp/eax: (addr int) <- copy 0
624   var tmp2/ecx: int <- copy 0
625 #?   # temporary: stop
626 #?   tmp <- get self, ncols
627 #?   tmp2 <- copy *tmp
628 #?   tmp <- get self, rightcol
629 #?   copy-to *tmp, tmp2
630   # real: multiple pages
631   # self->leftcol = self->rightcol + left-margin
632   tmp <- get self, rightcol
633   tmp2 <- copy *tmp
634   tmp <- get self, left-margin
635   tmp2 <- add *tmp
636   tmp <- get self, leftcol
637   copy-to *tmp, tmp2
638 #?   print-string-to-real-screen "left: "
639 #?   print-int32-hex-to-real-screen tmp2
640 #?   print-string-to-real-screen "\n"
641   # self->rightcol = self->leftcol + page-width
642   tmp <- get self, page-width
643   tmp2 <- copy *tmp
644   tmp <- get self, leftcol
645   tmp2 <- add *tmp
646   tmp <- get self, rightcol
647   copy-to *tmp, tmp2
648 #?   print-string-to-real-screen "right: "
649 #?   print-int32-hex-to-real-screen tmp2
650 #?   print-string-to-real-screen "\n"
651   # self->row = self->toprow
652   tmp <- get self, toprow
653   tmp2 <- copy *tmp
654   tmp <- get self, row
655   copy-to *tmp, tmp2
656   # self->col = self->leftcol
657   tmp <- get self, leftcol
658   tmp2 <- copy *tmp
659   tmp <- get self, col
660   copy-to *tmp, tmp2
661 }