summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorStefan Haller <stefan@haller-berlin.de>2024-01-29 17:50:45 +0100
committerStefan Haller <stefan@haller-berlin.de>2024-02-16 13:51:15 +0100
commit649048c3369f03f5f5f1d5fd107c616f676d5caf (patch)
tree0f2df53bbdb360cac3c1f2a62a75e9ea68b959ce
parent57ac9c2189458a7f0e63c2e9cac8334694a3d545 (diff)
Optionally keep sort order stable when filtering lists
For some lists it is useful to keep the same sort order when filtering (rather than sorting by best match like we usually do). Add an optional function to FilteredList to make this possible, and use it whenever we show lists of things sorted by date (branches, stashes, reflog entries), as well as menu items because this allows us to keep the section headers in the keybindings menu, which is useful for understanding what you are looking at when filtering.
-rw-r--r--pkg/gui/context/branches_context.go1
-rw-r--r--pkg/gui/context/filtered_list.go19
-rw-r--r--pkg/gui/context/filtered_list_view_model.go4
-rw-r--r--pkg/gui/context/menu_context.go4
-rw-r--r--pkg/gui/context/reflog_commits_context.go1
-rw-r--r--pkg/gui/context/remote_branches_context.go1
-rw-r--r--pkg/gui/context/remotes_context.go1
-rw-r--r--pkg/gui/context/stash_context.go1
-rw-r--r--pkg/gui/context/submodules_context.go1
-rw-r--r--pkg/gui/context/tags_context.go1
-rw-r--r--pkg/gui/context/worktrees_context.go1
-rw-r--r--pkg/integration/tests/filter_and_search/filter_updates_when_model_changes.go5
12 files changed, 32 insertions, 8 deletions
diff --git a/pkg/gui/context/branches_context.go b/pkg/gui/context/branches_context.go
index d2647ef84..6317a60b2 100644
--- a/pkg/gui/context/branches_context.go
+++ b/pkg/gui/context/branches_context.go
@@ -22,6 +22,7 @@ func NewBranchesContext(c *ContextCommon) *BranchesContext {
func(branch *models.Branch) []string {
return []string{branch.Name}
},
+ func() bool { return c.AppState.LocalBranchSortOrder != "alphabetical" },
)
getDisplayStrings := func(_ int, _ int) [][]string {
diff --git a/pkg/gui/context/filtered_list.go b/pkg/gui/context/filtered_list.go
index 82d9b81c8..13b9c166a 100644
--- a/pkg/gui/context/filtered_list.go
+++ b/pkg/gui/context/filtered_list.go
@@ -1,6 +1,7 @@
package context
import (
+ "slices"
"strings"
"github.com/jesseduffield/lazygit/pkg/utils"
@@ -16,14 +17,21 @@ type FilteredList[T any] struct {
getFilterFields func(T) []string
filter string
+ // Normally, filtered items are presented sorted by best match. If this
+ // function returns true, they retain their original sort order instead;
+ // this is useful for lists that show items sorted by date, for example.
+ // Leaving this nil is equivalent to returning false.
+ shouldRetainSortOrder func() bool
+
mutex *deadlock.Mutex
}
-func NewFilteredList[T any](getList func() []T, getFilterFields func(T) []string) *FilteredList[T] {
+func NewFilteredList[T any](getList func() []T, getFilterFields func(T) []string, shouldRetainSortOrder func() bool) *FilteredList[T] {
return &FilteredList[T]{
- getList: getList,
- getFilterFields: getFilterFields,
- mutex: &deadlock.Mutex{},
+ getList: getList,
+ getFilterFields: getFilterFields,
+ shouldRetainSortOrder: shouldRetainSortOrder,
+ mutex: &deadlock.Mutex{},
}
}
@@ -92,6 +100,9 @@ func (self *FilteredList[T]) applyFilter() {
self.filteredIndices = lo.Map(matches, func(match fuzzy.Match, _ int) int {
return match.Index
})
+ if self.shouldRetainSortOrder != nil && self.shouldRetainSortOrder() {
+ slices.Sort(self.filteredIndices)
+ }
}
}
diff --git a/pkg/gui/context/filtered_list_view_model.go b/pkg/gui/context/filtered_list_view_model.go
index 2c2841964..b52fcbc0a 100644
--- a/pkg/gui/context/filtered_list_view_model.go
+++ b/pkg/gui/context/filtered_list_view_model.go
@@ -6,8 +6,8 @@ type FilteredListViewModel[T HasID] struct {
*SearchHistory
}
-func NewFilteredListViewModel[T HasID](getList func() []T, getFilterFields func(T) []string) *FilteredListViewModel[T] {
- filteredList := NewFilteredList(getList, getFilterFields)
+func NewFilteredListViewModel[T HasID](getList func() []T, getFilterFields func(T) []string, shouldRetainSortOrder func() bool) *FilteredListViewModel[T] {
+ filteredList := NewFilteredList(getList, getFilterFields, shouldRetainSortOrder)
self := &FilteredListViewModel[T]{
FilteredList: filteredList,
diff --git a/pkg/gui/context/menu_context.go b/pkg/gui/context/menu_context.go
index bb1060de6..32d6d7610 100644
--- a/pkg/gui/context/menu_context.go
+++ b/pkg/gui/context/menu_context.go
@@ -61,6 +61,10 @@ func NewMenuViewModel(c *ContextCommon) *MenuViewModel {
self.FilteredListViewModel = NewFilteredListViewModel(
func() []*types.MenuItem { return self.menuItems },
func(item *types.MenuItem) []string { return item.LabelColumns },
+ // The only menu that the user is likely to filter in is the keybindings
+ // menu; retain the sort order in that one because this allows us to
+ // keep the section headers while filtering:
+ func() bool { return true },
)
return self
diff --git a/pkg/gui/context/reflog_commits_context.go b/pkg/gui/context/reflog_commits_context.go
index 65137d633..6791932ba 100644
--- a/pkg/gui/context/reflog_commits_context.go
+++ b/pkg/gui/context/reflog_commits_context.go
@@ -24,6 +24,7 @@ func NewReflogCommitsContext(c *ContextCommon) *ReflogCommitsContext {
func(commit *models.Commit) []string {
return []string{commit.ShortSha(), commit.Name}
},
+ func() bool { return true },
)
getDisplayStrings := func(_ int, _ int) [][]string {
diff --git a/pkg/gui/context/remote_branches_context.go b/pkg/gui/context/remote_branches_context.go
index 884d3debb..9de792f27 100644
--- a/pkg/gui/context/remote_branches_context.go
+++ b/pkg/gui/context/remote_branches_context.go
@@ -26,6 +26,7 @@ func NewRemoteBranchesContext(
func(remoteBranch *models.RemoteBranch) []string {
return []string{remoteBranch.Name}
},
+ func() bool { return c.AppState.RemoteBranchSortOrder != "alphabetical" },
)
getDisplayStrings := func(_ int, _ int) [][]string {
diff --git a/pkg/gui/context/remotes_context.go b/pkg/gui/context/remotes_context.go
index 73ea428aa..51fc1c036 100644
--- a/pkg/gui/context/remotes_context.go
+++ b/pkg/gui/context/remotes_context.go
@@ -22,6 +22,7 @@ func NewRemotesContext(c *ContextCommon) *RemotesContext {
func(remote *models.Remote) []string {
return []string{remote.Name}
},
+ nil,
)
getDisplayStrings := func(_ int, _ int) [][]string {
diff --git a/pkg/gui/context/stash_context.go b/pkg/gui/context/stash_context.go
index c8d487688..c832f85ff 100644
--- a/pkg/gui/context/stash_context.go
+++ b/pkg/gui/context/stash_context.go
@@ -24,6 +24,7 @@ func NewStashContext(
func(stashEntry *models.StashEntry) []string {
return []string{stashEntry.Name}
},
+ func() bool { return true },
)
getDisplayStrings := func(_ int, _ int) [][]string {
diff --git a/pkg/gui/context/submodules_context.go b/pkg/gui/context/submodules_context.go
index 82deb25af..aff8f64ab 100644
--- a/pkg/gui/context/submodules_context.go
+++ b/pkg/gui/context/submodules_context.go
@@ -19,6 +19,7 @@ func NewSubmodulesContext(c *ContextCommon) *SubmodulesContext {
func(submodule *models.SubmoduleConfig) []string {
return []string{submodule.Name}
},
+ nil,
)
getDisplayStrings := func(_ int, _ int) [][]string {
diff --git a/pkg/gui/context/tags_context.go b/pkg/gui/context/tags_context.go
index d827564dd..c5ae2ccd5 100644
--- a/pkg/gui/context/tags_context.go
+++ b/pkg/gui/context/tags_context.go
@@ -24,6 +24,7 @@ func NewTagsContext(
func(tag *models.Tag) []string {
return []string{tag.Name, tag.Message}
},
+ nil,
)
getDisplayStrings := func(_ int, _ int) [][]string {
diff --git a/pkg/gui/context/worktrees_context.go b/pkg/gui/context/worktrees_context.go
index 3e45f2d45..55618de85 100644
--- a/pkg/gui/context/worktrees_context.go
+++ b/pkg/gui/context/worktrees_context.go
@@ -19,6 +19,7 @@ func NewWorktreesContext(c *ContextCommon) *WorktreesContext {
func(Worktree *models.Worktree) []string {
return []string{Worktree.Name}
},
+ nil,
)
getDisplayStrings := func(_ int, _ int) [][]string {
diff --git a/pkg/integration/tests/filter_and_search/filter_updates_when_model_changes.go b/pkg/integration/tests/filter_and_search/filter_updates_when_model_changes.go
index ae3c862c0..60ce9b580 100644
--- a/pkg/integration/tests/filter_and_search/filter_updates_when_model_changes.go
+++ b/pkg/integration/tests/filter_and_search/filter_updates_when_model_changes.go
@@ -27,9 +27,10 @@ var FilterUpdatesWhenModelChanges = NewIntegrationTest(NewIntegrationTestArgs{
).
FilterOrSearch("branch").
Lines(
- Contains("branch-to-delete").IsSelected(),
- Contains("checked-out-branch"),
+ Contains("checked-out-branch").IsSelected(),
+ Contains("branch-to-delete"),
).
+ SelectNextItem().
Press(keys.Universal.Remove).
Tap(func() {
t.ExpectPopup().