From bf5871cc4fe8bd7f431e5603447ea0bc29b3d642 Mon Sep 17 00:00:00 2001 From: Jesse Duffield Date: Sat, 27 May 2023 20:38:37 +1000 Subject: [PATCH] Case insensitive string comparison --- pkg/gui/context/filtered_list.go | 12 +++- pkg/gui/context/working_tree_context.go | 1 - pkg/utils/fuzzy_search_test.go | 53 ---------------- pkg/utils/{fuzzy_search.go => search.go} | 8 +++ pkg/utils/search_test.go | 80 ++++++++++++++++++++++++ 5 files changed, 97 insertions(+), 57 deletions(-) delete mode 100644 pkg/utils/fuzzy_search_test.go rename pkg/utils/{fuzzy_search.go => search.go} (72%) create mode 100644 pkg/utils/search_test.go diff --git a/pkg/gui/context/filtered_list.go b/pkg/gui/context/filtered_list.go index 5a7257388..b848b96d4 100644 --- a/pkg/gui/context/filtered_list.go +++ b/pkg/gui/context/filtered_list.go @@ -1,8 +1,6 @@ package context import ( - "strings" - "github.com/jesseduffield/lazygit/pkg/utils" ) @@ -35,6 +33,10 @@ func (self *FilteredList[T]) ClearFilter() { self.SetFilter("") } +func (self *FilteredList[T]) IsFiltering() bool { + return self.filter != "" +} + func (self *FilteredList[T]) GetFilteredList() []T { if self.filteredIndices == nil { return self.getList() @@ -54,7 +56,7 @@ func (self *FilteredList[T]) applyFilter() { self.filteredIndices = []int{} for i, item := range self.getList() { for _, field := range self.getFilterFields(item) { - if strings.Contains(field, self.filter) { + if self.match(field, self.filter) { self.filteredIndices = append(self.filteredIndices, i) break } @@ -62,3 +64,7 @@ func (self *FilteredList[T]) applyFilter() { } } } + +func (self *FilteredList[T]) match(haystack string, needle string) bool { + return utils.CaseInsensitiveContains(haystack, needle) +} diff --git a/pkg/gui/context/working_tree_context.go b/pkg/gui/context/working_tree_context.go index 0c8c2bc5e..ee053eea1 100644 --- a/pkg/gui/context/working_tree_context.go +++ b/pkg/gui/context/working_tree_context.go @@ -32,7 +32,6 @@ func NewWorkingTreeContext(c *ContextCommon) *WorkingTreeContext { ) getDisplayStrings := func(startIdx int, length int) [][]string { - c.Log.Warn("in get display strings") lines := presentation.RenderFileTree(viewModel, c.Modes().Diffing.Ref, c.Model().Submodules) return slices.Map(lines, func(line string) []string { return []string{line} diff --git a/pkg/utils/fuzzy_search_test.go b/pkg/utils/fuzzy_search_test.go deleted file mode 100644 index 808d83772..000000000 --- a/pkg/utils/fuzzy_search_test.go +++ /dev/null @@ -1,53 +0,0 @@ -package utils - -import ( - "testing" - - "github.com/stretchr/testify/assert" -) - -// TestFuzzySearch is a function. -func TestFuzzySearch(t *testing.T) { - type scenario struct { - needle string - haystack []string - expected []string - } - - scenarios := []scenario{ - { - needle: "", - haystack: []string{"test"}, - expected: []string{}, - }, - { - needle: "test", - haystack: []string{"test"}, - expected: []string{"test"}, - }, - { - needle: "o", - haystack: []string{"a", "o", "e"}, - expected: []string{"o"}, - }, - { - needle: "mybranch", - haystack: []string{"my_branch", "mybranch", "branch", "this is my branch"}, - expected: []string{"mybranch", "my_branch", "this is my branch"}, - }, - { - needle: "test", - haystack: []string{"not a good match", "this 'test' is a good match", "test"}, - expected: []string{"test", "this 'test' is a good match"}, - }, - { - needle: "test", - haystack: []string{"Test"}, - expected: []string{"Test"}, - }, - } - - for _, s := range scenarios { - assert.EqualValues(t, s.expected, FuzzySearch(s.needle, s.haystack)) - } -} diff --git a/pkg/utils/fuzzy_search.go b/pkg/utils/search.go similarity index 72% rename from pkg/utils/fuzzy_search.go rename to pkg/utils/search.go index 5fce3dde9..e90d2b5b0 100644 --- a/pkg/utils/fuzzy_search.go +++ b/pkg/utils/search.go @@ -2,6 +2,7 @@ package utils import ( "sort" + "strings" "github.com/jesseduffield/generics/slices" "github.com/sahilm/fuzzy" @@ -19,3 +20,10 @@ func FuzzySearch(needle string, haystack []string) []string { return match.Str }) } + +func CaseInsensitiveContains(a, b string) bool { + return strings.Contains( + strings.ToLower(a), + strings.ToLower(b), + ) +} diff --git a/pkg/utils/search_test.go b/pkg/utils/search_test.go new file mode 100644 index 000000000..79668c0f5 --- /dev/null +++ b/pkg/utils/search_test.go @@ -0,0 +1,80 @@ +package utils + +import ( + "fmt" + "testing" + + "github.com/stretchr/testify/assert" +) + +// TestFuzzySearch is a function. +func TestFuzzySearch(t *testing.T) { + type scenario struct { + needle string + haystack []string + expected []string + } + + scenarios := []scenario{ + { + needle: "", + haystack: []string{"test"}, + expected: []string{}, + }, + { + needle: "test", + haystack: []string{"test"}, + expected: []string{"test"}, + }, + { + needle: "o", + haystack: []string{"a", "o", "e"}, + expected: []string{"o"}, + }, + { + needle: "mybranch", + haystack: []string{"my_branch", "mybranch", "branch", "this is my branch"}, + expected: []string{"mybranch", "my_branch", "this is my branch"}, + }, + { + needle: "test", + haystack: []string{"not a good match", "this 'test' is a good match", "test"}, + expected: []string{"test", "this 'test' is a good match"}, + }, + { + needle: "test", + haystack: []string{"Test"}, + expected: []string{"Test"}, + }, + } + + for _, s := range scenarios { + assert.EqualValues(t, s.expected, FuzzySearch(s.needle, s.haystack)) + } +} + +func TestCaseInsensitiveContains(t *testing.T) { + testCases := []struct { + haystack string + needle string + expected bool + }{ + {"Hello, World!", "world", true}, // Case-insensitive match + {"Hello, World!", "WORLD", true}, // Case-insensitive match + {"Hello, World!", "orl", true}, // Case-insensitive match + {"Hello, World!", "o, W", true}, // Case-insensitive match + {"Hello, World!", "hello", true}, // Case-insensitive match + {"Hello, World!", "Foo", false}, // No match + {"Hello, World!", "Hello, World!!", false}, // No match + {"Hello, World!", "", true}, // Empty needle matches + {"", "Hello", false}, // Empty haystack doesn't match + {"", "", true}, // Empty strings match + {"", " ", false}, // Empty haystack, non-empty needle + {" ", "", true}, // Non-empty haystack, empty needle + } + + for i, testCase := range testCases { + result := CaseInsensitiveContains(testCase.haystack, testCase.needle) + assert.Equal(t, testCase.expected, result, fmt.Sprintf("Test case %d failed. Expected '%v', got '%v' for '%s' in '%s'", i, testCase.expected, result, testCase.needle, testCase.haystack)) + } +}