doing 2.0.20 → 2.0.21

Sign up to get free protection for your applications and to get access to all the features.
Files changed (93) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +6 -0
  3. data/Gemfile.lock +1 -1
  4. data/README.md +1 -1
  5. data/doing.rdoc +1 -1
  6. data/lib/doing/version.rb +1 -1
  7. data/lib/helpers/fzf/.goreleaser.yml +119 -0
  8. data/lib/helpers/fzf/.rubocop.yml +28 -0
  9. data/lib/helpers/fzf/ADVANCED.md +565 -0
  10. data/lib/helpers/fzf/BUILD.md +49 -0
  11. data/lib/helpers/fzf/CHANGELOG.md +1193 -0
  12. data/lib/helpers/fzf/Dockerfile +11 -0
  13. data/lib/helpers/fzf/LICENSE +21 -0
  14. data/lib/helpers/fzf/Makefile +166 -0
  15. data/lib/helpers/fzf/README-VIM.md +486 -0
  16. data/lib/helpers/fzf/README.md +712 -0
  17. data/lib/helpers/fzf/bin/fzf-tmux +233 -0
  18. data/lib/helpers/fzf/doc/fzf.txt +512 -0
  19. data/lib/helpers/fzf/go.mod +17 -0
  20. data/lib/helpers/fzf/go.sum +31 -0
  21. data/lib/helpers/fzf/install +382 -0
  22. data/lib/helpers/fzf/install.ps1 +65 -0
  23. data/lib/helpers/fzf/main.go +14 -0
  24. data/lib/helpers/fzf/man/man1/fzf-tmux.1 +68 -0
  25. data/lib/helpers/fzf/man/man1/fzf.1 +1001 -0
  26. data/lib/helpers/fzf/plugin/fzf.vim +1048 -0
  27. data/lib/helpers/fzf/shell/completion.bash +381 -0
  28. data/lib/helpers/fzf/shell/completion.zsh +329 -0
  29. data/lib/helpers/fzf/shell/key-bindings.bash +96 -0
  30. data/lib/helpers/fzf/shell/key-bindings.fish +172 -0
  31. data/lib/helpers/fzf/shell/key-bindings.zsh +114 -0
  32. data/lib/helpers/fzf/src/LICENSE +21 -0
  33. data/lib/helpers/fzf/src/algo/algo.go +884 -0
  34. data/lib/helpers/fzf/src/algo/algo_test.go +197 -0
  35. data/lib/helpers/fzf/src/algo/normalize.go +492 -0
  36. data/lib/helpers/fzf/src/ansi.go +409 -0
  37. data/lib/helpers/fzf/src/ansi_test.go +427 -0
  38. data/lib/helpers/fzf/src/cache.go +81 -0
  39. data/lib/helpers/fzf/src/cache_test.go +39 -0
  40. data/lib/helpers/fzf/src/chunklist.go +89 -0
  41. data/lib/helpers/fzf/src/chunklist_test.go +80 -0
  42. data/lib/helpers/fzf/src/constants.go +85 -0
  43. data/lib/helpers/fzf/src/core.go +351 -0
  44. data/lib/helpers/fzf/src/history.go +96 -0
  45. data/lib/helpers/fzf/src/history_test.go +68 -0
  46. data/lib/helpers/fzf/src/item.go +44 -0
  47. data/lib/helpers/fzf/src/item_test.go +23 -0
  48. data/lib/helpers/fzf/src/matcher.go +235 -0
  49. data/lib/helpers/fzf/src/merger.go +120 -0
  50. data/lib/helpers/fzf/src/merger_test.go +88 -0
  51. data/lib/helpers/fzf/src/options.go +1691 -0
  52. data/lib/helpers/fzf/src/options_test.go +457 -0
  53. data/lib/helpers/fzf/src/pattern.go +425 -0
  54. data/lib/helpers/fzf/src/pattern_test.go +209 -0
  55. data/lib/helpers/fzf/src/protector/protector.go +8 -0
  56. data/lib/helpers/fzf/src/protector/protector_openbsd.go +10 -0
  57. data/lib/helpers/fzf/src/reader.go +201 -0
  58. data/lib/helpers/fzf/src/reader_test.go +63 -0
  59. data/lib/helpers/fzf/src/result.go +243 -0
  60. data/lib/helpers/fzf/src/result_others.go +16 -0
  61. data/lib/helpers/fzf/src/result_test.go +159 -0
  62. data/lib/helpers/fzf/src/result_x86.go +16 -0
  63. data/lib/helpers/fzf/src/terminal.go +2832 -0
  64. data/lib/helpers/fzf/src/terminal_test.go +638 -0
  65. data/lib/helpers/fzf/src/terminal_unix.go +26 -0
  66. data/lib/helpers/fzf/src/terminal_windows.go +45 -0
  67. data/lib/helpers/fzf/src/tokenizer.go +253 -0
  68. data/lib/helpers/fzf/src/tokenizer_test.go +112 -0
  69. data/lib/helpers/fzf/src/tui/dummy.go +46 -0
  70. data/lib/helpers/fzf/src/tui/light.go +987 -0
  71. data/lib/helpers/fzf/src/tui/light_unix.go +110 -0
  72. data/lib/helpers/fzf/src/tui/light_windows.go +145 -0
  73. data/lib/helpers/fzf/src/tui/tcell.go +721 -0
  74. data/lib/helpers/fzf/src/tui/tcell_test.go +392 -0
  75. data/lib/helpers/fzf/src/tui/ttyname_unix.go +47 -0
  76. data/lib/helpers/fzf/src/tui/ttyname_windows.go +14 -0
  77. data/lib/helpers/fzf/src/tui/tui.go +625 -0
  78. data/lib/helpers/fzf/src/tui/tui_test.go +20 -0
  79. data/lib/helpers/fzf/src/util/atomicbool.go +34 -0
  80. data/lib/helpers/fzf/src/util/atomicbool_test.go +17 -0
  81. data/lib/helpers/fzf/src/util/chars.go +198 -0
  82. data/lib/helpers/fzf/src/util/chars_test.go +46 -0
  83. data/lib/helpers/fzf/src/util/eventbox.go +96 -0
  84. data/lib/helpers/fzf/src/util/eventbox_test.go +61 -0
  85. data/lib/helpers/fzf/src/util/slab.go +12 -0
  86. data/lib/helpers/fzf/src/util/util.go +138 -0
  87. data/lib/helpers/fzf/src/util/util_test.go +40 -0
  88. data/lib/helpers/fzf/src/util/util_unix.go +47 -0
  89. data/lib/helpers/fzf/src/util/util_windows.go +83 -0
  90. data/lib/helpers/fzf/test/fzf.vader +175 -0
  91. data/lib/helpers/fzf/test/test_go.rb +2626 -0
  92. data/lib/helpers/fzf/uninstall +117 -0
  93. metadata +87 -1
@@ -0,0 +1,721 @@
1
+ // +build tcell windows
2
+
3
+ package tui
4
+
5
+ import (
6
+ "os"
7
+ "time"
8
+
9
+ "runtime"
10
+
11
+ "github.com/gdamore/tcell"
12
+ "github.com/gdamore/tcell/encoding"
13
+
14
+ "github.com/mattn/go-runewidth"
15
+ "github.com/rivo/uniseg"
16
+ )
17
+
18
+ func HasFullscreenRenderer() bool {
19
+ return true
20
+ }
21
+
22
+ func (p ColorPair) style() tcell.Style {
23
+ style := tcell.StyleDefault
24
+ return style.Foreground(tcell.Color(p.Fg())).Background(tcell.Color(p.Bg()))
25
+ }
26
+
27
+ type Attr tcell.Style
28
+
29
+ type TcellWindow struct {
30
+ color bool
31
+ preview bool
32
+ top int
33
+ left int
34
+ width int
35
+ height int
36
+ normal ColorPair
37
+ lastX int
38
+ lastY int
39
+ moveCursor bool
40
+ borderStyle BorderStyle
41
+ }
42
+
43
+ func (w *TcellWindow) Top() int {
44
+ return w.top
45
+ }
46
+
47
+ func (w *TcellWindow) Left() int {
48
+ return w.left
49
+ }
50
+
51
+ func (w *TcellWindow) Width() int {
52
+ return w.width
53
+ }
54
+
55
+ func (w *TcellWindow) Height() int {
56
+ return w.height
57
+ }
58
+
59
+ func (w *TcellWindow) Refresh() {
60
+ if w.moveCursor {
61
+ _screen.ShowCursor(w.left+w.lastX, w.top+w.lastY)
62
+ w.moveCursor = false
63
+ }
64
+ w.lastX = 0
65
+ w.lastY = 0
66
+
67
+ w.drawBorder()
68
+ }
69
+
70
+ func (w *TcellWindow) FinishFill() {
71
+ // NO-OP
72
+ }
73
+
74
+ const (
75
+ Bold Attr = Attr(tcell.AttrBold)
76
+ Dim = Attr(tcell.AttrDim)
77
+ Blink = Attr(tcell.AttrBlink)
78
+ Reverse = Attr(tcell.AttrReverse)
79
+ Underline = Attr(tcell.AttrUnderline)
80
+ Italic = Attr(tcell.AttrItalic)
81
+ )
82
+
83
+ const (
84
+ AttrUndefined = Attr(0)
85
+ AttrRegular = Attr(1 << 7)
86
+ AttrClear = Attr(1 << 8)
87
+ )
88
+
89
+ func (r *FullscreenRenderer) defaultTheme() *ColorTheme {
90
+ if _screen.Colors() >= 256 {
91
+ return Dark256
92
+ }
93
+ return Default16
94
+ }
95
+
96
+ var (
97
+ _colorToAttribute = []tcell.Color{
98
+ tcell.ColorBlack,
99
+ tcell.ColorRed,
100
+ tcell.ColorGreen,
101
+ tcell.ColorYellow,
102
+ tcell.ColorBlue,
103
+ tcell.ColorDarkMagenta,
104
+ tcell.ColorLightCyan,
105
+ tcell.ColorWhite,
106
+ }
107
+ )
108
+
109
+ func (c Color) Style() tcell.Color {
110
+ if c <= colDefault {
111
+ return tcell.ColorDefault
112
+ } else if c >= colBlack && c <= colWhite {
113
+ return _colorToAttribute[int(c)]
114
+ } else {
115
+ return tcell.Color(c)
116
+ }
117
+ }
118
+
119
+ func (a Attr) Merge(b Attr) Attr {
120
+ return a | b
121
+ }
122
+
123
+ // handle the following as private members of FullscreenRenderer instance
124
+ // they are declared here to prevent introducing tcell library in non-windows builds
125
+ var (
126
+ _screen tcell.Screen
127
+ _prevMouseButton tcell.ButtonMask
128
+ )
129
+
130
+ func (r *FullscreenRenderer) initScreen() {
131
+ s, e := tcell.NewScreen()
132
+ if e != nil {
133
+ errorExit(e.Error())
134
+ }
135
+ if e = s.Init(); e != nil {
136
+ errorExit(e.Error())
137
+ }
138
+ if r.mouse {
139
+ s.EnableMouse()
140
+ } else {
141
+ s.DisableMouse()
142
+ }
143
+ _screen = s
144
+ }
145
+
146
+ func (r *FullscreenRenderer) Init() {
147
+ if os.Getenv("TERM") == "cygwin" {
148
+ os.Setenv("TERM", "")
149
+ }
150
+ encoding.Register()
151
+
152
+ r.initScreen()
153
+ initTheme(r.theme, r.defaultTheme(), r.forceBlack)
154
+ }
155
+
156
+ func (r *FullscreenRenderer) MaxX() int {
157
+ ncols, _ := _screen.Size()
158
+ return int(ncols)
159
+ }
160
+
161
+ func (r *FullscreenRenderer) MaxY() int {
162
+ _, nlines := _screen.Size()
163
+ return int(nlines)
164
+ }
165
+
166
+ func (w *TcellWindow) X() int {
167
+ return w.lastX
168
+ }
169
+
170
+ func (w *TcellWindow) Y() int {
171
+ return w.lastY
172
+ }
173
+
174
+ func (r *FullscreenRenderer) Clear() {
175
+ _screen.Sync()
176
+ _screen.Clear()
177
+ }
178
+
179
+ func (r *FullscreenRenderer) Refresh() {
180
+ // noop
181
+ }
182
+
183
+ func (r *FullscreenRenderer) GetChar() Event {
184
+ ev := _screen.PollEvent()
185
+ switch ev := ev.(type) {
186
+ case *tcell.EventResize:
187
+ return Event{Resize, 0, nil}
188
+
189
+ // process mouse events:
190
+ case *tcell.EventMouse:
191
+ // mouse down events have zeroed buttons, so we can't use them
192
+ // mouse up event consists of two events, 1. (main) event with modifier and other metadata, 2. event with zeroed buttons
193
+ // so mouse click is three consecutive events, but the first and last are indistinguishable from movement events (with released buttons)
194
+ // dragging has same structure, it only repeats the middle (main) event appropriately
195
+ x, y := ev.Position()
196
+ mod := ev.Modifiers() != 0
197
+
198
+ // since we dont have mouse down events (unlike LightRenderer), we need to track state in prevButton
199
+ prevButton, button := _prevMouseButton, ev.Buttons()
200
+ _prevMouseButton = button
201
+ drag := prevButton == button
202
+
203
+ switch {
204
+ case button&tcell.WheelDown != 0:
205
+ return Event{Mouse, 0, &MouseEvent{y, x, -1, false, false, false, mod}}
206
+ case button&tcell.WheelUp != 0:
207
+ return Event{Mouse, 0, &MouseEvent{y, x, +1, false, false, false, mod}}
208
+ case button&tcell.Button1 != 0 && !drag:
209
+ // all potential double click events put their 'line' coordinate in the clickY array
210
+ // double click event has two conditions, temporal and spatial, the first is checked here
211
+ now := time.Now()
212
+ if now.Sub(r.prevDownTime) < doubleClickDuration {
213
+ r.clickY = append(r.clickY, y)
214
+ } else {
215
+ r.clickY = []int{y}
216
+ }
217
+ r.prevDownTime = now
218
+
219
+ // detect double clicks (also check for spatial condition)
220
+ n := len(r.clickY)
221
+ double := n > 1 && r.clickY[n-2] == r.clickY[n-1]
222
+ if double {
223
+ // make sure two consecutive double clicks require four clicks
224
+ r.clickY = []int{}
225
+ }
226
+
227
+ // fire single or double click event
228
+ return Event{Mouse, 0, &MouseEvent{y, x, 0, true, !double, double, mod}}
229
+ case button&tcell.Button2 != 0 && !drag:
230
+ return Event{Mouse, 0, &MouseEvent{y, x, 0, false, true, false, mod}}
231
+ case runtime.GOOS != "windows":
232
+
233
+ // double and single taps on Windows don't quite work due to
234
+ // the console acting on the events and not allowing us
235
+ // to consume them.
236
+
237
+ left := button&tcell.Button1 != 0
238
+ down := left || button&tcell.Button3 != 0
239
+ double := false
240
+ if down {
241
+ now := time.Now()
242
+ if !left {
243
+ r.clickY = []int{}
244
+ } else if now.Sub(r.prevDownTime) < doubleClickDuration {
245
+ r.clickY = append(r.clickY, x)
246
+ } else {
247
+ r.clickY = []int{x}
248
+ r.prevDownTime = now
249
+ }
250
+ } else {
251
+ if len(r.clickY) > 1 && r.clickY[0] == r.clickY[1] &&
252
+ time.Now().Sub(r.prevDownTime) < doubleClickDuration {
253
+ double = true
254
+ }
255
+ }
256
+
257
+ return Event{Mouse, 0, &MouseEvent{y, x, 0, left, down, double, mod}}
258
+ }
259
+
260
+ // process keyboard:
261
+ case *tcell.EventKey:
262
+ mods := ev.Modifiers()
263
+ none := mods == tcell.ModNone
264
+ alt := (mods & tcell.ModAlt) > 0
265
+ ctrl := (mods & tcell.ModCtrl) > 0
266
+ shift := (mods & tcell.ModShift) > 0
267
+ ctrlAlt := ctrl && alt
268
+ altShift := alt && shift
269
+
270
+ keyfn := func(r rune) Event {
271
+ if alt {
272
+ return CtrlAltKey(r)
273
+ }
274
+ return EventType(CtrlA.Int() - 'a' + int(r)).AsEvent()
275
+ }
276
+ switch ev.Key() {
277
+ // section 1: Ctrl+(Alt)+[a-z]
278
+ case tcell.KeyCtrlA:
279
+ return keyfn('a')
280
+ case tcell.KeyCtrlB:
281
+ return keyfn('b')
282
+ case tcell.KeyCtrlC:
283
+ return keyfn('c')
284
+ case tcell.KeyCtrlD:
285
+ return keyfn('d')
286
+ case tcell.KeyCtrlE:
287
+ return keyfn('e')
288
+ case tcell.KeyCtrlF:
289
+ return keyfn('f')
290
+ case tcell.KeyCtrlG:
291
+ return keyfn('g')
292
+ case tcell.KeyCtrlH:
293
+ switch ev.Rune() {
294
+ case 0:
295
+ if ctrl {
296
+ return Event{BSpace, 0, nil}
297
+ }
298
+ case rune(tcell.KeyCtrlH):
299
+ switch {
300
+ case ctrl:
301
+ return keyfn('h')
302
+ case alt:
303
+ return Event{AltBS, 0, nil}
304
+ case none, shift:
305
+ return Event{BSpace, 0, nil}
306
+ }
307
+ }
308
+ case tcell.KeyCtrlI:
309
+ return keyfn('i')
310
+ case tcell.KeyCtrlJ:
311
+ return keyfn('j')
312
+ case tcell.KeyCtrlK:
313
+ return keyfn('k')
314
+ case tcell.KeyCtrlL:
315
+ return keyfn('l')
316
+ case tcell.KeyCtrlM:
317
+ return keyfn('m')
318
+ case tcell.KeyCtrlN:
319
+ return keyfn('n')
320
+ case tcell.KeyCtrlO:
321
+ return keyfn('o')
322
+ case tcell.KeyCtrlP:
323
+ return keyfn('p')
324
+ case tcell.KeyCtrlQ:
325
+ return keyfn('q')
326
+ case tcell.KeyCtrlR:
327
+ return keyfn('r')
328
+ case tcell.KeyCtrlS:
329
+ return keyfn('s')
330
+ case tcell.KeyCtrlT:
331
+ return keyfn('t')
332
+ case tcell.KeyCtrlU:
333
+ return keyfn('u')
334
+ case tcell.KeyCtrlV:
335
+ return keyfn('v')
336
+ case tcell.KeyCtrlW:
337
+ return keyfn('w')
338
+ case tcell.KeyCtrlX:
339
+ return keyfn('x')
340
+ case tcell.KeyCtrlY:
341
+ return keyfn('y')
342
+ case tcell.KeyCtrlZ:
343
+ return keyfn('z')
344
+ // section 2: Ctrl+[ \]_]
345
+ case tcell.KeyCtrlSpace:
346
+ return Event{CtrlSpace, 0, nil}
347
+ case tcell.KeyCtrlBackslash:
348
+ return Event{CtrlBackSlash, 0, nil}
349
+ case tcell.KeyCtrlRightSq:
350
+ return Event{CtrlRightBracket, 0, nil}
351
+ case tcell.KeyCtrlCarat:
352
+ return Event{CtrlCaret, 0, nil}
353
+ case tcell.KeyCtrlUnderscore:
354
+ return Event{CtrlSlash, 0, nil}
355
+ // section 3: (Alt)+Backspace2
356
+ case tcell.KeyBackspace2:
357
+ if alt {
358
+ return Event{AltBS, 0, nil}
359
+ }
360
+ return Event{BSpace, 0, nil}
361
+
362
+ // section 4: (Alt+Shift)+Key(Up|Down|Left|Right)
363
+ case tcell.KeyUp:
364
+ if altShift {
365
+ return Event{AltSUp, 0, nil}
366
+ }
367
+ if shift {
368
+ return Event{SUp, 0, nil}
369
+ }
370
+ if alt {
371
+ return Event{AltUp, 0, nil}
372
+ }
373
+ return Event{Up, 0, nil}
374
+ case tcell.KeyDown:
375
+ if altShift {
376
+ return Event{AltSDown, 0, nil}
377
+ }
378
+ if shift {
379
+ return Event{SDown, 0, nil}
380
+ }
381
+ if alt {
382
+ return Event{AltDown, 0, nil}
383
+ }
384
+ return Event{Down, 0, nil}
385
+ case tcell.KeyLeft:
386
+ if altShift {
387
+ return Event{AltSLeft, 0, nil}
388
+ }
389
+ if shift {
390
+ return Event{SLeft, 0, nil}
391
+ }
392
+ if alt {
393
+ return Event{AltLeft, 0, nil}
394
+ }
395
+ return Event{Left, 0, nil}
396
+ case tcell.KeyRight:
397
+ if altShift {
398
+ return Event{AltSRight, 0, nil}
399
+ }
400
+ if shift {
401
+ return Event{SRight, 0, nil}
402
+ }
403
+ if alt {
404
+ return Event{AltRight, 0, nil}
405
+ }
406
+ return Event{Right, 0, nil}
407
+
408
+ // section 5: (Insert|Home|Delete|End|PgUp|PgDn|BackTab|F1-F12)
409
+ case tcell.KeyInsert:
410
+ return Event{Insert, 0, nil}
411
+ case tcell.KeyHome:
412
+ return Event{Home, 0, nil}
413
+ case tcell.KeyDelete:
414
+ return Event{Del, 0, nil}
415
+ case tcell.KeyEnd:
416
+ return Event{End, 0, nil}
417
+ case tcell.KeyPgUp:
418
+ return Event{PgUp, 0, nil}
419
+ case tcell.KeyPgDn:
420
+ return Event{PgDn, 0, nil}
421
+ case tcell.KeyBacktab:
422
+ return Event{BTab, 0, nil}
423
+ case tcell.KeyF1:
424
+ return Event{F1, 0, nil}
425
+ case tcell.KeyF2:
426
+ return Event{F2, 0, nil}
427
+ case tcell.KeyF3:
428
+ return Event{F3, 0, nil}
429
+ case tcell.KeyF4:
430
+ return Event{F4, 0, nil}
431
+ case tcell.KeyF5:
432
+ return Event{F5, 0, nil}
433
+ case tcell.KeyF6:
434
+ return Event{F6, 0, nil}
435
+ case tcell.KeyF7:
436
+ return Event{F7, 0, nil}
437
+ case tcell.KeyF8:
438
+ return Event{F8, 0, nil}
439
+ case tcell.KeyF9:
440
+ return Event{F9, 0, nil}
441
+ case tcell.KeyF10:
442
+ return Event{F10, 0, nil}
443
+ case tcell.KeyF11:
444
+ return Event{F11, 0, nil}
445
+ case tcell.KeyF12:
446
+ return Event{F12, 0, nil}
447
+
448
+ // section 6: (Ctrl+Alt)+'rune'
449
+ case tcell.KeyRune:
450
+ r := ev.Rune()
451
+
452
+ switch {
453
+ // translate native key events to ascii control characters
454
+ case r == ' ' && ctrl:
455
+ return Event{CtrlSpace, 0, nil}
456
+ // handle AltGr characters
457
+ case ctrlAlt:
458
+ return Event{Rune, r, nil} // dropping modifiers
459
+ // simple characters (possibly with modifier)
460
+ case alt:
461
+ return AltKey(r)
462
+ default:
463
+ return Event{Rune, r, nil}
464
+ }
465
+
466
+ // section 7: Esc
467
+ case tcell.KeyEsc:
468
+ return Event{ESC, 0, nil}
469
+ }
470
+ }
471
+
472
+ // section 8: Invalid
473
+ return Event{Invalid, 0, nil}
474
+ }
475
+
476
+ func (r *FullscreenRenderer) Pause(clear bool) {
477
+ if clear {
478
+ _screen.Fini()
479
+ }
480
+ }
481
+
482
+ func (r *FullscreenRenderer) Resume(clear bool, sigcont bool) {
483
+ if clear {
484
+ r.initScreen()
485
+ }
486
+ }
487
+
488
+ func (r *FullscreenRenderer) Close() {
489
+ _screen.Fini()
490
+ }
491
+
492
+ func (r *FullscreenRenderer) RefreshWindows(windows []Window) {
493
+ // TODO
494
+ for _, w := range windows {
495
+ w.Refresh()
496
+ }
497
+ _screen.Show()
498
+ }
499
+
500
+ func (r *FullscreenRenderer) NewWindow(top int, left int, width int, height int, preview bool, borderStyle BorderStyle) Window {
501
+ normal := ColNormal
502
+ if preview {
503
+ normal = ColPreview
504
+ }
505
+ return &TcellWindow{
506
+ color: r.theme.Colored,
507
+ preview: preview,
508
+ top: top,
509
+ left: left,
510
+ width: width,
511
+ height: height,
512
+ normal: normal,
513
+ borderStyle: borderStyle}
514
+ }
515
+
516
+ func (w *TcellWindow) Close() {
517
+ // TODO
518
+ }
519
+
520
+ func fill(x, y, w, h int, n ColorPair, r rune) {
521
+ for ly := 0; ly <= h; ly++ {
522
+ for lx := 0; lx <= w; lx++ {
523
+ _screen.SetContent(x+lx, y+ly, r, nil, n.style())
524
+ }
525
+ }
526
+ }
527
+
528
+ func (w *TcellWindow) Erase() {
529
+ fill(w.left-1, w.top, w.width+1, w.height, w.normal, ' ')
530
+ }
531
+
532
+ func (w *TcellWindow) Enclose(y int, x int) bool {
533
+ return x >= w.left && x < (w.left+w.width) &&
534
+ y >= w.top && y < (w.top+w.height)
535
+ }
536
+
537
+ func (w *TcellWindow) Move(y int, x int) {
538
+ w.lastX = x
539
+ w.lastY = y
540
+ w.moveCursor = true
541
+ }
542
+
543
+ func (w *TcellWindow) MoveAndClear(y int, x int) {
544
+ w.Move(y, x)
545
+ for i := w.lastX; i < w.width; i++ {
546
+ _screen.SetContent(i+w.left, w.lastY+w.top, rune(' '), nil, w.normal.style())
547
+ }
548
+ w.lastX = x
549
+ }
550
+
551
+ func (w *TcellWindow) Print(text string) {
552
+ w.printString(text, w.normal)
553
+ }
554
+
555
+ func (w *TcellWindow) printString(text string, pair ColorPair) {
556
+ lx := 0
557
+ a := pair.Attr()
558
+
559
+ style := pair.style()
560
+ if a&AttrClear == 0 {
561
+ style = style.
562
+ Reverse(a&Attr(tcell.AttrReverse) != 0).
563
+ Underline(a&Attr(tcell.AttrUnderline) != 0).
564
+ Italic(a&Attr(tcell.AttrItalic) != 0).
565
+ Blink(a&Attr(tcell.AttrBlink) != 0).
566
+ Dim(a&Attr(tcell.AttrDim) != 0)
567
+ }
568
+
569
+ gr := uniseg.NewGraphemes(text)
570
+ for gr.Next() {
571
+ rs := gr.Runes()
572
+
573
+ if len(rs) == 1 {
574
+ r := rs[0]
575
+ if r < rune(' ') { // ignore control characters
576
+ continue
577
+ } else if r == '\n' {
578
+ w.lastY++
579
+ lx = 0
580
+ continue
581
+ } else if r == '\u000D' { // skip carriage return
582
+ continue
583
+ }
584
+ }
585
+ var xPos = w.left + w.lastX + lx
586
+ var yPos = w.top + w.lastY
587
+ if xPos < (w.left+w.width) && yPos < (w.top+w.height) {
588
+ _screen.SetContent(xPos, yPos, rs[0], rs[1:], style)
589
+ }
590
+ lx += runewidth.StringWidth(string(rs))
591
+ }
592
+ w.lastX += lx
593
+ }
594
+
595
+ func (w *TcellWindow) CPrint(pair ColorPair, text string) {
596
+ w.printString(text, pair)
597
+ }
598
+
599
+ func (w *TcellWindow) fillString(text string, pair ColorPair) FillReturn {
600
+ lx := 0
601
+ a := pair.Attr()
602
+
603
+ var style tcell.Style
604
+ if w.color {
605
+ style = pair.style()
606
+ } else {
607
+ style = w.normal.style()
608
+ }
609
+ style = style.
610
+ Blink(a&Attr(tcell.AttrBlink) != 0).
611
+ Bold(a&Attr(tcell.AttrBold) != 0).
612
+ Dim(a&Attr(tcell.AttrDim) != 0).
613
+ Reverse(a&Attr(tcell.AttrReverse) != 0).
614
+ Underline(a&Attr(tcell.AttrUnderline) != 0).
615
+ Italic(a&Attr(tcell.AttrItalic) != 0)
616
+
617
+ gr := uniseg.NewGraphemes(text)
618
+ for gr.Next() {
619
+ rs := gr.Runes()
620
+ if len(rs) == 1 && rs[0] == '\n' {
621
+ w.lastY++
622
+ w.lastX = 0
623
+ lx = 0
624
+ continue
625
+ }
626
+
627
+ // word wrap:
628
+ xPos := w.left + w.lastX + lx
629
+ if xPos >= (w.left + w.width) {
630
+ w.lastY++
631
+ w.lastX = 0
632
+ lx = 0
633
+ xPos = w.left
634
+ }
635
+
636
+ yPos := w.top + w.lastY
637
+ if yPos >= (w.top + w.height) {
638
+ return FillSuspend
639
+ }
640
+
641
+ _screen.SetContent(xPos, yPos, rs[0], rs[1:], style)
642
+ lx += runewidth.StringWidth(string(rs))
643
+ }
644
+ w.lastX += lx
645
+ if w.lastX == w.width {
646
+ w.lastY++
647
+ w.lastX = 0
648
+ return FillNextLine
649
+ }
650
+
651
+ return FillContinue
652
+ }
653
+
654
+ func (w *TcellWindow) Fill(str string) FillReturn {
655
+ return w.fillString(str, w.normal)
656
+ }
657
+
658
+ func (w *TcellWindow) CFill(fg Color, bg Color, a Attr, str string) FillReturn {
659
+ if fg == colDefault {
660
+ fg = w.normal.Fg()
661
+ }
662
+ if bg == colDefault {
663
+ bg = w.normal.Bg()
664
+ }
665
+ return w.fillString(str, NewColorPair(fg, bg, a))
666
+ }
667
+
668
+ func (w *TcellWindow) drawBorder() {
669
+ shape := w.borderStyle.shape
670
+ if shape == BorderNone {
671
+ return
672
+ }
673
+
674
+ left := w.left
675
+ right := left + w.width
676
+ top := w.top
677
+ bot := top + w.height
678
+
679
+ var style tcell.Style
680
+ if w.color {
681
+ if w.preview {
682
+ style = ColPreviewBorder.style()
683
+ } else {
684
+ style = ColBorder.style()
685
+ }
686
+ } else {
687
+ style = w.normal.style()
688
+ }
689
+
690
+ switch shape {
691
+ case BorderRounded, BorderSharp, BorderHorizontal, BorderTop:
692
+ for x := left; x < right; x++ {
693
+ _screen.SetContent(x, top, w.borderStyle.horizontal, nil, style)
694
+ }
695
+ }
696
+ switch shape {
697
+ case BorderRounded, BorderSharp, BorderHorizontal, BorderBottom:
698
+ for x := left; x < right; x++ {
699
+ _screen.SetContent(x, bot-1, w.borderStyle.horizontal, nil, style)
700
+ }
701
+ }
702
+ switch shape {
703
+ case BorderRounded, BorderSharp, BorderVertical, BorderLeft:
704
+ for y := top; y < bot; y++ {
705
+ _screen.SetContent(left, y, w.borderStyle.vertical, nil, style)
706
+ }
707
+ }
708
+ switch shape {
709
+ case BorderRounded, BorderSharp, BorderVertical, BorderRight:
710
+ for y := top; y < bot; y++ {
711
+ _screen.SetContent(right-1, y, w.borderStyle.vertical, nil, style)
712
+ }
713
+ }
714
+ switch shape {
715
+ case BorderRounded, BorderSharp:
716
+ _screen.SetContent(left, top, w.borderStyle.topLeft, nil, style)
717
+ _screen.SetContent(right-1, top, w.borderStyle.topRight, nil, style)
718
+ _screen.SetContent(left, bot-1, w.borderStyle.bottomLeft, nil, style)
719
+ _screen.SetContent(right-1, bot-1, w.borderStyle.bottomRight, nil, style)
720
+ }
721
+ }