mirror of
https://github.com/jesseduffield/lazygit.git
synced 2025-02-15 14:03:06 +02:00
Add support for external diff commands (e.g. difftastic)
This commit is contained in:
parent
c67aa49856
commit
6266e19623
@ -62,3 +62,25 @@ git:
|
|||||||
```
|
```
|
||||||
|
|
||||||
If you set `useConfig: true`, lazygit will use whatever pager is specified in `$GIT_PAGER`, `$PAGER`, or your *git config*. If the pager ends with something like ` | less` we will strip that part out, because less doesn't play nice with our rendering approach. If the custom pager uses less under the hood, that will also break rendering (hence the `--paging=never` flag for the `delta` pager).
|
If you set `useConfig: true`, lazygit will use whatever pager is specified in `$GIT_PAGER`, `$PAGER`, or your *git config*. If the pager ends with something like ` | less` we will strip that part out, because less doesn't play nice with our rendering approach. If the custom pager uses less under the hood, that will also break rendering (hence the `--paging=never` flag for the `delta` pager).
|
||||||
|
|
||||||
|
## Using external diff commands
|
||||||
|
|
||||||
|
Some diff tools can't work as a simple pager like the ones above do, because they need access to the entire diff, so just post-processing git's diff is not enough for them. The most notable example is probably [difftastic](https://difftastic.wilfred.me.uk).
|
||||||
|
|
||||||
|
These can be used in lazygit by using the `externalDiffCommand` config; in the case of difftastic, that could be
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
git:
|
||||||
|
paging:
|
||||||
|
externalDiffCommand: difft --color=always
|
||||||
|
```
|
||||||
|
|
||||||
|
The `colorArg`, `pager`, and `useConfig` options are not used in this case.
|
||||||
|
|
||||||
|
You can add whatever extra arguments you prefer for your difftool; for instance
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
git:
|
||||||
|
paging:
|
||||||
|
externalDiffCommand: difft --color=always --display=inline --syntax-highlight=off
|
||||||
|
```
|
||||||
|
@ -199,9 +199,11 @@ func (self *CommitCommands) AmendHeadCmdObj() oscommands.ICmdObj {
|
|||||||
func (self *CommitCommands) ShowCmdObj(sha string, filterPath string, ignoreWhitespace bool) oscommands.ICmdObj {
|
func (self *CommitCommands) ShowCmdObj(sha string, filterPath string, ignoreWhitespace bool) oscommands.ICmdObj {
|
||||||
contextSize := self.UserConfig.Git.DiffContextSize
|
contextSize := self.UserConfig.Git.DiffContextSize
|
||||||
|
|
||||||
|
extDiffCmd := self.UserConfig.Git.Paging.ExternalDiffCommand
|
||||||
cmdArgs := NewGitCmd("show").
|
cmdArgs := NewGitCmd("show").
|
||||||
|
ConfigIf(extDiffCmd != "", "diff.external="+extDiffCmd).
|
||||||
|
ArgIfElse(extDiffCmd != "", "--ext-diff", "--no-ext-diff").
|
||||||
Arg("--submodule").
|
Arg("--submodule").
|
||||||
Arg("--no-ext-diff").
|
|
||||||
Arg("--color="+self.UserConfig.Git.Paging.ColorArg).
|
Arg("--color="+self.UserConfig.Git.Paging.ColorArg).
|
||||||
Arg(fmt.Sprintf("--unified=%d", contextSize)).
|
Arg(fmt.Sprintf("--unified=%d", contextSize)).
|
||||||
Arg("--stat").
|
Arg("--stat").
|
||||||
|
@ -186,6 +186,7 @@ func TestCommitShowCmdObj(t *testing.T) {
|
|||||||
filterPath string
|
filterPath string
|
||||||
contextSize int
|
contextSize int
|
||||||
ignoreWhitespace bool
|
ignoreWhitespace bool
|
||||||
|
extDiffCmd string
|
||||||
expected []string
|
expected []string
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -195,28 +196,40 @@ func TestCommitShowCmdObj(t *testing.T) {
|
|||||||
filterPath: "",
|
filterPath: "",
|
||||||
contextSize: 3,
|
contextSize: 3,
|
||||||
ignoreWhitespace: false,
|
ignoreWhitespace: false,
|
||||||
expected: []string{"show", "--submodule", "--no-ext-diff", "--color=always", "--unified=3", "--stat", "--decorate", "-p", "1234567890"},
|
extDiffCmd: "",
|
||||||
|
expected: []string{"show", "--no-ext-diff", "--submodule", "--color=always", "--unified=3", "--stat", "--decorate", "-p", "1234567890"},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
testName: "Default case with filter path",
|
testName: "Default case with filter path",
|
||||||
filterPath: "file.txt",
|
filterPath: "file.txt",
|
||||||
contextSize: 3,
|
contextSize: 3,
|
||||||
ignoreWhitespace: false,
|
ignoreWhitespace: false,
|
||||||
expected: []string{"show", "--submodule", "--no-ext-diff", "--color=always", "--unified=3", "--stat", "--decorate", "-p", "1234567890", "--", "file.txt"},
|
extDiffCmd: "",
|
||||||
|
expected: []string{"show", "--no-ext-diff", "--submodule", "--color=always", "--unified=3", "--stat", "--decorate", "-p", "1234567890", "--", "file.txt"},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
testName: "Show diff with custom context size",
|
testName: "Show diff with custom context size",
|
||||||
filterPath: "",
|
filterPath: "",
|
||||||
contextSize: 77,
|
contextSize: 77,
|
||||||
ignoreWhitespace: false,
|
ignoreWhitespace: false,
|
||||||
expected: []string{"show", "--submodule", "--no-ext-diff", "--color=always", "--unified=77", "--stat", "--decorate", "-p", "1234567890"},
|
extDiffCmd: "",
|
||||||
|
expected: []string{"show", "--no-ext-diff", "--submodule", "--color=always", "--unified=77", "--stat", "--decorate", "-p", "1234567890"},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
testName: "Show diff, ignoring whitespace",
|
testName: "Show diff, ignoring whitespace",
|
||||||
filterPath: "",
|
filterPath: "",
|
||||||
contextSize: 77,
|
contextSize: 77,
|
||||||
ignoreWhitespace: true,
|
ignoreWhitespace: true,
|
||||||
expected: []string{"show", "--submodule", "--no-ext-diff", "--color=always", "--unified=77", "--stat", "--decorate", "-p", "1234567890", "--ignore-all-space"},
|
extDiffCmd: "",
|
||||||
|
expected: []string{"show", "--no-ext-diff", "--submodule", "--color=always", "--unified=77", "--stat", "--decorate", "-p", "1234567890", "--ignore-all-space"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
testName: "Show diff with external diff command",
|
||||||
|
filterPath: "",
|
||||||
|
contextSize: 3,
|
||||||
|
ignoreWhitespace: false,
|
||||||
|
extDiffCmd: "difft --color=always",
|
||||||
|
expected: []string{"-c", "diff.external=difft --color=always", "show", "--ext-diff", "--submodule", "--color=always", "--unified=3", "--stat", "--decorate", "-p", "1234567890"},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -225,6 +238,7 @@ func TestCommitShowCmdObj(t *testing.T) {
|
|||||||
t.Run(s.testName, func(t *testing.T) {
|
t.Run(s.testName, func(t *testing.T) {
|
||||||
userConfig := config.GetDefaultConfig()
|
userConfig := config.GetDefaultConfig()
|
||||||
userConfig.Git.DiffContextSize = s.contextSize
|
userConfig.Git.DiffContextSize = s.contextSize
|
||||||
|
userConfig.Git.Paging.ExternalDiffCommand = s.extDiffCmd
|
||||||
|
|
||||||
runner := oscommands.NewFakeRunner(t).ExpectGitArgs(s.expected, "", nil)
|
runner := oscommands.NewFakeRunner(t).ExpectGitArgs(s.expected, "", nil)
|
||||||
instance := buildCommitCommands(commonDeps{userConfig: userConfig, runner: runner})
|
instance := buildCommitCommands(commonDeps{userConfig: userConfig, runner: runner})
|
||||||
|
@ -44,6 +44,14 @@ func (self *GitCommandBuilder) Config(value string) *GitCommandBuilder {
|
|||||||
return self
|
return self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (self *GitCommandBuilder) ConfigIf(condition bool, ifTrue string) *GitCommandBuilder {
|
||||||
|
if condition {
|
||||||
|
self.Config(ifTrue)
|
||||||
|
}
|
||||||
|
|
||||||
|
return self
|
||||||
|
}
|
||||||
|
|
||||||
// the -C arg will make git do a `cd` to the directory before doing anything else
|
// the -C arg will make git do a `cd` to the directory before doing anything else
|
||||||
func (self *GitCommandBuilder) Dir(path string) *GitCommandBuilder {
|
func (self *GitCommandBuilder) Dir(path string) *GitCommandBuilder {
|
||||||
// repo path comes before the command
|
// repo path comes before the command
|
||||||
|
@ -243,10 +243,13 @@ func (self *WorkingTreeCommands) WorktreeFileDiffCmdObj(node models.IFile, plain
|
|||||||
contextSize := self.UserConfig.Git.DiffContextSize
|
contextSize := self.UserConfig.Git.DiffContextSize
|
||||||
prevPath := node.GetPreviousPath()
|
prevPath := node.GetPreviousPath()
|
||||||
noIndex := !node.GetIsTracked() && !node.GetHasStagedChanges() && !cached && node.GetIsFile()
|
noIndex := !node.GetIsTracked() && !node.GetHasStagedChanges() && !cached && node.GetIsFile()
|
||||||
|
extDiffCmd := self.UserConfig.Git.Paging.ExternalDiffCommand
|
||||||
|
useExtDiff := extDiffCmd != "" && !plain
|
||||||
|
|
||||||
cmdArgs := NewGitCmd("diff").
|
cmdArgs := NewGitCmd("diff").
|
||||||
|
ConfigIf(useExtDiff, "diff.external="+extDiffCmd).
|
||||||
|
ArgIfElse(useExtDiff, "--ext-diff", "--no-ext-diff").
|
||||||
Arg("--submodule").
|
Arg("--submodule").
|
||||||
Arg("--no-ext-diff").
|
|
||||||
Arg(fmt.Sprintf("--unified=%d", contextSize)).
|
Arg(fmt.Sprintf("--unified=%d", contextSize)).
|
||||||
Arg(fmt.Sprintf("--color=%s", colorArg)).
|
Arg(fmt.Sprintf("--color=%s", colorArg)).
|
||||||
ArgIf(ignoreWhitespace, "--ignore-all-space").
|
ArgIf(ignoreWhitespace, "--ignore-all-space").
|
||||||
@ -279,9 +282,13 @@ func (self *WorkingTreeCommands) ShowFileDiffCmdObj(from string, to string, reve
|
|||||||
colorArg = "never"
|
colorArg = "never"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extDiffCmd := self.UserConfig.Git.Paging.ExternalDiffCommand
|
||||||
|
useExtDiff := extDiffCmd != "" && !plain
|
||||||
|
|
||||||
cmdArgs := NewGitCmd("diff").
|
cmdArgs := NewGitCmd("diff").
|
||||||
|
ConfigIf(useExtDiff, "diff.external="+extDiffCmd).
|
||||||
|
ArgIfElse(useExtDiff, "--ext-diff", "--no-ext-diff").
|
||||||
Arg("--submodule").
|
Arg("--submodule").
|
||||||
Arg("--no-ext-diff").
|
|
||||||
Arg(fmt.Sprintf("--unified=%d", contextSize)).
|
Arg(fmt.Sprintf("--unified=%d", contextSize)).
|
||||||
Arg("--no-renames").
|
Arg("--no-renames").
|
||||||
Arg(fmt.Sprintf("--color=%s", colorArg)).
|
Arg(fmt.Sprintf("--color=%s", colorArg)).
|
||||||
|
@ -231,7 +231,7 @@ func TestWorkingTreeDiff(t *testing.T) {
|
|||||||
ignoreWhitespace: false,
|
ignoreWhitespace: false,
|
||||||
contextSize: 3,
|
contextSize: 3,
|
||||||
runner: oscommands.NewFakeRunner(t).
|
runner: oscommands.NewFakeRunner(t).
|
||||||
ExpectGitArgs([]string{"diff", "--submodule", "--no-ext-diff", "--unified=3", "--color=always", "--", "test.txt"}, expectedResult, nil),
|
ExpectGitArgs([]string{"diff", "--no-ext-diff", "--submodule", "--unified=3", "--color=always", "--", "test.txt"}, expectedResult, nil),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
testName: "cached",
|
testName: "cached",
|
||||||
@ -245,7 +245,7 @@ func TestWorkingTreeDiff(t *testing.T) {
|
|||||||
ignoreWhitespace: false,
|
ignoreWhitespace: false,
|
||||||
contextSize: 3,
|
contextSize: 3,
|
||||||
runner: oscommands.NewFakeRunner(t).
|
runner: oscommands.NewFakeRunner(t).
|
||||||
ExpectGitArgs([]string{"diff", "--submodule", "--no-ext-diff", "--unified=3", "--color=always", "--cached", "--", "test.txt"}, expectedResult, nil),
|
ExpectGitArgs([]string{"diff", "--no-ext-diff", "--submodule", "--unified=3", "--color=always", "--cached", "--", "test.txt"}, expectedResult, nil),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
testName: "plain",
|
testName: "plain",
|
||||||
@ -259,7 +259,7 @@ func TestWorkingTreeDiff(t *testing.T) {
|
|||||||
ignoreWhitespace: false,
|
ignoreWhitespace: false,
|
||||||
contextSize: 3,
|
contextSize: 3,
|
||||||
runner: oscommands.NewFakeRunner(t).
|
runner: oscommands.NewFakeRunner(t).
|
||||||
ExpectGitArgs([]string{"diff", "--submodule", "--no-ext-diff", "--unified=3", "--color=never", "--", "test.txt"}, expectedResult, nil),
|
ExpectGitArgs([]string{"diff", "--no-ext-diff", "--submodule", "--unified=3", "--color=never", "--", "test.txt"}, expectedResult, nil),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
testName: "File not tracked and file has no staged changes",
|
testName: "File not tracked and file has no staged changes",
|
||||||
@ -273,7 +273,7 @@ func TestWorkingTreeDiff(t *testing.T) {
|
|||||||
ignoreWhitespace: false,
|
ignoreWhitespace: false,
|
||||||
contextSize: 3,
|
contextSize: 3,
|
||||||
runner: oscommands.NewFakeRunner(t).
|
runner: oscommands.NewFakeRunner(t).
|
||||||
ExpectGitArgs([]string{"diff", "--submodule", "--no-ext-diff", "--unified=3", "--color=always", "--no-index", "--", "/dev/null", "test.txt"}, expectedResult, nil),
|
ExpectGitArgs([]string{"diff", "--no-ext-diff", "--submodule", "--unified=3", "--color=always", "--no-index", "--", "/dev/null", "test.txt"}, expectedResult, nil),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
testName: "Default case (ignore whitespace)",
|
testName: "Default case (ignore whitespace)",
|
||||||
@ -287,7 +287,7 @@ func TestWorkingTreeDiff(t *testing.T) {
|
|||||||
ignoreWhitespace: true,
|
ignoreWhitespace: true,
|
||||||
contextSize: 3,
|
contextSize: 3,
|
||||||
runner: oscommands.NewFakeRunner(t).
|
runner: oscommands.NewFakeRunner(t).
|
||||||
ExpectGitArgs([]string{"diff", "--submodule", "--no-ext-diff", "--unified=3", "--color=always", "--ignore-all-space", "--", "test.txt"}, expectedResult, nil),
|
ExpectGitArgs([]string{"diff", "--no-ext-diff", "--submodule", "--unified=3", "--color=always", "--ignore-all-space", "--", "test.txt"}, expectedResult, nil),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
testName: "Show diff with custom context size",
|
testName: "Show diff with custom context size",
|
||||||
@ -301,7 +301,7 @@ func TestWorkingTreeDiff(t *testing.T) {
|
|||||||
ignoreWhitespace: false,
|
ignoreWhitespace: false,
|
||||||
contextSize: 17,
|
contextSize: 17,
|
||||||
runner: oscommands.NewFakeRunner(t).
|
runner: oscommands.NewFakeRunner(t).
|
||||||
ExpectGitArgs([]string{"diff", "--submodule", "--no-ext-diff", "--unified=17", "--color=always", "--", "test.txt"}, expectedResult, nil),
|
ExpectGitArgs([]string{"diff", "--no-ext-diff", "--submodule", "--unified=17", "--color=always", "--", "test.txt"}, expectedResult, nil),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -343,7 +343,7 @@ func TestWorkingTreeShowFileDiff(t *testing.T) {
|
|||||||
ignoreWhitespace: false,
|
ignoreWhitespace: false,
|
||||||
contextSize: 3,
|
contextSize: 3,
|
||||||
runner: oscommands.NewFakeRunner(t).
|
runner: oscommands.NewFakeRunner(t).
|
||||||
ExpectGitArgs([]string{"diff", "--submodule", "--no-ext-diff", "--unified=3", "--no-renames", "--color=always", "1234567890", "0987654321", "--", "test.txt"}, expectedResult, nil),
|
ExpectGitArgs([]string{"diff", "--no-ext-diff", "--submodule", "--unified=3", "--no-renames", "--color=always", "1234567890", "0987654321", "--", "test.txt"}, expectedResult, nil),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
testName: "Show diff with custom context size",
|
testName: "Show diff with custom context size",
|
||||||
@ -354,7 +354,7 @@ func TestWorkingTreeShowFileDiff(t *testing.T) {
|
|||||||
ignoreWhitespace: false,
|
ignoreWhitespace: false,
|
||||||
contextSize: 123,
|
contextSize: 123,
|
||||||
runner: oscommands.NewFakeRunner(t).
|
runner: oscommands.NewFakeRunner(t).
|
||||||
ExpectGitArgs([]string{"diff", "--submodule", "--no-ext-diff", "--unified=123", "--no-renames", "--color=always", "1234567890", "0987654321", "--", "test.txt"}, expectedResult, nil),
|
ExpectGitArgs([]string{"diff", "--no-ext-diff", "--submodule", "--unified=123", "--no-renames", "--color=always", "1234567890", "0987654321", "--", "test.txt"}, expectedResult, nil),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
testName: "Default case (ignore whitespace)",
|
testName: "Default case (ignore whitespace)",
|
||||||
@ -365,7 +365,7 @@ func TestWorkingTreeShowFileDiff(t *testing.T) {
|
|||||||
ignoreWhitespace: true,
|
ignoreWhitespace: true,
|
||||||
contextSize: 3,
|
contextSize: 3,
|
||||||
runner: oscommands.NewFakeRunner(t).
|
runner: oscommands.NewFakeRunner(t).
|
||||||
ExpectGitArgs([]string{"diff", "--submodule", "--no-ext-diff", "--unified=3", "--no-renames", "--color=always", "1234567890", "0987654321", "--ignore-all-space", "--", "test.txt"}, expectedResult, nil),
|
ExpectGitArgs([]string{"diff", "--no-ext-diff", "--submodule", "--unified=3", "--no-renames", "--color=always", "1234567890", "0987654321", "--ignore-all-space", "--", "test.txt"}, expectedResult, nil),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -104,6 +104,7 @@ type PagingConfig struct {
|
|||||||
ColorArg string `yaml:"colorArg"`
|
ColorArg string `yaml:"colorArg"`
|
||||||
Pager string `yaml:"pager"`
|
Pager string `yaml:"pager"`
|
||||||
UseConfig bool `yaml:"useConfig"`
|
UseConfig bool `yaml:"useConfig"`
|
||||||
|
ExternalDiffCommand string `yaml:"externalDiffCommand"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type CommitConfig struct {
|
type CommitConfig struct {
|
||||||
@ -472,6 +473,7 @@ func GetDefaultConfig() *UserConfig {
|
|||||||
ColorArg: "always",
|
ColorArg: "always",
|
||||||
Pager: "",
|
Pager: "",
|
||||||
UseConfig: false,
|
UseConfig: false,
|
||||||
|
ExternalDiffCommand: "",
|
||||||
},
|
},
|
||||||
Commit: CommitConfig{
|
Commit: CommitConfig{
|
||||||
SignOff: false,
|
SignOff: false,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user