https://github.com/akkartik/mu/blob/main/browse-slack/environment.mu
  1 type environment {
  2   item-index: int
  3 }
  4 
  5 # static buffer sizes in this file:
  6 #   main-panel-hor            # in characters
  7 #   item-padding-hor          # in pixels
  8 #   item-padding-ver          # in characters
  9 #   avatar-side               # in pixels
 10 #   avatar-space-hor          # in characters
 11 #   avatar-space-ver          # in characters
 12 #   search-position-x         # in characters
 13 #   search-space-ver          # in characters
 14 #   author-name-padding-ver   # in characters
 15 #   post-right-coord          # in characters
 16 #   channel-offset-x          # in characters
 17 #   menu-space-ver            # in characters
 18 
 19 fn initialize-environment _self: (addr environment), _items: (addr item-list) {
 20   var self/esi: (addr environment) <- copy _self
 21   var items/eax: (addr item-list) <- copy _items
 22   var newest-item-a/eax: (addr int) <- get items, newest
 23   var newest-item/eax: int <- copy *newest-item-a
 24   var dest/edi: (addr int) <- get self, item-index
 25   copy-to *dest, newest-item
 26 }
 27 
 28 fn render-environment screen: (addr screen), env: (addr environment), users: (addr array user), channels: (addr array channel), items: (addr item-list) {
 29   clear-screen screen
 30   render-search-input screen, env
 31   render-channels screen, env, channels
 32   render-item-list screen, env, items, users
 33   render-menu screen
 34 }
 35 
 36 fn render-channels screen: (addr screen), env: (addr environment), _channels: (addr array channel) {
 37   var channels/esi: (addr array channel) <- copy _channels
 38   var y/ebx: int <- copy 2/search-space-ver
 39   y <- add 1/item-padding-ver
 40   var i/ecx: int <- copy 0
 41   var max/edx: int <- length channels
 42   {
 43     compare i, max
 44     break-if->=
 45     var offset/eax: (offset channel) <- compute-offset channels, i
 46     var curr/eax: (addr channel) <- index channels, offset
 47     var name-ah/eax: (addr handle array byte) <- get curr, name
 48     var name/eax: (addr array byte) <- lookup *name-ah
 49     compare name, 0
 50     break-if-=
 51     set-cursor-position screen, 2/x y
 52     draw-text-wrapping-right-then-down-from-cursor-over-full-screen screen, "#", 0xf/grey 0/black
 53     draw-text-wrapping-right-then-down-from-cursor-over-full-screen screen, name, 0xf/grey 0/black
 54     y <- add 2/channel-padding
 55     i <- increment
 56     loop
 57   }
 58 }
 59 
 60 fn render-item-list screen: (addr screen), _env: (addr environment), _items: (addr item-list), users: (addr array user) {
 61   var env/esi: (addr environment) <- copy _env
 62   var tmp-width/eax: int <- copy 0
 63   var tmp-height/ecx: int <- copy 0
 64   tmp-width, tmp-height <- screen-size screen
 65   var screen-width: int
 66   copy-to screen-width, tmp-width
 67   var screen-height: int
 68   copy-to screen-height, tmp-height
 69   #
 70   var y/ecx: int <- copy 2/search-space-ver
 71   y <- add 1/item-padding-ver
 72   var newest-item/eax: (addr int) <- get env, item-index
 73   var i/ebx: int <- copy *newest-item
 74   var items/esi: (addr item-list) <- copy _items
 75   var items-data-ah/eax: (addr handle array item) <- get items, data
 76   var _items-data/eax: (addr array item) <- lookup *items-data-ah
 77   var items-data/edi: (addr array item) <- copy _items-data
 78   {
 79     compare i, 0
 80     break-if-<
 81     compare y, screen-height
 82     break-if->=
 83     var offset/eax: (offset item) <- compute-offset items-data, i
 84     var curr-item/eax: (addr item) <- index items-data, offset
 85     y <- render-item screen, curr-item, users, y, screen-height
 86     i <- decrement
 87     loop
 88   }
 89   var top/eax: int <- copy screen-height
 90   top <- subtract 2/menu-space-ver
 91   clear-rect screen, 0 top, screen-width screen-height, 0/bg
 92 }
 93 
 94 fn render-search-input screen: (addr screen), env: (addr environment) {
 95   set-cursor-position 0/screen, 0x22/x=search-position-x 1/y
 96   draw-text-wrapping-right-then-down-from-cursor-over-full-screen screen, "search ", 7/fg 0/bg
 97   draw-text-wrapping-right-then-down-from-cursor-over-full-screen screen, "________________________________", 0xf/fg 0/bg
 98 }
 99 
100 fn render-menu screen: (addr screen) {
101   var width/eax: int <- copy 0
102   var y/ecx: int <- copy 0
103   width, y <- screen-size screen
104   y <- decrement
105   set-cursor-position screen, 2/x, y
106   draw-text-rightward-from-cursor screen, " / ", width, 0/fg 0xf/bg
107   draw-text-rightward-from-cursor screen, " search  ", width, 0xf/fg, 0/bg
108   draw-text-rightward-from-cursor screen, " ^f ", width, 0/fg 0xf/bg
109   draw-text-rightward-from-cursor screen, " next page  ", width, 0xf/fg, 0/bg
110   draw-text-rightward-from-cursor screen, " ^b ", width, 0/fg 0xf/bg
111   draw-text-rightward-from-cursor screen, " previous page  ", width, 0xf/fg, 0/bg
112 }
113 
114 fn render-item screen: (addr screen), _item: (addr item), _users: (addr array user), y: int, screen-height: int -> _/ecx: int {
115   var item/esi: (addr item) <- copy _item
116   var users/edi: (addr array user) <- copy _users
117   var author-index-addr/ecx: (addr int) <- get item, by
118   var author-index/ecx: int <- copy *author-index-addr
119   var author-offset/ecx: (offset user) <- compute-offset users, author-index
120   var author/ecx: (addr user) <- index users, author-offset
121   # author avatar
122   var author-avatar-ah/eax: (addr handle image) <- get author, avatar
123   var _author-avatar/eax: (addr image) <- lookup *author-avatar-ah
124   var author-avatar/ebx: (addr image) <- copy _author-avatar
125   {
126     compare author-avatar, 0
127     break-if-=
128     var y/edx: int <- copy y
129     y <- shift-left 4/log2font-height
130     var x/eax: int <- copy 0x20/main-panel-hor
131     x <- shift-left 3/log2font-width
132     x <- add 0x18/item-padding-hor
133     render-image screen, author-avatar, x, y, 0x50/avatar-side, 0x50/avatar-side
134   }
135   # channel
136   var channel-name-ah/eax: (addr handle array byte) <- get item, channel
137   var channel-name/eax: (addr array byte) <- lookup *channel-name-ah
138   {
139     var x/eax: int <- copy 0x20/main-panel-hor
140     x <- add 0x40/channel-offset-x
141     set-cursor-position screen, x y
142   }
143   draw-text-wrapping-right-then-down-from-cursor-over-full-screen screen, "#", 7/grey 0/black
144   draw-text-wrapping-right-then-down-from-cursor-over-full-screen screen, channel-name, 7/grey 0/black
145   # author name
146   var author-real-name-ah/eax: (addr handle array byte) <- get author, real-name
147   var author-real-name/eax: (addr array byte) <- lookup *author-real-name-ah
148   {
149     var x/ecx: int <- copy 0x20/main-panel-hor
150     x <- add 0x10/avatar-space-hor
151     set-cursor-position screen, x y
152     draw-text-wrapping-right-then-down-from-cursor-over-full-screen screen, author-real-name, 0xf/white 0/black
153   }
154   increment y
155   # text
156   var text-ah/eax: (addr handle array byte) <- get item, text
157   var _text/eax: (addr array byte) <- lookup *text-ah
158   var text/edx: (addr array byte) <- copy _text
159   var x/eax: int <- copy 0x20/main-panel-hor
160   x <- add 0x10/avatar-space-hor
161   var text-y/ecx: int <- copy y
162   text-y <- add 1/author-name-padding-ver
163   x, text-y <- draw-text-wrapping-right-then-down screen, text, x text-y, 0x70/xmax=post-right-coord screen-height, x text-y, 7/fg 0/bg
164   text-y <- add 2/item-padding-ver
165   # flush
166   add-to y, 6/avatar-space-ver
167   compare y, text-y
168   {
169     break-if-<
170     return y
171   }
172   return text-y
173 }
174 
175 fn update-environment env: (addr environment), key: byte, items: (addr item-list) {
176   {
177     compare key, 6/ctrl-f
178     break-if-!=
179     page-down env, items
180     return
181   }
182   {
183     compare key, 2/ctrl-b
184     break-if-!=
185     page-up env, items
186     return
187   }
188 }
189 
190 fn page-down _env: (addr environment), _items: (addr item-list) {
191   var env/edi: (addr environment) <- copy _env
192   var items/esi: (addr item-list) <- copy _items
193   var items-data-ah/eax: (addr handle array item) <- get items, data
194   var _items-data/eax: (addr array item) <- lookup *items-data-ah
195   var items-data/ebx: (addr array item) <- copy _items-data
196   var src/eax: (addr int) <- get env, item-index
197   var new-item-index/ecx: int <- copy *src
198   var y/edx: int <- copy 2
199   {
200     compare new-item-index, 0
201     break-if-<
202     compare y, 0x28/screen-height-minus-menu
203     break-if->=
204     var offset/eax: (offset item) <- compute-offset items-data, new-item-index
205     var item/eax: (addr item) <- index items-data, offset
206     var item-text-ah/eax: (addr handle array byte) <- get item, text
207     var item-text/eax: (addr array byte) <- lookup *item-text-ah
208     var h/eax: int <- estimate-height item-text
209     set-cursor-position 0/screen, 0 0
210     draw-int32-decimal-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, h, 4/fg 0/bg
211     y <- add h
212     new-item-index <- decrement
213     loop
214   }
215   new-item-index <- increment
216   var dest/eax: (addr int) <- get env, item-index
217   copy-to *dest, new-item-index
218 }
219 
220 fn page-up _env: (addr environment), _items: (addr item-list) {
221   var env/edi: (addr environment) <- copy _env
222   var items/esi: (addr item-list) <- copy _items
223   var items-data-ah/eax: (addr handle array item) <- get items, data
224   var _items-data/eax: (addr array item) <- lookup *items-data-ah
225   var items-data/ebx: (addr array item) <- copy _items-data
226   var newest-item-index-a/esi: (addr int) <- get items, newest
227   var src/eax: (addr int) <- get env, item-index
228   var new-item-index/ecx: int <- copy *src
229   var y/edx: int <- copy 2
230   {
231     compare new-item-index, *newest-item-index-a
232     break-if->
233     compare y, 0x28/screen-height-minus-menu
234     break-if->=
235     var offset/eax: (offset item) <- compute-offset items-data, new-item-index
236     var item/eax: (addr item) <- index items-data, offset
237     var item-text-ah/eax: (addr handle array byte) <- get item, text
238     var item-text/eax: (addr array byte) <- lookup *item-text-ah
239     var h/eax: int <- estimate-height item-text
240     set-cursor-position 0/screen, 0 0
241     draw-int32-decimal-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, h, 4/fg 0/bg
242     y <- add h
243     new-item-index <- increment
244     loop
245   }
246   new-item-index <- decrement
247   var dest/eax: (addr int) <- get env, item-index
248   copy-to *dest, new-item-index
249 }
250 
251 # keep sync'd with render-item
252 fn estimate-height _message-text: (addr array byte) -> _/eax: int {
253   var message-text/esi: (addr array byte) <- copy _message-text
254   var result/eax: int <- length message-text
255   var remainder/edx: int <- copy 0
256   result, remainder <- integer-divide result, 0x40/post-width
257   compare remainder, 0
258   {
259     break-if-=
260     result <- increment
261   }
262   result <- add 2/item-padding-ver
263   compare result, 6/avatar-space-ver
264   {
265     break-if->
266     return 6/avatar-space-ver
267   }
268   return result
269 }