diff options
author | Stefan Haller <stefan@haller-berlin.de> | 2024-02-16 13:57:36 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-02-16 13:57:36 +0100 |
commit | a2ff2e6dd92c7b1bcfa41798548d3cd4f439dfa8 (patch) | |
tree | 0fa1e4bff75ae6f5269abc9b9c27440ce0f444dd | |
parent | c4eedec9d59feb3942af5a425bd38611a386c3c9 (diff) | |
parent | 9f0b4d0000c52d23a2dfe0092fe2f6f1714e6ea5 (diff) |
Keep sort order when filtering lists sorted by date (#3282)
- **PR Description**
Keep the sort order stable when filtering lists of things sorted by date
(branches, stashes, reflog entries).
-rw-r--r-- | .github/workflows/cd.yml | 2 | ||||
-rw-r--r-- | .github/workflows/ci.yml | 12 | ||||
-rw-r--r-- | .golangci.yml | 2 | ||||
-rw-r--r-- | Dockerfile | 2 | ||||
-rw-r--r-- | go.mod | 2 | ||||
-rw-r--r-- | go.sum | 1 | ||||
-rw-r--r-- | pkg/gui/context/branches_context.go | 1 | ||||
-rw-r--r-- | pkg/gui/context/filtered_list.go | 19 | ||||
-rw-r--r-- | pkg/gui/context/filtered_list_view_model.go | 4 | ||||
-rw-r--r-- | pkg/gui/context/menu_context.go | 11 | ||||
-rw-r--r-- | pkg/gui/context/reflog_commits_context.go | 1 | ||||
-rw-r--r-- | pkg/gui/context/remote_branches_context.go | 1 | ||||
-rw-r--r-- | pkg/gui/context/remotes_context.go | 1 | ||||
-rw-r--r-- | pkg/gui/context/stash_context.go | 1 | ||||
-rw-r--r-- | pkg/gui/context/submodules_context.go | 1 | ||||
-rw-r--r-- | pkg/gui/context/tags_context.go | 1 | ||||
-rw-r--r-- | pkg/gui/context/worktrees_context.go | 1 | ||||
-rw-r--r-- | pkg/integration/tests/filter_and_search/filter_menu.go | 1 | ||||
-rw-r--r-- | pkg/integration/tests/filter_and_search/filter_menu_cancel_filter_with_escape.go | 1 | ||||
-rw-r--r-- | pkg/integration/tests/filter_and_search/filter_updates_when_model_changes.go | 5 |
20 files changed, 45 insertions, 25 deletions
diff --git a/.github/workflows/cd.yml b/.github/workflows/cd.yml index b1a1a08d2..0d126d16e 100644 --- a/.github/workflows/cd.yml +++ b/.github/workflows/cd.yml @@ -16,7 +16,7 @@ jobs: - name: Setup Go uses: actions/setup-go@v4 with: - go-version: 1.20.x + go-version: 1.21.x - name: Run goreleaser uses: goreleaser/goreleaser-action@v4 with: diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 14bc6e304..9f225ccfa 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,7 +1,7 @@ name: Continuous Integration env: - GO_VERSION: 1.20 + GO_VERSION: 1.21 on: push: @@ -32,7 +32,7 @@ jobs: - name: Setup Go uses: actions/setup-go@v4 with: - go-version: 1.20.x + go-version: 1.21.x - name: Test code # we're passing -short so that we skip the integration tests, which will be run in parallel below run: | @@ -89,7 +89,7 @@ jobs: - name: Setup Go uses: actions/setup-go@v4 with: - go-version: 1.20.x + go-version: 1.21.x - name: Print git version run: git --version - name: Test code @@ -115,7 +115,7 @@ jobs: - name: Setup Go uses: actions/setup-go@v4 with: - go-version: 1.20.x + go-version: 1.21.x - name: Build linux binary run: | GOOS=linux go build @@ -142,7 +142,7 @@ jobs: - name: Setup Go uses: actions/setup-go@v4 with: - go-version: 1.20.x + go-version: 1.21.x - name: Check Vendor Directory # ensure our vendor directory matches up with our go modules run: | @@ -168,7 +168,7 @@ jobs: - name: Setup Go uses: actions/setup-go@v4 with: - go-version: 1.20.x + go-version: 1.21.x - name: Lint uses: golangci/golangci-lint-action@v3.7.0 with: diff --git a/.golangci.yml b/.golangci.yml index 258660b62..c8884c93a 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -30,5 +30,5 @@ linters-settings: max-func-lines: 0 run: - go: '1.20' + go: '1.21' timeout: 10m diff --git a/Dockerfile b/Dockerfile index 90a69b445..976f2221d 100644 --- a/Dockerfile +++ b/Dockerfile @@ -2,7 +2,7 @@ # docker build -t lazygit . # docker run -it lazygit:latest /bin/sh -FROM golang:1.20 as build +FROM golang:1.21 as build WORKDIR /go/src/github.com/jesseduffield/lazygit/ COPY go.mod go.sum ./ RUN go mod download @@ -1,6 +1,6 @@ module github.com/jesseduffield/lazygit -go 1.20 +go 1.21 require ( github.com/OpenPeeDeeP/xdg v1.0.0 @@ -299,6 +299,7 @@ github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk= github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/thoas/go-funk v0.9.1 h1:O549iLZqPpTUQ10ykd26sZhzD+rmR5pWhuElrhbC20M= +github.com/thoas/go-funk v0.9.1/go.mod h1:+IWnUfUmFO1+WVYQWQtIJHeRRdaIyyYglZN7xzUPe4Q= github.com/urfave/cli v1.20.1-0.20180226030253-8e01ec4cd3e2/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= github.com/wk8/go-ordered-map/v2 v2.1.8 h1:5h/BUHu93oj4gIdvHHHGsScSTMijfx5PeYkE/fJgbpc= github.com/wk8/go-ordered-map/v2 v2.1.8/go.mod h1:5nJHM5DyteebpVlHnWMV0rPz6Zp7+xBAnxjb1X5vnTw= 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..7f8656fe7 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 @@ -108,13 +112,6 @@ func (self *MenuViewModel) GetDisplayStrings(_ int, _ int) [][]string { } func (self *MenuViewModel) GetNonModelItems() []*NonModelItem { - // Don't display section headers when we are filtering. The reason is that - // filtering changes the order of the items (they are sorted by best match), - // so all the sections would be messed up. - if self.FilteredListViewModel.IsFiltering() { - return []*NonModelItem{} - } - result := []*NonModelItem{} menuItems := self.FilteredListViewModel.GetItems() var prevSection *types.MenuSection = nil 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_menu.go b/pkg/integration/tests/filter_and_search/filter_menu.go index 70c8244f8..59c47fb71 100644 --- a/pkg/integration/tests/filter_and_search/filter_menu.go +++ b/pkg/integration/tests/filter_and_search/filter_menu.go @@ -26,6 +26,7 @@ var FilterMenu = NewIntegrationTest(NewIntegrationTestArgs{ Filter("Ignore"). Lines( // menu has filtered down to the one item that matches the filter + Contains(`--- Local ---`), Contains(`Ignore`).IsSelected(), ). Confirm() diff --git a/pkg/integration/tests/filter_and_search/filter_menu_cancel_filter_with_escape.go b/pkg/integration/tests/filter_and_search/filter_menu_cancel_filter_with_escape.go index 6fb7166ca..daf55fd0d 100644 --- a/pkg/integration/tests/filter_and_search/filter_menu_cancel_filter_with_escape.go +++ b/pkg/integration/tests/filter_and_search/filter_menu_cancel_filter_with_escape.go @@ -20,6 +20,7 @@ var FilterMenuCancelFilterWithEscape = NewIntegrationTest(NewIntegrationTestArgs Filter("Ignore"). Lines( // menu has filtered down to the one item that matches the filter + Contains(`--- Local ---`), Contains(`Ignore`).IsSelected(), ) 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(). |