Carry the selection to the next change after staging

Staging takes the lines it acted on out of the diff, so the selection has
nothing to sit on afterwards and would be left wherever those lines used to
be. What the user wants is the change that moved up into their place, so
that pressing the key again goes on to the next one — which is how staging
line by line through a file works.

The line acted on is gone, so it can't be remembered by identity the way a
re-render of the same diff remembers one; what is remembered instead is its
place in the sequence of the diff's changes, which the change after it
inherits. Staging the last change is the one case with nothing to inherit
it, and there the selection stays on the last change there is.

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
Stefan Haller
2026-10-01 17:07:53 +02:00
co-authored by Claude Opus 5
parent a677104871
commit 4146c52f4f
6 changed files with 168 additions and 4 deletions
@@ -0,0 +1,54 @@
package main_view
import (
"github.com/jesseduffield/lazygit/pkg/config"
. "github.com/jesseduffield/lazygit/pkg/integration/components"
)
var SelectNextChangeAfterStaging = NewIntegrationTest(NewIntegrationTestArgs{
Description: "After staging from the focused main view the selection lands on the change that took the place of the one staged",
ExtraCmdArgs: []string{},
Skip: false,
SetupConfig: func(cfg *config.AppConfig) {
cfg.GetUserConfig().Gui.UseHunkModeInStagingView = false
},
SetupRepo: func(shell *Shell) {
shell.CreateFileAndAdd("file1", "one\ntwo\nthree\nfour\nfive\nsix\nseven\neight\nnine\nten\n")
shell.Commit("one")
shell.UpdateFile("file1", "one\nADD1\nADD2\ntwo\nthree\nfour\nfive\nsix\nseven\neight\nNINE\nten\n")
},
Run: func(t *TestDriver, keys config.KeybindingConfig) {
t.Views().Files().
IsFocused().
Press(keys.Universal.FocusMainView)
// Line by line, each press leaves the selection on the next change to stage.
t.Views().Main().
IsFocused().
SelectedLines(
Contains("+ADD1"),
).
PressPrimaryAction().
SelectedLines(
Contains("+ADD2"),
).
PressPrimaryAction().
SelectedLines(
Contains("-nine"),
).
// A hunk goes the same way: the block after the one staged takes its place,
// and here there is none, so the last change stays selected.
Press(keys.Main.ToggleSelectHunk).
SelectedLines(
Contains("-nine"),
Contains("+NINE"),
).
PressPrimaryAction().
Tap(func() {
t.Views().Files().Lines(
Contains("M file1"),
)
})
},
})
+1
View File
@@ -405,6 +405,7 @@ var tests = []*components.IntegrationTest{
main_view.SelectHunkOnFocusingMainView,
main_view.SelectInADiffReadInPart,
main_view.SelectLineWhenWholeFileIsOneHunk,
main_view.SelectNextChangeAfterStaging,
main_view.SelectVisibleChangeOnFocusingMainView,
main_view.SelectVisibleHunkOnFocusingMainView,
main_view.SelectionCommandsOnlyWhereTheyApply,