From 14434015c739c843b5257116bc63d36531092bd2 Mon Sep 17 00:00:00 2001 From: Stefan Haller Date: Fri, 24 Jul 2026 08:18:30 +0200 Subject: [PATCH] Keep range drags moving at panel edges Give the list views the same edge autoscroll during drag selection that the staging view already has; the new mouse-release binding stops the autoscroll when the drag ends. --- pkg/gui/controllers/list_controller.go | 68 ++++++++++++++++--- .../tests/ui/range_select_with_autoscroll.go | 9 +++ 2 files changed, 68 insertions(+), 9 deletions(-) diff --git a/pkg/gui/controllers/list_controller.go b/pkg/gui/controllers/list_controller.go index 828a9d7db..8136c6aa9 100644 --- a/pkg/gui/controllers/list_controller.go +++ b/pkg/gui/controllers/list_controller.go @@ -2,6 +2,7 @@ package controllers import ( "github.com/jesseduffield/lazygit/pkg/gocui" + "github.com/jesseduffield/lazygit/pkg/gui/controllers/helpers" "github.com/jesseduffield/lazygit/pkg/gui/types" ) @@ -16,18 +17,27 @@ func NewListControllerFactory(c *ControllerCommon) *ListControllerFactory { } func (self *ListControllerFactory) Create(context types.IListContext) *ListController { - return &ListController{ + controller := &ListController{ baseController: baseController{}, c: self.c, context: context, } + controller.dragAutoscroller = helpers.NewDragAutoscroller( + self.c.HelperCommon, + context, + func(int) bool { return context.GetList().IsSelectingRange() }, + controller.handleDragAutoscroll, + ) + return controller } type ListController struct { baseController c *ControllerCommon - context types.IListContext + context types.IListContext + dragAutoscroller *helpers.DragAutoscroller + draggingWithMouse bool } func (self *ListController) Context() types.Context { @@ -258,14 +268,47 @@ func (self *ListController) HandleClick(opts gocui.ViewMouseBindingOpts) error { } func (self *ListController) HandleDrag(opts gocui.ViewMouseBindingOpts) error { + self.draggingWithMouse = true + self.selectRangeThroughViewIndex(opts.Y) + originY, _ := self.context.GetViewTrait().ViewPortYBounds() + self.dragAutoscroller.Update(opts.Y - originY) + return nil +} + +func (self *ListController) selectRangeThroughViewIndex(viewIndex int) { list := self.context.GetList() - newSelectedLineIdx := self.context.ViewIndexToModelIndex(opts.Y) + newSelectedLineIdx := self.context.ViewIndexToModelIndex(viewIndex) list.ExpandNonStickyRange(newSelectedLineIdx - list.GetSelectedLineIdx()) self.context.HandleFocus(types.OnFocusOpts{}) +} + +func (self *ListController) handleDragAutoscroll(viewIndex int) bool { + if !self.context.GetList().IsSelectingRange() { + return false + } + + self.context.SetNeedRerenderVisibleLines() + self.selectRangeThroughViewIndex(viewIndex) + return true +} + +func (self *ListController) handleDragRelease() error { + self.draggingWithMouse = false + self.dragAutoscroller.Cancel() return nil } +func (self *ListController) GetOnFocusLost() func(types.OnFocusLostOpts) { + return func(types.OnFocusLostOpts) { + self.dragAutoscroller.Cancel() + if self.draggingWithMouse { + self.draggingWithMouse = false + self.c.GocuiGui().CancelMouseCapture() + } + } +} + func (self *ListController) pushContextIfNotFocused() error { if !self.isFocused() { self.c.Context().Push(self.context, types.OnFocusOpts{}) @@ -323,12 +366,19 @@ func (self *ListController) GetMouseKeybindings(opts types.KeybindingsOpts) []*g } if self.context.RangeSelectEnabled() { - bindings = append(bindings, &gocui.ViewMouseBinding{ - ViewName: self.context.GetViewName(), - Key: gocui.MouseLeft, - Modifier: gocui.ModMotion, - Handler: self.HandleDrag, - }) + bindings = append(bindings, + &gocui.ViewMouseBinding{ + ViewName: self.context.GetViewName(), + Key: gocui.MouseLeft, + Modifier: gocui.ModMotion, + Handler: self.HandleDrag, + }, + &gocui.ViewMouseBinding{ + ViewName: self.context.GetViewName(), + Key: gocui.MouseRelease, + Handler: func(gocui.ViewMouseBindingOpts) error { return self.handleDragRelease() }, + }, + ) } return bindings diff --git a/pkg/integration/tests/ui/range_select_with_autoscroll.go b/pkg/integration/tests/ui/range_select_with_autoscroll.go index 83d2bcba3..94a4fb4a5 100644 --- a/pkg/integration/tests/ui/range_select_with_autoscroll.go +++ b/pkg/integration/tests/ui/range_select_with_autoscroll.go @@ -17,6 +17,7 @@ var RangeSelectWithAutoscroll = NewIntegrationTest(NewIntegrationTestArgs{ config.GetUserConfig().Gui.UseHunkModeInStagingView = false }, SetupRepo: func(shell *Shell) { + shell.CreateNCommits(40) fileContent := "base\n" shell.CreateFileAndAdd("file1", fileContent) for i := 1; i <= 40; i++ { @@ -25,6 +26,14 @@ var RangeSelectWithAutoscroll = NewIntegrationTest(NewIntegrationTestArgs{ shell.UpdateFile("file1", fileContent) }, Run: func(t *TestDriver, keys config.KeybindingConfig) { + t.Views().Branches().Focus() + t.Views().Commits(). + ClickAndHold(1, 0). + MouseMoveToBottom(1). + OriginYAtLeast(3). + SelectedLineIdxAtLeast(3). + MouseRelease() + t.Views().Files(). Focus(). PressEnter()