mirror of
https://github.com/jesseduffield/lazygit.git
synced 2026-09-14 01:26:24 -04:00
Show the search status of what a re-rendered view now holds
Rendering a view's content again while a search is on leaves the "x of y" describing the content that has just been replaced. The status is worked out when the search is typed and again when a key steps through the matches, and a render is neither. Change the diff context size while searching the focused main view, and the count stays as it was, however many matches the wider context brought in or took away. Run the search again over the new content once the render has finished putting it there. Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
04a7ae3ec8
commit
811b3fbdd1
|
|
@ -311,6 +311,19 @@ func (v *View) refreshSearchPositionsIfNeeded() {
|
|||
}
|
||||
}
|
||||
|
||||
// RefreshSearch runs the search again over content the view has just been re-rendered
|
||||
// with, and shows the "x of y" status of what it finds. The view stays where it is: the
|
||||
// position in the content is the user's, and the search follows it rather than moving
|
||||
// it.
|
||||
func (v *View) RefreshSearch() {
|
||||
if !v.IsSearching() {
|
||||
return
|
||||
}
|
||||
|
||||
v.UpdateSearchResults(v.searcher.searchString, v.searcher.modelSearchResults)
|
||||
v.renderSearchStatus(v.searcher.currentSearchIndex, len(v.searcher.searchPositions))
|
||||
}
|
||||
|
||||
func (v *View) gotoNextMatch() error {
|
||||
v.refreshSearchPositions()
|
||||
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ package gui
|
|||
|
||||
import (
|
||||
"github.com/jesseduffield/lazygit/pkg/gocui"
|
||||
"github.com/jesseduffield/lazygit/pkg/gui/context"
|
||||
"github.com/jesseduffield/lazygit/pkg/gui/types"
|
||||
)
|
||||
|
||||
|
|
@ -139,3 +140,17 @@ func (gui *Gui) refreshMainViews(opts types.RefreshMainOpts) {
|
|||
func (gui *Gui) splitMainPanel(splitMainPanel bool) {
|
||||
gui.State.SplitMainPanel = splitMainPanel
|
||||
}
|
||||
|
||||
// reApplySearch runs a search the view holds again over the content a render has just
|
||||
// finished putting there, so that the matches highlighted and the "x of y" status
|
||||
// describe what the view shows now rather than what it showed when the search was
|
||||
// typed. Call it once the content is final.
|
||||
func (gui *Gui) reApplySearch(view *gocui.View) {
|
||||
// While the prompt is open, the search view holds what the user is typing, and the
|
||||
// status would be written over it.
|
||||
if gui.State.ContextMgr.Current().GetKey() == context.SEARCH_CONTEXT_KEY {
|
||||
return
|
||||
}
|
||||
|
||||
view.RefreshSearch()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -91,6 +91,7 @@ func (gui *Gui) newStringTaskWithoutScroll(view *gocui.View, str string) error {
|
|||
f := func(tasks.TaskOpts) error {
|
||||
return gui.g.OnUIThreadAndWaitBackground(func() {
|
||||
gui.c.SetViewContent(view, str)
|
||||
gui.reApplySearch(view)
|
||||
})
|
||||
}
|
||||
|
||||
|
|
@ -108,6 +109,7 @@ func (gui *Gui) newStringTaskWithScroll(view *gocui.View, str string, originX in
|
|||
return gui.g.OnUIThreadAndWaitBackground(func() {
|
||||
gui.c.SetViewContent(view, str)
|
||||
view.SetOrigin(originX, originY)
|
||||
gui.reApplySearch(view)
|
||||
})
|
||||
}
|
||||
|
||||
|
|
@ -125,6 +127,7 @@ func (gui *Gui) newStringTaskWithKey(view *gocui.View, str string, key string) e
|
|||
return gui.g.OnUIThreadAndWaitBackground(func() {
|
||||
gui.c.ResetViewOrigin(view)
|
||||
gui.c.SetViewContent(view, str)
|
||||
gui.reApplySearch(view)
|
||||
})
|
||||
}
|
||||
|
||||
|
|
@ -170,6 +173,8 @@ func (gui *Gui) getManager(view *gocui.View) *tasks.ViewBufferManager {
|
|||
|
||||
view.SetOrigin(0, newOriginY)
|
||||
}
|
||||
|
||||
gui.reApplySearch(view)
|
||||
},
|
||||
func() {
|
||||
view.SetOrigin(0, 0)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,45 @@
|
|||
package filter_and_search
|
||||
|
||||
import (
|
||||
"github.com/jesseduffield/lazygit/pkg/config"
|
||||
. "github.com/jesseduffield/lazygit/pkg/integration/components"
|
||||
)
|
||||
|
||||
var SearchStatusAfterARerender = NewIntegrationTest(NewIntegrationTestArgs{
|
||||
Description: "The search status counts the matches in a diff that has been rendered again",
|
||||
ExtraCmdArgs: []string{},
|
||||
Skip: false,
|
||||
SetupConfig: func(config *config.AppConfig) {},
|
||||
SetupRepo: func(shell *Shell) {
|
||||
shell.CreateFileAndAdd("file1",
|
||||
"line 1\nline 2\nline 3\nline 4\nline 5\nline 6\nline 7\nline 8\nline 9\nNEEDLE\nline 11\nline 12\nline 13\nline 14\n")
|
||||
shell.Commit("one")
|
||||
|
||||
// Four lines above NEEDLE, so that it is context at a context size of 4 but
|
||||
// not at 3.
|
||||
shell.UpdateFile("file1",
|
||||
"line 1\nline 2\nline 3\nline 4\nline 5\nchanged\nline 7\nline 8\nline 9\nNEEDLE\nline 11\nline 12\nline 13\nline 14\n")
|
||||
},
|
||||
Run: func(t *TestDriver, keys config.KeybindingConfig) {
|
||||
t.Views().Files().
|
||||
IsFocused().
|
||||
Press(keys.Universal.FocusMainView)
|
||||
|
||||
t.Views().Main().
|
||||
IsFocused().
|
||||
Content(DoesNotContain("NEEDLE")).
|
||||
FilterOrSearch("NEEDLE")
|
||||
|
||||
t.Views().Search().Content(Contains("No matches for 'NEEDLE'"))
|
||||
|
||||
// A wider context brings NEEDLE into the diff, and the search counts it.
|
||||
t.Views().Main().
|
||||
Press(keys.Universal.IncreaseContextInDiffView).
|
||||
Tap(func() {
|
||||
t.ExpectToast(Equals("Changed diff context size to 4"))
|
||||
}).
|
||||
Content(Contains("NEEDLE"))
|
||||
|
||||
t.Views().Search().Content(Contains("matches for 'NEEDLE' (1 of 1)"))
|
||||
},
|
||||
})
|
||||
|
|
@ -278,6 +278,7 @@ var tests = []*components.IntegrationTest{
|
|||
filter_and_search.NestedFilterTransient,
|
||||
filter_and_search.NewSearch,
|
||||
filter_and_search.SearchALongDiff,
|
||||
filter_and_search.SearchStatusAfterARerender,
|
||||
filter_and_search.StageAllStagesOnlyTrackedFilesInTrackedOnlyFilter,
|
||||
filter_and_search.StagingFolderStagesOnlyTrackedFilesInTrackedOnlyFilter,
|
||||
filter_by_author.SelectAuthor,
|
||||
|
|
|
|||
Loading…
Reference in a new issue