Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
kardolus
GitHub Repository: kardolus/chatgpt-cli
Path: blob/main/vendor/github.com/chzyer/readline/term.go
2875 views
1
// Copyright 2011 The Go Authors. All rights reserved.
2
// Use of this source code is governed by a BSD-style
3
// license that can be found in the LICENSE file.
4
5
// +build aix darwin dragonfly freebsd linux,!appengine netbsd openbsd os400 solaris
6
7
// Package terminal provides support functions for dealing with terminals, as
8
// commonly found on UNIX systems.
9
//
10
// Putting a terminal into raw mode is the most common requirement:
11
//
12
// oldState, err := terminal.MakeRaw(0)
13
// if err != nil {
14
// panic(err)
15
// }
16
// defer terminal.Restore(0, oldState)
17
package readline
18
19
import (
20
"io"
21
"syscall"
22
)
23
24
// State contains the state of a terminal.
25
type State struct {
26
termios Termios
27
}
28
29
// IsTerminal returns true if the given file descriptor is a terminal.
30
func IsTerminal(fd int) bool {
31
_, err := getTermios(fd)
32
return err == nil
33
}
34
35
// MakeRaw put the terminal connected to the given file descriptor into raw
36
// mode and returns the previous state of the terminal so that it can be
37
// restored.
38
func MakeRaw(fd int) (*State, error) {
39
var oldState State
40
41
if termios, err := getTermios(fd); err != nil {
42
return nil, err
43
} else {
44
oldState.termios = *termios
45
}
46
47
newState := oldState.termios
48
// This attempts to replicate the behaviour documented for cfmakeraw in
49
// the termios(3) manpage.
50
newState.Iflag &^= syscall.IGNBRK | syscall.BRKINT | syscall.PARMRK | syscall.ISTRIP | syscall.INLCR | syscall.IGNCR | syscall.ICRNL | syscall.IXON
51
// newState.Oflag &^= syscall.OPOST
52
newState.Lflag &^= syscall.ECHO | syscall.ECHONL | syscall.ICANON | syscall.ISIG | syscall.IEXTEN
53
newState.Cflag &^= syscall.CSIZE | syscall.PARENB
54
newState.Cflag |= syscall.CS8
55
56
newState.Cc[syscall.VMIN] = 1
57
newState.Cc[syscall.VTIME] = 0
58
59
return &oldState, setTermios(fd, &newState)
60
}
61
62
// GetState returns the current state of a terminal which may be useful to
63
// restore the terminal after a signal.
64
func GetState(fd int) (*State, error) {
65
termios, err := getTermios(fd)
66
if err != nil {
67
return nil, err
68
}
69
70
return &State{termios: *termios}, nil
71
}
72
73
// Restore restores the terminal connected to the given file descriptor to a
74
// previous state.
75
func restoreTerm(fd int, state *State) error {
76
return setTermios(fd, &state.termios)
77
}
78
79
// ReadPassword reads a line of input from a terminal without local echo. This
80
// is commonly used for inputting passwords and other sensitive data. The slice
81
// returned does not include the \n.
82
func ReadPassword(fd int) ([]byte, error) {
83
oldState, err := getTermios(fd)
84
if err != nil {
85
return nil, err
86
}
87
88
newState := oldState
89
newState.Lflag &^= syscall.ECHO
90
newState.Lflag |= syscall.ICANON | syscall.ISIG
91
newState.Iflag |= syscall.ICRNL
92
if err := setTermios(fd, newState); err != nil {
93
return nil, err
94
}
95
96
defer func() {
97
setTermios(fd, oldState)
98
}()
99
100
var buf [16]byte
101
var ret []byte
102
for {
103
n, err := syscall.Read(fd, buf[:])
104
if err != nil {
105
return nil, err
106
}
107
if n == 0 {
108
if len(ret) == 0 {
109
return nil, io.EOF
110
}
111
break
112
}
113
if buf[n-1] == '\n' {
114
n--
115
}
116
ret = append(ret, buf[:n]...)
117
if n < len(buf) {
118
break
119
}
120
}
121
122
return ret, nil
123
}
124
125