forked from charmbracelet/ultraviolet
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathconsole.go
More file actions
219 lines (183 loc) Β· 5.54 KB
/
Copy pathconsole.go
File metadata and controls
219 lines (183 loc) Β· 5.54 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
package uv
import (
"io"
"os"
"runtime"
"github.com/charmbracelet/x/term"
)
var isWindows = runtime.GOOS == "windows"
// File is an interface that represents a file with a file descriptor.
//
// This is typically an [os.File] like [os.Stdin] and [os.Stdout].
type File interface {
io.ReadWriteCloser
term.File
// Name returns the name of the file.
Name() string
}
// Winsize represents the size of a terminal in cells and pixels.
//
// This is the same as [unix.Winsize], but defined here for cross-platform compatibility.
type Winsize struct {
Row uint16
Col uint16
Xpixel uint16
Ypixel uint16
}
// Console represents a cross-platform console I/O interface.
type Console interface {
io.ReadWriteCloser
// Environ returns the console's environment variables.
Environ() []string
// Getenv retrieves the value of the environment variable named by the key.
Getenv(key string) string
// LookupEnv retrieves the value of the environment variable named by the key
// and a boolean indicating whether the variable is present.
LookupEnv(key string) (string, bool)
// Reader returns the input reader of the console.
Reader() io.Reader
// Writer returns the output writer of the console.
Writer() io.Writer
// MakeRaw puts the console input side into raw mode.
MakeRaw() (state *term.State, err error)
// Restore restores the console to its previous state.
Restore() error
// GetSize returns the current size of the console.
GetSize() (width, height int, err error)
// GetWinsize returns the current size of the console in cells and pixels.
GetWinsize() (*Winsize, error)
}
// TTY represents a Unix TTY device. It implements the [Console] interface.
type TTY struct {
*console
}
var _ Console = (*TTY)(nil)
// WinCon represents a Windows Console. It implements the [Console] interface.
type WinCon struct {
*console
}
var _ Console = (*WinCon)(nil)
// Console is a cross-platform console I/O.
type console struct {
input File
inputState *term.State
output File
outputState *term.State
environ Environ
}
// DefaultConsole returns a new default console instance that uses standard I/O
// [os.Stdin], [os.Stdout], and [os.Environ].
//
// To use [os.Stderr] as the output, you can create a new console with
// [NewConsole] and pass [os.Stderr] as the output parameter.
func DefaultConsole() Console {
return NewConsole(os.Stdin, os.Stdout, os.Environ())
}
// ControllingConsole returns a new console instance that uses the current
// controlling terminal's input and output file descriptors.
func ControllingConsole() (Console, error) {
inTty, outTty, err := OpenTTY()
if err != nil {
return nil, err
}
return NewConsole(inTty, outTty, os.Environ()), nil
}
// NewConsole creates a new [Console] with the given input, output, and
// environment variables.
//
// You can use [OpenTTY] to open the current controlling console files and pass
// them to this function. Use [ControllingConsole] for a convenience function
// that does this for you.
//
// Use this to create a new terminal for PTY processes by passing the PTY slave
// file as the input and output and any environment variables the process
// needs.
func NewConsole(input, output File, environ []string) Console {
if input == nil {
input = os.Stdin
}
if output == nil {
output = os.Stdout
}
if environ == nil {
environ = os.Environ()
}
return newConsole(input, output, environ)
}
// Environ returns the console's environment variables.
func (t *console) Environ() []string {
return t.environ
}
// Writer returns the output writer of the console.
func (t *console) Writer() io.Writer {
return t.output
}
// Reader returns the input reader of the console.
func (t *console) Reader() io.Reader {
return t.input
}
// Write writes data to the console's output.
func (t *console) Write(p []byte) (n int, err error) {
return t.output.Write(p)
}
// Read reads data from the console's input.
func (t *console) Read(p []byte) (n int, err error) {
return t.input.Read(p)
}
// Getenv retrieves the value of the environment variable named by the key.
func (t *console) Getenv(key string) string {
return t.environ.Getenv(key)
}
// LookupEnv retrieves the value of the environment variable named by the key
// and a boolean indicating whether the variable is present.
func (t *console) LookupEnv(key string) (string, bool) {
return t.environ.LookupEnv(key)
}
// MakeRaw puts the console input side into raw mode.
func (t *console) MakeRaw() (state *term.State, err error) {
inState, outState, err := makeRaw(t.input, t.output)
if err != nil {
return nil, err
}
t.inputState = inState
t.outputState = outState
if inState != nil {
return inState, nil
}
return outState, nil
}
// Restore restores the console to its previous state.
func (t *console) Restore() error {
if t.inputState != nil {
if err := term.Restore(t.input.Fd(), t.inputState); err != nil {
return err
}
t.inputState = nil
}
if t.outputState != nil {
if err := term.Restore(t.output.Fd(), t.outputState); err != nil {
return err
}
t.outputState = nil
}
return nil
}
// Close restores the console to its previous state and releases resources.
func (t *console) Close() error {
if err := t.Restore(); err != nil {
return err
}
return nil
}
// GetSize returns the current size of the console.
func (t *console) GetSize() (width, height int, err error) {
return getSize(t.input, t.output)
}
// GetWinsize returns the current size of the console in cells and pixels.
func (t *console) GetWinsize() (*Winsize, error) {
ws, err := getWinsize(t.input, t.output)
if err != nil {
return nil, err
}
return &ws, nil
}