doing 2.0.19 → 2.0.23
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +15 -0
- data/Gemfile.lock +15 -5
- data/README.md +1 -1
- data/bin/doing +2 -18
- data/doing.gemspec +5 -4
- data/doing.rdoc +2 -2
- data/generate_completions.sh +3 -3
- data/lib/doing/cli_status.rb +6 -2
- data/lib/doing/completion/bash_completion.rb +185 -0
- data/lib/doing/completion/fish_completion.rb +175 -0
- data/lib/doing/completion/string.rb +17 -0
- data/lib/doing/completion/zsh_completion.rb +140 -0
- data/lib/doing/completion.rb +39 -0
- data/lib/doing/version.rb +1 -1
- data/lib/doing/wwid.rb +19 -5
- data/lib/doing.rb +1 -1
- data/lib/helpers/fzf/.goreleaser.yml +119 -0
- data/lib/helpers/fzf/.rubocop.yml +28 -0
- data/lib/helpers/fzf/ADVANCED.md +565 -0
- data/lib/helpers/fzf/BUILD.md +49 -0
- data/lib/helpers/fzf/CHANGELOG.md +1193 -0
- data/lib/helpers/fzf/Dockerfile +11 -0
- data/lib/helpers/fzf/LICENSE +21 -0
- data/lib/helpers/fzf/Makefile +166 -0
- data/lib/helpers/fzf/README-VIM.md +486 -0
- data/lib/helpers/fzf/README.md +712 -0
- data/lib/helpers/fzf/bin/fzf-tmux +233 -0
- data/lib/helpers/fzf/doc/fzf.txt +512 -0
- data/lib/helpers/fzf/go.mod +17 -0
- data/lib/helpers/fzf/go.sum +31 -0
- data/lib/helpers/fzf/install +382 -0
- data/lib/helpers/fzf/install.ps1 +65 -0
- data/lib/helpers/fzf/main.go +14 -0
- data/lib/helpers/fzf/man/man1/fzf-tmux.1 +68 -0
- data/lib/helpers/fzf/man/man1/fzf.1 +1001 -0
- data/lib/helpers/fzf/plugin/fzf.vim +1048 -0
- data/lib/helpers/fzf/shell/completion.bash +381 -0
- data/lib/helpers/fzf/shell/completion.zsh +329 -0
- data/lib/helpers/fzf/shell/key-bindings.bash +96 -0
- data/lib/helpers/fzf/shell/key-bindings.fish +172 -0
- data/lib/helpers/fzf/shell/key-bindings.zsh +114 -0
- data/lib/helpers/fzf/src/LICENSE +21 -0
- data/lib/helpers/fzf/src/algo/algo.go +884 -0
- data/lib/helpers/fzf/src/algo/algo_test.go +197 -0
- data/lib/helpers/fzf/src/algo/normalize.go +492 -0
- data/lib/helpers/fzf/src/ansi.go +409 -0
- data/lib/helpers/fzf/src/ansi_test.go +427 -0
- data/lib/helpers/fzf/src/cache.go +81 -0
- data/lib/helpers/fzf/src/cache_test.go +39 -0
- data/lib/helpers/fzf/src/chunklist.go +89 -0
- data/lib/helpers/fzf/src/chunklist_test.go +80 -0
- data/lib/helpers/fzf/src/constants.go +85 -0
- data/lib/helpers/fzf/src/core.go +351 -0
- data/lib/helpers/fzf/src/history.go +96 -0
- data/lib/helpers/fzf/src/history_test.go +68 -0
- data/lib/helpers/fzf/src/item.go +44 -0
- data/lib/helpers/fzf/src/item_test.go +23 -0
- data/lib/helpers/fzf/src/matcher.go +235 -0
- data/lib/helpers/fzf/src/merger.go +120 -0
- data/lib/helpers/fzf/src/merger_test.go +88 -0
- data/lib/helpers/fzf/src/options.go +1691 -0
- data/lib/helpers/fzf/src/options_test.go +457 -0
- data/lib/helpers/fzf/src/pattern.go +425 -0
- data/lib/helpers/fzf/src/pattern_test.go +209 -0
- data/lib/helpers/fzf/src/protector/protector.go +8 -0
- data/lib/helpers/fzf/src/protector/protector_openbsd.go +10 -0
- data/lib/helpers/fzf/src/reader.go +201 -0
- data/lib/helpers/fzf/src/reader_test.go +63 -0
- data/lib/helpers/fzf/src/result.go +243 -0
- data/lib/helpers/fzf/src/result_others.go +16 -0
- data/lib/helpers/fzf/src/result_test.go +159 -0
- data/lib/helpers/fzf/src/result_x86.go +16 -0
- data/lib/helpers/fzf/src/terminal.go +2832 -0
- data/lib/helpers/fzf/src/terminal_test.go +638 -0
- data/lib/helpers/fzf/src/terminal_unix.go +26 -0
- data/lib/helpers/fzf/src/terminal_windows.go +45 -0
- data/lib/helpers/fzf/src/tokenizer.go +253 -0
- data/lib/helpers/fzf/src/tokenizer_test.go +112 -0
- data/lib/helpers/fzf/src/tui/dummy.go +46 -0
- data/lib/helpers/fzf/src/tui/light.go +987 -0
- data/lib/helpers/fzf/src/tui/light_unix.go +110 -0
- data/lib/helpers/fzf/src/tui/light_windows.go +145 -0
- data/lib/helpers/fzf/src/tui/tcell.go +721 -0
- data/lib/helpers/fzf/src/tui/tcell_test.go +392 -0
- data/lib/helpers/fzf/src/tui/ttyname_unix.go +47 -0
- data/lib/helpers/fzf/src/tui/ttyname_windows.go +14 -0
- data/lib/helpers/fzf/src/tui/tui.go +625 -0
- data/lib/helpers/fzf/src/tui/tui_test.go +20 -0
- data/lib/helpers/fzf/src/util/atomicbool.go +34 -0
- data/lib/helpers/fzf/src/util/atomicbool_test.go +17 -0
- data/lib/helpers/fzf/src/util/chars.go +198 -0
- data/lib/helpers/fzf/src/util/chars_test.go +46 -0
- data/lib/helpers/fzf/src/util/eventbox.go +96 -0
- data/lib/helpers/fzf/src/util/eventbox_test.go +61 -0
- data/lib/helpers/fzf/src/util/slab.go +12 -0
- data/lib/helpers/fzf/src/util/util.go +138 -0
- data/lib/helpers/fzf/src/util/util_test.go +40 -0
- data/lib/helpers/fzf/src/util/util_unix.go +47 -0
- data/lib/helpers/fzf/src/util/util_windows.go +83 -0
- data/lib/helpers/fzf/test/fzf.vader +175 -0
- data/lib/helpers/fzf/test/test_go.rb +2626 -0
- data/lib/helpers/fzf/uninstall +117 -0
- data/scripts/generate_bash_completions.rb +6 -12
- data/scripts/generate_fish_completions.rb +7 -16
- data/scripts/generate_zsh_completions.rb +6 -15
- metadata +144 -9
@@ -0,0 +1,625 @@
|
|
1
|
+
package tui
|
2
|
+
|
3
|
+
import (
|
4
|
+
"fmt"
|
5
|
+
"os"
|
6
|
+
"strconv"
|
7
|
+
"time"
|
8
|
+
)
|
9
|
+
|
10
|
+
// Types of user action
|
11
|
+
type EventType int
|
12
|
+
|
13
|
+
const (
|
14
|
+
Rune EventType = iota
|
15
|
+
|
16
|
+
CtrlA
|
17
|
+
CtrlB
|
18
|
+
CtrlC
|
19
|
+
CtrlD
|
20
|
+
CtrlE
|
21
|
+
CtrlF
|
22
|
+
CtrlG
|
23
|
+
CtrlH
|
24
|
+
Tab
|
25
|
+
CtrlJ
|
26
|
+
CtrlK
|
27
|
+
CtrlL
|
28
|
+
CtrlM
|
29
|
+
CtrlN
|
30
|
+
CtrlO
|
31
|
+
CtrlP
|
32
|
+
CtrlQ
|
33
|
+
CtrlR
|
34
|
+
CtrlS
|
35
|
+
CtrlT
|
36
|
+
CtrlU
|
37
|
+
CtrlV
|
38
|
+
CtrlW
|
39
|
+
CtrlX
|
40
|
+
CtrlY
|
41
|
+
CtrlZ
|
42
|
+
ESC
|
43
|
+
CtrlSpace
|
44
|
+
|
45
|
+
// https://apple.stackexchange.com/questions/24261/how-do-i-send-c-that-is-control-slash-to-the-terminal
|
46
|
+
CtrlBackSlash
|
47
|
+
CtrlRightBracket
|
48
|
+
CtrlCaret
|
49
|
+
CtrlSlash
|
50
|
+
|
51
|
+
Invalid
|
52
|
+
Resize
|
53
|
+
Mouse
|
54
|
+
DoubleClick
|
55
|
+
LeftClick
|
56
|
+
RightClick
|
57
|
+
|
58
|
+
BTab
|
59
|
+
BSpace
|
60
|
+
|
61
|
+
Del
|
62
|
+
PgUp
|
63
|
+
PgDn
|
64
|
+
|
65
|
+
Up
|
66
|
+
Down
|
67
|
+
Left
|
68
|
+
Right
|
69
|
+
Home
|
70
|
+
End
|
71
|
+
Insert
|
72
|
+
|
73
|
+
SUp
|
74
|
+
SDown
|
75
|
+
SLeft
|
76
|
+
SRight
|
77
|
+
|
78
|
+
F1
|
79
|
+
F2
|
80
|
+
F3
|
81
|
+
F4
|
82
|
+
F5
|
83
|
+
F6
|
84
|
+
F7
|
85
|
+
F8
|
86
|
+
F9
|
87
|
+
F10
|
88
|
+
F11
|
89
|
+
F12
|
90
|
+
|
91
|
+
Change
|
92
|
+
BackwardEOF
|
93
|
+
|
94
|
+
AltBS
|
95
|
+
|
96
|
+
AltUp
|
97
|
+
AltDown
|
98
|
+
AltLeft
|
99
|
+
AltRight
|
100
|
+
|
101
|
+
AltSUp
|
102
|
+
AltSDown
|
103
|
+
AltSLeft
|
104
|
+
AltSRight
|
105
|
+
|
106
|
+
Alt
|
107
|
+
CtrlAlt
|
108
|
+
)
|
109
|
+
|
110
|
+
func (t EventType) AsEvent() Event {
|
111
|
+
return Event{t, 0, nil}
|
112
|
+
}
|
113
|
+
|
114
|
+
func (t EventType) Int() int {
|
115
|
+
return int(t)
|
116
|
+
}
|
117
|
+
|
118
|
+
func (t EventType) Byte() byte {
|
119
|
+
return byte(t)
|
120
|
+
}
|
121
|
+
|
122
|
+
func (e Event) Comparable() Event {
|
123
|
+
// Ignore MouseEvent pointer
|
124
|
+
return Event{e.Type, e.Char, nil}
|
125
|
+
}
|
126
|
+
|
127
|
+
func Key(r rune) Event {
|
128
|
+
return Event{Rune, r, nil}
|
129
|
+
}
|
130
|
+
|
131
|
+
func AltKey(r rune) Event {
|
132
|
+
return Event{Alt, r, nil}
|
133
|
+
}
|
134
|
+
|
135
|
+
func CtrlAltKey(r rune) Event {
|
136
|
+
return Event{CtrlAlt, r, nil}
|
137
|
+
}
|
138
|
+
|
139
|
+
const (
|
140
|
+
doubleClickDuration = 500 * time.Millisecond
|
141
|
+
)
|
142
|
+
|
143
|
+
type Color int32
|
144
|
+
|
145
|
+
func (c Color) IsDefault() bool {
|
146
|
+
return c == colDefault
|
147
|
+
}
|
148
|
+
|
149
|
+
func (c Color) is24() bool {
|
150
|
+
return c > 0 && (c&(1<<24)) > 0
|
151
|
+
}
|
152
|
+
|
153
|
+
type ColorAttr struct {
|
154
|
+
Color Color
|
155
|
+
Attr Attr
|
156
|
+
}
|
157
|
+
|
158
|
+
func NewColorAttr() ColorAttr {
|
159
|
+
return ColorAttr{Color: colUndefined, Attr: AttrUndefined}
|
160
|
+
}
|
161
|
+
|
162
|
+
const (
|
163
|
+
colUndefined Color = -2
|
164
|
+
colDefault Color = -1
|
165
|
+
)
|
166
|
+
|
167
|
+
const (
|
168
|
+
colBlack Color = iota
|
169
|
+
colRed
|
170
|
+
colGreen
|
171
|
+
colYellow
|
172
|
+
colBlue
|
173
|
+
colMagenta
|
174
|
+
colCyan
|
175
|
+
colWhite
|
176
|
+
)
|
177
|
+
|
178
|
+
type FillReturn int
|
179
|
+
|
180
|
+
const (
|
181
|
+
FillContinue FillReturn = iota
|
182
|
+
FillNextLine
|
183
|
+
FillSuspend
|
184
|
+
)
|
185
|
+
|
186
|
+
type ColorPair struct {
|
187
|
+
fg Color
|
188
|
+
bg Color
|
189
|
+
attr Attr
|
190
|
+
}
|
191
|
+
|
192
|
+
func HexToColor(rrggbb string) Color {
|
193
|
+
r, _ := strconv.ParseInt(rrggbb[1:3], 16, 0)
|
194
|
+
g, _ := strconv.ParseInt(rrggbb[3:5], 16, 0)
|
195
|
+
b, _ := strconv.ParseInt(rrggbb[5:7], 16, 0)
|
196
|
+
return Color((1 << 24) + (r << 16) + (g << 8) + b)
|
197
|
+
}
|
198
|
+
|
199
|
+
func NewColorPair(fg Color, bg Color, attr Attr) ColorPair {
|
200
|
+
return ColorPair{fg, bg, attr}
|
201
|
+
}
|
202
|
+
|
203
|
+
func (p ColorPair) Fg() Color {
|
204
|
+
return p.fg
|
205
|
+
}
|
206
|
+
|
207
|
+
func (p ColorPair) Bg() Color {
|
208
|
+
return p.bg
|
209
|
+
}
|
210
|
+
|
211
|
+
func (p ColorPair) Attr() Attr {
|
212
|
+
return p.attr
|
213
|
+
}
|
214
|
+
|
215
|
+
func (p ColorPair) HasBg() bool {
|
216
|
+
return p.attr&Reverse == 0 && p.bg != colDefault ||
|
217
|
+
p.attr&Reverse > 0 && p.fg != colDefault
|
218
|
+
}
|
219
|
+
|
220
|
+
func (p ColorPair) merge(other ColorPair, except Color) ColorPair {
|
221
|
+
dup := p
|
222
|
+
dup.attr = dup.attr.Merge(other.attr)
|
223
|
+
if other.fg != except {
|
224
|
+
dup.fg = other.fg
|
225
|
+
}
|
226
|
+
if other.bg != except {
|
227
|
+
dup.bg = other.bg
|
228
|
+
}
|
229
|
+
return dup
|
230
|
+
}
|
231
|
+
|
232
|
+
func (p ColorPair) WithAttr(attr Attr) ColorPair {
|
233
|
+
dup := p
|
234
|
+
dup.attr = dup.attr.Merge(attr)
|
235
|
+
return dup
|
236
|
+
}
|
237
|
+
|
238
|
+
func (p ColorPair) MergeAttr(other ColorPair) ColorPair {
|
239
|
+
return p.WithAttr(other.attr)
|
240
|
+
}
|
241
|
+
|
242
|
+
func (p ColorPair) Merge(other ColorPair) ColorPair {
|
243
|
+
return p.merge(other, colUndefined)
|
244
|
+
}
|
245
|
+
|
246
|
+
func (p ColorPair) MergeNonDefault(other ColorPair) ColorPair {
|
247
|
+
return p.merge(other, colDefault)
|
248
|
+
}
|
249
|
+
|
250
|
+
type ColorTheme struct {
|
251
|
+
Colored bool
|
252
|
+
Input ColorAttr
|
253
|
+
Disabled ColorAttr
|
254
|
+
Fg ColorAttr
|
255
|
+
Bg ColorAttr
|
256
|
+
PreviewFg ColorAttr
|
257
|
+
PreviewBg ColorAttr
|
258
|
+
DarkBg ColorAttr
|
259
|
+
Gutter ColorAttr
|
260
|
+
Prompt ColorAttr
|
261
|
+
Match ColorAttr
|
262
|
+
Current ColorAttr
|
263
|
+
CurrentMatch ColorAttr
|
264
|
+
Spinner ColorAttr
|
265
|
+
Info ColorAttr
|
266
|
+
Cursor ColorAttr
|
267
|
+
Selected ColorAttr
|
268
|
+
Header ColorAttr
|
269
|
+
Border ColorAttr
|
270
|
+
}
|
271
|
+
|
272
|
+
type Event struct {
|
273
|
+
Type EventType
|
274
|
+
Char rune
|
275
|
+
MouseEvent *MouseEvent
|
276
|
+
}
|
277
|
+
|
278
|
+
type MouseEvent struct {
|
279
|
+
Y int
|
280
|
+
X int
|
281
|
+
S int
|
282
|
+
Left bool
|
283
|
+
Down bool
|
284
|
+
Double bool
|
285
|
+
Mod bool
|
286
|
+
}
|
287
|
+
|
288
|
+
type BorderShape int
|
289
|
+
|
290
|
+
const (
|
291
|
+
BorderNone BorderShape = iota
|
292
|
+
BorderRounded
|
293
|
+
BorderSharp
|
294
|
+
BorderHorizontal
|
295
|
+
BorderVertical
|
296
|
+
BorderTop
|
297
|
+
BorderBottom
|
298
|
+
BorderLeft
|
299
|
+
BorderRight
|
300
|
+
)
|
301
|
+
|
302
|
+
type BorderStyle struct {
|
303
|
+
shape BorderShape
|
304
|
+
horizontal rune
|
305
|
+
vertical rune
|
306
|
+
topLeft rune
|
307
|
+
topRight rune
|
308
|
+
bottomLeft rune
|
309
|
+
bottomRight rune
|
310
|
+
}
|
311
|
+
|
312
|
+
type BorderCharacter int
|
313
|
+
|
314
|
+
func MakeBorderStyle(shape BorderShape, unicode bool) BorderStyle {
|
315
|
+
if unicode {
|
316
|
+
if shape == BorderRounded {
|
317
|
+
return BorderStyle{
|
318
|
+
shape: shape,
|
319
|
+
horizontal: '─',
|
320
|
+
vertical: '│',
|
321
|
+
topLeft: '╭',
|
322
|
+
topRight: '╮',
|
323
|
+
bottomLeft: '╰',
|
324
|
+
bottomRight: '╯',
|
325
|
+
}
|
326
|
+
}
|
327
|
+
return BorderStyle{
|
328
|
+
shape: shape,
|
329
|
+
horizontal: '─',
|
330
|
+
vertical: '│',
|
331
|
+
topLeft: '┌',
|
332
|
+
topRight: '┐',
|
333
|
+
bottomLeft: '└',
|
334
|
+
bottomRight: '┘',
|
335
|
+
}
|
336
|
+
}
|
337
|
+
return BorderStyle{
|
338
|
+
shape: shape,
|
339
|
+
horizontal: '-',
|
340
|
+
vertical: '|',
|
341
|
+
topLeft: '+',
|
342
|
+
topRight: '+',
|
343
|
+
bottomLeft: '+',
|
344
|
+
bottomRight: '+',
|
345
|
+
}
|
346
|
+
}
|
347
|
+
|
348
|
+
func MakeTransparentBorder() BorderStyle {
|
349
|
+
return BorderStyle{
|
350
|
+
shape: BorderRounded,
|
351
|
+
horizontal: ' ',
|
352
|
+
vertical: ' ',
|
353
|
+
topLeft: ' ',
|
354
|
+
topRight: ' ',
|
355
|
+
bottomLeft: ' ',
|
356
|
+
bottomRight: ' '}
|
357
|
+
}
|
358
|
+
|
359
|
+
type Renderer interface {
|
360
|
+
Init()
|
361
|
+
Pause(clear bool)
|
362
|
+
Resume(clear bool, sigcont bool)
|
363
|
+
Clear()
|
364
|
+
RefreshWindows(windows []Window)
|
365
|
+
Refresh()
|
366
|
+
Close()
|
367
|
+
|
368
|
+
GetChar() Event
|
369
|
+
|
370
|
+
MaxX() int
|
371
|
+
MaxY() int
|
372
|
+
|
373
|
+
NewWindow(top int, left int, width int, height int, preview bool, borderStyle BorderStyle) Window
|
374
|
+
}
|
375
|
+
|
376
|
+
type Window interface {
|
377
|
+
Top() int
|
378
|
+
Left() int
|
379
|
+
Width() int
|
380
|
+
Height() int
|
381
|
+
|
382
|
+
Refresh()
|
383
|
+
FinishFill()
|
384
|
+
Close()
|
385
|
+
|
386
|
+
X() int
|
387
|
+
Y() int
|
388
|
+
Enclose(y int, x int) bool
|
389
|
+
|
390
|
+
Move(y int, x int)
|
391
|
+
MoveAndClear(y int, x int)
|
392
|
+
Print(text string)
|
393
|
+
CPrint(color ColorPair, text string)
|
394
|
+
Fill(text string) FillReturn
|
395
|
+
CFill(fg Color, bg Color, attr Attr, text string) FillReturn
|
396
|
+
Erase()
|
397
|
+
}
|
398
|
+
|
399
|
+
type FullscreenRenderer struct {
|
400
|
+
theme *ColorTheme
|
401
|
+
mouse bool
|
402
|
+
forceBlack bool
|
403
|
+
prevDownTime time.Time
|
404
|
+
clickY []int
|
405
|
+
}
|
406
|
+
|
407
|
+
func NewFullscreenRenderer(theme *ColorTheme, forceBlack bool, mouse bool) Renderer {
|
408
|
+
r := &FullscreenRenderer{
|
409
|
+
theme: theme,
|
410
|
+
mouse: mouse,
|
411
|
+
forceBlack: forceBlack,
|
412
|
+
prevDownTime: time.Unix(0, 0),
|
413
|
+
clickY: []int{}}
|
414
|
+
return r
|
415
|
+
}
|
416
|
+
|
417
|
+
var (
|
418
|
+
Default16 *ColorTheme
|
419
|
+
Dark256 *ColorTheme
|
420
|
+
Light256 *ColorTheme
|
421
|
+
|
422
|
+
ColPrompt ColorPair
|
423
|
+
ColNormal ColorPair
|
424
|
+
ColInput ColorPair
|
425
|
+
ColDisabled ColorPair
|
426
|
+
ColMatch ColorPair
|
427
|
+
ColCursor ColorPair
|
428
|
+
ColCursorEmpty ColorPair
|
429
|
+
ColSelected ColorPair
|
430
|
+
ColCurrent ColorPair
|
431
|
+
ColCurrentMatch ColorPair
|
432
|
+
ColCurrentCursor ColorPair
|
433
|
+
ColCurrentCursorEmpty ColorPair
|
434
|
+
ColCurrentSelected ColorPair
|
435
|
+
ColCurrentSelectedEmpty ColorPair
|
436
|
+
ColSpinner ColorPair
|
437
|
+
ColInfo ColorPair
|
438
|
+
ColHeader ColorPair
|
439
|
+
ColBorder ColorPair
|
440
|
+
ColPreview ColorPair
|
441
|
+
ColPreviewBorder ColorPair
|
442
|
+
)
|
443
|
+
|
444
|
+
func EmptyTheme() *ColorTheme {
|
445
|
+
return &ColorTheme{
|
446
|
+
Colored: true,
|
447
|
+
Input: ColorAttr{colUndefined, AttrUndefined},
|
448
|
+
Disabled: ColorAttr{colUndefined, AttrUndefined},
|
449
|
+
Fg: ColorAttr{colUndefined, AttrUndefined},
|
450
|
+
Bg: ColorAttr{colUndefined, AttrUndefined},
|
451
|
+
PreviewFg: ColorAttr{colUndefined, AttrUndefined},
|
452
|
+
PreviewBg: ColorAttr{colUndefined, AttrUndefined},
|
453
|
+
DarkBg: ColorAttr{colUndefined, AttrUndefined},
|
454
|
+
Gutter: ColorAttr{colUndefined, AttrUndefined},
|
455
|
+
Prompt: ColorAttr{colUndefined, AttrUndefined},
|
456
|
+
Match: ColorAttr{colUndefined, AttrUndefined},
|
457
|
+
Current: ColorAttr{colUndefined, AttrUndefined},
|
458
|
+
CurrentMatch: ColorAttr{colUndefined, AttrUndefined},
|
459
|
+
Spinner: ColorAttr{colUndefined, AttrUndefined},
|
460
|
+
Info: ColorAttr{colUndefined, AttrUndefined},
|
461
|
+
Cursor: ColorAttr{colUndefined, AttrUndefined},
|
462
|
+
Selected: ColorAttr{colUndefined, AttrUndefined},
|
463
|
+
Header: ColorAttr{colUndefined, AttrUndefined},
|
464
|
+
Border: ColorAttr{colUndefined, AttrUndefined}}
|
465
|
+
}
|
466
|
+
|
467
|
+
func NoColorTheme() *ColorTheme {
|
468
|
+
return &ColorTheme{
|
469
|
+
Colored: false,
|
470
|
+
Input: ColorAttr{colDefault, AttrRegular},
|
471
|
+
Disabled: ColorAttr{colDefault, AttrRegular},
|
472
|
+
Fg: ColorAttr{colDefault, AttrRegular},
|
473
|
+
Bg: ColorAttr{colDefault, AttrRegular},
|
474
|
+
PreviewFg: ColorAttr{colDefault, AttrRegular},
|
475
|
+
PreviewBg: ColorAttr{colDefault, AttrRegular},
|
476
|
+
DarkBg: ColorAttr{colDefault, AttrRegular},
|
477
|
+
Gutter: ColorAttr{colDefault, AttrRegular},
|
478
|
+
Prompt: ColorAttr{colDefault, AttrRegular},
|
479
|
+
Match: ColorAttr{colDefault, Underline},
|
480
|
+
Current: ColorAttr{colDefault, Reverse},
|
481
|
+
CurrentMatch: ColorAttr{colDefault, Reverse | Underline},
|
482
|
+
Spinner: ColorAttr{colDefault, AttrRegular},
|
483
|
+
Info: ColorAttr{colDefault, AttrRegular},
|
484
|
+
Cursor: ColorAttr{colDefault, AttrRegular},
|
485
|
+
Selected: ColorAttr{colDefault, AttrRegular},
|
486
|
+
Header: ColorAttr{colDefault, AttrRegular},
|
487
|
+
Border: ColorAttr{colDefault, AttrRegular}}
|
488
|
+
}
|
489
|
+
|
490
|
+
func errorExit(message string) {
|
491
|
+
fmt.Fprintln(os.Stderr, message)
|
492
|
+
os.Exit(2)
|
493
|
+
}
|
494
|
+
|
495
|
+
func init() {
|
496
|
+
Default16 = &ColorTheme{
|
497
|
+
Colored: true,
|
498
|
+
Input: ColorAttr{colDefault, AttrUndefined},
|
499
|
+
Disabled: ColorAttr{colUndefined, AttrUndefined},
|
500
|
+
Fg: ColorAttr{colDefault, AttrUndefined},
|
501
|
+
Bg: ColorAttr{colDefault, AttrUndefined},
|
502
|
+
PreviewFg: ColorAttr{colUndefined, AttrUndefined},
|
503
|
+
PreviewBg: ColorAttr{colUndefined, AttrUndefined},
|
504
|
+
DarkBg: ColorAttr{colBlack, AttrUndefined},
|
505
|
+
Gutter: ColorAttr{colUndefined, AttrUndefined},
|
506
|
+
Prompt: ColorAttr{colBlue, AttrUndefined},
|
507
|
+
Match: ColorAttr{colGreen, AttrUndefined},
|
508
|
+
Current: ColorAttr{colYellow, AttrUndefined},
|
509
|
+
CurrentMatch: ColorAttr{colGreen, AttrUndefined},
|
510
|
+
Spinner: ColorAttr{colGreen, AttrUndefined},
|
511
|
+
Info: ColorAttr{colWhite, AttrUndefined},
|
512
|
+
Cursor: ColorAttr{colRed, AttrUndefined},
|
513
|
+
Selected: ColorAttr{colMagenta, AttrUndefined},
|
514
|
+
Header: ColorAttr{colCyan, AttrUndefined},
|
515
|
+
Border: ColorAttr{colBlack, AttrUndefined}}
|
516
|
+
Dark256 = &ColorTheme{
|
517
|
+
Colored: true,
|
518
|
+
Input: ColorAttr{colDefault, AttrUndefined},
|
519
|
+
Disabled: ColorAttr{colUndefined, AttrUndefined},
|
520
|
+
Fg: ColorAttr{colDefault, AttrUndefined},
|
521
|
+
Bg: ColorAttr{colDefault, AttrUndefined},
|
522
|
+
PreviewFg: ColorAttr{colUndefined, AttrUndefined},
|
523
|
+
PreviewBg: ColorAttr{colUndefined, AttrUndefined},
|
524
|
+
DarkBg: ColorAttr{236, AttrUndefined},
|
525
|
+
Gutter: ColorAttr{colUndefined, AttrUndefined},
|
526
|
+
Prompt: ColorAttr{110, AttrUndefined},
|
527
|
+
Match: ColorAttr{108, AttrUndefined},
|
528
|
+
Current: ColorAttr{254, AttrUndefined},
|
529
|
+
CurrentMatch: ColorAttr{151, AttrUndefined},
|
530
|
+
Spinner: ColorAttr{148, AttrUndefined},
|
531
|
+
Info: ColorAttr{144, AttrUndefined},
|
532
|
+
Cursor: ColorAttr{161, AttrUndefined},
|
533
|
+
Selected: ColorAttr{168, AttrUndefined},
|
534
|
+
Header: ColorAttr{109, AttrUndefined},
|
535
|
+
Border: ColorAttr{59, AttrUndefined}}
|
536
|
+
Light256 = &ColorTheme{
|
537
|
+
Colored: true,
|
538
|
+
Input: ColorAttr{colDefault, AttrUndefined},
|
539
|
+
Disabled: ColorAttr{colUndefined, AttrUndefined},
|
540
|
+
Fg: ColorAttr{colDefault, AttrUndefined},
|
541
|
+
Bg: ColorAttr{colDefault, AttrUndefined},
|
542
|
+
PreviewFg: ColorAttr{colUndefined, AttrUndefined},
|
543
|
+
PreviewBg: ColorAttr{colUndefined, AttrUndefined},
|
544
|
+
DarkBg: ColorAttr{251, AttrUndefined},
|
545
|
+
Gutter: ColorAttr{colUndefined, AttrUndefined},
|
546
|
+
Prompt: ColorAttr{25, AttrUndefined},
|
547
|
+
Match: ColorAttr{66, AttrUndefined},
|
548
|
+
Current: ColorAttr{237, AttrUndefined},
|
549
|
+
CurrentMatch: ColorAttr{23, AttrUndefined},
|
550
|
+
Spinner: ColorAttr{65, AttrUndefined},
|
551
|
+
Info: ColorAttr{101, AttrUndefined},
|
552
|
+
Cursor: ColorAttr{161, AttrUndefined},
|
553
|
+
Selected: ColorAttr{168, AttrUndefined},
|
554
|
+
Header: ColorAttr{31, AttrUndefined},
|
555
|
+
Border: ColorAttr{145, AttrUndefined}}
|
556
|
+
}
|
557
|
+
|
558
|
+
func initTheme(theme *ColorTheme, baseTheme *ColorTheme, forceBlack bool) {
|
559
|
+
if forceBlack {
|
560
|
+
theme.Bg = ColorAttr{colBlack, AttrUndefined}
|
561
|
+
}
|
562
|
+
|
563
|
+
o := func(a ColorAttr, b ColorAttr) ColorAttr {
|
564
|
+
c := a
|
565
|
+
if b.Color != colUndefined {
|
566
|
+
c.Color = b.Color
|
567
|
+
}
|
568
|
+
if b.Attr != AttrUndefined {
|
569
|
+
c.Attr = b.Attr
|
570
|
+
}
|
571
|
+
return c
|
572
|
+
}
|
573
|
+
theme.Input = o(baseTheme.Input, theme.Input)
|
574
|
+
theme.Disabled = o(theme.Input, o(baseTheme.Disabled, theme.Disabled))
|
575
|
+
theme.Fg = o(baseTheme.Fg, theme.Fg)
|
576
|
+
theme.Bg = o(baseTheme.Bg, theme.Bg)
|
577
|
+
theme.PreviewFg = o(theme.Fg, o(baseTheme.PreviewFg, theme.PreviewFg))
|
578
|
+
theme.PreviewBg = o(theme.Bg, o(baseTheme.PreviewBg, theme.PreviewBg))
|
579
|
+
theme.DarkBg = o(baseTheme.DarkBg, theme.DarkBg)
|
580
|
+
theme.Gutter = o(theme.DarkBg, o(baseTheme.Gutter, theme.Gutter))
|
581
|
+
theme.Prompt = o(baseTheme.Prompt, theme.Prompt)
|
582
|
+
theme.Match = o(baseTheme.Match, theme.Match)
|
583
|
+
theme.Current = o(baseTheme.Current, theme.Current)
|
584
|
+
theme.CurrentMatch = o(baseTheme.CurrentMatch, theme.CurrentMatch)
|
585
|
+
theme.Spinner = o(baseTheme.Spinner, theme.Spinner)
|
586
|
+
theme.Info = o(baseTheme.Info, theme.Info)
|
587
|
+
theme.Cursor = o(baseTheme.Cursor, theme.Cursor)
|
588
|
+
theme.Selected = o(baseTheme.Selected, theme.Selected)
|
589
|
+
theme.Header = o(baseTheme.Header, theme.Header)
|
590
|
+
theme.Border = o(baseTheme.Border, theme.Border)
|
591
|
+
|
592
|
+
initPalette(theme)
|
593
|
+
}
|
594
|
+
|
595
|
+
func initPalette(theme *ColorTheme) {
|
596
|
+
pair := func(fg, bg ColorAttr) ColorPair {
|
597
|
+
if fg.Color == colDefault && (fg.Attr&Reverse) > 0 {
|
598
|
+
bg.Color = colDefault
|
599
|
+
}
|
600
|
+
return ColorPair{fg.Color, bg.Color, fg.Attr}
|
601
|
+
}
|
602
|
+
blank := theme.Fg
|
603
|
+
blank.Attr = AttrRegular
|
604
|
+
|
605
|
+
ColPrompt = pair(theme.Prompt, theme.Bg)
|
606
|
+
ColNormal = pair(theme.Fg, theme.Bg)
|
607
|
+
ColInput = pair(theme.Input, theme.Bg)
|
608
|
+
ColDisabled = pair(theme.Disabled, theme.Bg)
|
609
|
+
ColMatch = pair(theme.Match, theme.Bg)
|
610
|
+
ColCursor = pair(theme.Cursor, theme.Gutter)
|
611
|
+
ColCursorEmpty = pair(blank, theme.Gutter)
|
612
|
+
ColSelected = pair(theme.Selected, theme.Gutter)
|
613
|
+
ColCurrent = pair(theme.Current, theme.DarkBg)
|
614
|
+
ColCurrentMatch = pair(theme.CurrentMatch, theme.DarkBg)
|
615
|
+
ColCurrentCursor = pair(theme.Cursor, theme.DarkBg)
|
616
|
+
ColCurrentCursorEmpty = pair(blank, theme.DarkBg)
|
617
|
+
ColCurrentSelected = pair(theme.Selected, theme.DarkBg)
|
618
|
+
ColCurrentSelectedEmpty = pair(blank, theme.DarkBg)
|
619
|
+
ColSpinner = pair(theme.Spinner, theme.Bg)
|
620
|
+
ColInfo = pair(theme.Info, theme.Bg)
|
621
|
+
ColHeader = pair(theme.Header, theme.Bg)
|
622
|
+
ColBorder = pair(theme.Border, theme.Bg)
|
623
|
+
ColPreview = pair(theme.PreviewFg, theme.PreviewBg)
|
624
|
+
ColPreviewBorder = pair(theme.Border, theme.PreviewBg)
|
625
|
+
}
|
@@ -0,0 +1,20 @@
|
|
1
|
+
package tui
|
2
|
+
|
3
|
+
import "testing"
|
4
|
+
|
5
|
+
func TestHexToColor(t *testing.T) {
|
6
|
+
assert := func(expr string, r, g, b int) {
|
7
|
+
color := HexToColor(expr)
|
8
|
+
if !color.is24() ||
|
9
|
+
int((color>>16)&0xff) != r ||
|
10
|
+
int((color>>8)&0xff) != g ||
|
11
|
+
int((color)&0xff) != b {
|
12
|
+
t.Fail()
|
13
|
+
}
|
14
|
+
}
|
15
|
+
|
16
|
+
assert("#ff0000", 255, 0, 0)
|
17
|
+
assert("#010203", 1, 2, 3)
|
18
|
+
assert("#102030", 16, 32, 48)
|
19
|
+
assert("#ffffff", 255, 255, 255)
|
20
|
+
}
|
@@ -0,0 +1,34 @@
|
|
1
|
+
package util
|
2
|
+
|
3
|
+
import (
|
4
|
+
"sync/atomic"
|
5
|
+
)
|
6
|
+
|
7
|
+
func convertBoolToInt32(b bool) int32 {
|
8
|
+
if b {
|
9
|
+
return 1
|
10
|
+
}
|
11
|
+
return 0
|
12
|
+
}
|
13
|
+
|
14
|
+
// AtomicBool is a boxed-class that provides synchronized access to the
|
15
|
+
// underlying boolean value
|
16
|
+
type AtomicBool struct {
|
17
|
+
state int32 // "1" is true, "0" is false
|
18
|
+
}
|
19
|
+
|
20
|
+
// NewAtomicBool returns a new AtomicBool
|
21
|
+
func NewAtomicBool(initialState bool) *AtomicBool {
|
22
|
+
return &AtomicBool{state: convertBoolToInt32(initialState)}
|
23
|
+
}
|
24
|
+
|
25
|
+
// Get returns the current boolean value synchronously
|
26
|
+
func (a *AtomicBool) Get() bool {
|
27
|
+
return atomic.LoadInt32(&a.state) == 1
|
28
|
+
}
|
29
|
+
|
30
|
+
// Set updates the boolean value synchronously
|
31
|
+
func (a *AtomicBool) Set(newState bool) bool {
|
32
|
+
atomic.StoreInt32(&a.state, convertBoolToInt32(newState))
|
33
|
+
return newState
|
34
|
+
}
|
@@ -0,0 +1,17 @@
|
|
1
|
+
package util
|
2
|
+
|
3
|
+
import "testing"
|
4
|
+
|
5
|
+
func TestAtomicBool(t *testing.T) {
|
6
|
+
if !NewAtomicBool(true).Get() || NewAtomicBool(false).Get() {
|
7
|
+
t.Error("Invalid initial value")
|
8
|
+
}
|
9
|
+
|
10
|
+
ab := NewAtomicBool(true)
|
11
|
+
if ab.Set(false) {
|
12
|
+
t.Error("Invalid return value")
|
13
|
+
}
|
14
|
+
if ab.Get() {
|
15
|
+
t.Error("Invalid state")
|
16
|
+
}
|
17
|
+
}
|