mirror of
https://github.com/jesseduffield/lazygit.git
synced 2026-09-10 07:36:27 -04:00
Derive the selection highlight from the context stack
A view drew a selection because something told it to, from four places on three different schedules: a context being focused, a context losing focus, a context being activated over another one, and a list being re-rendered. Whether the flags ended up describing the state of the app depended on which of those had run last, and the last one to run was often none of them: a refresh only re-focuses the view that has the focus, so a list whose contents changed underneath an unfocused panel kept whichever highlight it happened to have. Derive both flags instead, in one place, from the two things they mean: a view shows a selection while its context is on the stack and has something to select, and the context the user is in shows an active one where the ones behind it show inactive ones. Nothing else needs to say anything about highlighting, so nothing else can leave a view saying something untrue about where the focus is. Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
d1707d5dd2
commit
ec3f681ebf
|
|
@ -3,6 +3,7 @@ package gui
|
|||
import (
|
||||
"sync"
|
||||
|
||||
"github.com/jesseduffield/generics/set"
|
||||
"github.com/jesseduffield/lazygit/pkg/gui/context"
|
||||
"github.com/jesseduffield/lazygit/pkg/gui/types"
|
||||
"github.com/jesseduffield/lazygit/pkg/utils"
|
||||
|
|
@ -180,10 +181,6 @@ func (self *ContextMgr) Activate(c types.Context, opts types.OnFocusOpts) {
|
|||
|
||||
self.gui.helpers.Window.MoveToTopOfWindow(c)
|
||||
inputViewName := c.GetInputViewName()
|
||||
oldView := self.gui.c.GocuiGui().CurrentView()
|
||||
if oldView != nil && oldView.Name() != inputViewName {
|
||||
oldView.HighlightInactive = true
|
||||
}
|
||||
if _, err := self.gui.c.GocuiGui().SetCurrentView(inputViewName); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
|
@ -199,9 +196,37 @@ func (self *ContextMgr) Activate(c types.Context, opts types.OnFocusOpts) {
|
|||
|
||||
self.gui.c.GocuiGui().Cursor = v.Editable && v.Mask == ""
|
||||
|
||||
self.updateSelectionHighlights()
|
||||
|
||||
c.HandleFocus(opts)
|
||||
}
|
||||
|
||||
// updateSelectionHighlights re-derives which views draw a selection, and which of
|
||||
// them draw theirs as the active one: a view shows a selection while its context is
|
||||
// on the stack and has something to select, and the context the user is in shows the
|
||||
// active selection while the ones behind it show inactive ones.
|
||||
//
|
||||
// Both of those can change, so this is called wherever they do: from Activate, which
|
||||
// every change to the stack goes through; after a refresh, since that is when the
|
||||
// contents of a list change; and from whoever tells a context that its content has
|
||||
// gained or lost something to select.
|
||||
func (self *ContextMgr) updateSelectionHighlights() {
|
||||
self.RLock()
|
||||
defer self.RUnlock()
|
||||
|
||||
onStack := set.NewFromSlice(lo.Map(self.ContextStack,
|
||||
func(c types.Context, _ int) types.ContextKey { return c.GetKey() }))
|
||||
currentKey := self.currentContextWithoutLock().GetKey()
|
||||
|
||||
for _, c := range self.allContexts.Flatten() {
|
||||
// The global context has no view of its own.
|
||||
if view := c.GetView(); view != nil {
|
||||
view.Highlight = onStack.Includes(c.GetKey()) && c.HasSelectableContent()
|
||||
view.HighlightInactive = c.GetKey() != currentKey
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (self *ContextMgr) Current() types.Context {
|
||||
self.RLock()
|
||||
defer self.RUnlock()
|
||||
|
|
|
|||
|
|
@ -106,8 +106,6 @@ func formatListFooter(selectedLineIdx int, length int) string {
|
|||
func (self *ListContextTrait) HandleFocus(opts types.OnFocusOpts) {
|
||||
self.FocusLine(!opts.KeepScrollPosition)
|
||||
|
||||
self.GetViewTrait().SetHighlight(self.HasSelectableContent())
|
||||
|
||||
self.Context.HandleFocus(opts)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -33,10 +33,6 @@ func NewDisplayContext(key types.ContextKey, view *gocui.View, windowName string
|
|||
}
|
||||
|
||||
func (self *SimpleContext) HandleFocus(opts types.OnFocusOpts) {
|
||||
if self.hasSelectableContent {
|
||||
self.GetViewTrait().SetHighlight(true)
|
||||
}
|
||||
|
||||
for _, fn := range self.onFocusFns {
|
||||
fn(opts)
|
||||
}
|
||||
|
|
@ -47,7 +43,6 @@ func (self *SimpleContext) HandleFocus(opts types.OnFocusOpts) {
|
|||
}
|
||||
|
||||
func (self *SimpleContext) HandleFocusLost(opts types.OnFocusLostOpts) {
|
||||
self.GetViewTrait().SetHighlight(false)
|
||||
self.view.SetOriginX(0)
|
||||
for _, fn := range self.onFocusLostFns {
|
||||
fn(opts)
|
||||
|
|
|
|||
|
|
@ -43,11 +43,6 @@ func (self *ViewTrait) SetContent(content string) {
|
|||
self.view.SetContent(content)
|
||||
}
|
||||
|
||||
func (self *ViewTrait) SetHighlight(highlight bool) {
|
||||
self.view.Highlight = highlight
|
||||
self.view.HighlightInactive = false
|
||||
}
|
||||
|
||||
func (self *ViewTrait) SetFooter(value string) {
|
||||
self.view.Footer = value
|
||||
}
|
||||
|
|
|
|||
|
|
@ -229,7 +229,6 @@ type IViewTrait interface {
|
|||
ScrollDown(value int)
|
||||
PageDelta() int
|
||||
SelectedLineIdx() int
|
||||
SetHighlight(bool)
|
||||
}
|
||||
|
||||
type OnFocusOpts struct {
|
||||
|
|
|
|||
|
|
@ -140,6 +140,10 @@ func (gui *Gui) postRefreshUpdate(c types.Context, opts types.OnFocusOpts) {
|
|||
|
||||
c.HandleRender()
|
||||
|
||||
// The render may have given the context its first item, or taken its last one
|
||||
// away, which decides whether its view draws a selection at all.
|
||||
gui.State.ContextMgr.updateSelectionHighlights()
|
||||
|
||||
if gui.currentViewName() == c.GetInputViewName() {
|
||||
c.HandleFocus(opts)
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -31,9 +31,6 @@ var UnfocusedListHidesSelectionWhenEmptied = NewIntegrationTest(NewIntegrationTe
|
|||
t.RefreshInBackground()
|
||||
}).
|
||||
IsEmpty().
|
||||
/* EXPECTED:
|
||||
SelectionIsHidden()
|
||||
ACTUAL: */
|
||||
SelectionIsInactive()
|
||||
},
|
||||
})
|
||||
|
|
|
|||
|
|
@ -29,9 +29,6 @@ var UnfocusedListShowsSelectionWhenFilled = NewIntegrationTest(NewIntegrationTes
|
|||
t.RefreshInBackground()
|
||||
}).
|
||||
Lines(Contains("file2")).
|
||||
/* EXPECTED:
|
||||
SelectionIsInactive()
|
||||
ACTUAL: */
|
||||
SelectionIsHidden()
|
||||
},
|
||||
})
|
||||
|
|
|
|||
Loading…
Reference in a new issue