//+build linux
package console
import "core:fmt"
import "core:os"
import "core:io"
import "core:intrinsics"
import "core:sys/unix"
Console :: struct {
input_stream: io.Reader,
prev_input_state: termios,
width: int,
height: int,
destroy: proc(con: ^Console),
clear: proc(con: ^Console),
write: proc(con: ^Console, msg: string),
write_at: proc(con: ^Console, msg: string, x, y: int),
putch: proc(con: ^Console, c: rune, x, y: int),
putch_s: proc(con: ^Console, c: rune, x, y: int) -> string,
wait_for_input: proc(con: ^Console) -> Keys,
read_input: proc(con: ^Console) -> Keys,
get_size: proc(con: ^Console) -> (int, int),
}
@(private)
TCGETS :: 0x5401
@(private)
TCSETS :: 0x5402
@(private)
TIOCWINSZ :: 0x5413
ECHOKE :: (1 << 0)
ECHOE :: (1 << 1)
ECHOK :: (1 << 2)
ECHO :: (1 << 3)
ECHONL :: (1 << 4)
ECHOPRT :: (1 << 5)
ECHOCTL :: (1 << 6)
ISIG :: (1 << 7)
ICANON :: (1 << 8)
ALTWERASE :: (1 << 9)
IEXTEN :: (1 << 10)
EXTPROC :: (1 << 11)
TOSTOP :: (1 << 22)
FLUSHO :: (1 << 23)
XCASE :: (1 << 24)
NOKERNINFO :: (1 << 25)
PENDIN :: (1 << 29)
NOFLSH :: (1 << 31)
@(private)
winsize :: struct {
ws_row: u16,
ws_col: u16,
ws_xpixel: u16,
ws_ypixel: u16,
}
@(private)
termios :: struct {
c_iflag: u32,
c_oflag: u32,
c_cflag: u32,
c_lflag: u32,
c_cc: [20]byte,
c_ispeed: i32,
c_ospeed: i32,
}
create :: proc() -> Console {
con := Console {
input_stream = io.Reader(io.Reader_From{os.stream_from_handle(os.stdin)}),
destroy = con_destroy,
clear = con_clear,
write = con_write,
write_at = con_write_at,
putch = con_putch,
putch_s = con_putch_s,
wait_for_input = con_wait_for_input,
get_size = con_get_size,
}
con->write(CURSOR_HIDE)
term: termios
intrinsics.syscall(unix.SYS_ioctl, uintptr(os.stdin), TCGETS, uintptr(&term))
con.prev_input_state = term
term.c_lflag = ISIG | EXTPROC
intrinsics.syscall(unix.SYS_ioctl, uintptr(os.stdin), TCSETS, uintptr(&term))
con.width, con.height = con->get_size()
return con
}
@(private)
con_destroy :: proc(con: ^Console) {
intrinsics.syscall(unix.SYS_ioctl, uintptr(os.stdin), TCSETS, uintptr(&con.prev_input_state))
con->write(CURSOR_SHOW)
}
@(private)
con_clear :: proc(con: ^Console) {
con->write(CLEAR)
}
@(private)
con_write :: proc(con: ^Console, msg: string) {
fmt.print(msg)
}
@(private)
con_write_at :: proc(con: ^Console, msg: string, x, y: int) {
con->write(fmt.tprintf(CURSOR_POSITION + "%s", y, x, msg))
}
@(private)
con_putch :: proc(con: ^Console, c: rune, x, y: int) {
con->write(fmt.tprintf(CURSOR_POSITION + "%c", y, x, c))
}
@(private)
con_putch_s :: proc(con: ^Console, c: rune, x, y: int) -> string {
return fmt.tprintf(CURSOR_POSITION + "%c", y, x, c)
}
@(private)
con_wait_for_input :: proc(con: ^Console) -> Keys {
buffer: [256]u8
to_read := 10
io.read(con.input_stream, buffer[:], &to_read)
if (buffer[0] == 27 && buffer[1] == 0) || buffer[0] == 3 || buffer[0] == 113 { // 27 = Escape, 3 = CTRL+C, 113 = q
return .quit
} else if buffer[0] == 32 { // 32 = Space
return .forward
} else {
input := [?]u8{buffer[0], buffer[1], buffer[2]}
if (input == [?]u8{27, 91, 68}) {
return .back
} else if (input == [?]u8{27, 91, 67}) {
return .forward
}
}
return .unk
}
@(private)
con_get_size :: proc(con: ^Console) -> (width: int, height: int) {
size: winsize
intrinsics.syscall(unix.SYS_ioctl, uintptr(os.stdin), TIOCWINSZ, uintptr(&size))
width = int(size.ws_col)
height = int(size.ws_row)
return
}