92 lines
1.9 KiB
Go
92 lines
1.9 KiB
Go
// +build !windows
|
|
|
|
package prompt
|
|
|
|
import (
|
|
"syscall"
|
|
"unsafe"
|
|
|
|
"github.com/c-bata/go-prompt/internal/term"
|
|
)
|
|
|
|
const maxReadBytes = 1024
|
|
|
|
// PosixParser is a ConsoleParser implementation for POSIX environment.
|
|
type PosixParser struct {
|
|
fd int
|
|
origTermios syscall.Termios
|
|
}
|
|
|
|
// Setup should be called before starting input
|
|
func (t *PosixParser) Setup() error {
|
|
// Set NonBlocking mode because if syscall.Read block this goroutine, it cannot receive data from stopCh.
|
|
if err := syscall.SetNonblock(t.fd, true); err != nil {
|
|
return err
|
|
}
|
|
if err := term.SetRaw(t.fd); err != nil {
|
|
return err
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// TearDown should be called after stopping input
|
|
func (t *PosixParser) TearDown() error {
|
|
if err := syscall.SetNonblock(t.fd, false); err != nil {
|
|
return err
|
|
}
|
|
if err := term.Restore(); err != nil {
|
|
return err
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// Read returns byte array.
|
|
func (t *PosixParser) Read() ([]byte, error) {
|
|
buf := make([]byte, maxReadBytes)
|
|
n, err := syscall.Read(t.fd, buf)
|
|
if err != nil {
|
|
return []byte{}, err
|
|
}
|
|
return buf[:n], nil
|
|
}
|
|
|
|
// winsize is winsize struct got from the ioctl(2) system call.
|
|
type ioctlWinsize struct {
|
|
Row uint16
|
|
Col uint16
|
|
X uint16 // pixel value
|
|
Y uint16 // pixel value
|
|
}
|
|
|
|
// GetWinSize returns WinSize object to represent width and height of terminal.
|
|
func (t *PosixParser) GetWinSize() *WinSize {
|
|
ws := &ioctlWinsize{}
|
|
retCode, _, errno := syscall.Syscall(
|
|
syscall.SYS_IOCTL,
|
|
uintptr(t.fd),
|
|
uintptr(syscall.TIOCGWINSZ),
|
|
uintptr(unsafe.Pointer(ws)))
|
|
|
|
if int(retCode) == -1 {
|
|
panic(errno)
|
|
}
|
|
return &WinSize{
|
|
Row: ws.Row,
|
|
Col: ws.Col,
|
|
}
|
|
}
|
|
|
|
var _ ConsoleParser = &PosixParser{}
|
|
|
|
// NewStandardInputParser returns ConsoleParser object to read from stdin.
|
|
func NewStandardInputParser() *PosixParser {
|
|
in, err := syscall.Open("/dev/tty", syscall.O_RDONLY, 0)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
return &PosixParser{
|
|
fd: in,
|
|
}
|
|
}
|