Follow the selection with the search in the focused main view

Search the diff, then move the selection with the arrow keys, and
pressing "n" goes to the match after the one the search was last on
rather than to the one after the selection. So walking through the diff
and then picking up the search where you got to takes as many presses as
there are matches behind you.

List views and the staging view keep the current match in step with their
selection; do the same here.

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
Stefan Haller
2026-10-04 19:01:02 +02:00
co-authored by Claude Opus 5
parent 63ff603adc
commit fe2ecfc60f
3 changed files with 54 additions and 0 deletions
@@ -329,6 +329,10 @@ func (self *MainViewController) onDragInFocusedView(opts gocui.ViewMouseBindingO
func (self *MainViewController) onDragRelease(gocui.ViewMouseBindingOpts) error {
self.draggingWithMouse = false
self.dragAutoscroller.Cancel()
// The drag moved the selection without going through showSelectionAtLine: gocui
// moves the cursor for it. Let the search catch up with where it ended.
self.context.GetView().SetNearestSearchPosition()
return nil
}
@@ -489,6 +493,11 @@ func hunkModeApplies(c *ControllerCommon, view *gocui.View, changeViewLine int)
// screen already.
func showSelectionAtLine(view *gocui.View, lineIdx int, scrollIntoView bool) {
view.FocusPoint(0, lo.Clamp(lineIdx, 0, max(0, view.ViewLinesHeight()-1)), scrollIntoView)
// A search carries on from where the selection now is, so that stepping to the
// next match goes to the one after it rather than the one after the match the
// user last stepped to.
view.SetNearestSearchPosition()
}
func (self *MainViewController) selectHunkAround(changeViewLine int, scrollIntoView bool) {
@@ -0,0 +1,44 @@
package main_view
import (
"github.com/jesseduffield/lazygit/pkg/config"
. "github.com/jesseduffield/lazygit/pkg/integration/components"
)
var SearchFollowsTheSelection = NewIntegrationTest(NewIntegrationTestArgs{
Description: "Stepping to the next match in the focused main view carries on from the selection",
ExtraCmdArgs: []string{},
Skip: false,
SetupConfig: func(config *config.AppConfig) {},
SetupRepo: func(shell *Shell) {
shell.CreateFileAndAdd("file1", "")
shell.Commit("one")
shell.UpdateFile("file1", "NEEDLE a\ntwo\nNEEDLE b\nfour\nNEEDLE c\n")
},
Run: func(t *TestDriver, keys config.KeybindingConfig) {
t.Views().Files().
IsFocused().
Press(keys.Universal.FocusMainView)
t.Views().Main().
IsFocused().
FilterOrSearch("NEEDLE").
SelectedLines(Contains("+NEEDLE a")).
Tap(func() {
t.Views().Search().Content(Contains("matches for 'NEEDLE' (1 of 3)"))
}).
// Move the selection past the second match by hand.
SelectNextItem().
SelectNextItem().
SelectNextItem().
SelectedLines(Contains("+four")).
Tap(func() {
t.Views().Search().Content(Contains("matches for 'NEEDLE' (2 of 3)"))
}).
// So the next match is the one after where the selection is, not the one
// after the match it was last on.
Press(keys.Universal.NextMatch).
SelectedLines(Contains("+NEEDLE c"))
},
})
+1
View File
@@ -378,6 +378,7 @@ var tests = []*components.IntegrationTest{
main_view.NoSelectionWhenNoChanges,
main_view.RangeSelectDiffLines,
main_view.SearchCollapsesTheSelection,
main_view.SearchFollowsTheSelection,
main_view.SelectBelowALongCommitMessage,
main_view.SelectBelowALongDiffstat,
main_view.SelectDiffLines,