Move the post-action reveal onto the diff-line helper

It is built entirely on that helper, and the render chokepoint that is about
to want it lives in the gui package, which cannot reach a controller.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
Stefan Haller
2026-10-05 11:20:32 +02:00
co-authored by Claude Opus 5
parent f5577d16c3
commit 163a0c576b
3 changed files with 46 additions and 47 deletions
@@ -543,3 +543,48 @@ func patchLineOf(info types.DiffLineInfo) patchLine {
return patchLine{path: info.Path, kind: types.DiffLineContext, line: info.NewLine}
}
}
// RevealSelectionAfterAction moves a diff pane's selection to the change that takes the
// place of the one just acted on, once the changed diff has re-rendered. Call it with
// the pane acted in, the pane the work carries on in, and the buffer line the selection
// starts on, before triggering the re-render.
//
// The line acted on is gone from the diff, so what is remembered is its place among the
// diff's changes: the next change moves up into it, which is where you want to be to
// carry on. A range collapses to a single line at its start, and hunk mode selects the
// whole block it lands in, so that pressing the key again acts on the next hunk. The
// target pane inherits that select mode, this being the same piece of work continuing
// in another pane — and shows no selection until the restore places one, so that what
// it was left showing the last time it was used doesn't appear for a frame.
//
// done is called once the selection is where it belongs, or once it turns out that no
// render is coming to put it there, for a caller that must not let the user act again
// in between.
func (self *DiffLineHelper) RevealSelectionAfterAction(
source types.DiffPaneContext, target types.DiffPaneContext, firstBufferLine int, done func(),
) {
ordinal := self.ChangeLineOrdinal(source.GetView(), firstBufferLine)
sel := source.DiffSelectState()
if sel.Mode == types.DiffSelectModeRange {
sel.Mode = types.DiffSelectModeLine
sel.RangeIsSticky = false
}
*target.DiffSelectState() = *sel
selectHunk := sel.Mode == types.DiffSelectModeHunk
targetView := target.GetView()
if target != source {
target.SetHasSelectableContent(false)
self.c.Context().UpdateSelectionHighlights()
}
self.RevealChangeLineAtOrdinal(targetView, ordinal, func(viewLine int) {
if selectHunk {
self.SelectChangeBlock(target, viewLine, true)
return
}
targetView.CancelRangeSelect()
self.ShowSelectionAtLine(targetView, viewLine, true)
}, done)
}
@@ -343,52 +343,6 @@ func (self *MainViewController) primaryAction() error {
return actions.PrimaryAction(self.context, first, last)
}
// revealSelectionAfterAction moves the selection to the change that takes the place of
// the one just acted on, once the changed diff has re-rendered. Call it from the panel's
// action handler with the pane it acted in, the pane the work carries on in, and the
// buffer line the selection starts on, before triggering the re-render.
//
// The line acted on is gone from the diff, so what is remembered is its place among the
// diff's changes: the next change moves up into it, which is where you want to be to
// carry on. A range collapses to a single line at its start, and hunk mode selects the
// whole block it lands in, so that pressing the key again acts on the next hunk. The
// target pane inherits that select mode, this being the same piece of work continuing
// in another pane — and shows no selection until the restore places one, so that what
// it was left showing the last time it was used doesn't appear for a frame.
//
// done is called once the selection is where it belongs, or once it turns out that no
// render is coming to put it there, for a caller that must not let the user act again
// in between.
func revealSelectionAfterAction(
c *ControllerCommon, source types.DiffPaneContext, target types.DiffPaneContext,
firstBufferLine int, done func(),
) {
ordinal := c.Helpers().DiffLine.ChangeLineOrdinal(source.GetView(), firstBufferLine)
sel := source.DiffSelectState()
if sel.Mode == types.DiffSelectModeRange {
sel.Mode = types.DiffSelectModeLine
sel.RangeIsSticky = false
}
*target.DiffSelectState() = *sel
selectHunk := sel.Mode == types.DiffSelectModeHunk
targetView := target.GetView()
if target != source {
target.SetHasSelectableContent(false)
c.Context().UpdateSelectionHighlights()
}
c.Helpers().DiffLine.RevealChangeLineAtOrdinal(targetView, ordinal, func(viewLine int) {
if selectHunk {
c.Helpers().DiffLine.SelectChangeBlock(target, viewLine, true)
return
}
targetView.CancelRangeSelect()
c.Helpers().DiffLine.ShowSelectionAtLine(targetView, viewLine, true)
}, done)
}
// discardSelection takes the selected diff lines back out of what they are part of,
// which — like the primary action — is the panel's business, and so is the re-render
// that follows.
@@ -378,7 +378,7 @@ func (self *WorkingTreeDiffActions) revealSelectionInPaneItLandsIn(
// that, and until it has been the selection is still on lines that aren't there any
// more — so a key pressed meanwhile would act on nothing.
self.c.GocuiGui().BeginBlockingEvents()
revealSelectionAfterAction(self.c, pane, target, firstBufferLine,
self.c.Helpers().DiffLine.RevealSelectionAfterAction(pane, target, firstBufferLine,
self.c.GocuiGui().EndBlockingEvents)
}