1// +build !windows
2
3package prompt
4
5import (
6	"syscall"
7
8	"github.com/c-bata/go-prompt/internal/term"
9	"golang.org/x/sys/unix"
10)
11
12const maxReadBytes = 1024
13
14// PosixParser is a ConsoleParser implementation for POSIX environment.
15type PosixParser struct {
16	fd          int
17	origTermios syscall.Termios
18}
19
20// Setup should be called before starting input
21func (t *PosixParser) Setup() error {
22	// Set NonBlocking mode because if syscall.Read block this goroutine, it cannot receive data from stopCh.
23	if err := syscall.SetNonblock(t.fd, true); err != nil {
24		return err
25	}
26	if err := term.SetRaw(t.fd); err != nil {
27		return err
28	}
29	return nil
30}
31
32// TearDown should be called after stopping input
33func (t *PosixParser) TearDown() error {
34	if err := syscall.SetNonblock(t.fd, false); err != nil {
35		return err
36	}
37	if err := term.Restore(); err != nil {
38		return err
39	}
40	return nil
41}
42
43// Read returns byte array.
44func (t *PosixParser) Read() ([]byte, error) {
45	buf := make([]byte, maxReadBytes)
46	n, err := syscall.Read(t.fd, buf)
47	if err != nil {
48		return []byte{}, err
49	}
50	return buf[:n], nil
51}
52
53// GetWinSize returns WinSize object to represent width and height of terminal.
54func (t *PosixParser) GetWinSize() *WinSize {
55	ws, err := unix.IoctlGetWinsize(t.fd, unix.TIOCGWINSZ)
56	if err != nil {
57		panic(err)
58	}
59	return &WinSize{
60		Row: ws.Row,
61		Col: ws.Col,
62	}
63}
64
65var _ ConsoleParser = &PosixParser{}
66
67// NewStandardInputParser returns ConsoleParser object to read from stdin.
68func NewStandardInputParser() *PosixParser {
69	in, err := syscall.Open("/dev/tty", syscall.O_RDONLY, 0)
70	if err != nil {
71		panic(err)
72	}
73
74	return &PosixParser{
75		fd: in,
76	}
77}
78