Use fuzzy search when filtering a view

This adds fuzzy filtering instead of exact match filtering, which is more forgiving of typos
and allows more efficiency.
This commit is contained in:
Jesse Duffield
2023-07-22 13:04:39 +10:00
parent 084c0a19bc
commit b46623ebef
4 changed files with 64 additions and 12 deletions

View File

@@ -1,7 +1,11 @@
package context
import (
"strings"
"github.com/jesseduffield/lazygit/pkg/utils"
"github.com/sahilm/fuzzy"
"github.com/samber/lo"
"github.com/sasha-s/go-deadlock"
)
@@ -53,6 +57,21 @@ func (self *FilteredList[T]) UnfilteredLen() int {
return len(self.getList())
}
type fuzzySource[T any] struct {
list []T
getFilterFields func(T) []string
}
var _ fuzzy.Source = &fuzzySource[string]{}
func (self *fuzzySource[T]) String(i int) string {
return strings.Join(self.getFilterFields(self.list[i]), " ")
}
func (self *fuzzySource[T]) Len() int {
return len(self.list)
}
func (self *FilteredList[T]) applyFilter() {
self.mutex.Lock()
defer self.mutex.Unlock()
@@ -60,20 +79,16 @@ func (self *FilteredList[T]) applyFilter() {
if self.filter == "" {
self.filteredIndices = nil
} else {
self.filteredIndices = []int{}
for i, item := range self.getList() {
for _, field := range self.getFilterFields(item) {
if self.match(field, self.filter) {
self.filteredIndices = append(self.filteredIndices, i)
break
}
}
source := &fuzzySource[T]{
list: self.getList(),
getFilterFields: self.getFilterFields,
}
}
}
func (self *FilteredList[T]) match(haystack string, needle string) bool {
return utils.CaseAwareContains(haystack, needle)
matches := fuzzy.FindFrom(self.filter, source)
self.filteredIndices = lo.Map(matches, func(match fuzzy.Match, _ int) int {
return match.Index
})
}
}
func (self *FilteredList[T]) UnfilteredIndex(index int) int {