99 lines
2.0 KiB
Go
99 lines
2.0 KiB
Go
package terminal
|
|||
|
|
|
||
|
|
import (
|
||
|
|
"fmt"
|
||
|
|
"syscall"
|
||
|
|
"unsafe"
|
||
|
|
)
|
||
|
|
|
||
|
|
const (
|
||
|
|
ClearScreen = "\u001Bc"
|
||
|
|
CursorHide = "\u001B[?25l"
|
||
|
|
CursorShow = "\u001B[?25h"
|
||
|
|
CursorTopLeft = "\u001B[H"
|
||
|
|
EraseLine = "\u001B[K"
|
||
|
|
|
||
|
|
SetCursorFmt = "\u001B[%d;%dH"
|
||
|
|
)
|
||
|
|
|
||
|
|
type Terminal struct {
|
||
|
|
fd uintptr
|
||
|
|
termios *syscall.Termios
|
||
|
|
}
|
||
|
|
|
||
|
|
type Size struct {
|
||
|
|
Rows uint16
|
||
|
|
Columns uint16
|
||
|
|
XPixels uint16
|
||
|
|
YPixels uint16
|
||
|
|
}
|
||
|
|
|
||
|
|
func New(fd uintptr) (*Terminal, error) {
|
||
|
|
var t = &Terminal{
|
||
|
|
fd: fd,
|
||
|
|
termios: &syscall.Termios{},
|
||
|
|
}
|
||
|
|
|
||
|
|
if _, _, err := syscall.Syscall(
|
||
|
|
syscall.SYS_IOCTL,
|
||
|
|
fd,
|
||
|
|
syscall.TCGETS,
|
||
|
|
uintptr(unsafe.Pointer(t.termios)),
|
||
|
|
); err != 0 {
|
||
|
|
return nil, fmt.Errorf("ioctl syscall: %w", err)
|
||
|
|
}
|
||
|
|
|
||
|
|
return t, nil
|
||
|
|
}
|
||
|
|
|
||
|
|
// Reset the terminal into the original termios.
|
||
|
|
func (t *Terminal) Reset() error {
|
||
|
|
if _, _, err := syscall.Syscall(
|
||
|
|
syscall.SYS_IOCTL,
|
||
|
|
t.fd,
|
||
|
|
uintptr(syscall.TCSETS),
|
||
|
|
uintptr(unsafe.Pointer(t.termios)),
|
||
|
|
); err != 0 {
|
||
|
|
return fmt.Errorf("ioctl syscall: %w", err)
|
||
|
|
}
|
||
|
|
|
||
|
|
return nil
|
||
|
|
}
|
||
|
|
|
||
|
|
// SetRaw enables raw mode.
|
||
|
|
func (t *Terminal) SetRaw() error {
|
||
|
|
var termios = *t.termios
|
||
|
|
termios.Iflag &^= syscall.IGNBRK | syscall.BRKINT | syscall.PARMRK | syscall.ISTRIP | syscall.INLCR | syscall.IGNCR | syscall.ICRNL | syscall.IXON
|
||
|
|
termios.Oflag &^= syscall.OPOST
|
||
|
|
termios.Lflag &^= syscall.ECHO | syscall.ECHONL | syscall.ICANON | syscall.ISIG | syscall.IEXTEN
|
||
|
|
termios.Cflag &^= syscall.CSIZE | syscall.PARENB
|
||
|
|
termios.Cflag |= syscall.CS8
|
||
|
|
termios.Cc[syscall.VMIN] = 1
|
||
|
|
termios.Cc[syscall.VTIME] = 0
|
||
|
|
|
||
|
|
if _, _, err := syscall.Syscall(
|
||
|
|
syscall.SYS_IOCTL,
|
||
|
|
t.fd,
|
||
|
|
uintptr(syscall.TCSETS),
|
||
|
|
uintptr(unsafe.Pointer(&termios)),
|
||
|
|
); err != 0 {
|
||
|
|
return fmt.Errorf("ioctl syscall: %w", err)
|
||
|
|
}
|
||
|
|
|
||
|
|
return nil
|
||
|
|
}
|
||
|
|
|
||
|
|
func (t *Terminal) Size() (*Size, error) {
|
||
|
|
var size = &Size{}
|
||
|
|
if _, _, err := syscall.Syscall(
|
||
|
|
syscall.SYS_IOCTL,
|
||
|
|
t.fd,
|
||
|
|
syscall.TIOCGWINSZ,
|
||
|
|
uintptr(unsafe.Pointer(size)),
|
||
|
|
); err != 0 {
|
||
|
|
return nil, fmt.Errorf("ioctl syscall: %w", err)
|
||
|
|
}
|
||
|
|
|
||
|
|
return size, nil
|
||
|
|
}
|