From e8f1a969c41e7cd5d08dde3ad8ac900a35837356 Mon Sep 17 00:00:00 2001 From: Stefan Haller Date: Sun, 9 Aug 2026 19:28:21 +0200 Subject: [PATCH] Classify which side panels show a diff in their main view MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The focused main view is about to show a selection, but only where there are diff lines to act on: a branch's commit log or the status dashboard has nothing to select. Rather than have the main view guess from the rendered content, let the side panels say so, since each of them knows what it renders. The classification is finer than a yes/no because acting on a selection means different things per panel — staging into the working tree for the files panel, taking lines into a custom patch for the commit panels — and those actions want the same one answer as this. Only whether a panel shows a diff at all is read for now. Co-authored-by: Claude Opus 5 (1M context) --- pkg/gui/context/commit_files_context.go | 11 +++++--- pkg/gui/context/local_commits_context.go | 11 +++++--- pkg/gui/context/reflog_commits_context.go | 9 +++++-- pkg/gui/context/stash_context.go | 9 +++++-- pkg/gui/context/sub_commits_context.go | 11 +++++--- pkg/gui/context/working_tree_context.go | 9 +++++-- pkg/gui/types/context.go | 33 +++++++++++++++++++++++ 7 files changed, 78 insertions(+), 15 deletions(-) diff --git a/pkg/gui/context/commit_files_context.go b/pkg/gui/context/commit_files_context.go index f819a2eb4..9689df29b 100644 --- a/pkg/gui/context/commit_files_context.go +++ b/pkg/gui/context/commit_files_context.go @@ -19,11 +19,16 @@ type CommitFilesContext struct { } var ( - _ types.IListContext = (*CommitFilesContext)(nil) - _ types.DiffableContext = (*CommitFilesContext)(nil) - _ types.IFilterableContext = (*CommitFilesContext)(nil) + _ types.IListContext = (*CommitFilesContext)(nil) + _ types.DiffableContext = (*CommitFilesContext)(nil) + _ types.IFilterableContext = (*CommitFilesContext)(nil) + _ types.DiffMainViewContext = (*CommitFilesContext)(nil) ) +func (self *CommitFilesContext) GetDiffMainViewType() types.DiffMainViewType { + return types.DiffMainViewTypePatchBuilding +} + func NewCommitFilesContext(c *ContextCommon) *CommitFilesContext { viewModel := filetree.NewCommitFileTreeViewModel( func() []*models.CommitFile { return c.Model().CommitFiles }, diff --git a/pkg/gui/context/local_commits_context.go b/pkg/gui/context/local_commits_context.go index 6f3049f24..4c489a706 100644 --- a/pkg/gui/context/local_commits_context.go +++ b/pkg/gui/context/local_commits_context.go @@ -32,11 +32,16 @@ type commitDropIndicator struct { } var ( - _ types.IListContext = (*LocalCommitsContext)(nil) - _ types.DiffableContext = (*LocalCommitsContext)(nil) - _ types.ISearchableContext = (*LocalCommitsContext)(nil) + _ types.IListContext = (*LocalCommitsContext)(nil) + _ types.DiffableContext = (*LocalCommitsContext)(nil) + _ types.ISearchableContext = (*LocalCommitsContext)(nil) + _ types.DiffMainViewContext = (*LocalCommitsContext)(nil) ) +func (self *LocalCommitsContext) GetDiffMainViewType() types.DiffMainViewType { + return types.DiffMainViewTypePatchBuilding +} + func NewLocalCommitsContext(c *ContextCommon) *LocalCommitsContext { dropIndicator := &commitDropIndicator{insertionIndex: -1} viewModel := NewLocalCommitsViewModel( diff --git a/pkg/gui/context/reflog_commits_context.go b/pkg/gui/context/reflog_commits_context.go index 71314bf66..f7dd1828a 100644 --- a/pkg/gui/context/reflog_commits_context.go +++ b/pkg/gui/context/reflog_commits_context.go @@ -14,10 +14,15 @@ type ReflogCommitsContext struct { } var ( - _ types.IListContext = (*ReflogCommitsContext)(nil) - _ types.DiffableContext = (*ReflogCommitsContext)(nil) + _ types.IListContext = (*ReflogCommitsContext)(nil) + _ types.DiffableContext = (*ReflogCommitsContext)(nil) + _ types.DiffMainViewContext = (*ReflogCommitsContext)(nil) ) +func (self *ReflogCommitsContext) GetDiffMainViewType() types.DiffMainViewType { + return types.DiffMainViewTypePatchBuilding +} + func NewReflogCommitsContext(c *ContextCommon) *ReflogCommitsContext { viewModel := NewFilteredListViewModel( func() []*models.Commit { return c.Model().FilteredReflogCommits }, diff --git a/pkg/gui/context/stash_context.go b/pkg/gui/context/stash_context.go index 2014de9f3..99919868a 100644 --- a/pkg/gui/context/stash_context.go +++ b/pkg/gui/context/stash_context.go @@ -12,10 +12,15 @@ type StashContext struct { } var ( - _ types.IListContext = (*StashContext)(nil) - _ types.DiffableContext = (*StashContext)(nil) + _ types.IListContext = (*StashContext)(nil) + _ types.DiffableContext = (*StashContext)(nil) + _ types.DiffMainViewContext = (*StashContext)(nil) ) +func (self *StashContext) GetDiffMainViewType() types.DiffMainViewType { + return types.DiffMainViewTypePatchBuilding +} + func NewStashContext( c *ContextCommon, ) *StashContext { diff --git a/pkg/gui/context/sub_commits_context.go b/pkg/gui/context/sub_commits_context.go index 86938797a..d0211bb1a 100644 --- a/pkg/gui/context/sub_commits_context.go +++ b/pkg/gui/context/sub_commits_context.go @@ -21,11 +21,16 @@ type SubCommitsContext struct { } var ( - _ types.IListContext = (*SubCommitsContext)(nil) - _ types.DiffableContext = (*SubCommitsContext)(nil) - _ types.ISearchableContext = (*SubCommitsContext)(nil) + _ types.IListContext = (*SubCommitsContext)(nil) + _ types.DiffableContext = (*SubCommitsContext)(nil) + _ types.ISearchableContext = (*SubCommitsContext)(nil) + _ types.DiffMainViewContext = (*SubCommitsContext)(nil) ) +func (self *SubCommitsContext) GetDiffMainViewType() types.DiffMainViewType { + return types.DiffMainViewTypePatchBuilding +} + func NewSubCommitsContext( c *ContextCommon, ) *SubCommitsContext { diff --git a/pkg/gui/context/working_tree_context.go b/pkg/gui/context/working_tree_context.go index d82037e44..706bed3b6 100644 --- a/pkg/gui/context/working_tree_context.go +++ b/pkg/gui/context/working_tree_context.go @@ -15,10 +15,15 @@ type WorkingTreeContext struct { } var ( - _ types.IListContext = (*WorkingTreeContext)(nil) - _ types.IFilterableContext = (*WorkingTreeContext)(nil) + _ types.IListContext = (*WorkingTreeContext)(nil) + _ types.IFilterableContext = (*WorkingTreeContext)(nil) + _ types.DiffMainViewContext = (*WorkingTreeContext)(nil) ) +func (self *WorkingTreeContext) GetDiffMainViewType() types.DiffMainViewType { + return types.DiffMainViewTypeStaging +} + func NewWorkingTreeContext(c *ContextCommon) *WorkingTreeContext { viewModel := filetree.NewFileTreeViewModel( func() []*models.File { return c.Model().Files }, diff --git a/pkg/gui/types/context.go b/pkg/gui/types/context.go index 93b92c70e..3f75f41ea 100644 --- a/pkg/gui/types/context.go +++ b/pkg/gui/types/context.go @@ -180,6 +180,39 @@ type DiffableContext interface { RefForAdjustingLineNumberInDiff() string } +// DiffMainViewContext is implemented by the side panel contexts whose focused +// main view shows a unified diff — files, local commits, sub-commits, reflog, +// stash, and commit files — as opposed to a commit log or other non-diff content +// (branches, tags, status, …). It is distinct from DiffableContext, which is +// about producing a diff between two refs for the diff menu. The focused main +// view shows a selection only for a context that implements this: a selection is +// only meaningful where there are diff lines to act on (edit one, copy some, jump +// by hunk or file). The returned type additionally classifies what acting on that +// selection means. +type DiffMainViewContext interface { + Context + + GetDiffMainViewType() DiffMainViewType +} + +// DiffMainViewType classifies what the focused main view's diff belongs to, which +// decides what acting on a selection in it means. +type DiffMainViewType int + +const ( + // DiffMainViewTypeNone: the main view holds no diff, so there is nothing to + // select. A side panel that doesn't implement DiffMainViewContext counts as + // this; no panel returns it itself. + DiffMainViewTypeNone DiffMainViewType = iota + // DiffMainViewTypeStaging: the diff is the working tree's, so the selection can + // be staged or unstaged (the files panel). + DiffMainViewTypeStaging + // DiffMainViewTypePatchBuilding: the diff belongs to a commit, so the selection + // can be taken into a custom patch (the commit files / commits / sub-commits / + // reflog / stash panels). + DiffMainViewTypePatchBuilding +) + type IListContext interface { Context