mu/304screen.subx

337 lines
7.2 KiB
Plaintext

# Primitives for screen control.
# Require Linux and a modern terminal.
== code
enable-screen-grid-mode:
# . prologue
55/push-ebp
89/<- %ebp 4/r32/esp
#
(flush Stdout)
(flush Stderr)
# switch to second screen buffer
(write 2 Esc)
(write 2 "[?1049h")
#
(clear-screen)
$enable-screen-grid-mode:end:
# . epilogue
89/<- %esp 5/r32/ebp
5d/pop-to-ebp
c3/return
enable-screen-type-mode:
# . prologue
55/push-ebp
89/<- %ebp 4/r32/esp
# switch to first screen buffer
(write 2 Esc)
(write 2 "[?1049l")
$enable-screen-type-mode:end:
# . epilogue
89/<- %esp 5/r32/ebp
5d/pop-to-ebp
c3/return
screen-size: # -> nrows/eax: int, ncols/ecx: int
# . prologue
55/push-ebp
89/<- %ebp 4/r32/esp
# . save registers
52/push-edx
53/push-ebx
56/push-esi
57/push-edi
#
(_maybe-open-terminal)
# var window-size-info/esi: (addr winsize)
# winsize is a type from the Linux kernel. We don't care how large it is.
81 5/subop/subtract %esp 0x40/imm32
89/<- %esi 4/r32/esp
# ioctl(*Terminal-file-descriptor, TIOCGWINSZ, window-size-info)
89/<- %edx 6/r32/esi
b9/copy-to-ecx 0x5413/imm32/TIOCGWINSZ
8b/-> *Terminal-file-descriptor 3/r32/ebx
e8/call syscall_ioctl/disp32
# some bitworking to extract 2 16-bit shorts
8b/-> *esi 0/r32/eax
81 4/subop/and %eax 0xffff/imm32
8b/-> *esi 1/r32/ecx
c1/shift 5/subop/logical-right %ecx 0x10/imm8
$screen-size:end:
# . reclaim locals
81 0/subop/add %esp 0x40/imm32
# . restore registers
5f/pop-to-edi
5e/pop-to-esi
5b/pop-to-ebx
5a/pop-to-edx
# . epilogue
89/<- %esp 5/r32/ebp
5d/pop-to-ebp
c3/return
clear-screen:
# . prologue
55/push-ebp
89/<- %ebp 4/r32/esp
#
(write 2 Esc)
(write 2 "[H")
(write 2 Esc)
(write 2 "[2J")
$clear-screen:end:
# . epilogue
89/<- %esp 5/r32/ebp
5d/pop-to-ebp
c3/return
# row and col count from the top-left as (1, 1)
move-cursor-on-screen: # row: int, column: int
# . prologue
55/push-ebp
89/<- %ebp 4/r32/esp
# . save registers
51/push-ecx
# var buf/ecx: (stream byte 32)
81 5/subop/subtract %esp 0x20/imm32
68/push 0x20/imm32/size
68/push 0/imm32/read
68/push 0/imm32/write
89/<- %ecx 4/r32/esp
# construct directive in buf
(write %ecx Esc)
(write %ecx "[")
(write-int32-decimal %ecx *(ebp+8))
(write %ecx ";")
(write-int32-decimal %ecx *(ebp+0xc))
(write %ecx "H")
# flush
(write-stream 2 %ecx)
$move-cursor-on-screen:end:
# . reclaim locals
81 0/subop/add %esp 0x2c/imm32
# . restore registers
59/pop-to-ecx
# . epilogue
89/<- %esp 5/r32/ebp
5d/pop-to-ebp
c3/return
print-string-to-screen: # s: (addr array byte)
# . prologue
55/push-ebp
89/<- %ebp 4/r32/esp
#
(write 2 *(ebp+8))
$print-string-to-screen:end:
# . epilogue
89/<- %esp 5/r32/ebp
5d/pop-to-ebp
c3/return
print-byte-to-screen: # c: byte
# . prologue
55/push-ebp
89/<- %ebp 4/r32/esp
# . save registers
51/push-ecx
# var s/ecx: (addr array byte)
ff 6/subop/push *(ebp+8)
68/push 4/imm32/size
89/<- %ecx 4/r32/esp
(write 2 %ecx)
$print-byte-to-screen:end:
# . reclaim locals
81 0/subop/add %esp 8/imm32
# . restore registers
59/pop-to-ecx
# . epilogue
89/<- %esp 5/r32/ebp
5d/pop-to-ebp
c3/return
print-int32-hex-to-screen: # n: int
# . prologue
55/push-ebp
89/<- %ebp 4/r32/esp
#
(write-int32-hex-buffered Stdout *(ebp+8))
(flush Stdout)
$print-int32-hex-to-screen:end:
# . epilogue
89/<- %esp 5/r32/ebp
5d/pop-to-ebp
c3/return
reset-formatting-on-screen:
# . prologue
55/push-ebp
89/<- %ebp 4/r32/esp
#
(write 2 Esc)
(write 2 "(B")
(write 2 Esc)
(write 2 "[m")
$reset-formatting-on-screen:end:
# . epilogue
89/<- %esp 5/r32/ebp
5d/pop-to-ebp
c3/return
start-color-on-screen: # fg: int, bg: int
# . prologue
55/push-ebp
89/<- %ebp 4/r32/esp
# . save registers
51/push-ecx
# var buf/ecx: (stream byte 32)
81 5/subop/subtract %esp 0x20/imm32
68/push 0x20/imm32/size
68/push 0/imm32/read
68/push 0/imm32/write
89/<- %ecx 4/r32/esp
# construct directive in buf
# . set fg
(write %ecx Esc)
(write %ecx "[38;5;")
(write-int32-decimal %ecx *(ebp+8))
(write %ecx "m")
# . set bg
(write %ecx Esc)
(write %ecx "[48;5;")
(write-int32-decimal %ecx *(ebp+0xc))
(write %ecx "m")
# flush
(write-stream 2 %ecx)
$start-color-on-screen:end:
# . reclaim locals
81 0/subop/add %esp 0x2c/imm32
# . restore registers
59/pop-to-ecx
# . epilogue
89/<- %esp 5/r32/ebp
5d/pop-to-ebp
c3/return
start-bold-on-screen:
# . prologue
55/push-ebp
89/<- %ebp 4/r32/esp
#
(write 2 Esc)
(write 2 "[1m")
$start-bold-on-screen:end:
# . epilogue
89/<- %esp 5/r32/ebp
5d/pop-to-ebp
c3/return
start-underline-on-screen:
# . prologue
55/push-ebp
89/<- %ebp 4/r32/esp
#
(write 2 Esc)
(write 2 "[4m")
$start-underline-on-screen:end:
# . epilogue
89/<- %esp 5/r32/ebp
5d/pop-to-ebp
c3/return
start-reverse-video-on-screen:
# . prologue
55/push-ebp
89/<- %ebp 4/r32/esp
#
(write 2 Esc)
(write 2 "[7m")
$start-reverse-video-on-screen:end:
# . epilogue
89/<- %esp 5/r32/ebp
5d/pop-to-ebp
c3/return
# might require enabling blinking in your terminal program
start-blinking-on-screen:
# . prologue
55/push-ebp
89/<- %ebp 4/r32/esp
#
(write 2 Esc)
(write 2 "[5m")
$start-blinking-on-screen:end:
# . epilogue
89/<- %esp 5/r32/ebp
5d/pop-to-ebp
c3/return
hide-cursor-on-screen:
# . prologue
55/push-ebp
89/<- %ebp 4/r32/esp
#
(write 2 Esc)
(write 2 "[?25l")
$hide-cursor-on-screen:end:
# . epilogue
89/<- %esp 5/r32/ebp
5d/pop-to-ebp
c3/return
show-cursor-on-screen:
# . prologue
55/push-ebp
89/<- %ebp 4/r32/esp
#
(write 2 Esc)
(write 2 "[?12l")
(write 2 Esc)
(write 2 "[?25h")
$show-cursor-on-screen:end:
# . epilogue
89/<- %esp 5/r32/ebp
5d/pop-to-ebp
c3/return
# This is a low-level detail; I don't think everything should be a file.
#
# Open "/dev/tty" if necessary and cache its file descriptor in Terminal-file-descriptor
# where later primitives can use it.
_maybe-open-terminal:
81 7/subop/compare *Terminal-file-descriptor -1/imm32
75/jump-if-!= $_maybe-open-terminal:epilogue/disp8
# . save registers
50/push-eax
51/push-ecx
53/push-ebx
# open("/dev/tty", O_RDWR)
bb/copy-to-ebx Terminal-filename/imm32
b9/copy-to-ecx 2/imm32/O_RDWR
e8/call syscall_open/disp32
89/<- *Terminal-file-descriptor 0/r32/eax
$_maybe-open-terminal:end:
# . restore registers
5b/pop-to-ebx
59/pop-to-ecx
58/pop-to-eax
$_maybe-open-terminal:epilogue:
c3/return
== data
Terminal-file-descriptor: # (addr int)
-1/imm32
Esc: # (addr array byte)
# size
1/imm32
# data
0x1b
Terminal-filename: # (addr kernel-string)
# "/dev/null"
2f/slash 64/d 65/e 76/v 2f/slash 74/t 74/t 79/y 0/nul