make room for a task before fractional numbers
[mu.git] / linux / 304screen.subx
blob0b24fdbfb091b5f06dddf5ee9ad8caccd2f16e3b
1 # Primitives for screen control.
2 # Require Linux and a modern terminal.
4 == code
6 enable-screen-grid-mode:
7     # . prologue
8     55/push-ebp
9     89/<- %ebp 4/r32/esp
10     #
11     (flush Stdout)
12     (flush Stderr)
13     # switch to second screen buffer
14     (write 1 Esc)
15     (write 1 "[?1049h")
16     #
17     (clear-real-screen)
18 $enable-screen-grid-mode:end:
19     # . epilogue
20     89/<- %esp 5/r32/ebp
21     5d/pop-to-ebp
22     c3/return
24 enable-screen-type-mode:
25     # . prologue
26     55/push-ebp
27     89/<- %ebp 4/r32/esp
28     # switch to first screen buffer
29     (write 1 Esc)
30     (write 1 "[?1049l")
31 $enable-screen-type-mode:end:
32     # . epilogue
33     89/<- %esp 5/r32/ebp
34     5d/pop-to-ebp
35     c3/return
37 real-screen-size:  # -> nrows/eax: int, ncols/ecx: int
38     # . prologue
39     55/push-ebp
40     89/<- %ebp 4/r32/esp
41     # . save registers
42     52/push-edx
43     53/push-ebx
44     56/push-esi
45     57/push-edi
46     #
47     (_maybe-open-terminal)
48     # var window-size-info/esi: (addr winsize)
49     # winsize is a type from the Linux kernel. We don't care how large it is.
50     81 5/subop/subtract %esp 0x40/imm32
51     89/<- %esi 4/r32/esp
52     # ioctl(*Terminal-file-descriptor, TIOCGWINSZ, window-size-info)
53     89/<- %edx 6/r32/esi
54     b9/copy-to-ecx 0x5413/imm32/TIOCGWINSZ
55     8b/-> *Terminal-file-descriptor 3/r32/ebx
56     e8/call syscall_ioctl/disp32
57     # some bitworking to extract 2 16-bit shorts
58     8b/-> *esi 0/r32/eax
59     25/and-eax-with 0xffff/imm32
60     8b/-> *esi 1/r32/ecx
61     c1/shift 5/subop/logical-right %ecx 0x10/imm8
62 $real-screen-size:end:
63     # . reclaim locals
64     81 0/subop/add %esp 0x40/imm32
65     # . restore registers
66     5f/pop-to-edi
67     5e/pop-to-esi
68     5b/pop-to-ebx
69     5a/pop-to-edx
70     # . epilogue
71     89/<- %esp 5/r32/ebp
72     5d/pop-to-ebp
73     c3/return
75 clear-real-screen:
76     # . prologue
77     55/push-ebp
78     89/<- %ebp 4/r32/esp
79     #
80     (write 1 Esc)
81     (write 1 "[H")
82     (write 1 Esc)
83     (write 1 "[2J")
84 $clear-real-screen:end:
85     # . epilogue
86     89/<- %esp 5/r32/ebp
87     5d/pop-to-ebp
88     c3/return
90 # row and col count from the top-left as (1, 1)
91 move-cursor-on-real-screen:  # row: int, column: int
92     # . prologue
93     55/push-ebp
94     89/<- %ebp 4/r32/esp
95     # . save registers
96     51/push-ecx
97     # var buf/ecx: (stream byte 32)
98     81 5/subop/subtract %esp 0x20/imm32
99     68/push 0x20/imm32/size
100     68/push 0/imm32/read
101     68/push 0/imm32/write
102     89/<- %ecx 4/r32/esp
103     # construct directive in buf
104     (write %ecx Esc)
105     (write %ecx "[")
106     (write-int32-decimal %ecx *(ebp+8))
107     (write %ecx ";")
108     (write-int32-decimal %ecx *(ebp+0xc))
109     (write %ecx "H")
110     # flush
111     (write-stream 2 %ecx)
112 $move-cursor-on-real-screen:end:
113     # . reclaim locals
114     81 0/subop/add %esp 0x2c/imm32
115     # . restore registers
116     59/pop-to-ecx
117     # . epilogue
118     89/<- %esp 5/r32/ebp
119     5d/pop-to-ebp
120     c3/return
122 print-string-to-real-screen:  # s: (addr array byte)
123     # . prologue
124     55/push-ebp
125     89/<- %ebp 4/r32/esp
126     #
127     (write 1 *(ebp+8))
128 $print-string-to-real-screen:end:
129     # . epilogue
130     89/<- %esp 5/r32/ebp
131     5d/pop-to-ebp
132     c3/return
134 print-slice-to-real-screen:  # s: (addr slice)
135     # . prologue
136     55/push-ebp
137     89/<- %ebp 4/r32/esp
138     #
139     (write-slice-buffered Stdout *(ebp+8))
140     (flush Stdout)
141 $print-slice-to-real-screen:end:
142     # . epilogue
143     89/<- %esp 5/r32/ebp
144     5d/pop-to-ebp
145     c3/return
147 print-stream-to-real-screen:  # s: (addr stream byte)
148     # . prologue
149     55/push-ebp
150     89/<- %ebp 4/r32/esp
151     #
152     (write-stream-data Stdout *(ebp+8))
153     (flush Stdout)
154 $print-stream-to-real-screen:end:
155     # . epilogue
156     89/<- %esp 5/r32/ebp
157     5d/pop-to-ebp
158     c3/return
160 # print a grapheme in utf-8 (only up to 4 bytes so far)
161 print-grapheme-to-real-screen:  # c: grapheme
162     # . prologue
163     55/push-ebp
164     89/<- %ebp 4/r32/esp
165     # . save registers
166     50/push-eax
167     # var curr/eax: byte = 0
168     b8/copy-to-eax 0/imm32
169     # curr = *(ebp+8)
170     8a/byte-> *(ebp+8) 0/r32/al
171     # if (curr == 0) return
172     3d/compare-eax-and 0/imm32
173     74/jump-if-= $print-grapheme-to-real-screen:end/disp8
174     #
175     (print-byte-to-real-screen %eax)
176     # curr = *(ebp+9)
177     8a/byte-> *(ebp+9) 0/r32/al
178     # if (curr == 0) return
179     3d/compare-eax-and 0/imm32
180     74/jump-if-= $print-grapheme-to-real-screen:end/disp8
181     #
182     (print-byte-to-real-screen %eax)
183     # curr = *(ebp+10)
184     8a/byte-> *(ebp+0xa) 0/r32/al
185     # if (curr == 0) return
186     3d/compare-eax-and 0/imm32
187     74/jump-if-= $print-grapheme-to-real-screen:end/disp8
188     #
189     (print-byte-to-real-screen %eax)
190     # curr = *(ebp+11)
191     8a/byte-> *(ebp+0xb) 0/r32/al
192     # if (curr == 0) return
193     3d/compare-eax-and 0/imm32
194     74/jump-if-= $print-grapheme-to-real-screen:end/disp8
195     #
196     (print-byte-to-real-screen %eax)
197 $print-grapheme-to-real-screen:end:
198     # . restore registers
199     58/pop-to-eax
200     # . epilogue
201     89/<- %esp 5/r32/ebp
202     5d/pop-to-ebp
203     c3/return
205 print-byte-to-real-screen:  # c: byte
206     # . prologue
207     55/push-ebp
208     89/<- %ebp 4/r32/esp
209     # . save registers
210     51/push-ecx
211     # var s/ecx: (addr array byte)
212     ff 6/subop/push *(ebp+8)
213     68/push 1/imm32/size
214     89/<- %ecx 4/r32/esp
215     (write 1 %ecx)
216 $print-byte-to-real-screen:end:
217     # . reclaim locals
218     81 0/subop/add %esp 8/imm32
219     # . restore registers
220     59/pop-to-ecx
221     # . epilogue
222     89/<- %esp 5/r32/ebp
223     5d/pop-to-ebp
224     c3/return
226 print-int32-hex-to-real-screen:  # n: int
227     # . prologue
228     55/push-ebp
229     89/<- %ebp 4/r32/esp
230     #
231     (write-int32-hex-buffered Stdout *(ebp+8))
232     (flush Stdout)
233 $print-int32-hex-to-real-screen:end:
234     # . epilogue
235     89/<- %esp 5/r32/ebp
236     5d/pop-to-ebp
237     c3/return
239 print-int32-hex-bits-to-real-screen:  # n: int, bits: int
240     # . prologue
241     55/push-ebp
242     89/<- %ebp 4/r32/esp
243     #
244     (write-int32-hex-bits-buffered Stdout *(ebp+8) *(ebp+0xc) *(ebp+0x10))
245     (flush Stdout)
246 $print-int32-hex-bits-to-real-screen:end:
247     # . epilogue
248     89/<- %esp 5/r32/ebp
249     5d/pop-to-ebp
250     c3/return
252 print-int32-decimal-to-real-screen:  # n: int
253     # . prologue
254     55/push-ebp
255     89/<- %ebp 4/r32/esp
256     #
257     (write-int32-decimal-buffered Stdout *(ebp+8))
258     (flush Stdout)
259 $print-int32-decimal-to-real-screen:end:
260     # . epilogue
261     89/<- %esp 5/r32/ebp
262     5d/pop-to-ebp
263     c3/return
265 write-int32-decimal-buffered:  # f: (addr buffered-file), n: int
266     # . prologue
267     55/push-ebp
268     89/<- %ebp 4/r32/esp
269     # . save registers
270     51/push-ecx
271     # var ecx: (stream byte 16)
272     81 5/subop/subtract %esp 0x10/imm32
273     68/push 0x10/imm32/size
274     68/push 0/imm32/read
275     68/push 0/imm32/write
276     89/<- %ecx 4/r32/esp
277     (write-int32-decimal %ecx *(ebp+0xc))
278     (write-stream-data *(ebp+8) %ecx)
279 $write-int32-decimal-buffered:end:
280     # . reclaim locals
281     81 0/subop/add %esp 0x1c/imm32
282     # . restore registers
283     59/pop-to-ecx
284     # . epilogue
285     89/<- %esp 5/r32/ebp
286     5d/pop-to-ebp
287     c3/return
289 reset-formatting-on-real-screen:
290     # . prologue
291     55/push-ebp
292     89/<- %ebp 4/r32/esp
293     #
294     (write 1 Esc)
295     (write 1 "(B")
296     (write 1 Esc)
297     (write 1 "[m")
298 $reset-formatting-on-real-screen:end:
299     # . epilogue
300     89/<- %esp 5/r32/ebp
301     5d/pop-to-ebp
302     c3/return
304 start-color-on-real-screen:  # fg: int, bg: int
305     # . prologue
306     55/push-ebp
307     89/<- %ebp 4/r32/esp
308     # . save registers
309     51/push-ecx
310     # var buf/ecx: (stream byte 32)
311     81 5/subop/subtract %esp 0x20/imm32
312     68/push 0x20/imm32/size
313     68/push 0/imm32/read
314     68/push 0/imm32/write
315     89/<- %ecx 4/r32/esp
316     # construct directive in buf
317     # . set fg
318     (write %ecx Esc)
319     (write %ecx "[38;5;")
320     (write-int32-decimal %ecx *(ebp+8))
321     (write %ecx "m")
322     # . set bg
323     (write %ecx Esc)
324     (write %ecx "[48;5;")
325     (write-int32-decimal %ecx *(ebp+0xc))
326     (write %ecx "m")
327     # flush
328     (write-stream 2 %ecx)
329 $start-color-on-real-screen:end:
330     # . reclaim locals
331     81 0/subop/add %esp 0x2c/imm32
332     # . restore registers
333     59/pop-to-ecx
334     # . epilogue
335     89/<- %esp 5/r32/ebp
336     5d/pop-to-ebp
337     c3/return
339 start-bold-on-real-screen:
340     # . prologue
341     55/push-ebp
342     89/<- %ebp 4/r32/esp
343     #
344     (write 1 Esc)
345     (write 1 "[1m")
346 $start-bold-on-real-screen:end:
347     # . epilogue
348     89/<- %esp 5/r32/ebp
349     5d/pop-to-ebp
350     c3/return
352 start-underline-on-real-screen:
353     # . prologue
354     55/push-ebp
355     89/<- %ebp 4/r32/esp
356     #
357     (write 1 Esc)
358     (write 1 "[4m")
359 $start-underline-on-real-screen:end:
360     # . epilogue
361     89/<- %esp 5/r32/ebp
362     5d/pop-to-ebp
363     c3/return
365 start-reverse-video-on-real-screen:
366     # . prologue
367     55/push-ebp
368     89/<- %ebp 4/r32/esp
369     #
370     (write 1 Esc)
371     (write 1 "[7m")
372 $start-reverse-video-on-real-screen:end:
373     # . epilogue
374     89/<- %esp 5/r32/ebp
375     5d/pop-to-ebp
376     c3/return
378 # might require enabling blinking in your terminal program
379 start-blinking-on-real-screen:
380     # . prologue
381     55/push-ebp
382     89/<- %ebp 4/r32/esp
383     #
384     (write 1 Esc)
385     (write 1 "[5m")
386 $start-blinking-on-real-screen:end:
387     # . epilogue
388     89/<- %esp 5/r32/ebp
389     5d/pop-to-ebp
390     c3/return
392 hide-cursor-on-real-screen:
393     # . prologue
394     55/push-ebp
395     89/<- %ebp 4/r32/esp
396     #
397     (write 1 Esc)
398     (write 1 "[?25l")
399 $hide-cursor-on-real-screen:end:
400     # . epilogue
401     89/<- %esp 5/r32/ebp
402     5d/pop-to-ebp
403     c3/return
405 show-cursor-on-real-screen:
406     # . prologue
407     55/push-ebp
408     89/<- %ebp 4/r32/esp
409     #
410     (write 1 Esc)
411     (write 1 "[?12l")
412     (write 1 Esc)
413     (write 1 "[?25h")
414 $show-cursor-on-real-screen:end:
415     # . epilogue
416     89/<- %esp 5/r32/ebp
417     5d/pop-to-ebp
418     c3/return
420 # This is a low-level detail; I don't think everything should be a file.
422 # Open "/dev/tty" if necessary and cache its file descriptor in Terminal-file-descriptor
423 # where later primitives can use it.
424 _maybe-open-terminal:
425     81 7/subop/compare *Terminal-file-descriptor -1/imm32
426     75/jump-if-!= $_maybe-open-terminal:epilogue/disp8
427     # . save registers
428     50/push-eax
429     51/push-ecx
430     53/push-ebx
431     # open("/dev/tty", O_RDWR)
432     bb/copy-to-ebx Terminal-filename/imm32
433     b9/copy-to-ecx 2/imm32/O_RDWR
434     e8/call syscall_open/disp32
435     89/<- *Terminal-file-descriptor 0/r32/eax
436 $_maybe-open-terminal:end:
437     # . restore registers
438     5b/pop-to-ebx
439     59/pop-to-ecx
440     58/pop-to-eax
441 $_maybe-open-terminal:epilogue:
442     c3/return
444 == data
446 Terminal-file-descriptor:  # (addr int)
447   -1/imm32
449 Esc:  # (addr array byte)
450   # size
451   1/imm32
452   # data
453   0x1b
455 Terminal-filename:  # (addr kernel-string)
456   # "/dev/tty"
457   2f/slash 64/d 65/e 76/v 2f/slash 74/t 74/t 79/y 0/nul
458   # on Linux console
459 #?   # "/dev/console"
460 #?   2f/slash 64/d 65/e 76/v 2f/slash 63/c 6f/o 6e/n 73/s 6f/o 6c/l 65/e 0/nul