mirror of
https://github.com/jesseduffield/lazygit.git
synced 2026-09-10 15:46:26 -04:00
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>
157 lines
4.5 KiB
Go
157 lines
4.5 KiB
Go
package gui
|
|
|
|
import (
|
|
"github.com/jesseduffield/lazygit/pkg/gocui"
|
|
"github.com/jesseduffield/lazygit/pkg/gui/context"
|
|
"github.com/jesseduffield/lazygit/pkg/gui/types"
|
|
)
|
|
|
|
func (gui *Gui) runTaskForView(view *gocui.View, task types.UpdateTask) error {
|
|
switch v := task.(type) {
|
|
case *types.RenderStringTask:
|
|
return gui.newStringTask(view, v.Str)
|
|
|
|
case *types.RenderStringWithoutScrollTask:
|
|
return gui.newStringTaskWithoutScroll(view, v.Str)
|
|
|
|
case *types.RenderStringWithScrollTask:
|
|
return gui.newStringTaskWithScroll(view, v.Str, v.OriginX, v.OriginY)
|
|
|
|
case *types.RunCommandTask:
|
|
return gui.newCmdTask(view, v.Cmd, v.Prefix)
|
|
|
|
case *types.RunPtyTask:
|
|
return gui.newPtyTask(view, v.Cmd, v.Prefix)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (gui *Gui) moveMainContextPairToTop(pair types.MainContextPair) {
|
|
gui.moveMainContextToTop(pair.Main)
|
|
if pair.Secondary != nil {
|
|
gui.moveMainContextToTop(pair.Secondary)
|
|
}
|
|
}
|
|
|
|
func (gui *Gui) moveMainContextToTop(context types.Context) {
|
|
gui.helpers.Window.SetWindowContext(context)
|
|
|
|
view := context.GetView()
|
|
|
|
topView := gui.helpers.Window.TopViewInWindow(context.GetWindowName(), true)
|
|
|
|
if topView != nil && topView != view {
|
|
// We need to copy the content to avoid a flicker effect: If we're flicking
|
|
// through files in the files panel, we use a different view to render the
|
|
// files vs the directories, and if you select dir A, then file B, then dir
|
|
// C, you'll briefly see dir A's contents again before the view is updated.
|
|
// So here we're copying the content from the top window to avoid that
|
|
// flicker effect.
|
|
gui.g.CopyContent(topView, view)
|
|
|
|
if err := gui.g.SetViewOnTopOf(view.Name(), topView.Name()); err != nil {
|
|
gui.Log.Error(err)
|
|
}
|
|
}
|
|
}
|
|
|
|
func (gui *Gui) RefreshMainView(opts *types.ViewUpdateOpts, context types.Context) {
|
|
view := context.GetView()
|
|
|
|
if opts.Title != "" {
|
|
view.Title = opts.Title
|
|
}
|
|
|
|
view.Subtitle = opts.SubTitle
|
|
|
|
if err := gui.runTaskForView(view, opts.Task); err != nil {
|
|
gui.c.Log.Error(err)
|
|
}
|
|
}
|
|
|
|
func (gui *Gui) normalMainContextPair() types.MainContextPair {
|
|
return types.NewMainContextPair(
|
|
gui.State.Contexts.Normal,
|
|
gui.State.Contexts.NormalSecondary,
|
|
)
|
|
}
|
|
|
|
func (gui *Gui) stagingMainContextPair() types.MainContextPair {
|
|
return types.NewMainContextPair(
|
|
gui.State.Contexts.Staging,
|
|
gui.State.Contexts.StagingSecondary,
|
|
)
|
|
}
|
|
|
|
func (gui *Gui) patchBuildingMainContextPair() types.MainContextPair {
|
|
return types.NewMainContextPair(
|
|
gui.State.Contexts.CustomPatchBuilder,
|
|
gui.State.Contexts.CustomPatchBuilderSecondary,
|
|
)
|
|
}
|
|
|
|
func (gui *Gui) mergingMainContextPair() types.MainContextPair {
|
|
return types.NewMainContextPair(
|
|
gui.State.Contexts.MergeConflicts,
|
|
nil,
|
|
)
|
|
}
|
|
|
|
func (gui *Gui) allMainContextPairs() []types.MainContextPair {
|
|
return []types.MainContextPair{
|
|
gui.normalMainContextPair(),
|
|
gui.stagingMainContextPair(),
|
|
gui.patchBuildingMainContextPair(),
|
|
gui.mergingMainContextPair(),
|
|
}
|
|
}
|
|
|
|
func (gui *Gui) refreshMainViews(opts types.RefreshMainOpts) {
|
|
gui.moveMainContextPairToTop(opts.Pair)
|
|
|
|
if opts.Main != nil {
|
|
gui.RefreshMainView(opts.Main, opts.Pair.Main)
|
|
}
|
|
|
|
if opts.Secondary != nil {
|
|
gui.RefreshMainView(opts.Secondary, opts.Pair.Secondary)
|
|
} else if opts.Pair.Secondary != nil {
|
|
opts.Pair.Secondary.GetView().Clear()
|
|
}
|
|
|
|
// Reset the scroll positions of all the other main views. We do this after
|
|
// moving this pair to the top (which copies the previously-shown view's
|
|
// content into the now-visible one to avoid a blank frame): resetting first
|
|
// would zero that source view's scroll before it gets copied, forcing the
|
|
// placeholder to the top instead of leaving it where the screen already was.
|
|
for _, pair := range gui.allMainContextPairs() {
|
|
if pair.Main != opts.Pair.Main {
|
|
pair.Main.GetView().SetOrigin(0, 0)
|
|
}
|
|
if pair.Secondary != nil && pair.Secondary != opts.Pair.Secondary {
|
|
pair.Secondary.GetView().SetOrigin(0, 0)
|
|
}
|
|
}
|
|
|
|
gui.splitMainPanel(opts.Secondary != nil)
|
|
}
|
|
|
|
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()
|
|
}
|