mirror of
https://github.com/jesseduffield/lazygit.git
synced 2026-09-10 07:36:27 -04:00
Let the post-stage reveal target a different pane than the one acted on
Staging or unstaging can move the acted-on side to the other half of the focused main view — unstaging the first hunk of an only-staged file splits it, pushing the staged remainder to the secondary pane. The reveal that re-selects the nearest surviving change after the op then has to ride the re-render of that other pane, not the one the user acted in. Split RevealSelectionAfterStaging's single view into a source (where the candidate lines are read) and a target (where they're found again and re-selected), and get-or-create the target's buffer manager so the restore can be installed on a pane that hasn't rendered yet. Behavior-preserving: the sole caller passes the same view for both, as before. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
e58f6d43ad
commit
a2e1254a96
|
|
@ -270,32 +270,39 @@ func (self *StagingHelper) RestoreFocusedMainViewOnEscape(explorerView, mainView
|
|||
// focused main view's diff, for the selection to land on the change nearest the one
|
||||
// just acted on rather than at a stale (and possibly off-content) position — the same
|
||||
// "advance to the next change" the staging view does. firstLine and lastLine bound
|
||||
// the just-staged selection in the current (pre-staging) diff; place positions and
|
||||
// re-selects the landed line in the current select mode. Install it before triggering
|
||||
// the re-render: it rides the next render of view, like RestoreFocusedMainViewOnEscape.
|
||||
// the just-staged selection in sourceView's current (pre-staging) diff; place
|
||||
// positions and re-selects the landed line in the current select mode. Install it
|
||||
// before triggering the re-render: it rides the next render of targetView, like
|
||||
// RestoreFocusedMainViewOnEscape.
|
||||
//
|
||||
// sourceView is the pane the user acted in; targetView is the pane to re-select in.
|
||||
// They are usually the same, but staging or unstaging can move the acted-on side to
|
||||
// the other pane — e.g. unstaging the first hunk of an only-staged file splits it,
|
||||
// pushing the staged remainder to the secondary half — in which case the candidate
|
||||
// lines, captured from sourceView, are found again in targetView's re-render.
|
||||
//
|
||||
// The candidates, in priority order, are the change block after the selection, then
|
||||
// the one before it (both survive staging — only the selection itself was staged),
|
||||
// then the selection's own first line, which only turns up when the whole side was
|
||||
// staged and the view flips to show the other (staged) side. If none survives, place
|
||||
// isn't called and the view re-renders without moving the selection.
|
||||
func (self *StagingHelper) RevealSelectionAfterStaging(view *gocui.View, firstLine int, lastLine int, place func(viewLine int)) {
|
||||
func (self *StagingHelper) RevealSelectionAfterStaging(sourceView *gocui.View, targetView *gocui.View, firstLine int, lastLine int, place func(viewLine int)) {
|
||||
var candidates []diffLineAnchor
|
||||
addByViewLine := func(viewLine int) {
|
||||
if info, ok := self.GetDiffLineInfoForView(view, viewLine); ok {
|
||||
if info, ok := self.GetDiffLineInfoForView(sourceView, viewLine); ok {
|
||||
candidates = append(candidates, diffLineAnchor{identity: info})
|
||||
}
|
||||
}
|
||||
|
||||
if next, ok := self.AdjacentChangeBlock(view, lastLine, true); ok {
|
||||
if next, ok := self.AdjacentChangeBlock(sourceView, lastLine, true); ok {
|
||||
addByViewLine(next)
|
||||
}
|
||||
if prev, ok := self.AdjacentChangeBlock(view, firstLine, false); ok {
|
||||
if prev, ok := self.AdjacentChangeBlock(sourceView, firstLine, false); ok {
|
||||
addByViewLine(prev)
|
||||
}
|
||||
addByViewLine(firstLine)
|
||||
|
||||
self.restoreDiffLinePositionOnRerender(view, candidates, func(_ diffLineAnchor, viewLine int) {
|
||||
self.restoreDiffLinePositionOnRerender(targetView, candidates, func(_ diffLineAnchor, viewLine int) {
|
||||
place(viewLine)
|
||||
})
|
||||
}
|
||||
|
|
@ -325,7 +332,10 @@ func (self *StagingHelper) restoreDiffLinePositionOnRerender(view *gocui.View, c
|
|||
if len(candidates) == 0 {
|
||||
return
|
||||
}
|
||||
manager := self.c.GetViewBufferManagerForView(view)
|
||||
// Get-or-create: the target pane may not have rendered yet (the secondary half
|
||||
// when a stage/unstage first splits the diff), so the restore has to be set on a
|
||||
// manager that the upcoming render will then reuse.
|
||||
manager := self.c.GetOrCreateViewBufferManagerForView(view)
|
||||
if manager == nil {
|
||||
return
|
||||
}
|
||||
|
|
|
|||
|
|
@ -296,7 +296,7 @@ func (self *MainViewController) stageSelectedLine() error {
|
|||
// The diff re-renders after staging; install a restore (before the handler
|
||||
// triggers that re-render) so the selection lands on the next change rather than
|
||||
// at a now-meaningless position.
|
||||
self.c.Helpers().Staging.RevealSelectionAfterStaging(v, first, last, func(viewLine int) {
|
||||
self.c.Helpers().Staging.RevealSelectionAfterStaging(v, v, first, last, func(viewLine int) {
|
||||
if self.sel().Mode == context.DiffSelectModeHunk {
|
||||
self.selectHunkAround(viewLine)
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -185,6 +185,10 @@ func (self *guiCommon) ReadLinesToFillView(view *gocui.View) {
|
|||
self.gui.readLinesToFillView(view)
|
||||
}
|
||||
|
||||
func (self *guiCommon) GetOrCreateViewBufferManagerForView(view *gocui.View) *tasks.ViewBufferManager {
|
||||
return self.gui.getManager(view)
|
||||
}
|
||||
|
||||
func (self *guiCommon) State() types.IStateAccessor {
|
||||
return self.gui.stateAccessor
|
||||
}
|
||||
|
|
|
|||
|
|
@ -67,6 +67,10 @@ type IGuiCommon interface {
|
|||
|
||||
// return the view buffer manager for the given view, or nil if it doesn't have one
|
||||
GetViewBufferManagerForView(view *gocui.View) *tasks.ViewBufferManager
|
||||
// return the view buffer manager for the given view, creating it if the view
|
||||
// hasn't rendered yet. Used to install a render restore on a pane that is about
|
||||
// to appear (e.g. the secondary half when a stage/unstage splits the diff).
|
||||
GetOrCreateViewBufferManagerForView(view *gocui.View) *tasks.ViewBufferManager
|
||||
|
||||
// read enough lines into the given view's buffer to fill it at its current
|
||||
// scroll position, plus some read-ahead for smooth scrolling
|
||||
|
|
|
|||
Loading…
Reference in a new issue