Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
kardolus
GitHub Repository: kardolus/chatgpt-cli
Path: blob/main/vendor/github.com/chzyer/readline/ansi_windows.go
2875 views
1
// +build windows
2
3
package readline
4
5
import (
6
"bufio"
7
"io"
8
"strconv"
9
"strings"
10
"sync"
11
"unicode/utf8"
12
"unsafe"
13
)
14
15
const (
16
_ = uint16(0)
17
COLOR_FBLUE = 0x0001
18
COLOR_FGREEN = 0x0002
19
COLOR_FRED = 0x0004
20
COLOR_FINTENSITY = 0x0008
21
22
COLOR_BBLUE = 0x0010
23
COLOR_BGREEN = 0x0020
24
COLOR_BRED = 0x0040
25
COLOR_BINTENSITY = 0x0080
26
27
COMMON_LVB_UNDERSCORE = 0x8000
28
COMMON_LVB_BOLD = 0x0007
29
)
30
31
var ColorTableFg = []word{
32
0, // 30: Black
33
COLOR_FRED, // 31: Red
34
COLOR_FGREEN, // 32: Green
35
COLOR_FRED | COLOR_FGREEN, // 33: Yellow
36
COLOR_FBLUE, // 34: Blue
37
COLOR_FRED | COLOR_FBLUE, // 35: Magenta
38
COLOR_FGREEN | COLOR_FBLUE, // 36: Cyan
39
COLOR_FRED | COLOR_FBLUE | COLOR_FGREEN, // 37: White
40
}
41
42
var ColorTableBg = []word{
43
0, // 40: Black
44
COLOR_BRED, // 41: Red
45
COLOR_BGREEN, // 42: Green
46
COLOR_BRED | COLOR_BGREEN, // 43: Yellow
47
COLOR_BBLUE, // 44: Blue
48
COLOR_BRED | COLOR_BBLUE, // 45: Magenta
49
COLOR_BGREEN | COLOR_BBLUE, // 46: Cyan
50
COLOR_BRED | COLOR_BBLUE | COLOR_BGREEN, // 47: White
51
}
52
53
type ANSIWriter struct {
54
target io.Writer
55
wg sync.WaitGroup
56
ctx *ANSIWriterCtx
57
sync.Mutex
58
}
59
60
func NewANSIWriter(w io.Writer) *ANSIWriter {
61
a := &ANSIWriter{
62
target: w,
63
ctx: NewANSIWriterCtx(w),
64
}
65
return a
66
}
67
68
func (a *ANSIWriter) Close() error {
69
a.wg.Wait()
70
return nil
71
}
72
73
type ANSIWriterCtx struct {
74
isEsc bool
75
isEscSeq bool
76
arg []string
77
target *bufio.Writer
78
wantFlush bool
79
}
80
81
func NewANSIWriterCtx(target io.Writer) *ANSIWriterCtx {
82
return &ANSIWriterCtx{
83
target: bufio.NewWriter(target),
84
}
85
}
86
87
func (a *ANSIWriterCtx) Flush() {
88
a.target.Flush()
89
}
90
91
func (a *ANSIWriterCtx) process(r rune) bool {
92
if a.wantFlush {
93
if r == 0 || r == CharEsc {
94
a.wantFlush = false
95
a.target.Flush()
96
}
97
}
98
if a.isEscSeq {
99
a.isEscSeq = a.ioloopEscSeq(a.target, r, &a.arg)
100
return true
101
}
102
103
switch r {
104
case CharEsc:
105
a.isEsc = true
106
case '[':
107
if a.isEsc {
108
a.arg = nil
109
a.isEscSeq = true
110
a.isEsc = false
111
break
112
}
113
fallthrough
114
default:
115
a.target.WriteRune(r)
116
a.wantFlush = true
117
}
118
return true
119
}
120
121
func (a *ANSIWriterCtx) ioloopEscSeq(w *bufio.Writer, r rune, argptr *[]string) bool {
122
arg := *argptr
123
var err error
124
125
if r >= 'A' && r <= 'D' {
126
count := short(GetInt(arg, 1))
127
info, err := GetConsoleScreenBufferInfo()
128
if err != nil {
129
return false
130
}
131
switch r {
132
case 'A': // up
133
info.dwCursorPosition.y -= count
134
case 'B': // down
135
info.dwCursorPosition.y += count
136
case 'C': // right
137
info.dwCursorPosition.x += count
138
case 'D': // left
139
info.dwCursorPosition.x -= count
140
}
141
SetConsoleCursorPosition(&info.dwCursorPosition)
142
return false
143
}
144
145
switch r {
146
case 'J':
147
killLines()
148
case 'K':
149
eraseLine()
150
case 'm':
151
color := word(0)
152
for _, item := range arg {
153
var c int
154
c, err = strconv.Atoi(item)
155
if err != nil {
156
w.WriteString("[" + strings.Join(arg, ";") + "m")
157
break
158
}
159
if c >= 30 && c < 40 {
160
color ^= COLOR_FINTENSITY
161
color |= ColorTableFg[c-30]
162
} else if c >= 40 && c < 50 {
163
color ^= COLOR_BINTENSITY
164
color |= ColorTableBg[c-40]
165
} else if c == 4 {
166
color |= COMMON_LVB_UNDERSCORE | ColorTableFg[7]
167
} else if c == 1 {
168
color |= COMMON_LVB_BOLD | COLOR_FINTENSITY
169
} else { // unknown code treat as reset
170
color = ColorTableFg[7]
171
}
172
}
173
if err != nil {
174
break
175
}
176
kernel.SetConsoleTextAttribute(stdout, uintptr(color))
177
case '\007': // set title
178
case ';':
179
if len(arg) == 0 || arg[len(arg)-1] != "" {
180
arg = append(arg, "")
181
*argptr = arg
182
}
183
return true
184
default:
185
if len(arg) == 0 {
186
arg = append(arg, "")
187
}
188
arg[len(arg)-1] += string(r)
189
*argptr = arg
190
return true
191
}
192
*argptr = nil
193
return false
194
}
195
196
func (a *ANSIWriter) Write(b []byte) (int, error) {
197
a.Lock()
198
defer a.Unlock()
199
200
off := 0
201
for len(b) > off {
202
r, size := utf8.DecodeRune(b[off:])
203
if size == 0 {
204
return off, io.ErrShortWrite
205
}
206
off += size
207
a.ctx.process(r)
208
}
209
a.ctx.Flush()
210
return off, nil
211
}
212
213
func killLines() error {
214
sbi, err := GetConsoleScreenBufferInfo()
215
if err != nil {
216
return err
217
}
218
219
size := (sbi.dwCursorPosition.y - sbi.dwSize.y) * sbi.dwSize.x
220
size += sbi.dwCursorPosition.x
221
222
var written int
223
kernel.FillConsoleOutputAttribute(stdout, uintptr(ColorTableFg[7]),
224
uintptr(size),
225
sbi.dwCursorPosition.ptr(),
226
uintptr(unsafe.Pointer(&written)),
227
)
228
return kernel.FillConsoleOutputCharacterW(stdout, uintptr(' '),
229
uintptr(size),
230
sbi.dwCursorPosition.ptr(),
231
uintptr(unsafe.Pointer(&written)),
232
)
233
}
234
235
func eraseLine() error {
236
sbi, err := GetConsoleScreenBufferInfo()
237
if err != nil {
238
return err
239
}
240
241
size := sbi.dwSize.x
242
sbi.dwCursorPosition.x = 0
243
var written int
244
return kernel.FillConsoleOutputCharacterW(stdout, uintptr(' '),
245
uintptr(size),
246
sbi.dwCursorPosition.ptr(),
247
uintptr(unsafe.Pointer(&written)),
248
)
249
}
250
251