From 57ac9c2189458a7f0e63c2e9cac8334694a3d545 Mon Sep 17 00:00:00 2001 From: Stefan Haller Date: Sun, 4 Feb 2024 19:45:08 +0100 Subject: Bump required go version to 1.21 We'll need this to use the slices.Sort function in the next commit. It would also be possible to use sort.Ints instead, but it's slower. --- .github/workflows/cd.yml | 2 +- .github/workflows/ci.yml | 12 ++++++------ .golangci.yml | 2 +- Dockerfile | 2 +- go.mod | 2 +- go.sum | 1 + 6 files changed, 11 insertions(+), 10 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 diff --git a/go.mod b/go.mod index 4ecdfe514..64ecc4c6d 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module github.com/jesseduffield/lazygit -go 1.20 +go 1.21 require ( github.com/OpenPeeDeeP/xdg v1.0.0 diff --git a/go.sum b/go.sum index fcf3fbf79..733c1c268 100644 --- a/go.sum +++ b/go.sum @@ -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= -- cgit v1.2.3 From 649048c3369f03f5f5f1d5fd107c616f676d5caf Mon Sep 17 00:00:00 2001 From: Stefan Haller Date: Mon, 29 Jan 2024 17:50:45 +0100 Subject: 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. --- pkg/gui/context/branches_context.go | 1 + pkg/gui/context/filtered_list.go | 19 +++++++++++++++---- pkg/gui/context/filtered_list_view_model.go | 4 ++-- pkg/gui/context/menu_context.go | 4 ++++ pkg/gui/context/reflog_commits_context.go | 1 + pkg/gui/context/remote_branches_context.go | 1 + pkg/gui/context/remotes_context.go | 1 + pkg/gui/context/stash_context.go | 1 + pkg/gui/context/submodules_context.go | 1 + pkg/gui/context/tags_context.go | 1 + pkg/gui/context/worktrees_context.go | 1 + .../filter_updates_when_model_changes.go | 5 +++-- 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(). -- cgit v1.2.3 From 9f0b4d0000c52d23a2dfe0092fe2f6f1714e6ea5 Mon Sep 17 00:00:00 2001 From: Stefan Haller Date: Mon, 29 Jan 2024 18:04:50 +0100 Subject: Don't omit section headers when filtering the keybindings menu --- pkg/gui/context/menu_context.go | 7 ------- pkg/integration/tests/filter_and_search/filter_menu.go | 1 + .../filter_and_search/filter_menu_cancel_filter_with_escape.go | 1 + 3 files changed, 2 insertions(+), 7 deletions(-) diff --git a/pkg/gui/context/menu_context.go b/pkg/gui/context/menu_context.go index 32d6d7610..7f8656fe7 100644 --- a/pkg/gui/context/menu_context.go +++ b/pkg/gui/context/menu_context.go @@ -112,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/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(), ) -- cgit v1.2.3