From 517e0f824849e28cf24e3125418761c86eafb0cd Mon Sep 17 00:00:00 2001 From: Stefan Haller Date: Sun, 5 Mar 2023 14:15:31 +0100 Subject: [PATCH] Add command to open git difftool --- pkg/commands/git_commands/diff.go | 38 +++++++++++++++++++ pkg/config/user_config.go | 2 + .../controllers/basic_commits_controller.go | 21 ++++++++++ .../controllers/commits_files_controller.go | 22 +++++++++++ pkg/gui/controllers/files_controller.go | 26 +++++++++++++ pkg/i18n/english.go | 4 ++ 6 files changed, 113 insertions(+) diff --git a/pkg/commands/git_commands/diff.go b/pkg/commands/git_commands/diff.go index 1e5f9824402..41e71e94116 100644 --- a/pkg/commands/git_commands/diff.go +++ b/pkg/commands/git_commands/diff.go @@ -40,3 +40,41 @@ func (self *DiffCommands) GetAllDiff(staged bool) (string, error) { ToArgv(), ).RunWithOutput() } + +type DiffToolCmdOptions struct { + // The path to show a diff for. Pass "." for the entire repo. + Filepath string + + // The commit against which to show the diff. Leave empty to show a diff of + // the working copy. + FromCommit string + + // The commit to diff against FromCommit. Leave empty to diff the working + // copy against FromCommit. Leave both FromCommit and ToCommit empty to show + // the diff of the unstaged working copy changes against the index if Staged + // is false, or the staged changes against HEAD if Staged is true. + ToCommit string + + // Whether to reverse the left and right sides of the diff. + Reverse bool + + // Whether the given Filepath is a directory. We'll pass --dir-diff to + // git-difftool in that case. + IsDirectory bool + + // Whether to show the staged or the unstaged changes. Must be false if both + // FromCommit and ToCommit are non-empty. + Staged bool +} + +func (self *DiffCommands) OpenDiffToolCmdObj(opts DiffToolCmdOptions) oscommands.ICmdObj { + return self.cmd.New(NewGitCmd("difftool"). + Arg("--no-prompt"). + ArgIf(opts.IsDirectory, "--dir-diff"). + ArgIf(opts.Staged, "--cached"). + ArgIf(opts.FromCommit != "", opts.FromCommit). + ArgIf(opts.ToCommit != "", opts.ToCommit). + ArgIf(opts.Reverse, "-R"). + Arg("--", opts.Filepath). + ToArgv()) +} diff --git a/pkg/config/user_config.go b/pkg/config/user_config.go index 749b4182240..2392d49cf6e 100644 --- a/pkg/config/user_config.go +++ b/pkg/config/user_config.go @@ -347,6 +347,7 @@ type KeybindingUniversalConfig struct { ToggleWhitespaceInDiffView string `yaml:"toggleWhitespaceInDiffView"` IncreaseContextInDiffView string `yaml:"increaseContextInDiffView"` DecreaseContextInDiffView string `yaml:"decreaseContextInDiffView"` + OpenDiffTool string `yaml:"openDiffTool"` } type KeybindingStatusConfig struct { @@ -743,6 +744,7 @@ func GetDefaultConfig() *UserConfig { ToggleWhitespaceInDiffView: "", IncreaseContextInDiffView: "}", DecreaseContextInDiffView: "{", + OpenDiffTool: "", }, Status: KeybindingStatusConfig{ CheckForUpdate: "u", diff --git a/pkg/gui/controllers/basic_commits_controller.go b/pkg/gui/controllers/basic_commits_controller.go index 0e98d7b4e28..5513494667a 100644 --- a/pkg/gui/controllers/basic_commits_controller.go +++ b/pkg/gui/controllers/basic_commits_controller.go @@ -3,6 +3,7 @@ package controllers import ( "fmt" + "github.com/jesseduffield/lazygit/pkg/commands/git_commands" "github.com/jesseduffield/lazygit/pkg/commands/models" "github.com/jesseduffield/lazygit/pkg/gui/types" ) @@ -76,6 +77,11 @@ func (self *BasicCommitsController) GetKeybindings(opts types.KeybindingsOpts) [ Handler: self.c.Helpers().CherryPick.Reset, Description: self.c.Tr.ResetCherryPick, }, + { + Key: opts.GetKey(opts.Config.Universal.OpenDiffTool), + Handler: self.checkSelected(self.openDiffTool), + Description: self.c.Tr.OpenDiffTool, + }, } return bindings @@ -272,3 +278,18 @@ func (self *BasicCommitsController) copy(commit *models.Commit) error { func (self *BasicCommitsController) copyRange(*models.Commit) error { return self.c.Helpers().CherryPick.CopyRange(self.context.GetSelectedLineIdx(), self.context.GetCommits(), self.context) } + +func (self *BasicCommitsController) openDiffTool(commit *models.Commit) error { + to := commit.RefName() + from, reverse := self.c.Modes().Diffing.GetFromAndReverseArgsForDiff(commit.ParentRefName()) + _, err := self.c.RunSubprocess(self.c.Git().Diff.OpenDiffToolCmdObj( + git_commands.DiffToolCmdOptions{ + Filepath: ".", + FromCommit: from, + ToCommit: to, + Reverse: reverse, + IsDirectory: true, + Staged: false, + })) + return err +} diff --git a/pkg/gui/controllers/commits_files_controller.go b/pkg/gui/controllers/commits_files_controller.go index 3730a096591..5b3097363d9 100644 --- a/pkg/gui/controllers/commits_files_controller.go +++ b/pkg/gui/controllers/commits_files_controller.go @@ -2,6 +2,7 @@ package controllers import ( "github.com/jesseduffield/gocui" + "github.com/jesseduffield/lazygit/pkg/commands/git_commands" "github.com/jesseduffield/lazygit/pkg/commands/models" "github.com/jesseduffield/lazygit/pkg/commands/patch" "github.com/jesseduffield/lazygit/pkg/gui/context" @@ -47,6 +48,11 @@ func (self *CommitFilesController) GetKeybindings(opts types.KeybindingsOpts) [] Handler: self.checkSelected(self.edit), Description: self.c.Tr.EditFile, }, + { + Key: opts.GetKey(opts.Config.Universal.OpenDiffTool), + Handler: self.checkSelected(self.openDiffTool), + Description: self.c.Tr.OpenDiffTool, + }, { Key: opts.GetKey(opts.Config.Universal.Select), Handler: self.checkSelected(self.toggleForPatch), @@ -201,6 +207,22 @@ func (self *CommitFilesController) edit(node *filetree.CommitFileNode) error { return self.c.Helpers().Files.EditFile(node.GetPath()) } +func (self *CommitFilesController) openDiffTool(node *filetree.CommitFileNode) error { + ref := self.context().GetRef() + to := ref.RefName() + from, reverse := self.c.Modes().Diffing.GetFromAndReverseArgsForDiff(ref.ParentRefName()) + _, err := self.c.RunSubprocess(self.c.Git().Diff.OpenDiffToolCmdObj( + git_commands.DiffToolCmdOptions{ + Filepath: node.GetPath(), + FromCommit: from, + ToCommit: to, + Reverse: reverse, + IsDirectory: !node.IsFile(), + Staged: false, + })) + return err +} + func (self *CommitFilesController) toggleForPatch(node *filetree.CommitFileNode) error { toggle := func() error { return self.c.WithWaitingStatus(self.c.Tr.UpdatingPatch, func(gocui.Task) error { diff --git a/pkg/gui/controllers/files_controller.go b/pkg/gui/controllers/files_controller.go index 733487d5ad5..0db509ca3b0 100644 --- a/pkg/gui/controllers/files_controller.go +++ b/pkg/gui/controllers/files_controller.go @@ -4,6 +4,7 @@ import ( "strings" "github.com/jesseduffield/gocui" + "github.com/jesseduffield/lazygit/pkg/commands/git_commands" "github.com/jesseduffield/lazygit/pkg/commands/models" "github.com/jesseduffield/lazygit/pkg/gui/context" "github.com/jesseduffield/lazygit/pkg/gui/filetree" @@ -122,6 +123,11 @@ func (self *FilesController) GetKeybindings(opts types.KeybindingsOpts) []*types Handler: self.toggleTreeView, Description: self.c.Tr.ToggleTreeView, }, + { + Key: opts.GetKey(opts.Config.Universal.OpenDiffTool), + Handler: self.checkSelectedFileNode(self.openDiffTool), + Description: self.c.Tr.OpenDiffTool, + }, { Key: opts.GetKey(opts.Config.Files.OpenMergeTool), Handler: self.c.Helpers().WorkingTree.OpenMergeTool, @@ -684,6 +690,26 @@ func (self *FilesController) Open() error { return self.c.Helpers().Files.OpenFile(node.GetPath()) } +func (self *FilesController) openDiffTool(node *filetree.FileNode) error { + fromCommit := "" + reverse := false + if self.c.Modes().Diffing.Active() { + fromCommit = self.c.Modes().Diffing.Ref + reverse = self.c.Modes().Diffing.Reverse + } + return self.c.RunSubprocessAndRefresh( + self.c.Git().Diff.OpenDiffToolCmdObj( + git_commands.DiffToolCmdOptions{ + Filepath: node.Path, + FromCommit: fromCommit, + ToCommit: "", + Reverse: reverse, + IsDirectory: !node.IsFile(), + Staged: !node.GetHasUnstagedChanges(), + }), + ) +} + func (self *FilesController) switchToMerge() error { file := self.getSelectedFile() if file == nil { diff --git a/pkg/i18n/english.go b/pkg/i18n/english.go index 06c66d0a62f..34df4aba187 100644 --- a/pkg/i18n/english.go +++ b/pkg/i18n/english.go @@ -46,6 +46,7 @@ type TranslationSet struct { ToggleStaged string ToggleStagedAll string ToggleTreeView string + OpenDiffTool string OpenMergeTool string Refresh string Push string @@ -782,6 +783,7 @@ type Actions struct { Undo string Redo string CopyPullRequestURL string + OpenDiffTool string OpenMergeTool string OpenCommitInBrowser string OpenPullRequest string @@ -862,6 +864,7 @@ func EnglishTranslationSet() TranslationSet { ToggleStaged: "Toggle staged", ToggleStagedAll: "Stage/unstage all", ToggleTreeView: "Toggle file tree view", + OpenDiffTool: "Open external diff tool (git difftool)", OpenMergeTool: "Open external merge tool (git mergetool)", Refresh: "Refresh", Push: "Push", @@ -1558,6 +1561,7 @@ func EnglishTranslationSet() TranslationSet { Undo: "Undo", Redo: "Redo", CopyPullRequestURL: "Copy pull request URL", + OpenDiffTool: "Open diff tool", OpenMergeTool: "Open merge tool", OpenCommitInBrowser: "Open commit in browser", OpenPullRequest: "Open pull request in browser",