From 660cc2f3d1d5253817d52e8991f74e836d3db6ba Mon Sep 17 00:00:00 2001 From: Jesse Duffield Date: Fri, 7 Aug 2020 18:27:18 +1000 Subject: follow cursor when staging and unstaging a file rename --- pkg/commands/file.go | 20 ++++++++++++++++++-- pkg/commands/git.go | 11 ++++++++--- pkg/commands/git_test.go | 2 +- pkg/gui/files_panel.go | 15 ++++++++++++++- pkg/utils/utils.go | 12 ++++++++++++ 5 files changed, 53 insertions(+), 7 deletions(-) (limited to 'pkg') diff --git a/pkg/commands/file.go b/pkg/commands/file.go index 754b2871f..4a277be22 100644 --- a/pkg/commands/file.go +++ b/pkg/commands/file.go @@ -1,6 +1,10 @@ package commands -import "strings" +import ( + "strings" + + "github.com/jesseduffield/lazygit/pkg/utils" +) // File : A file from git status // duplicating this for now @@ -17,6 +21,18 @@ type File struct { ShortStatus string // e.g. 'AD', ' A', 'M ', '??' } +const RENAME_SEPARATOR = " -> " + func (f *File) IsRename() bool { - return strings.Contains(f.Name, " -> ") + return strings.Contains(f.Name, RENAME_SEPARATOR) +} + +// Names returns an array containing just the filename, or in the case of a rename, the after filename and the before filename +func (f *File) Names() []string { + return strings.Split(f.Name, RENAME_SEPARATOR) +} + +// returns true if the file names are the same or if a a file rename includes the filename of the other +func (f *File) Matches(f2 *File) bool { + return utils.StringArraysOverlap(f.Names(), f2.Names()) } diff --git a/pkg/commands/git.go b/pkg/commands/git.go index 20cbd9fb2..249221c1f 100644 --- a/pkg/commands/git.go +++ b/pkg/commands/git.go @@ -279,7 +279,7 @@ func (c *GitCommand) StashSave(message string) error { } // MergeStatusFiles merge status files -func (c *GitCommand) MergeStatusFiles(oldFiles, newFiles []*File) []*File { +func (c *GitCommand) MergeStatusFiles(oldFiles, newFiles []*File, selectedFile *File) []*File { if len(oldFiles) == 0 { return newFiles } @@ -290,10 +290,15 @@ func (c *GitCommand) MergeStatusFiles(oldFiles, newFiles []*File) []*File { result := []*File{} for _, oldFile := range oldFiles { for newIndex, newFile := range newFiles { - if oldFile.Name == newFile.Name { + if includesInt(appendedIndexes, newIndex) { + continue + } + // if we just staged B and in doing so created 'A -> B' and we are currently have oldFile: A and newFile: 'A -> B', we want to wait until we come across B so the our cursor isn't jumping anywhere + waitForMatchingFile := selectedFile != nil && newFile.IsRename() && !selectedFile.IsRename() && newFile.Matches(selectedFile) && !oldFile.Matches(selectedFile) + + if oldFile.Matches(newFile) && !waitForMatchingFile { result = append(result, newFile) appendedIndexes = append(appendedIndexes, newIndex) - break } } } diff --git a/pkg/commands/git_test.go b/pkg/commands/git_test.go index 43accd654..9b0ef5e11 100644 --- a/pkg/commands/git_test.go +++ b/pkg/commands/git_test.go @@ -541,7 +541,7 @@ func TestGitCommandMergeStatusFiles(t *testing.T) { t.Run(s.testName, func(t *testing.T) { gitCmd := NewDummyGitCommand() - s.test(gitCmd.MergeStatusFiles(s.oldFiles, s.newFiles)) + s.test(gitCmd.MergeStatusFiles(s.oldFiles, s.newFiles, nil)) }) } } diff --git a/pkg/gui/files_panel.go b/pkg/gui/files_panel.go index 6cba05715..0c6d2c9f3 100644 --- a/pkg/gui/files_panel.go +++ b/pkg/gui/files_panel.go @@ -410,14 +410,27 @@ func (gui *Gui) handleRefreshFiles(g *gocui.Gui, v *gocui.View) error { } func (gui *Gui) refreshStateFiles() error { + // keep track of where the cursor is currently and the current file names + // when we refresh, go looking for a matching name + // move the cursor to there. + selectedFile, _ := gui.getSelectedFile() + // get files to stage files := gui.GitCommand.GetStatusFiles(commands.GetStatusFileOptions{}) - gui.State.Files = gui.GitCommand.MergeStatusFiles(gui.State.Files, files) + gui.State.Files = gui.GitCommand.MergeStatusFiles(gui.State.Files, files, selectedFile) if err := gui.fileWatcher.addFilesToFileWatcher(files); err != nil { return err } + // let's try to find our file again and move the cursor to that + for idx, f := range gui.State.Files { + if selectedFile != nil && f.Matches(selectedFile) { + gui.State.Panels.Files.SelectedLine = idx + break + } + } + gui.refreshSelectedLine(&gui.State.Panels.Files.SelectedLine, len(gui.State.Files)) return nil } diff --git a/pkg/utils/utils.go b/pkg/utils/utils.go index 2e17527aa..6eca59a6b 100644 --- a/pkg/utils/utils.go +++ b/pkg/utils/utils.go @@ -322,3 +322,15 @@ func FindStringSubmatch(str string, regexpStr string) (bool, []string) { match := re.FindStringSubmatch(str) return len(match) > 0, match } + +func StringArraysOverlap(strArrA []string, strArrB []string) bool { + for _, first := range strArrA { + for _, second := range strArrB { + if first == second { + return true + } + } + } + + return false +} -- cgit v1.2.3