jesseduffield.lazygit/pkg/gui/controllers/sub_commits_controller.go
Stefan Haller 86ce3ba798 Build a custom patch from the commits / sub-commits / stash main views
Until now space toggled lines into a custom patch only from the commit files
main view (the per-file diff). Register the same toggle handler on the commits,
sub-commits and stash panels, so a patch can be built straight from the
whole-commit (multi-file) diff their main view shows, without first diving into
the commit files panel.

The handler lives on SwitchToDiffFilesController, which is already bound to
exactly those three panels and already knows how to derive the patch target
(from/to/reverse/canRebase) for the selected ref — pulled out of enter() into a
shared canRebase helper and the reused FromAndToForDiff. The post-toggle refresh
is the cheap one: these panels have no per-file patch indicator to update, so we
just re-render their own main + secondary views rather than reloading the whole
commit list on every keystroke.

Sub-commits and stash didn't render the secondary patch view at all; give them
the same secondaryPatchPanelUpdateOpts the commits panel uses, and recompute the
inclusion gutter as their diff (re-)renders, so the cumulative patch and the
gutter track the toggle.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-08-08 12:59:00 +02:00

79 lines
2.2 KiB
Go

package controllers
import (
"github.com/jesseduffield/lazygit/pkg/commands/models"
"github.com/jesseduffield/lazygit/pkg/gui/context"
"github.com/jesseduffield/lazygit/pkg/gui/types"
)
type SubCommitsController struct {
baseController
*ListControllerTrait[*models.Commit]
c *ControllerCommon
}
var _ types.IController = &SubCommitsController{}
func NewSubCommitsController(
c *ControllerCommon,
) *SubCommitsController {
return &SubCommitsController{
baseController: baseController{},
ListControllerTrait: NewListControllerTrait(
c,
c.Contexts().SubCommits,
c.Contexts().SubCommits.GetSelected,
c.Contexts().SubCommits.GetSelectedItems,
),
c: c,
}
}
func (self *SubCommitsController) Context() types.Context {
return self.context()
}
func (self *SubCommitsController) context() *context.SubCommitsContext {
return self.c.Contexts().SubCommits
}
func (self *SubCommitsController) GetOnRenderToMain() func() {
return func() {
self.c.Helpers().Diff.WithDiffModeCheck(func() {
commit := self.context().GetSelected()
var task types.UpdateTask
if commit == nil {
task = types.NewRenderStringTask("No commits")
} else {
refRange := self.context().GetSelectedRefRangeForDiffFiles()
task = self.c.Helpers().Diff.GetUpdateTaskForRenderingCommitsDiff(commit, refRange)
}
// Keep the inclusion gutter in step with the content as this diff
// (re-)renders; a no-op unless the main view is focused and a patch is being
// built from this panel. See LocalCommitsController.GetOnRenderToMain.
self.c.Helpers().Staging.RefreshInclusionGutter()
self.c.RenderToMainViews(types.RefreshMainOpts{
Pair: self.c.MainViewPairs().Normal,
Main: &types.ViewUpdateOpts{
Title: "Commit",
SubTitle: self.c.Helpers().Diff.IgnoringWhitespaceSubTitle(),
Task: task,
},
Secondary: secondaryPatchPanelUpdateOpts(self.c),
})
})
}
}
func (self *SubCommitsController) GetOnFocus() func(types.OnFocusOpts) {
return func(types.OnFocusOpts) {
context := self.context()
if context.GetSelectedLineIdx() > COMMIT_THRESHOLD && context.GetLimitCommits() {
context.SetLimitCommits(false)
self.c.Refresh(types.RefreshOptions{Scope: []types.RefreshableView{types.SUB_COMMITS}})
}
}
}