Skip to content

Commit

Permalink
Use fuzzy search when filtering a view
Browse files Browse the repository at this point in the history
This adds fuzzy filtering instead of exact match filtering, which is more forgiving of typos
and allows more efficiency.
  • Loading branch information
jesseduffield committed Jul 22, 2023
1 parent 084c0a1 commit d22ff9a
Showing 1 changed file with 27 additions and 12 deletions.
39 changes: 27 additions & 12 deletions pkg/gui/context/filtered_list.go
Original file line number Diff line number Diff line change
@@ -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"
)

Expand Down Expand Up @@ -53,27 +57,38 @@ 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()

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 {
Expand Down

0 comments on commit d22ff9a

Please sign in to comment.