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