Ask each context whether it has content to select

Whether a view draws a selection is about to be derived in one place from
the context stack, which needs to ask any context — list or not — whether
there is something for a selection to sit on. Name the existing flag after
that question, and let a list context answer it from its length.

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
Stefan Haller 2026-08-21 10:46:41 +02:00
parent eb760ee928
commit 4b391acec0
7 changed files with 30 additions and 18 deletions

View file

@ -28,7 +28,7 @@ type BaseContext struct {
hasControlledBounds bool
needsRerenderOnWidthChange types.NeedsRerenderOnWidthChangeLevel
needsRerenderOnHeightChange bool
highlightOnFocus bool
hasSelectableContent bool
*ParentContextMgr
}
@ -49,7 +49,7 @@ type NewBaseContextOpts struct {
Focusable bool
Transient bool
HasUncontrolledBounds bool // negating for the sake of making false the default
HighlightOnFocus bool
HasSelectableContent bool
NeedsRerenderOnWidthChange types.NeedsRerenderOnWidthChangeLevel
NeedsRerenderOnHeightChange bool
@ -70,7 +70,7 @@ func NewBaseContext(opts NewBaseContextOpts) *BaseContext {
focusable: opts.Focusable,
transient: opts.Transient,
hasControlledBounds: hasControlledBounds,
highlightOnFocus: opts.HighlightOnFocus,
hasSelectableContent: opts.HasSelectableContent,
needsRerenderOnWidthChange: opts.NeedsRerenderOnWidthChange,
needsRerenderOnHeightChange: opts.NeedsRerenderOnHeightChange,
ParentContextMgr: &ParentContextMgr{},
@ -118,6 +118,10 @@ func (self *BaseContext) GetKind() types.ContextKind {
return self.kind
}
func (self *BaseContext) HasSelectableContent() bool {
return self.hasSelectableContent
}
func (self *BaseContext) GetKey() types.ContextKey {
return self.key
}

View file

@ -37,6 +37,10 @@ type ListContextTrait struct {
func (self *ListContextTrait) IsListContext() {}
func (self *ListContextTrait) HasSelectableContent() bool {
return self.list.Len() > 0
}
func (self *ListContextTrait) FocusLine(scrollIntoView bool) {
self.Context.FocusLine(scrollIntoView)
@ -102,7 +106,7 @@ func formatListFooter(selectedLineIdx int, length int) string {
func (self *ListContextTrait) HandleFocus(opts types.OnFocusOpts) {
self.FocusLine(!opts.KeepScrollPosition)
self.GetViewTrait().SetHighlight(self.list.Len() > 0)
self.GetViewTrait().SetHighlight(self.HasSelectableContent())
self.Context.HandleFocus(opts)
}

View file

@ -21,12 +21,12 @@ func NewMainContext(
ctx := &MainContext{
SimpleContext: NewSimpleContext(
NewBaseContext(NewBaseContextOpts{
Kind: types.MAIN_CONTEXT,
View: view,
WindowName: windowName,
Key: key,
Focusable: true,
HighlightOnFocus: false,
Kind: types.MAIN_CONTEXT,
View: view,
WindowName: windowName,
Key: key,
Focusable: true,
HasSelectableContent: false,
})),
SearchTrait: NewSearchTrait(c),
}

View file

@ -35,12 +35,12 @@ func NewMergeConflictsContext(
viewModel: viewModel,
Context: NewSimpleContext(
NewBaseContext(NewBaseContextOpts{
Kind: types.MAIN_CONTEXT,
View: c.Views().MergeConflicts,
WindowName: "main",
Key: MERGE_CONFLICTS_CONTEXT_KEY,
Focusable: true,
HighlightOnFocus: true,
Kind: types.MAIN_CONTEXT,
View: c.Views().MergeConflicts,
WindowName: "main",
Key: MERGE_CONFLICTS_CONTEXT_KEY,
Focusable: true,
HasSelectableContent: true,
}),
),
c: c,

View file

@ -47,7 +47,7 @@ func NewPatchExplorerContext(
Key: key,
Kind: types.MAIN_CONTEXT,
Focusable: true,
HighlightOnFocus: true,
HasSelectableContent: true,
NeedsRerenderOnWidthChange: types.NEEDS_RERENDER_ON_WIDTH_CHANGE_WHEN_WIDTH_CHANGES,
})),
SearchTrait: NewSearchTrait(c),

View file

@ -33,7 +33,7 @@ func NewDisplayContext(key types.ContextKey, view *gocui.View, windowName string
}
func (self *SimpleContext) HandleFocus(opts types.OnFocusOpts) {
if self.highlightOnFocus {
if self.hasSelectableContent {
self.GetViewTrait().SetHighlight(true)
}

View file

@ -75,6 +75,10 @@ type IBaseContext interface {
// determined independently.
HasControlledBounds() bool
// true if the context holds something for a selection to sit on. Contexts that
// don't show a selection at all say false, and so do lists with nothing in them.
HasSelectableContent() bool
// the total height of the content that the view is currently showing
TotalContentHeight() int