https://github.com/akkartik/mu/blob/master/apps/browse.mu
  1 # render text with word-wrap
  2 
  3 fn main args: (addr array (addr array byte)) -> exit-status/ebx: int {
  4   var filename/eax: (addr array byte) <- first-arg args
  5   var file/esi: (addr buffered-file) <- load-file filename
  6   enable-screen-grid-mode
  7   var nrows/eax: int <- copy 0
  8   var ncols/ecx: int <- copy 0
  9   nrows, ncols <- screen-size
 10   enable-keyboard-immediate-mode
 11   {
 12     render file, nrows, ncols
 13     var key/eax: byte <- read-key
 14     compare key, 0x71  # 'q'
 15     loop-if-!=
 16   }
 17   enable-keyboard-type-mode
 18   enable-screen-type-mode
 19   exit-status <- copy 0
 20 }
 21 
 22 # decide how to lay out pages on screen
 23 fn render in: (addr buffered-file), nrows: int, ncols: int {
 24   # Fit n pages on screen on separate columns, each wide enough to read
 25   # comfortably.
 26   # Pages are separated horizontally by a 'page margin'. Among other reasons,
 27   # this allows the odd line to bleed out on the right if necessary.
 28   #
 29   # hardcoded parameters:
 30   #   top-margin
 31   #   page-margin
 32   #   text-width
 33   var npages/eax: int <- num-pages ncols, 0x40, 5  # text-width, page-margin
 34   var toprow/eax: int <- copy 2  # top-margin
 35   var botrow/ecx: int <- copy nrows
 36   var leftcol/edx: int <- copy 5  # page-margin
 37   var rightcol/ebx: int <- copy leftcol
 38   rightcol <- add 0x40  # text-width = 64 characters
 39   {
 40     compare rightcol, ncols
 41     break-if->=
 42     render-page in, toprow, leftcol, botrow, rightcol
 43     leftcol <- copy rightcol
 44     leftcol <- add 5  # page-margin
 45     rightcol <- copy leftcol
 46     rightcol <- add 0x40  # text-width
 47     loop
 48   }
 49 }
 50 
 51 fn num-pages ncols: int, text-width: int, page-margin: int -> result/eax: int {
 52   result <- copy 3
 53 }
 54 
 55 fn render-page in: (addr buffered-file), toprow: int, leftcol: int, botrow: int, rightcol: int {
 56   clear toprow, leftcol, botrow, rightcol
 57   # render screen rows
 58   var row/ecx: int <- copy toprow
 59 $line-loop:  {
 60     compare row, botrow
 61     break-if->=
 62     var col/edx: int <- copy leftcol
 63     move-cursor row, col
 64     {
 65       compare col, rightcol
 66       break-if->=
 67       var c/eax: byte <- read-byte-buffered in
 68       compare c, 0xffffffff  # EOF marker
 69       break-if-= $line-loop
 70       compare c, 0xa  # newline
 71       break-if-=  # no need to print newlines
 72       print-byte c
 73       col <- increment
 74       loop
 75     }
 76     row <- increment
 77     loop
 78   }
 79 }
 80 
 81 fn clear toprow: int, leftcol: int, botrow: int, rightcol: int {
 82   var row/ecx: int <- copy toprow
 83   {
 84     compare row, botrow
 85     break-if->=
 86     var col/edx: int <- copy leftcol
 87     move-cursor row, col
 88     {
 89       compare col, rightcol
 90       break-if->=
 91       print-string " "
 92       col <- increment
 93       loop
 94     }
 95     row <- increment
 96     loop
 97   }
 98 }
 99 
100 fn first-arg args-on-stack: (addr array (addr array byte)) -> out/eax: (addr array byte) {
101   var args/eax: (addr array (addr array byte)) <- copy args-on-stack
102   var result/eax: (addr addr array byte) <- index args, 1
103   out <- copy *result
104 }
105 
106 fn load-file filename: (addr array byte) -> out/esi: (addr buffered-file) {
107   var result: (handle buffered-file)
108   {
109     var tmp1/eax: (addr handle buffered-file) <- address result
110     open filename, 0, tmp1
111   }
112   var tmp2/eax: (addr buffered-file) <- lookup result
113   out <- copy tmp2
114 }
115 
116 fn dump in: (addr buffered-file) {
117   var c/eax: byte <- read-byte-buffered in
118   compare c, 0xffffffff  # EOF marker
119   break-if-=
120   print-byte c
121   loop
122 }