57 lines
1.3 KiB
Go
57 lines
1.3 KiB
Go
package autocomplete
|
|
|
|
import (
|
|
"bytes"
|
|
"cmp"
|
|
"slices"
|
|
"sync"
|
|
|
|
"github.com/junegunn/fzf/src/algo"
|
|
"github.com/junegunn/fzf/src/util"
|
|
)
|
|
|
|
// Set is an autocomplete set.
|
|
type Set[V any] struct {
|
|
keys []util.Chars
|
|
vals []V
|
|
}
|
|
|
|
// Add associates a value with a key in the autocomplete set.
|
|
// The behavior is undefined if the key already has a value.
|
|
func (s *Set[V]) Add(key string, val V) {
|
|
k := util.ToChars([]byte(key))
|
|
i, _ := slices.BinarySearchFunc(s.keys, k, func(a, b util.Chars) int {
|
|
return bytes.Compare(a.Bytes(), b.Bytes())
|
|
})
|
|
s.keys = slices.Insert(s.keys, i, k)
|
|
s.vals = slices.Insert(s.vals, i, val)
|
|
}
|
|
|
|
// Find appends to r all values in the set with keys that key matches.
|
|
func (s *Set[V]) Find(r []V, key string) []V {
|
|
initFzf()
|
|
var (
|
|
p = []rune(key)
|
|
|
|
got []V
|
|
t []algo.Result
|
|
slab util.Slab
|
|
)
|
|
for i := range s.keys {
|
|
res, _ := algo.FuzzyMatchV2(false, true, true, &s.keys[i], p, false, &slab)
|
|
if res.Score <= 0 {
|
|
continue
|
|
}
|
|
j, _ := slices.BinarySearchFunc(t, res, func(a, b algo.Result) int { return -cmp.Compare(a.Score, b.Score) })
|
|
// Insert after all other matches with the same score for stability.
|
|
for j < len(t) && t[j].Score == res.Score {
|
|
j++
|
|
}
|
|
t = slices.Insert(t, j, res)
|
|
got = slices.Insert(got, j, s.vals[i])
|
|
}
|
|
return append(r, got...)
|
|
}
|
|
|
|
var initFzf = sync.OnceFunc(func() { algo.Init("default") })
|