1
0
mirror of https://github.com/jesseduffield/lazygit.git synced 2024-12-12 11:15:00 +02:00
lazygit/pkg/gui/controllers/list_controller.go
Stefan Haller e5dd4d3110 Allow the selected line of a list view to be outside the visible area
I don't see a reason why this restriction to have the selection be always
visible was necessary. Removing it has two benefits:

1. Scrolling a list view doesn't change the selection. A common scenario: you
   look at one of the commits of your current branch; you want to see the how
   many'th commit this is, but the beginning of the branch is scrolled off the
   bottom of the commits panel. You scroll down to find the beginning of your
   branch, but this changes the selection and shows a different commit now - not
   what you want.

2. It is possible to scroll a panel that is not the current one without changing
   the focus to it. That's how windows in other GUIs usually behave.
2023-05-11 13:23:58 +02:00

187 lines
5.6 KiB
Go

package controllers
import (
"github.com/jesseduffield/gocui"
"github.com/jesseduffield/lazygit/pkg/gui/types"
)
type ListControllerFactory struct {
c *ControllerCommon
}
func NewListControllerFactory(c *ControllerCommon) *ListControllerFactory {
return &ListControllerFactory{
c: c,
}
}
func (self *ListControllerFactory) Create(context types.IListContext) *ListController {
return &ListController{
baseController: baseController{},
c: self.c,
context: context,
}
}
type ListController struct {
baseController
c *ControllerCommon
context types.IListContext
}
func (self *ListController) Context() types.Context {
return self.context
}
func (self *ListController) HandlePrevLine() error {
return self.handleLineChange(-1)
}
func (self *ListController) HandleNextLine() error {
return self.handleLineChange(1)
}
func (self *ListController) HandleScrollLeft() error {
return self.scrollHorizontal(self.context.GetViewTrait().ScrollLeft)
}
func (self *ListController) HandleScrollRight() error {
return self.scrollHorizontal(self.context.GetViewTrait().ScrollRight)
}
func (self *ListController) HandleScrollUp() error {
scrollHeight := self.c.UserConfig.Gui.ScrollHeight
self.context.GetViewTrait().ScrollUp(scrollHeight)
return nil
}
func (self *ListController) HandleScrollDown() error {
scrollHeight := self.c.UserConfig.Gui.ScrollHeight
self.context.GetViewTrait().ScrollDown(scrollHeight)
return nil
}
func (self *ListController) scrollHorizontal(scrollFunc func()) error {
scrollFunc()
return self.context.HandleFocus(types.OnFocusOpts{})
}
func (self *ListController) handleLineChange(change int) error {
before := self.context.GetList().GetSelectedLineIdx()
self.context.GetList().MoveSelectedLine(change)
after := self.context.GetList().GetSelectedLineIdx()
if err := self.pushContextIfNotFocused(); err != nil {
return err
}
// doing this check so that if we're holding the up key at the start of the list
// we're not constantly re-rendering the main view.
if before != after {
return self.context.HandleFocus(types.OnFocusOpts{})
}
return nil
}
func (self *ListController) HandlePrevPage() error {
return self.handleLineChange(-self.context.GetViewTrait().PageDelta())
}
func (self *ListController) HandleNextPage() error {
return self.handleLineChange(self.context.GetViewTrait().PageDelta())
}
func (self *ListController) HandleGotoTop() error {
return self.handleLineChange(-self.context.GetList().Len())
}
func (self *ListController) HandleGotoBottom() error {
return self.handleLineChange(self.context.GetList().Len())
}
func (self *ListController) HandleClick(opts gocui.ViewMouseBindingOpts) error {
prevSelectedLineIdx := self.context.GetList().GetSelectedLineIdx()
newSelectedLineIdx := opts.Y
alreadyFocused := self.isFocused()
if err := self.pushContextIfNotFocused(); err != nil {
return err
}
if newSelectedLineIdx > self.context.GetList().Len()-1 {
return nil
}
self.context.GetList().SetSelectedLineIdx(newSelectedLineIdx)
if prevSelectedLineIdx == newSelectedLineIdx && alreadyFocused && self.context.GetOnClick() != nil {
return self.context.GetOnClick()()
}
return self.context.HandleFocus(types.OnFocusOpts{})
}
func (self *ListController) pushContextIfNotFocused() error {
if !self.isFocused() {
if err := self.c.PushContext(self.context); err != nil {
return err
}
}
return nil
}
func (self *ListController) isFocused() bool {
return self.c.CurrentContext().GetKey() == self.context.GetKey()
}
func (self *ListController) GetKeybindings(opts types.KeybindingsOpts) []*types.Binding {
return []*types.Binding{
{Tag: "navigation", Key: opts.GetKey(opts.Config.Universal.PrevItemAlt), Handler: self.HandlePrevLine},
{Tag: "navigation", Key: opts.GetKey(opts.Config.Universal.PrevItem), Handler: self.HandlePrevLine},
{Tag: "navigation", Key: opts.GetKey(opts.Config.Universal.NextItemAlt), Handler: self.HandleNextLine},
{Tag: "navigation", Key: opts.GetKey(opts.Config.Universal.NextItem), Handler: self.HandleNextLine},
{Tag: "navigation", Key: opts.GetKey(opts.Config.Universal.PrevPage), Handler: self.HandlePrevPage, Description: self.c.Tr.LcPrevPage},
{Tag: "navigation", Key: opts.GetKey(opts.Config.Universal.NextPage), Handler: self.HandleNextPage, Description: self.c.Tr.LcNextPage},
{Tag: "navigation", Key: opts.GetKey(opts.Config.Universal.GotoTop), Handler: self.HandleGotoTop, Description: self.c.Tr.LcGotoTop},
{Tag: "navigation", Key: opts.GetKey(opts.Config.Universal.ScrollLeft), Handler: self.HandleScrollLeft},
{Tag: "navigation", Key: opts.GetKey(opts.Config.Universal.ScrollRight), Handler: self.HandleScrollRight},
{
Key: opts.GetKey(opts.Config.Universal.StartSearch),
Handler: func() error { self.c.OpenSearch(); return nil },
Description: self.c.Tr.LcStartSearch,
Tag: "navigation",
},
{
Key: opts.GetKey(opts.Config.Universal.GotoBottom),
Description: self.c.Tr.LcGotoBottom,
Handler: self.HandleGotoBottom,
Tag: "navigation",
},
}
}
func (self *ListController) GetMouseKeybindings(opts types.KeybindingsOpts) []*gocui.ViewMouseBinding {
return []*gocui.ViewMouseBinding{
{
ViewName: self.context.GetViewName(),
Key: gocui.MouseWheelUp,
Handler: func(gocui.ViewMouseBindingOpts) error { return self.HandleScrollUp() },
},
{
ViewName: self.context.GetViewName(),
Key: gocui.MouseLeft,
Handler: func(opts gocui.ViewMouseBindingOpts) error { return self.HandleClick(opts) },
},
{
ViewName: self.context.GetViewName(),
Key: gocui.MouseWheelDown,
Handler: func(gocui.ViewMouseBindingOpts) error { return self.HandleScrollDown() },
},
}
}