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, ok := slices.BinarySearchFunc(s.keys, k, func(a, b util.Chars) int { return bytes.Compare(a.Bytes(), b.Bytes()) }) if ok { s.vals[i] = val return } 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") })