Fix broken commit auto-scrolling (#5972)
Some checks are pending
Continuous Integration / ci - ${{matrix.os}} (~/.cache/go-build, ubuntu-latest) (push) Waiting to run
Continuous Integration / ci - ${{matrix.os}} (~\AppData\Local\go-build, windows-latest) (push) Waiting to run
Continuous Integration / Integration Tests - git ${{matrix.git-version}}${{ matrix.race && ' (race)' || '' }} (2.32.0, false) (push) Waiting to run
Continuous Integration / Integration Tests - git ${{matrix.git-version}}${{ matrix.race && ' (race)' || '' }} (2.38.2, false) (push) Waiting to run
Continuous Integration / check-codebase (push) Waiting to run
Continuous Integration / Integration Tests - git ${{matrix.git-version}}${{ matrix.race && ' (race)' || '' }} (2.44.0, false) (push) Waiting to run
Continuous Integration / Integration Tests - git ${{matrix.git-version}}${{ matrix.race && ' (race)' || '' }} (latest, false) (push) Waiting to run
Continuous Integration / Integration Tests - git ${{matrix.git-version}}${{ matrix.race && ' (race)' || '' }} (latest, true) (push) Waiting to run
Continuous Integration / build (push) Waiting to run
Continuous Integration / lint (push) Waiting to run
Continuous Integration / upload-coverage (push) Blocked by required conditions
Continuous Integration / check-for-fixups (push) Waiting to run
Codespell / Check for spelling errors (push) Waiting to run
Generate Sponsors README / deploy (push) Waiting to run

Fix a bug introduced in #5928: dragging a commit with auto-scrolling so
that the original commit leaves the viewport, and then dragging back
into the view would snap the original commit back into view.

Labeled as ignore-for-release because it's a regression in a PR that
wasn't released yet.
This commit is contained in:
Stefan Haller 2026-08-27 09:55:00 +02:00 committed by GitHub
commit c300c319f9
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 71 additions and 8 deletions

View file

@ -191,7 +191,7 @@ func (self *LocalCommitsController) handleCommitDrag(opts gocui.ViewMouseBinding
self.commitDrag.hasMoved = true
if self.updateCommitDragInsertion(opts.Y) {
self.c.PostRefreshUpdate(self.context())
self.c.PostRefreshUpdateKeepingScrollPosition(self.context())
}
originY := self.context().GetView().OriginY()
self.dragAutoscroller.Update(opts.Y - originY)

View file

@ -28,6 +28,9 @@ type fakeGuiDriver struct {
heldCoordinates []coordinate
movedCoordinates []coordinate
releasedCoordinates []coordinate
scrolledCoordinates []coordinate
onUIThread bool
onUIThreadCallCount int
}
var _ integrationTypes.GuiDriver = &fakeGuiDriver{}
@ -57,13 +60,17 @@ func (self *fakeGuiDriver) MouseRelease(x, y int) {
}
func (self *fakeGuiDriver) ScrollWheelDown(x, y int) {
self.scrolledCoordinates = append(self.scrolledCoordinates, coordinate{x: x, y: y})
}
func (self *fakeGuiDriver) RefreshInBackground() {
}
func (self *fakeGuiDriver) OnUIThreadAndWait(f func()) {
self.onUIThreadCallCount++
self.onUIThread = true
f()
self.onUIThread = false
}
func (self *fakeGuiDriver) FocusIn() {
@ -167,6 +174,42 @@ func TestSuccess(t *testing.T) {
assert.Equal(t, "", driver.failureMessage)
}
func TestViewDriverPointerCoordinates(t *testing.T) {
guiDriver := &fakeGuiDriver{}
testDriver := NewTestDriver(guiDriver, nil, config.KeybindingConfig{}, 0)
view := gocui.NewView("source", 10, 20, 30, 31, gocui.OutputNormal)
targetView := gocui.NewView("target", 40, 50, 60, 61, gocui.OutputNormal)
viewDriver := &ViewDriver{
getView: func() *gocui.View {
assert.True(t, guiDriver.onUIThread)
return view
},
t: testDriver,
}
targetViewDriver := &ViewDriver{
getView: func() *gocui.View {
assert.True(t, guiDriver.onUIThread)
return targetView
},
t: testDriver,
}
viewDriver.
Click(1, 2).
FocusInAndClick(3, 4).
ClickAndHold(5, 6).
MouseMove(7, 8).
MouseMoveToBottom(9).
MouseMoveToView(targetViewDriver, 10, 11).
ScrollWheelDown()
assert.Equal(t, []coordinate{{12, 23}, {14, 25}}, guiDriver.clickedCoordinates)
assert.Equal(t, []coordinate{{16, 27}}, guiDriver.heldCoordinates)
assert.Equal(t, []coordinate{{18, 29}, {20, 30}, {51, 62}}, guiDriver.movedCoordinates)
assert.Equal(t, []coordinate{{11, 21}}, guiDriver.scrolledCoordinates)
assert.Equal(t, 7, guiDriver.onUIThreadCallCount)
}
func TestFailingFixture(t *testing.T) {
test := NewIntegrationTest(NewIntegrationTestArgs{
Description: unitTestDescription,

View file

@ -517,7 +517,7 @@ func (self *ViewDriver) PressRapidly(keys ...config.Keybinding) *ViewDriver {
}
func (self *ViewDriver) Click(x, y int) *ViewDriver {
offsetX, offsetY, _, _ := self.getView().Dimensions()
offsetX, offsetY, _ := self.viewGeometry()
self.t.click(offsetX+1+x, offsetY+1+y)
@ -525,7 +525,7 @@ func (self *ViewDriver) Click(x, y int) *ViewDriver {
}
func (self *ViewDriver) FocusInAndClick(x, y int) *ViewDriver {
offsetX, offsetY, _, _ := self.getView().Dimensions()
offsetX, offsetY, _ := self.viewGeometry()
self.t.focusInAndClick(offsetX+1+x, offsetY+1+y)
@ -533,7 +533,7 @@ func (self *ViewDriver) FocusInAndClick(x, y int) *ViewDriver {
}
func (self *ViewDriver) MouseMoveToView(target *ViewDriver, x, y int) *ViewDriver {
offsetX, offsetY, _, _ := target.getView().Dimensions()
offsetX, offsetY, _ := target.viewGeometry()
self.t.mouseMove(offsetX+1+x, offsetY+1+y)
return self
}
@ -543,30 +543,42 @@ func (self *ViewDriver) Drag(fromX, fromY, toX, toY int) *ViewDriver {
}
func (self *ViewDriver) ClickAndHold(x, y int) *ViewDriver {
offsetX, offsetY, _, _ := self.getView().Dimensions()
offsetX, offsetY, _ := self.viewGeometry()
self.t.clickAndHold(offsetX+1+x, offsetY+1+y)
return self
}
func (self *ViewDriver) MouseMove(x, y int) *ViewDriver {
offsetX, offsetY, _, _ := self.getView().Dimensions()
offsetX, offsetY, _ := self.viewGeometry()
self.t.mouseMove(offsetX+1+x, offsetY+1+y)
return self
}
func (self *ViewDriver) MouseMoveToBottom(x int) *ViewDriver {
return self.MouseMove(x, self.getView().InnerHeight()-1)
offsetX, offsetY, innerHeight := self.viewGeometry()
self.t.mouseMove(offsetX+1+x, offsetY+innerHeight)
return self
}
// scrolls the view down by one notch of the mouse wheel, i.e. by
// gui.scrollHeight lines. This moves the scroll position without moving the
// selection.
func (self *ViewDriver) ScrollWheelDown() *ViewDriver {
offsetX, offsetY, _, _ := self.getView().Dimensions()
offsetX, offsetY, _ := self.viewGeometry()
self.t.scrollWheelDown(offsetX+1, offsetY+1)
return self
}
func (self *ViewDriver) viewGeometry() (offsetX int, offsetY int, innerHeight int) {
self.t.gui.OnUIThreadAndWait(func() {
view := self.getView()
offsetX, offsetY, _, _ = view.Dimensions()
innerHeight = view.InnerHeight()
})
return offsetX, offsetY, innerHeight
}
func (self *ViewDriver) RepeatMouseMove() *ViewDriver {
self.t.repeatMouseMove()
return self

View file

@ -19,14 +19,22 @@ var DragToReorderWithAutoscroll = NewIntegrationTest(NewIntegrationTestArgs{
TopLines(
Contains("commit-40").IsSelected(),
).
// Click and hold the first commit
ClickAndHold(1, 0).
// Move the mouse to the bottom of the panel to trigger autoscroll
MouseMoveToBottom(1).
// Verify that the view scrolls
OriginYAtLeast(3).
// Move the mouse back into the viewport
MouseMove(1, 1).
// This keeps the scroll as it was
OriginYAtLeast(3).
MouseRelease().
SelectedLines(
Contains("commit-40"),
).
SelectedLineIdxAtLeast(3).
// Scroll back to verify that the original commit is no longer at the top
GotoTop().
TopLines(
Contains("commit-39").IsSelected(),