Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
kardolus
GitHub Repository: kardolus/chatgpt-cli
Path: blob/main/vendor/github.com/chzyer/readline/term_windows.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 windows
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
"unsafe"
23
)
24
25
const (
26
enableLineInput = 2
27
enableEchoInput = 4
28
enableProcessedInput = 1
29
enableWindowInput = 8
30
enableMouseInput = 16
31
enableInsertMode = 32
32
enableQuickEditMode = 64
33
enableExtendedFlags = 128
34
enableAutoPosition = 256
35
enableProcessedOutput = 1
36
enableWrapAtEolOutput = 2
37
)
38
39
var kernel32 = syscall.NewLazyDLL("kernel32.dll")
40
41
var (
42
procGetConsoleMode = kernel32.NewProc("GetConsoleMode")
43
procSetConsoleMode = kernel32.NewProc("SetConsoleMode")
44
procGetConsoleScreenBufferInfo = kernel32.NewProc("GetConsoleScreenBufferInfo")
45
)
46
47
type (
48
coord struct {
49
x short
50
y short
51
}
52
smallRect struct {
53
left short
54
top short
55
right short
56
bottom short
57
}
58
consoleScreenBufferInfo struct {
59
size coord
60
cursorPosition coord
61
attributes word
62
window smallRect
63
maximumWindowSize coord
64
}
65
)
66
67
type State struct {
68
mode uint32
69
}
70
71
// IsTerminal returns true if the given file descriptor is a terminal.
72
func IsTerminal(fd int) bool {
73
var st uint32
74
r, _, e := syscall.Syscall(procGetConsoleMode.Addr(), 2, uintptr(fd), uintptr(unsafe.Pointer(&st)), 0)
75
return r != 0 && e == 0
76
}
77
78
// MakeRaw put the terminal connected to the given file descriptor into raw
79
// mode and returns the previous state of the terminal so that it can be
80
// restored.
81
func MakeRaw(fd int) (*State, error) {
82
var st uint32
83
_, _, e := syscall.Syscall(procGetConsoleMode.Addr(), 2, uintptr(fd), uintptr(unsafe.Pointer(&st)), 0)
84
if e != 0 {
85
return nil, error(e)
86
}
87
raw := st &^ (enableEchoInput | enableProcessedInput | enableLineInput | enableProcessedOutput)
88
_, _, e = syscall.Syscall(procSetConsoleMode.Addr(), 2, uintptr(fd), uintptr(raw), 0)
89
if e != 0 {
90
return nil, error(e)
91
}
92
return &State{st}, nil
93
}
94
95
// GetState returns the current state of a terminal which may be useful to
96
// restore the terminal after a signal.
97
func GetState(fd int) (*State, error) {
98
var st uint32
99
_, _, e := syscall.Syscall(procGetConsoleMode.Addr(), 2, uintptr(fd), uintptr(unsafe.Pointer(&st)), 0)
100
if e != 0 {
101
return nil, error(e)
102
}
103
return &State{st}, nil
104
}
105
106
// Restore restores the terminal connected to the given file descriptor to a
107
// previous state.
108
func restoreTerm(fd int, state *State) error {
109
_, _, err := syscall.Syscall(procSetConsoleMode.Addr(), 2, uintptr(fd), uintptr(state.mode), 0)
110
return err
111
}
112
113
// GetSize returns the dimensions of the given terminal.
114
func GetSize(fd int) (width, height int, err error) {
115
var info consoleScreenBufferInfo
116
_, _, e := syscall.Syscall(procGetConsoleScreenBufferInfo.Addr(), 2, uintptr(fd), uintptr(unsafe.Pointer(&info)), 0)
117
if e != 0 {
118
return 0, 0, error(e)
119
}
120
return int(info.size.x), int(info.size.y), nil
121
}
122
123
// ReadPassword reads a line of input from a terminal without local echo. This
124
// is commonly used for inputting passwords and other sensitive data. The slice
125
// returned does not include the \n.
126
func ReadPassword(fd int) ([]byte, error) {
127
var st uint32
128
_, _, e := syscall.Syscall(procGetConsoleMode.Addr(), 2, uintptr(fd), uintptr(unsafe.Pointer(&st)), 0)
129
if e != 0 {
130
return nil, error(e)
131
}
132
old := st
133
134
st &^= (enableEchoInput)
135
st |= (enableProcessedInput | enableLineInput | enableProcessedOutput)
136
_, _, e = syscall.Syscall(procSetConsoleMode.Addr(), 2, uintptr(fd), uintptr(st), 0)
137
if e != 0 {
138
return nil, error(e)
139
}
140
141
defer func() {
142
syscall.Syscall(procSetConsoleMode.Addr(), 2, uintptr(fd), uintptr(old), 0)
143
}()
144
145
var buf [16]byte
146
var ret []byte
147
for {
148
n, err := syscall.Read(syscall.Handle(fd), buf[:])
149
if err != nil {
150
return nil, err
151
}
152
if n == 0 {
153
if len(ret) == 0 {
154
return nil, io.EOF
155
}
156
break
157
}
158
if buf[n-1] == '\n' {
159
n--
160
}
161
if n > 0 && buf[n-1] == '\r' {
162
n--
163
}
164
ret = append(ret, buf[:n]...)
165
if n < len(buf) {
166
break
167
}
168
}
169
170
return ret, nil
171
}
172
173