Skip to content

Commit

Permalink
Use fuzzy search when filtering a view (#2808)
Browse files Browse the repository at this point in the history
  • Loading branch information
jesseduffield committed Jul 22, 2023
2 parents 084c0a1 + b46623e commit b284970
Show file tree
Hide file tree
Showing 4 changed files with 64 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
1 change: 1 addition & 0 deletions pkg/integration/components/view_driver.go
Original file line number Diff line number Diff line change
Expand Up @@ -539,6 +539,7 @@ func (self *ViewDriver) FilterOrSearch(text string) *ViewDriver {
self.Press(self.t.keys.Universal.StartSearch).
Tap(func() {
self.t.ExpectSearch().
Clear().
Type(text).
Confirm()

Expand Down
35 changes: 35 additions & 0 deletions pkg/integration/tests/filter_and_search/filter_fuzzy.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package filter_and_search

import (
"github.com/jesseduffield/lazygit/pkg/config"
. "github.com/jesseduffield/lazygit/pkg/integration/components"
)

var FilterFuzzy = NewIntegrationTest(NewIntegrationTestArgs{
Description: "Verify that fuzzy filtering works (not just exact matches)",
ExtraCmdArgs: []string{},
Skip: false,
SetupConfig: func(config *config.AppConfig) {},
SetupRepo: func(shell *Shell) {
shell.NewBranch("this-is-my-branch")
shell.EmptyCommit("first commit")
shell.NewBranch("other-branch")
},
Run: func(t *TestDriver, keys config.KeybindingConfig) {
t.Views().Branches().
Focus().
Lines(
Contains(`other-branch`).IsSelected(),
Contains(`this-is-my-branch`),
).
FilterOrSearch("timb"). // using first letters of words
Lines(
Contains(`this-is-my-branch`).IsSelected(),
).
FilterOrSearch("brnch"). // allows missing letter
Lines(
Contains(`other-branch`).IsSelected(),
Contains(`this-is-my-branch`),
)
},
})
1 change: 1 addition & 0 deletions pkg/integration/tests/test_list.go
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@ var tests = []*components.IntegrationTest{
file.RememberCommitMessageAfterFail,
filter_and_search.FilterCommitFiles,
filter_and_search.FilterFiles,
filter_and_search.FilterFuzzy,
filter_and_search.FilterMenu,
filter_and_search.FilterRemoteBranches,
filter_and_search.NestedFilter,
Expand Down

0 comments on commit b284970

Please sign in to comment.