doing 2.0.20 → 2.0.21

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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,235 @@
1
+ package fzf
2
+
3
+ import (
4
+ "fmt"
5
+ "runtime"
6
+ "sort"
7
+ "sync"
8
+ "time"
9
+
10
+ "github.com/junegunn/fzf/src/util"
11
+ )
12
+
13
+ // MatchRequest represents a search request
14
+ type MatchRequest struct {
15
+ chunks []*Chunk
16
+ pattern *Pattern
17
+ final bool
18
+ sort bool
19
+ clearCache bool
20
+ }
21
+
22
+ // Matcher is responsible for performing search
23
+ type Matcher struct {
24
+ patternBuilder func([]rune) *Pattern
25
+ sort bool
26
+ tac bool
27
+ eventBox *util.EventBox
28
+ reqBox *util.EventBox
29
+ partitions int
30
+ slab []*util.Slab
31
+ mergerCache map[string]*Merger
32
+ }
33
+
34
+ const (
35
+ reqRetry util.EventType = iota
36
+ reqReset
37
+ )
38
+
39
+ // NewMatcher returns a new Matcher
40
+ func NewMatcher(patternBuilder func([]rune) *Pattern,
41
+ sort bool, tac bool, eventBox *util.EventBox) *Matcher {
42
+ partitions := util.Min(numPartitionsMultiplier*runtime.NumCPU(), maxPartitions)
43
+ return &Matcher{
44
+ patternBuilder: patternBuilder,
45
+ sort: sort,
46
+ tac: tac,
47
+ eventBox: eventBox,
48
+ reqBox: util.NewEventBox(),
49
+ partitions: partitions,
50
+ slab: make([]*util.Slab, partitions),
51
+ mergerCache: make(map[string]*Merger)}
52
+ }
53
+
54
+ // Loop puts Matcher in action
55
+ func (m *Matcher) Loop() {
56
+ prevCount := 0
57
+
58
+ for {
59
+ var request MatchRequest
60
+
61
+ m.reqBox.Wait(func(events *util.Events) {
62
+ for _, val := range *events {
63
+ switch val := val.(type) {
64
+ case MatchRequest:
65
+ request = val
66
+ default:
67
+ panic(fmt.Sprintf("Unexpected type: %T", val))
68
+ }
69
+ }
70
+ events.Clear()
71
+ })
72
+
73
+ if request.sort != m.sort || request.clearCache {
74
+ m.sort = request.sort
75
+ m.mergerCache = make(map[string]*Merger)
76
+ clearChunkCache()
77
+ }
78
+
79
+ // Restart search
80
+ patternString := request.pattern.AsString()
81
+ var merger *Merger
82
+ cancelled := false
83
+ count := CountItems(request.chunks)
84
+
85
+ foundCache := false
86
+ if count == prevCount {
87
+ // Look up mergerCache
88
+ if cached, found := m.mergerCache[patternString]; found {
89
+ foundCache = true
90
+ merger = cached
91
+ }
92
+ } else {
93
+ // Invalidate mergerCache
94
+ prevCount = count
95
+ m.mergerCache = make(map[string]*Merger)
96
+ }
97
+
98
+ if !foundCache {
99
+ merger, cancelled = m.scan(request)
100
+ }
101
+
102
+ if !cancelled {
103
+ if merger.cacheable() {
104
+ m.mergerCache[patternString] = merger
105
+ }
106
+ merger.final = request.final
107
+ m.eventBox.Set(EvtSearchFin, merger)
108
+ }
109
+ }
110
+ }
111
+
112
+ func (m *Matcher) sliceChunks(chunks []*Chunk) [][]*Chunk {
113
+ partitions := m.partitions
114
+ perSlice := len(chunks) / partitions
115
+
116
+ if perSlice == 0 {
117
+ partitions = len(chunks)
118
+ perSlice = 1
119
+ }
120
+
121
+ slices := make([][]*Chunk, partitions)
122
+ for i := 0; i < partitions; i++ {
123
+ start := i * perSlice
124
+ end := start + perSlice
125
+ if i == partitions-1 {
126
+ end = len(chunks)
127
+ }
128
+ slices[i] = chunks[start:end]
129
+ }
130
+ return slices
131
+ }
132
+
133
+ type partialResult struct {
134
+ index int
135
+ matches []Result
136
+ }
137
+
138
+ func (m *Matcher) scan(request MatchRequest) (*Merger, bool) {
139
+ startedAt := time.Now()
140
+
141
+ numChunks := len(request.chunks)
142
+ if numChunks == 0 {
143
+ return EmptyMerger, false
144
+ }
145
+ pattern := request.pattern
146
+ if pattern.IsEmpty() {
147
+ return PassMerger(&request.chunks, m.tac), false
148
+ }
149
+
150
+ cancelled := util.NewAtomicBool(false)
151
+
152
+ slices := m.sliceChunks(request.chunks)
153
+ numSlices := len(slices)
154
+ resultChan := make(chan partialResult, numSlices)
155
+ countChan := make(chan int, numChunks)
156
+ waitGroup := sync.WaitGroup{}
157
+
158
+ for idx, chunks := range slices {
159
+ waitGroup.Add(1)
160
+ if m.slab[idx] == nil {
161
+ m.slab[idx] = util.MakeSlab(slab16Size, slab32Size)
162
+ }
163
+ go func(idx int, slab *util.Slab, chunks []*Chunk) {
164
+ defer func() { waitGroup.Done() }()
165
+ count := 0
166
+ allMatches := make([][]Result, len(chunks))
167
+ for idx, chunk := range chunks {
168
+ matches := request.pattern.Match(chunk, slab)
169
+ allMatches[idx] = matches
170
+ count += len(matches)
171
+ if cancelled.Get() {
172
+ return
173
+ }
174
+ countChan <- len(matches)
175
+ }
176
+ sliceMatches := make([]Result, 0, count)
177
+ for _, matches := range allMatches {
178
+ sliceMatches = append(sliceMatches, matches...)
179
+ }
180
+ if m.sort {
181
+ if m.tac {
182
+ sort.Sort(ByRelevanceTac(sliceMatches))
183
+ } else {
184
+ sort.Sort(ByRelevance(sliceMatches))
185
+ }
186
+ }
187
+ resultChan <- partialResult{idx, sliceMatches}
188
+ }(idx, m.slab[idx], chunks)
189
+ }
190
+
191
+ wait := func() bool {
192
+ cancelled.Set(true)
193
+ waitGroup.Wait()
194
+ return true
195
+ }
196
+
197
+ count := 0
198
+ matchCount := 0
199
+ for matchesInChunk := range countChan {
200
+ count++
201
+ matchCount += matchesInChunk
202
+
203
+ if count == numChunks {
204
+ break
205
+ }
206
+
207
+ if m.reqBox.Peek(reqReset) {
208
+ return nil, wait()
209
+ }
210
+
211
+ if time.Since(startedAt) > progressMinDuration {
212
+ m.eventBox.Set(EvtSearchProgress, float32(count)/float32(numChunks))
213
+ }
214
+ }
215
+
216
+ partialResults := make([][]Result, numSlices)
217
+ for range slices {
218
+ partialResult := <-resultChan
219
+ partialResults[partialResult.index] = partialResult.matches
220
+ }
221
+ return NewMerger(pattern, partialResults, m.sort, m.tac), false
222
+ }
223
+
224
+ // Reset is called to interrupt/signal the ongoing search
225
+ func (m *Matcher) Reset(chunks []*Chunk, patternRunes []rune, cancel bool, final bool, sort bool, clearCache bool) {
226
+ pattern := m.patternBuilder(patternRunes)
227
+
228
+ var event util.EventType
229
+ if cancel {
230
+ event = reqReset
231
+ } else {
232
+ event = reqRetry
233
+ }
234
+ m.reqBox.Set(event, MatchRequest{chunks, pattern, final, sort && pattern.sortable, clearCache})
235
+ }
@@ -0,0 +1,120 @@
1
+ package fzf
2
+
3
+ import "fmt"
4
+
5
+ // EmptyMerger is a Merger with no data
6
+ var EmptyMerger = NewMerger(nil, [][]Result{}, false, false)
7
+
8
+ // Merger holds a set of locally sorted lists of items and provides the view of
9
+ // a single, globally-sorted list
10
+ type Merger struct {
11
+ pattern *Pattern
12
+ lists [][]Result
13
+ merged []Result
14
+ chunks *[]*Chunk
15
+ cursors []int
16
+ sorted bool
17
+ tac bool
18
+ final bool
19
+ count int
20
+ }
21
+
22
+ // PassMerger returns a new Merger that simply returns the items in the
23
+ // original order
24
+ func PassMerger(chunks *[]*Chunk, tac bool) *Merger {
25
+ mg := Merger{
26
+ pattern: nil,
27
+ chunks: chunks,
28
+ tac: tac,
29
+ count: 0}
30
+
31
+ for _, chunk := range *mg.chunks {
32
+ mg.count += chunk.count
33
+ }
34
+ return &mg
35
+ }
36
+
37
+ // NewMerger returns a new Merger
38
+ func NewMerger(pattern *Pattern, lists [][]Result, sorted bool, tac bool) *Merger {
39
+ mg := Merger{
40
+ pattern: pattern,
41
+ lists: lists,
42
+ merged: []Result{},
43
+ chunks: nil,
44
+ cursors: make([]int, len(lists)),
45
+ sorted: sorted,
46
+ tac: tac,
47
+ final: false,
48
+ count: 0}
49
+
50
+ for _, list := range mg.lists {
51
+ mg.count += len(list)
52
+ }
53
+ return &mg
54
+ }
55
+
56
+ // Length returns the number of items
57
+ func (mg *Merger) Length() int {
58
+ return mg.count
59
+ }
60
+
61
+ // Get returns the pointer to the Result object indexed by the given integer
62
+ func (mg *Merger) Get(idx int) Result {
63
+ if mg.chunks != nil {
64
+ if mg.tac {
65
+ idx = mg.count - idx - 1
66
+ }
67
+ chunk := (*mg.chunks)[idx/chunkSize]
68
+ return Result{item: &chunk.items[idx%chunkSize]}
69
+ }
70
+
71
+ if mg.sorted {
72
+ return mg.mergedGet(idx)
73
+ }
74
+
75
+ if mg.tac {
76
+ idx = mg.count - idx - 1
77
+ }
78
+ for _, list := range mg.lists {
79
+ numItems := len(list)
80
+ if idx < numItems {
81
+ return list[idx]
82
+ }
83
+ idx -= numItems
84
+ }
85
+ panic(fmt.Sprintf("Index out of bounds (unsorted, %d/%d)", idx, mg.count))
86
+ }
87
+
88
+ func (mg *Merger) cacheable() bool {
89
+ return mg.count < mergerCacheMax
90
+ }
91
+
92
+ func (mg *Merger) mergedGet(idx int) Result {
93
+ for i := len(mg.merged); i <= idx; i++ {
94
+ minRank := minRank()
95
+ minIdx := -1
96
+ for listIdx, list := range mg.lists {
97
+ cursor := mg.cursors[listIdx]
98
+ if cursor < 0 || cursor == len(list) {
99
+ mg.cursors[listIdx] = -1
100
+ continue
101
+ }
102
+ if cursor >= 0 {
103
+ rank := list[cursor]
104
+ if minIdx < 0 || compareRanks(rank, minRank, mg.tac) {
105
+ minRank = rank
106
+ minIdx = listIdx
107
+ }
108
+ }
109
+ }
110
+
111
+ if minIdx >= 0 {
112
+ chosen := mg.lists[minIdx]
113
+ mg.merged = append(mg.merged, chosen[mg.cursors[minIdx]])
114
+ mg.cursors[minIdx]++
115
+ } else {
116
+ panic(fmt.Sprintf("Index out of bounds (sorted, %d/%d)", i, mg.count))
117
+ }
118
+ }
119
+ return mg.merged[idx]
120
+ }
@@ -0,0 +1,88 @@
1
+ package fzf
2
+
3
+ import (
4
+ "fmt"
5
+ "math/rand"
6
+ "sort"
7
+ "testing"
8
+
9
+ "github.com/junegunn/fzf/src/util"
10
+ )
11
+
12
+ func assert(t *testing.T, cond bool, msg ...string) {
13
+ if !cond {
14
+ t.Error(msg)
15
+ }
16
+ }
17
+
18
+ func randResult() Result {
19
+ str := fmt.Sprintf("%d", rand.Uint32())
20
+ chars := util.ToChars([]byte(str))
21
+ chars.Index = rand.Int31()
22
+ return Result{item: &Item{text: chars}}
23
+ }
24
+
25
+ func TestEmptyMerger(t *testing.T) {
26
+ assert(t, EmptyMerger.Length() == 0, "Not empty")
27
+ assert(t, EmptyMerger.count == 0, "Invalid count")
28
+ assert(t, len(EmptyMerger.lists) == 0, "Invalid lists")
29
+ assert(t, len(EmptyMerger.merged) == 0, "Invalid merged list")
30
+ }
31
+
32
+ func buildLists(partiallySorted bool) ([][]Result, []Result) {
33
+ numLists := 4
34
+ lists := make([][]Result, numLists)
35
+ cnt := 0
36
+ for i := 0; i < numLists; i++ {
37
+ numResults := rand.Int() % 20
38
+ cnt += numResults
39
+ lists[i] = make([]Result, numResults)
40
+ for j := 0; j < numResults; j++ {
41
+ item := randResult()
42
+ lists[i][j] = item
43
+ }
44
+ if partiallySorted {
45
+ sort.Sort(ByRelevance(lists[i]))
46
+ }
47
+ }
48
+ items := []Result{}
49
+ for _, list := range lists {
50
+ items = append(items, list...)
51
+ }
52
+ return lists, items
53
+ }
54
+
55
+ func TestMergerUnsorted(t *testing.T) {
56
+ lists, items := buildLists(false)
57
+ cnt := len(items)
58
+
59
+ // Not sorted: same order
60
+ mg := NewMerger(nil, lists, false, false)
61
+ assert(t, cnt == mg.Length(), "Invalid Length")
62
+ for i := 0; i < cnt; i++ {
63
+ assert(t, items[i] == mg.Get(i), "Invalid Get")
64
+ }
65
+ }
66
+
67
+ func TestMergerSorted(t *testing.T) {
68
+ lists, items := buildLists(true)
69
+ cnt := len(items)
70
+
71
+ // Sorted sorted order
72
+ mg := NewMerger(nil, lists, true, false)
73
+ assert(t, cnt == mg.Length(), "Invalid Length")
74
+ sort.Sort(ByRelevance(items))
75
+ for i := 0; i < cnt; i++ {
76
+ if items[i] != mg.Get(i) {
77
+ t.Error("Not sorted", items[i], mg.Get(i))
78
+ }
79
+ }
80
+
81
+ // Inverse order
82
+ mg2 := NewMerger(nil, lists, true, false)
83
+ for i := cnt - 1; i >= 0; i-- {
84
+ if items[i] != mg2.Get(i) {
85
+ t.Error("Not sorted", items[i], mg2.Get(i))
86
+ }
87
+ }
88
+ }