diff --git a/pkg/gui/context/local_commits_context.go b/pkg/gui/context/local_commits_context.go index 604d51205..c6d7de991 100644 --- a/pkg/gui/context/local_commits_context.go +++ b/pkg/gui/context/local_commits_context.go @@ -8,6 +8,7 @@ import ( "github.com/jesseduffield/lazygit/pkg/commands/types/enums" "github.com/jesseduffield/lazygit/pkg/gui/presentation" "github.com/jesseduffield/lazygit/pkg/gui/types" + "github.com/samber/lo" ) type LocalCommitsContext struct { @@ -125,6 +126,29 @@ func (self *LocalCommitsContext) GetSelectedRef() types.Ref { return commit } +// Returns the commit hash of the selected commit, or an empty string if no +// commit is selected +func (self *LocalCommitsContext) GetSelectedCommitHash() string { + commit := self.GetSelected() + if commit == nil { + return "" + } + return commit.Sha +} + +func (self *LocalCommitsContext) SelectCommitByHash(hash string) bool { + if hash == "" { + return false + } + + if _, idx, found := lo.FindIndexOf(self.GetItems(), func(c *models.Commit) bool { return c.Sha == hash }); found { + self.SetSelection(idx) + return true + } + + return false +} + func (self *LocalCommitsContext) GetDiffTerminals() []string { itemId := self.GetSelectedItemId() diff --git a/pkg/gui/controllers/filtering_menu_action.go b/pkg/gui/controllers/filtering_menu_action.go index 9af0276e5..3771cdabd 100644 --- a/pkg/gui/controllers/filtering_menu_action.go +++ b/pkg/gui/controllers/filtering_menu_action.go @@ -109,6 +109,8 @@ func (self *FilteringMenuAction) setFilteringAuthor(author string) error { } func (self *FilteringMenuAction) setFiltering() error { + self.c.Modes().Filtering.SetSelectedCommitHash(self.c.Contexts().LocalCommits.GetSelectedCommitHash()) + repoState := self.c.State().GetRepoState() if repoState.GetScreenMode() == types.SCREEN_NORMAL { repoState.SetScreenMode(types.SCREEN_HALF) diff --git a/pkg/gui/controllers/helpers/mode_helper.go b/pkg/gui/controllers/helpers/mode_helper.go index a25862252..0745c2288 100644 --- a/pkg/gui/controllers/helpers/mode_helper.go +++ b/pkg/gui/controllers/helpers/mode_helper.go @@ -163,12 +163,25 @@ func (self *ModeHelper) ExitFilterMode() error { } func (self *ModeHelper) ClearFiltering() error { + selectedCommitHash := self.c.Contexts().LocalCommits.GetSelectedCommitHash() self.c.Modes().Filtering.Reset() if self.c.State().GetRepoState().GetScreenMode() == types.SCREEN_HALF { self.c.State().GetRepoState().SetScreenMode(types.SCREEN_NORMAL) } - return self.c.Refresh(types.RefreshOptions{Scope: []types.RefreshableView{types.COMMITS}}) + return self.c.Refresh(types.RefreshOptions{ + Scope: []types.RefreshableView{types.COMMITS}, + Then: func() { + // Find the commit that was last selected in filtering mode, and select it again after refreshing + if !self.c.Contexts().LocalCommits.SelectCommitByHash(selectedCommitHash) { + // If we couldn't find it (either because no commit was selected + // in filtering mode, or because the commit is outside the + // initial 300 range), go back to the commit that was selected + // before we entered filtering + self.c.Contexts().LocalCommits.SelectCommitByHash(self.c.Modes().Filtering.GetSelectedCommitHash()) + } + }, + }) } func (self *ModeHelper) SetSuppressRebasingMode(value bool) { diff --git a/pkg/gui/modes/filtering/filtering.go b/pkg/gui/modes/filtering/filtering.go index 368df31f2..acdb94e53 100644 --- a/pkg/gui/modes/filtering/filtering.go +++ b/pkg/gui/modes/filtering/filtering.go @@ -1,8 +1,9 @@ package filtering type Filtering struct { - path string // the filename that gets passed to git log - author string // the author that gets passed to git log + path string // the filename that gets passed to git log + author string // the author that gets passed to git log + selectedCommitHash string // the commit that was selected before we entered filtering mode } func New(path string, author string) Filtering { @@ -33,3 +34,11 @@ func (m *Filtering) SetAuthor(author string) { func (m *Filtering) GetAuthor() string { return m.author } + +func (m *Filtering) SetSelectedCommitHash(hash string) { + m.selectedCommitHash = hash +} + +func (m *Filtering) GetSelectedCommitHash() string { + return m.selectedCommitHash +} diff --git a/pkg/integration/tests/filter_by_path/keep_same_commit_selected_on_exit.go b/pkg/integration/tests/filter_by_path/keep_same_commit_selected_on_exit.go new file mode 100644 index 000000000..728a5aedf --- /dev/null +++ b/pkg/integration/tests/filter_by_path/keep_same_commit_selected_on_exit.go @@ -0,0 +1,51 @@ +package filter_by_path + +import ( + "github.com/jesseduffield/lazygit/pkg/config" + . "github.com/jesseduffield/lazygit/pkg/integration/components" +) + +var KeepSameCommitSelectedOnExit = NewIntegrationTest(NewIntegrationTestArgs{ + Description: "When exiting filtering mode, keep the same commit selected if possible", + ExtraCmdArgs: []string{}, + Skip: false, + SetupConfig: func(config *config.AppConfig) { + }, + SetupRepo: func(shell *Shell) { + commonSetup(shell) + }, + Run: func(t *TestDriver, keys config.KeybindingConfig) { + t.Views().Commits(). + Focus(). + Lines( + Contains(`none of the two`).IsSelected(), + Contains(`only filterFile`), + Contains(`only otherFile`), + Contains(`both files`), + ).Press(keys.Universal.FilteringMenu). + Tap(func() { + t.ExpectPopup().Menu(). + Title(Equals("Filtering")). + Select(Contains("Enter path to filter by")). + Confirm() + + t.ExpectPopup().Prompt(). + Title(Equals("Enter path:")). + Type("filterF"). + SuggestionLines(Equals("filterFile")). + ConfirmFirstSuggestion() + }). + Lines( + Contains(`only filterFile`).IsSelected(), + Contains(`both files`), + ). + SelectNextItem(). + PressEscape(). + Lines( + Contains(`none of the two`), + Contains(`only filterFile`), + Contains(`only otherFile`), + Contains(`both files`).IsSelected(), + ) + }, +}) diff --git a/pkg/integration/tests/test_list.go b/pkg/integration/tests/test_list.go index a7257fe91..c5a5b64d6 100644 --- a/pkg/integration/tests/test_list.go +++ b/pkg/integration/tests/test_list.go @@ -157,6 +157,7 @@ var tests = []*components.IntegrationTest{ filter_by_author.SelectAuthor, filter_by_author.TypeAuthor, filter_by_path.CliArg, + filter_by_path.KeepSameCommitSelectedOnExit, filter_by_path.SelectFile, filter_by_path.TypeFile, interactive_rebase.AdvancedInteractiveRebase,