mirror of
https://github.com/jesseduffield/lazygit.git
synced 2024-11-28 09:08:41 +02:00
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.
This commit is contained in:
parent
57ac9c2189
commit
649048c336
@ -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 {
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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
|
||||
|
@ -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 {
|
||||
|
@ -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 {
|
||||
|
@ -22,6 +22,7 @@ func NewRemotesContext(c *ContextCommon) *RemotesContext {
|
||||
func(remote *models.Remote) []string {
|
||||
return []string{remote.Name}
|
||||
},
|
||||
nil,
|
||||
)
|
||||
|
||||
getDisplayStrings := func(_ int, _ int) [][]string {
|
||||
|
@ -24,6 +24,7 @@ func NewStashContext(
|
||||
func(stashEntry *models.StashEntry) []string {
|
||||
return []string{stashEntry.Name}
|
||||
},
|
||||
func() bool { return true },
|
||||
)
|
||||
|
||||
getDisplayStrings := func(_ int, _ int) [][]string {
|
||||
|
@ -19,6 +19,7 @@ func NewSubmodulesContext(c *ContextCommon) *SubmodulesContext {
|
||||
func(submodule *models.SubmoduleConfig) []string {
|
||||
return []string{submodule.Name}
|
||||
},
|
||||
nil,
|
||||
)
|
||||
|
||||
getDisplayStrings := func(_ int, _ int) [][]string {
|
||||
|
@ -24,6 +24,7 @@ func NewTagsContext(
|
||||
func(tag *models.Tag) []string {
|
||||
return []string{tag.Name, tag.Message}
|
||||
},
|
||||
nil,
|
||||
)
|
||||
|
||||
getDisplayStrings := func(_ int, _ int) [][]string {
|
||||
|
@ -19,6 +19,7 @@ func NewWorktreesContext(c *ContextCommon) *WorktreesContext {
|
||||
func(Worktree *models.Worktree) []string {
|
||||
return []string{Worktree.Name}
|
||||
},
|
||||
nil,
|
||||
)
|
||||
|
||||
getDisplayStrings := func(_ int, _ int) [][]string {
|
||||
|
@ -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().
|
||||
|
Loading…
Reference in New Issue
Block a user