doing 2.0.19 → 2.0.23

Sign up to get free protection for your applications and to get access to all the features.
Files changed (107) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +15 -0
  3. data/Gemfile.lock +15 -5
  4. data/README.md +1 -1
  5. data/bin/doing +2 -18
  6. data/doing.gemspec +5 -4
  7. data/doing.rdoc +2 -2
  8. data/generate_completions.sh +3 -3
  9. data/lib/doing/cli_status.rb +6 -2
  10. data/lib/doing/completion/bash_completion.rb +185 -0
  11. data/lib/doing/completion/fish_completion.rb +175 -0
  12. data/lib/doing/completion/string.rb +17 -0
  13. data/lib/doing/completion/zsh_completion.rb +140 -0
  14. data/lib/doing/completion.rb +39 -0
  15. data/lib/doing/version.rb +1 -1
  16. data/lib/doing/wwid.rb +19 -5
  17. data/lib/doing.rb +1 -1
  18. data/lib/helpers/fzf/.goreleaser.yml +119 -0
  19. data/lib/helpers/fzf/.rubocop.yml +28 -0
  20. data/lib/helpers/fzf/ADVANCED.md +565 -0
  21. data/lib/helpers/fzf/BUILD.md +49 -0
  22. data/lib/helpers/fzf/CHANGELOG.md +1193 -0
  23. data/lib/helpers/fzf/Dockerfile +11 -0
  24. data/lib/helpers/fzf/LICENSE +21 -0
  25. data/lib/helpers/fzf/Makefile +166 -0
  26. data/lib/helpers/fzf/README-VIM.md +486 -0
  27. data/lib/helpers/fzf/README.md +712 -0
  28. data/lib/helpers/fzf/bin/fzf-tmux +233 -0
  29. data/lib/helpers/fzf/doc/fzf.txt +512 -0
  30. data/lib/helpers/fzf/go.mod +17 -0
  31. data/lib/helpers/fzf/go.sum +31 -0
  32. data/lib/helpers/fzf/install +382 -0
  33. data/lib/helpers/fzf/install.ps1 +65 -0
  34. data/lib/helpers/fzf/main.go +14 -0
  35. data/lib/helpers/fzf/man/man1/fzf-tmux.1 +68 -0
  36. data/lib/helpers/fzf/man/man1/fzf.1 +1001 -0
  37. data/lib/helpers/fzf/plugin/fzf.vim +1048 -0
  38. data/lib/helpers/fzf/shell/completion.bash +381 -0
  39. data/lib/helpers/fzf/shell/completion.zsh +329 -0
  40. data/lib/helpers/fzf/shell/key-bindings.bash +96 -0
  41. data/lib/helpers/fzf/shell/key-bindings.fish +172 -0
  42. data/lib/helpers/fzf/shell/key-bindings.zsh +114 -0
  43. data/lib/helpers/fzf/src/LICENSE +21 -0
  44. data/lib/helpers/fzf/src/algo/algo.go +884 -0
  45. data/lib/helpers/fzf/src/algo/algo_test.go +197 -0
  46. data/lib/helpers/fzf/src/algo/normalize.go +492 -0
  47. data/lib/helpers/fzf/src/ansi.go +409 -0
  48. data/lib/helpers/fzf/src/ansi_test.go +427 -0
  49. data/lib/helpers/fzf/src/cache.go +81 -0
  50. data/lib/helpers/fzf/src/cache_test.go +39 -0
  51. data/lib/helpers/fzf/src/chunklist.go +89 -0
  52. data/lib/helpers/fzf/src/chunklist_test.go +80 -0
  53. data/lib/helpers/fzf/src/constants.go +85 -0
  54. data/lib/helpers/fzf/src/core.go +351 -0
  55. data/lib/helpers/fzf/src/history.go +96 -0
  56. data/lib/helpers/fzf/src/history_test.go +68 -0
  57. data/lib/helpers/fzf/src/item.go +44 -0
  58. data/lib/helpers/fzf/src/item_test.go +23 -0
  59. data/lib/helpers/fzf/src/matcher.go +235 -0
  60. data/lib/helpers/fzf/src/merger.go +120 -0
  61. data/lib/helpers/fzf/src/merger_test.go +88 -0
  62. data/lib/helpers/fzf/src/options.go +1691 -0
  63. data/lib/helpers/fzf/src/options_test.go +457 -0
  64. data/lib/helpers/fzf/src/pattern.go +425 -0
  65. data/lib/helpers/fzf/src/pattern_test.go +209 -0
  66. data/lib/helpers/fzf/src/protector/protector.go +8 -0
  67. data/lib/helpers/fzf/src/protector/protector_openbsd.go +10 -0
  68. data/lib/helpers/fzf/src/reader.go +201 -0
  69. data/lib/helpers/fzf/src/reader_test.go +63 -0
  70. data/lib/helpers/fzf/src/result.go +243 -0
  71. data/lib/helpers/fzf/src/result_others.go +16 -0
  72. data/lib/helpers/fzf/src/result_test.go +159 -0
  73. data/lib/helpers/fzf/src/result_x86.go +16 -0
  74. data/lib/helpers/fzf/src/terminal.go +2832 -0
  75. data/lib/helpers/fzf/src/terminal_test.go +638 -0
  76. data/lib/helpers/fzf/src/terminal_unix.go +26 -0
  77. data/lib/helpers/fzf/src/terminal_windows.go +45 -0
  78. data/lib/helpers/fzf/src/tokenizer.go +253 -0
  79. data/lib/helpers/fzf/src/tokenizer_test.go +112 -0
  80. data/lib/helpers/fzf/src/tui/dummy.go +46 -0
  81. data/lib/helpers/fzf/src/tui/light.go +987 -0
  82. data/lib/helpers/fzf/src/tui/light_unix.go +110 -0
  83. data/lib/helpers/fzf/src/tui/light_windows.go +145 -0
  84. data/lib/helpers/fzf/src/tui/tcell.go +721 -0
  85. data/lib/helpers/fzf/src/tui/tcell_test.go +392 -0
  86. data/lib/helpers/fzf/src/tui/ttyname_unix.go +47 -0
  87. data/lib/helpers/fzf/src/tui/ttyname_windows.go +14 -0
  88. data/lib/helpers/fzf/src/tui/tui.go +625 -0
  89. data/lib/helpers/fzf/src/tui/tui_test.go +20 -0
  90. data/lib/helpers/fzf/src/util/atomicbool.go +34 -0
  91. data/lib/helpers/fzf/src/util/atomicbool_test.go +17 -0
  92. data/lib/helpers/fzf/src/util/chars.go +198 -0
  93. data/lib/helpers/fzf/src/util/chars_test.go +46 -0
  94. data/lib/helpers/fzf/src/util/eventbox.go +96 -0
  95. data/lib/helpers/fzf/src/util/eventbox_test.go +61 -0
  96. data/lib/helpers/fzf/src/util/slab.go +12 -0
  97. data/lib/helpers/fzf/src/util/util.go +138 -0
  98. data/lib/helpers/fzf/src/util/util_test.go +40 -0
  99. data/lib/helpers/fzf/src/util/util_unix.go +47 -0
  100. data/lib/helpers/fzf/src/util/util_windows.go +83 -0
  101. data/lib/helpers/fzf/test/fzf.vader +175 -0
  102. data/lib/helpers/fzf/test/test_go.rb +2626 -0
  103. data/lib/helpers/fzf/uninstall +117 -0
  104. data/scripts/generate_bash_completions.rb +6 -12
  105. data/scripts/generate_fish_completions.rb +7 -16
  106. data/scripts/generate_zsh_completions.rb +6 -15
  107. 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
+ }