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-on-stack: (addr array (addr array byte)) -> exit-status/ebx: int {
 10 +-- 20 lines: # var file/esi: (addr buffered-file) = open args-on-stack[1] for reading -------------------------------------------------------------------------------------------------------------------------------------------------------
 30   enable-screen-grid-mode
 31   var nrows/eax: int <- copy 0
 32   var ncols/ecx: int <- copy 0
 33   nrows, ncols <- screen-size
 34   enable-keyboard-immediate-mode
 35   {
 36     render file, nrows, ncols
 37     var key/eax: byte <- read-key
 38     compare key, 0x71  # 'q'
 39     loop-if-!=
 40   }
 41   enable-keyboard-type-mode
 42   enable-screen-type-mode
 43   exit-status <- copy 0
 44 }
 45 
 46 type render-state {
 47   current-state: int  # enum 0: normal, 1: bold
 48 }
 49 
 50 # decide how to lay out pages on screen
 51 fn render in: (addr buffered-file), nrows: int, ncols: int {
 52   # Fit multiple pages on screen on separate columns, each wide enough to read
 53   # comfortably.
 54   # Pages are separated horizontally by a 'page margin'. Among other reasons,
 55   # this allows the odd line to bleed out on the right if necessary.
 56   #
 57   # hardcoded parameters:
 58   #   top-margin
 59   #   page-margin
 60   #   page-width
 61   var _r: render-state
 62   var r/edi: (addr render-state) <- address _r
 63   var toprow/eax: int <- copy 2  # top-margin
 64   var botrow/ecx: int <- copy nrows
 65   var leftcol/edx: int <- copy 5  # page-margin
 66   var rightcol/ebx: int <- copy leftcol
 67   rightcol <- add 0x40  # page-width = 64 characters
 68   start-color 0xec, 7  # 236 = darkish gray
 69   {
 70     compare rightcol, ncols
 71     break-if->=
 72     render-page in, toprow, leftcol, botrow, rightcol, r
 73     leftcol <- copy rightcol
 74     leftcol <- add 5  # page-margin
 75     rightcol <- copy leftcol
 76     rightcol <- add 0x40  # page-width
 77     loop
 78   }
 79 }
 80 
 81 fn render-page in: (addr buffered-file), toprow: int, leftcol: int, botrow: int, rightcol: int, r: (addr render-state) {
 82   clear toprow, leftcol, botrow, rightcol
 83   # render screen rows
 84   var row/ecx: int <- copy toprow
 85 $line-loop: {
 86     compare row, botrow
 87     break-if->=
 88     var col/edx: int <- copy leftcol
 89     move-cursor row, col
 90     {
 91       compare col, rightcol
 92       break-if->=
 93       var c/eax: byte <- read-byte-buffered in
 94       compare c, 0xffffffff  # EOF marker
 95       break-if-= $line-loop
 96       update-attributes c, r
 97       compare c, 0xa  # newline
 98       break-if-=  # no need to print newlines
 99       print-byte c
100       col <- increment
101       loop
102     }
103     row <- increment
104     loop
105   }
106 }
107 
108 fn update-attributes c: byte, _r: (addr render-state) {
109   var r/edi: (addr render-state) <- copy _r
110   var state/esi: (addr int) <- get r, current-state
111 $update-attributes:check-state: {
112     compare *state, 0  # normal
113     {
114       break-if-!=
115       compare c, 0x2a  # '*'
116       {
117         break-if-!=
118         # r->current-state == 0 && c == '*'
119         start-bold
120         copy-to *state, 1
121         break $update-attributes:check-state
122       }
123       compare c, 0x5f  # '_'
124       {
125         break-if-!=
126         # r->current-state == 0 && c == '_'
127         start-bold
128         copy-to *state, 1
129         break $update-attributes:check-state
130       }
131       break $update-attributes:check-state
132     }
133     {
134       break-if-=
135       compare c, 0x2a  # '*'
136       {
137         break-if-!=
138         # r->current-state == 1 && c == '*'
139         reset-formatting
140         copy-to *state, 0
141         break $update-attributes:check-state
142       }
143       compare c, 0x5f  # '_'
144       {
145         break-if-!=
146         # r->current-state == 1 && c == '_'
147         reset-formatting
148         copy-to *state, 0
149         break $update-attributes:check-state
150       }
151       break $update-attributes:check-state
152     }
153   }
154 }
155 
156 fn clear toprow: int, leftcol: int, botrow: int, rightcol: int {
157   var row/ecx: int <- copy toprow
158   {
159     compare row, botrow
160     break-if->=
161     var col/edx: int <- copy leftcol
162     move-cursor row, col
163     {
164       compare col, rightcol
165       break-if->=
166       print-string " "
167       col <- increment
168       loop
169     }
170     row <- increment
171     loop
172   }
173 }
174 
175 fn dump in: (addr buffered-file) {
176   var c/eax: byte <- read-byte-buffered in
177   compare c, 0xffffffff  # EOF marker
178   break-if-=
179   print-byte c
180   loop
181 }