mirror of
https://github.com/jesseduffield/lazygit.git
synced 2026-10-05 21:46:49 -04:00
Keep your place in the diff when ignoring whitespace
Ignoring whitespace is how you ask whether what you are looking at is more than reindentation, so being dropped at the top of the diff is a poor answer: you have to find your way back to the change you were asking about to see what became of it. Unlike the other ways of re-rendering a diff, this one can take the line you were on away for good, along with the hunk or even the file it was in. When it does, the view lands on the nearest line the diff kept, wherever in it that is — the walk of fallbacks doesn't stop at the file's edge, since a file of nothing but reindentation leaves nothing nearer to land on. And when ignoring whitespace empties the diff altogether, there is nothing to keep and the view simply shows what is left. A whitespace-only change that shares a hunk with a real one is a happier case: it is shown as a context line rather than as a change, but it is still the same line of the same file, so we stay on it. Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
f1f5479d47
commit
1a9a8e5203
@@ -27,6 +27,12 @@ func (self *ToggleWhitespaceAction) Call() error {
|
||||
|
||||
self.c.UserConfig().Git.IgnoreWhitespaceInDiffView = !self.c.UserConfig().Git.IgnoreWhitespaceInDiffView
|
||||
|
||||
// You toggle this to see whether what you are looking at is more than
|
||||
// reindentation, so that is the thing to keep in front of you — even though
|
||||
// ignoring whitespace, unlike the other ways of re-rendering a diff, can take
|
||||
// the line away entirely along with the hunk or file it was in.
|
||||
self.c.Helpers().DiffLine.PreserveDiffPositionOnRerender(self.c.Contexts().Normal.GetView())
|
||||
self.c.Helpers().DiffLine.PreserveDiffPositionOnRerender(self.c.Contexts().NormalSecondary.GetView())
|
||||
self.c.Context().CurrentSide().HandleRenderToMain()
|
||||
return nil
|
||||
}
|
||||
|
||||
+70
@@ -0,0 +1,70 @@
|
||||
package main_view
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/jesseduffield/lazygit/pkg/config"
|
||||
. "github.com/jesseduffield/lazygit/pkg/integration/components"
|
||||
)
|
||||
|
||||
var KeepPositionInBothPanesWhenIgnoringWhitespace = NewIntegrationTest(NewIntegrationTestArgs{
|
||||
Description: "Ignoring whitespace keeps the place in the lower pane too, not only in the upper one",
|
||||
ExtraCmdArgs: []string{},
|
||||
Skip: false,
|
||||
Width: 120,
|
||||
Height: 30,
|
||||
SetupConfig: func(cfg *config.AppConfig) {
|
||||
cfg.GetUserConfig().Gui.UseHunkModeInStagingView = false
|
||||
},
|
||||
SetupRepo: func(shell *Shell) {
|
||||
lines := make([]string, 60)
|
||||
for i := range lines {
|
||||
lines[i] = fmt.Sprintf("line%02d", i+1)
|
||||
}
|
||||
shell.CreateFileAndAdd("file1", strings.Join(lines, "\n")+"\n")
|
||||
shell.Commit("one")
|
||||
|
||||
// Staged: real changes at lines 5, 25 and 45, and a whitespace-only one at 15,
|
||||
// whose hunk goes when whitespace stops counting.
|
||||
lines[4] = strings.ToUpper(lines[4])
|
||||
lines[14] = " " + lines[14]
|
||||
lines[24] = strings.ToUpper(lines[24])
|
||||
lines[44] = strings.ToUpper(lines[44])
|
||||
shell.UpdateFile("file1", strings.Join(lines, "\n")+"\n")
|
||||
shell.GitAddAll()
|
||||
|
||||
// And one unstaged change, to split the file's diff across both panes.
|
||||
lines[59] = strings.ToUpper(lines[59])
|
||||
shell.UpdateFile("file1", strings.Join(lines, "\n")+"\n")
|
||||
},
|
||||
Run: func(t *TestDriver, keys config.KeybindingConfig) {
|
||||
t.Views().Files().
|
||||
IsFocused().
|
||||
Press(keys.Universal.FocusMainView)
|
||||
|
||||
t.Views().Main().
|
||||
IsFocused().
|
||||
PressTab()
|
||||
|
||||
t.Views().Secondary().
|
||||
IsFocused().
|
||||
Press(keys.Main.NextHunk).
|
||||
Press(keys.Main.NextHunk).
|
||||
Press(keys.Main.NextHunk).
|
||||
SelectedLines(
|
||||
Contains("-line45"),
|
||||
).
|
||||
SelectedLineIdx(35).
|
||||
OriginY(14).
|
||||
Press(keys.Universal.ToggleWhitespaceInDiffView).
|
||||
// The hunk above this one held nothing but a whitespace change, so it is
|
||||
// gone and has taken nine lines of the lower pane's diff with it — leaving
|
||||
// the line we were on where it was on the screen.
|
||||
SelectedLines(
|
||||
Contains("-line45"),
|
||||
).
|
||||
SelectedLineIdx(26).
|
||||
OriginY(5)
|
||||
},
|
||||
})
|
||||
@@ -0,0 +1,85 @@
|
||||
package main_view
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/jesseduffield/lazygit/pkg/config"
|
||||
. "github.com/jesseduffield/lazygit/pkg/integration/components"
|
||||
)
|
||||
|
||||
var KeepPositionWhenIgnoringWhitespace = NewIntegrationTest(NewIntegrationTestArgs{
|
||||
Description: "Ignoring whitespace keeps the line you were looking at where it was, even when it turns into a context line",
|
||||
ExtraCmdArgs: []string{},
|
||||
Skip: false,
|
||||
Width: 120,
|
||||
Height: 30,
|
||||
SetupConfig: func(cfg *config.AppConfig) {
|
||||
cfg.GetUserConfig().Gui.UseHunkModeInStagingView = false
|
||||
},
|
||||
SetupRepo: func(shell *Shell) {
|
||||
lines := make([]string, 40)
|
||||
for i := range lines {
|
||||
lines[i] = fmt.Sprintf("line%02d", i+1)
|
||||
}
|
||||
shell.CreateFileAndAdd("file1", strings.Join(lines, "\n")+"\n")
|
||||
shell.Commit("one")
|
||||
|
||||
// Real changes at lines 5 and 25, whitespace-only ones at 15, 27 and 35. The
|
||||
// one at 27 shares a hunk with the change at 25, so ignoring whitespace turns
|
||||
// it into a context line rather than taking its hunk away.
|
||||
lines[4] = strings.ToUpper(lines[4])
|
||||
lines[14] = " " + lines[14]
|
||||
lines[24] = strings.ToUpper(lines[24])
|
||||
lines[26] = lines[26] + " "
|
||||
lines[34] = " " + lines[34]
|
||||
shell.UpdateFile("file1", strings.Join(lines, "\n")+"\n")
|
||||
},
|
||||
Run: func(t *TestDriver, keys config.KeybindingConfig) {
|
||||
t.Views().Files().
|
||||
IsFocused().
|
||||
Press(keys.Universal.FocusMainView)
|
||||
|
||||
t.Views().Main().
|
||||
IsFocused().
|
||||
Press(keys.Main.NextHunk).
|
||||
Press(keys.Main.NextHunk).
|
||||
SelectedLines(
|
||||
Contains("-line25"),
|
||||
).
|
||||
SelectedLineIdx(26).
|
||||
OriginY(14).
|
||||
Press(keys.Universal.ToggleWhitespaceInDiffView).
|
||||
// The hunk above this one held nothing but a whitespace change, so it is
|
||||
// gone and has taken nine lines of diff with it. This is still the line we
|
||||
// were on, on the row we were on (26 - 14 = 17 - 5).
|
||||
SelectedLines(
|
||||
Contains("-line25"),
|
||||
).
|
||||
SelectedLineIdx(17).
|
||||
OriginY(5).
|
||||
// And back again, whitespace and all.
|
||||
Press(keys.Universal.ToggleWhitespaceInDiffView).
|
||||
SelectedLines(
|
||||
Contains("-line25"),
|
||||
).
|
||||
SelectedLineIdx(26).
|
||||
OriginY(14).
|
||||
// The whitespace-only change further down this hunk is a line of the file
|
||||
// like any other: ignoring whitespace shows it as context instead of as a
|
||||
// change, and that is still where we are.
|
||||
Press(keys.Main.NextHunk).
|
||||
Press(keys.Universal.NextItem).
|
||||
SelectedLines(
|
||||
Contains("+line27"),
|
||||
).
|
||||
SelectedLineIdx(30).
|
||||
OriginY(14).
|
||||
Press(keys.Universal.ToggleWhitespaceInDiffView).
|
||||
SelectedLines(
|
||||
Contains(" line27"),
|
||||
).
|
||||
SelectedLineIdx(20).
|
||||
OriginY(4)
|
||||
},
|
||||
})
|
||||
@@ -0,0 +1,81 @@
|
||||
package main_view
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/jesseduffield/lazygit/pkg/config"
|
||||
. "github.com/jesseduffield/lazygit/pkg/integration/components"
|
||||
)
|
||||
|
||||
var KeepPositionWhenIgnoringWhitespaceRemovesIt = NewIntegrationTest(NewIntegrationTestArgs{
|
||||
Description: "Ignoring whitespace where that takes the line you were on out of the diff lands on the nearest line it kept",
|
||||
ExtraCmdArgs: []string{},
|
||||
Skip: false,
|
||||
Width: 120,
|
||||
Height: 30,
|
||||
SetupConfig: func(cfg *config.AppConfig) {
|
||||
cfg.GetUserConfig().Gui.UseHunkModeInStagingView = false
|
||||
},
|
||||
SetupRepo: func(shell *Shell) {
|
||||
lines := make([]string, 40)
|
||||
for i := range lines {
|
||||
lines[i] = fmt.Sprintf("line%02d", i+1)
|
||||
}
|
||||
shell.CreateFileAndAdd("file1", strings.Join(lines, "\n")+"\n")
|
||||
shell.CreateFileAndAdd("file2", "one\ntwo\nthree\n")
|
||||
shell.Commit("one")
|
||||
|
||||
// Real changes at lines 5, 15 and 25, and a whitespace-only one at 35, far
|
||||
// enough apart to be hunks of their own.
|
||||
for _, i := range []int{5, 15, 25} {
|
||||
lines[i-1] = strings.ToUpper(lines[i-1])
|
||||
}
|
||||
lines[34] = " " + lines[34]
|
||||
shell.UpdateFile("file1", strings.Join(lines, "\n")+"\n")
|
||||
|
||||
// Nothing but reindentation, so ignoring whitespace leaves no diff at all.
|
||||
shell.UpdateFile("file2", " one\n two\n three\n")
|
||||
},
|
||||
Run: func(t *TestDriver, keys config.KeybindingConfig) {
|
||||
t.Views().Files().
|
||||
IsFocused().
|
||||
SelectNextItem().
|
||||
SelectedLine(Contains("file1")).
|
||||
Press(keys.Universal.FocusMainView)
|
||||
|
||||
t.Views().Main().
|
||||
IsFocused().
|
||||
Press(keys.Main.NextHunk).
|
||||
Press(keys.Main.NextHunk).
|
||||
Press(keys.Main.NextHunk).
|
||||
SelectedLines(
|
||||
Contains("-line35"),
|
||||
).
|
||||
SelectedLineIdx(35).
|
||||
OriginY(14).
|
||||
Press(keys.Universal.ToggleWhitespaceInDiffView).
|
||||
// That hunk was a whitespace change and nothing else, so ignoring
|
||||
// whitespace takes it — and the context around it — out of the diff
|
||||
// entirely. The nearest line the diff kept is the last line of the hunk
|
||||
// above, so that is where the selection lands; it goes back on the row it
|
||||
// was on itself, which leaves everything above it exactly where it was.
|
||||
SelectedLines(
|
||||
Contains(" line28"),
|
||||
).
|
||||
SelectedLineIdx(30).
|
||||
OriginY(14).
|
||||
// The whole diff can go this way, and then there is nothing to land on.
|
||||
Press(keys.Universal.ToggleWhitespaceInDiffView).
|
||||
PressEscape()
|
||||
|
||||
t.Views().Files().
|
||||
IsFocused().
|
||||
SelectNextItem().
|
||||
SelectedLine(Contains("file2")).
|
||||
Press(keys.Universal.ToggleWhitespaceInDiffView)
|
||||
|
||||
t.Views().Main().
|
||||
Content(Equals(""))
|
||||
},
|
||||
})
|
||||
@@ -372,8 +372,11 @@ var tests = []*components.IntegrationTest{
|
||||
main_view.FileNavigationScrollsToTheTop,
|
||||
main_view.HideSelectionWhenChangesVanish,
|
||||
main_view.KeepPositionInBothPanesWhenChangingContextSize,
|
||||
main_view.KeepPositionInBothPanesWhenIgnoringWhitespace,
|
||||
main_view.KeepPositionInBothPanesWhenSwitchingDiffRenderers,
|
||||
main_view.KeepPositionWhenChangingContextSize,
|
||||
main_view.KeepPositionWhenIgnoringWhitespace,
|
||||
main_view.KeepPositionWhenIgnoringWhitespaceRemovesIt,
|
||||
main_view.KeepPositionWhenSwitchingDiffRenderers,
|
||||
main_view.KeepPositionWhenTheSelectionIsOffScreen,
|
||||
main_view.KeepScrollWhenTheDiffCantBeRead,
|
||||
|
||||
Reference in New Issue
Block a user