1
0
mirror of https://github.com/jesseduffield/lazygit.git synced 2026-01-26 01:41:35 +03:00

Avoid scrolling the selection into view on refresh

It is possible to scroll the selection out of view using the mouse wheel; after
doing this, it would sometimes scroll into view by itself again, for example
when a background fetch occurred. In the files panel this would even happen
every 10s with every regular files refresh.

Fix this by adding a scrollIntoView parameter to HandleFocus, which is false by
default, and is only set to true from controllers that change the selection.
This commit is contained in:
Stefan Haller
2025-12-22 16:08:29 +01:00
parent 37bc0dfc44
commit efd4298b5e
15 changed files with 35 additions and 26 deletions

View File

@@ -25,8 +25,8 @@ type ListContextTrait struct {
func (self *ListContextTrait) IsListContext() {}
func (self *ListContextTrait) FocusLine() {
self.Context.FocusLine()
func (self *ListContextTrait) FocusLine(scrollIntoView bool) {
self.Context.FocusLine(scrollIntoView)
// Doing this at the end of the layout function because we need the view to be
// resized before we focus the line, otherwise if we're in accordion mode
@@ -36,7 +36,7 @@ func (self *ListContextTrait) FocusLine() {
oldOrigin, _ := self.GetViewTrait().ViewPortYBounds()
self.GetViewTrait().FocusPoint(
self.ModelIndexToViewIndex(self.list.GetSelectedLineIdx()))
self.ModelIndexToViewIndex(self.list.GetSelectedLineIdx()), scrollIntoView)
selectRangeIndex, isSelectingRange := self.list.GetRangeStartIdx()
if isSelectingRange {
@@ -75,7 +75,7 @@ func formatListFooter(selectedLineIdx int, length int) string {
}
func (self *ListContextTrait) HandleFocus(opts types.OnFocusOpts) {
self.FocusLine()
self.FocusLine(opts.ScrollSelectionIntoView)
self.GetViewTrait().SetHighlight(self.list.Len() > 0)

View File

@@ -54,7 +54,7 @@ func (self *SimpleContext) HandleFocusLost(opts types.OnFocusLostOpts) {
}
}
func (self *SimpleContext) FocusLine() {
func (self *SimpleContext) FocusLine(scrollIntoView bool) {
}
func (self *SimpleContext) HandleRender() {

View File

@@ -17,8 +17,8 @@ func NewViewTrait(view *gocui.View) *ViewTrait {
return &ViewTrait{view: view}
}
func (self *ViewTrait) FocusPoint(yIdx int) {
self.view.FocusPoint(self.view.OriginX(), yIdx)
func (self *ViewTrait) FocusPoint(yIdx int, scrollIntoView bool) {
self.view.FocusPoint(self.view.OriginX(), yIdx, scrollIntoView)
}
func (self *ViewTrait) SetRangeSelectStart(yIdx int) {

View File

@@ -101,7 +101,7 @@ func (self *CherryPickHelper) Paste() error {
// below the selection.
if commit := self.c.Contexts().LocalCommits.GetSelected(); commit != nil && !commit.IsTODO() {
self.c.Contexts().LocalCommits.MoveSelection(len(cherryPickedCommits))
self.c.Contexts().LocalCommits.FocusLine()
self.c.Contexts().LocalCommits.FocusLine(true)
}
// If we're in the cherry-picking state at this point, it must

View File

@@ -35,6 +35,9 @@ func (self *RefsHelper) SelectFirstBranchAndFirstCommit() {
self.c.Contexts().Branches.SetSelection(0)
self.c.Contexts().ReflogCommits.SetSelection(0)
self.c.Contexts().LocalCommits.SetSelection(0)
self.c.Contexts().Branches.GetView().SetOriginY(0)
self.c.Contexts().ReflogCommits.GetView().SetOriginY(0)
self.c.Contexts().LocalCommits.GetView().SetOriginY(0)
}
func (self *RefsHelper) CheckoutRef(ref string, options types.CheckoutRefOptions) error {

View File

@@ -116,7 +116,7 @@ func (self *ListController) handleLineChangeAux(f func(int), change int) error {
}
if cursorMoved || rangeBefore != rangeAfter {
self.context.HandleFocus(types.OnFocusOpts{})
self.context.HandleFocus(types.OnFocusOpts{ScrollSelectionIntoView: true})
}
return nil
@@ -173,6 +173,8 @@ func (self *ListController) handlePageChange(delta int) error {
}
}
// Since we are maintaining the scroll position ourselves above, there's no point in passing
// ScrollSelectionIntoView=true here.
self.context.HandleFocus(types.OnFocusOpts{})
return nil

View File

@@ -869,7 +869,7 @@ func (self *LocalCommitsController) revert(commits []*models.Commit, start, end
return err
}
self.context().MoveSelection(len(commits))
self.context().HandleFocus(types.OnFocusOpts{})
self.context().HandleFocus(types.OnFocusOpts{ScrollSelectionIntoView: true})
if mustStash {
if err := self.c.Git().Stash.Pop(0); err != nil {

View File

@@ -205,7 +205,7 @@ func (self *StashController) handleRenameStashEntry(stashEntry *models.StashEntr
return err
}
self.context().SetSelection(0) // Select the renamed stash
self.context().FocusLine()
self.context().FocusLine(true)
self.c.Refresh(types.RefreshOptions{Scope: []types.RefreshableView{types.STASH}})
return nil
},

View File

@@ -109,7 +109,7 @@ type Context interface {
HandleFocus(opts OnFocusOpts)
HandleFocusLost(opts OnFocusLostOpts)
FocusLine()
FocusLine(scrollIntoView bool)
HandleRender()
HandleRenderToMain()
}
@@ -201,7 +201,7 @@ type IPatchExplorerContext interface {
}
type IViewTrait interface {
FocusPoint(yIdx int)
FocusPoint(yIdx int, scrollIntoView bool)
SetRangeSelectStart(yIdx int)
CancelRangeSelect()
SetViewPortContent(content string)
@@ -221,8 +221,9 @@ type IViewTrait interface {
}
type OnFocusOpts struct {
ClickedWindowName string
ClickedViewLineIdx int
ClickedWindowName string
ClickedViewLineIdx int
ScrollSelectionIntoView bool
}
type OnFocusLostOpts struct {

View File

@@ -140,7 +140,7 @@ func (gui *Gui) postRefreshUpdate(c types.Context) {
// non-focused views to ensure that an inactive selection is painted
// correctly, and that integration tests see the up to date selection
// state.
c.FocusLine()
c.FocusLine(false)
currentCtx := gui.State.ContextMgr.Current()
if currentCtx.GetKey() == context.NORMAL_MAIN_CONTEXT_KEY || currentCtx.GetKey() == context.NORMAL_SECONDARY_CONTEXT_KEY {

View File

@@ -51,7 +51,7 @@ func RunTUI(raceDetector bool) {
if err != nil {
return err
}
listView.FocusPoint(0, app.itemIdx)
listView.FocusPoint(0, app.itemIdx, true)
return nil
}); err != nil {
log.Panicln(err)
@@ -66,7 +66,7 @@ func RunTUI(raceDetector bool) {
if err != nil {
return err
}
listView.FocusPoint(0, app.itemIdx)
listView.FocusPoint(0, app.itemIdx, true)
return nil
}); err != nil {
log.Panicln(err)