1
0
mirror of https://github.com/jesseduffield/lazygit.git synced 2025-04-27 12:32:37 +02:00

Improve mouse support for commit message panel (#3836)

#### PR Description

* Fix some minor problems related to cursor movement in an auto-wrapped
  commit message
* Allow clicking in an editable view to set the cursor (most useful in
  longer commit descriptions)
* Allow switching between commit message and description by clicking
This commit is contained in:
Stefan Haller 2024-08-24 10:29:44 +02:00 committed by GitHub
commit 61ae5e16ae
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
9 changed files with 98 additions and 22 deletions

2
go.mod
View File

@ -16,7 +16,7 @@ require (
github.com/integrii/flaggy v1.4.0 github.com/integrii/flaggy v1.4.0
github.com/jesseduffield/generics v0.0.0-20220320043834-727e535cbe68 github.com/jesseduffield/generics v0.0.0-20220320043834-727e535cbe68
github.com/jesseduffield/go-git/v5 v5.1.2-0.20221018185014-fdd53fef665d github.com/jesseduffield/go-git/v5 v5.1.2-0.20221018185014-fdd53fef665d
github.com/jesseduffield/gocui v0.3.1-0.20240818082312-49cc572a9ffa github.com/jesseduffield/gocui v0.3.1-0.20240824081936-a3adeb73f602
github.com/jesseduffield/kill v0.0.0-20220618033138-bfbe04675d10 github.com/jesseduffield/kill v0.0.0-20220618033138-bfbe04675d10
github.com/jesseduffield/lazycore v0.0.0-20221012050358-03d2e40243c5 github.com/jesseduffield/lazycore v0.0.0-20221012050358-03d2e40243c5
github.com/jesseduffield/minimal/gitignore v0.3.3-0.20211018110810-9cde264e6b1e github.com/jesseduffield/minimal/gitignore v0.3.3-0.20211018110810-9cde264e6b1e

4
go.sum
View File

@ -188,8 +188,8 @@ github.com/jesseduffield/generics v0.0.0-20220320043834-727e535cbe68 h1:EQP2Tv8T
github.com/jesseduffield/generics v0.0.0-20220320043834-727e535cbe68/go.mod h1:+LLj9/WUPAP8LqCchs7P+7X0R98HiFujVFANdNaxhGk= github.com/jesseduffield/generics v0.0.0-20220320043834-727e535cbe68/go.mod h1:+LLj9/WUPAP8LqCchs7P+7X0R98HiFujVFANdNaxhGk=
github.com/jesseduffield/go-git/v5 v5.1.2-0.20221018185014-fdd53fef665d h1:bO+OmbreIv91rCe8NmscRwhFSqkDJtzWCPV4Y+SQuXE= github.com/jesseduffield/go-git/v5 v5.1.2-0.20221018185014-fdd53fef665d h1:bO+OmbreIv91rCe8NmscRwhFSqkDJtzWCPV4Y+SQuXE=
github.com/jesseduffield/go-git/v5 v5.1.2-0.20221018185014-fdd53fef665d/go.mod h1:nGNEErzf+NRznT+N2SWqmHnDnF9aLgANB1CUNEan09o= github.com/jesseduffield/go-git/v5 v5.1.2-0.20221018185014-fdd53fef665d/go.mod h1:nGNEErzf+NRznT+N2SWqmHnDnF9aLgANB1CUNEan09o=
github.com/jesseduffield/gocui v0.3.1-0.20240818082312-49cc572a9ffa h1:XZX6Rf60E3IuF1K+fvxjIr29f4p9kNY83mveGoJ5Uuo= github.com/jesseduffield/gocui v0.3.1-0.20240824081936-a3adeb73f602 h1:nzGt/sRT0WCancALG5Q9e4DlQWGo7QUMc35rApdt+aM=
github.com/jesseduffield/gocui v0.3.1-0.20240818082312-49cc572a9ffa/go.mod h1:XtEbqCbn45keRXEu+OMZkjN5gw6AEob59afsgHjokZ8= github.com/jesseduffield/gocui v0.3.1-0.20240824081936-a3adeb73f602/go.mod h1:XtEbqCbn45keRXEu+OMZkjN5gw6AEob59afsgHjokZ8=
github.com/jesseduffield/kill v0.0.0-20220618033138-bfbe04675d10 h1:jmpr7KpX2+2GRiE91zTgfq49QvgiqB0nbmlwZ8UnOx0= github.com/jesseduffield/kill v0.0.0-20220618033138-bfbe04675d10 h1:jmpr7KpX2+2GRiE91zTgfq49QvgiqB0nbmlwZ8UnOx0=
github.com/jesseduffield/kill v0.0.0-20220618033138-bfbe04675d10/go.mod h1:aA97kHeNA+sj2Hbki0pvLslmE4CbDyhBeSSTUUnOuVo= github.com/jesseduffield/kill v0.0.0-20220618033138-bfbe04675d10/go.mod h1:aA97kHeNA+sj2Hbki0pvLslmE4CbDyhBeSSTUUnOuVo=
github.com/jesseduffield/lazycore v0.0.0-20221012050358-03d2e40243c5 h1:CDuQmfOjAtb1Gms6a1p5L2P8RhbLUq5t8aL7PiQd2uY= github.com/jesseduffield/lazycore v0.0.0-20221012050358-03d2e40243c5 h1:CDuQmfOjAtb1Gms6a1p5L2P8RhbLUq5t8aL7PiQd2uY=

View File

@ -354,6 +354,7 @@ func (gui *Gui) resetHelpersAndControllers() {
controllers.AttachControllers(gui.State.Contexts.CommitDescription, controllers.AttachControllers(gui.State.Contexts.CommitDescription,
commitDescriptionController, commitDescriptionController,
verticalScrollControllerFactory.Create(gui.State.Contexts.CommitDescription),
) )
controllers.AttachControllers(gui.State.Contexts.RemoteBranches, controllers.AttachControllers(gui.State.Contexts.RemoteBranches,

View File

@ -1,6 +1,7 @@
package controllers package controllers
import ( import (
"github.com/jesseduffield/gocui"
"github.com/jesseduffield/lazygit/pkg/gui/context" "github.com/jesseduffield/lazygit/pkg/gui/context"
"github.com/jesseduffield/lazygit/pkg/gui/types" "github.com/jesseduffield/lazygit/pkg/gui/types"
) )
@ -45,11 +46,17 @@ func (self *CommitDescriptionController) GetKeybindings(opts types.KeybindingsOp
} }
func (self *CommitDescriptionController) Context() types.Context { func (self *CommitDescriptionController) Context() types.Context {
return self.context() return self.c.Contexts().CommitDescription
} }
func (self *CommitDescriptionController) context() *context.CommitMessageContext { func (self *CommitDescriptionController) GetMouseKeybindings(opts types.KeybindingsOpts) []*gocui.ViewMouseBinding {
return self.c.Contexts().CommitMessage return []*gocui.ViewMouseBinding{
{
ViewName: self.Context().GetViewName(),
Key: gocui.MouseLeft,
Handler: self.onClick,
},
}
} }
func (self *CommitDescriptionController) switchToCommitMessage() error { func (self *CommitDescriptionController) switchToCommitMessage() error {
@ -68,3 +75,12 @@ func (self *CommitDescriptionController) openCommitMenu() error {
authorSuggestion := self.c.Helpers().Suggestions.GetAuthorsSuggestionsFunc() authorSuggestion := self.c.Helpers().Suggestions.GetAuthorsSuggestionsFunc()
return self.c.Helpers().Commits.OpenCommitMenu(authorSuggestion) return self.c.Helpers().Commits.OpenCommitMenu(authorSuggestion)
} }
func (self *CommitDescriptionController) onClick(opts gocui.ViewMouseBindingOpts) error {
// Activate the description panel when the commit message panel is currently active
if self.c.Context().Current().GetKey() == context.COMMIT_MESSAGE_CONTEXT_KEY {
return self.c.Context().Replace(self.c.Contexts().CommitDescription)
}
return nil
}

View File

@ -3,6 +3,7 @@ package controllers
import ( import (
"errors" "errors"
"github.com/jesseduffield/gocui"
"github.com/jesseduffield/lazygit/pkg/commands/git_commands" "github.com/jesseduffield/lazygit/pkg/commands/git_commands"
"github.com/jesseduffield/lazygit/pkg/gui/context" "github.com/jesseduffield/lazygit/pkg/gui/context"
"github.com/jesseduffield/lazygit/pkg/gui/controllers/helpers" "github.com/jesseduffield/lazygit/pkg/gui/controllers/helpers"
@ -58,6 +59,16 @@ func (self *CommitMessageController) GetKeybindings(opts types.KeybindingsOpts)
return bindings return bindings
} }
func (self *CommitMessageController) GetMouseKeybindings(opts types.KeybindingsOpts) []*gocui.ViewMouseBinding {
return []*gocui.ViewMouseBinding{
{
ViewName: self.Context().GetViewName(),
Key: gocui.MouseLeft,
Handler: self.onClick,
},
}
}
func (self *CommitMessageController) GetOnFocusLost() func(types.OnFocusLostOpts) error { func (self *CommitMessageController) GetOnFocusLost() func(types.OnFocusLostOpts) error {
return func(types.OnFocusLostOpts) error { return func(types.OnFocusLostOpts) error {
self.context().RenderCommitLength() self.context().RenderCommitLength()
@ -137,3 +148,12 @@ func (self *CommitMessageController) openCommitMenu() error {
authorSuggestion := self.c.Helpers().Suggestions.GetAuthorsSuggestionsFunc() authorSuggestion := self.c.Helpers().Suggestions.GetAuthorsSuggestionsFunc()
return self.c.Helpers().Commits.OpenCommitMenu(authorSuggestion) return self.c.Helpers().Commits.OpenCommitMenu(authorSuggestion)
} }
func (self *CommitMessageController) onClick(opts gocui.ViewMouseBindingOpts) error {
// Activate the commit message panel when the commit description panel is currently active
if self.c.Context().Current().GetKey() == context.COMMIT_DESCRIPTION_CONTEXT_KEY {
return self.c.Context().Replace(self.c.Contexts().CommitMessage)
}
return nil
}

View File

@ -424,8 +424,14 @@ func (gui *Gui) SetKeybinding(binding *types.Binding) error {
func (gui *Gui) SetMouseKeybinding(binding *gocui.ViewMouseBinding) error { func (gui *Gui) SetMouseKeybinding(binding *gocui.ViewMouseBinding) error {
baseHandler := binding.Handler baseHandler := binding.Handler
newHandler := func(opts gocui.ViewMouseBindingOpts) error { newHandler := func(opts gocui.ViewMouseBindingOpts) error {
// we ignore click events on views that aren't popup panels, when a popup panel is focused // we ignore click events on views that aren't popup panels, when a popup panel is focused.
if gui.helpers.Confirmation.IsPopupPanelFocused() && gui.currentViewName() != binding.ViewName { // Unless both the current view and the clicked-on view are either commit message or commit
// description, because we want to allow switching between those two views by clicking.
isCommitMessageView := func(viewName string) bool {
return viewName == "commitMessage" || viewName == "commitDescription"
}
if gui.helpers.Confirmation.IsPopupPanelFocused() && gui.currentViewName() != binding.ViewName &&
(!isCommitMessageView(gui.currentViewName()) || !isCommitMessageView(binding.ViewName)) {
return nil return nil
} }

View File

@ -1327,23 +1327,48 @@ func (g *Gui) onKey(ev *GocuiEvent) error {
} }
} }
// newCx and newCy are relative to the view port, i.e. to the visible area of the view
newCx := mx - v.x0 - 1 newCx := mx - v.x0 - 1
newCy := my - v.y0 - 1 newCy := my - v.y0 - 1
// if view is editable don't go further than the furthest character for that line // newX and newY are relative to the view's content, independent of its scroll position
if v.Editable && newCy >= 0 && newCy <= len(v.lines)-1 { newX := newCx + v.ox
lastCharForLine := len(v.lines[newCy]) newY := newCy + v.oy
if lastCharForLine < newCx { // if view is editable don't go further than the furthest character for that line
newCx = lastCharForLine if v.Editable {
if newY < 0 {
newY = 0
newCy = -v.oy
} else if newY >= len(v.lines) {
newY = len(v.lines) - 1
newCy = newY - v.oy
}
lastCharForLine := len(v.lines[newY])
for lastCharForLine > 0 && v.lines[newY][lastCharForLine-1].chr == 0 {
lastCharForLine--
}
if lastCharForLine < newX {
newX = lastCharForLine
newCx = lastCharForLine - v.ox
} }
} }
if !IsMouseScrollKey(ev.Key) { if !IsMouseScrollKey(ev.Key) {
if err := v.SetCursor(newCx, newCy); err != nil { if err := v.SetCursor(newCx, newCy); err != nil {
return err return err
} }
if v.Editable {
v.TextArea.SetCursor2D(newX, newY)
// SetCursor2D might have adjusted the text area's cursor to the
// left to move left from a soft line break, so we need to
// update the view's cursor to match the text area's cursor.
cX, _ := v.TextArea.GetCursorXY()
v.SetCursorX(cX)
}
} }
if IsMouseKey(ev.Key) { if IsMouseKey(ev.Key) {
opts := ViewMouseBindingOpts{X: newCx + v.ox, Y: newCy + v.oy} opts := ViewMouseBindingOpts{X: newX, Y: newY}
matched, err := g.execMouseKeybindings(v, ev, opts) matched, err := g.execMouseKeybindings(v, ev, opts)
if err != nil { if err != nil {
return err return err

View File

@ -282,13 +282,7 @@ func (self *TextArea) GoToEndOfLine() {
self.cursor = self.closestNewlineOnRight() self.cursor = self.closestNewlineOnRight()
// If the end of line is a soft line break, we need to move left by one so self.moveLeftFromSoftLineBreak()
// that we end up at the last whitespace before the line break. Otherwise
// we'd be at the start of the next line, since the newline character
// doesn't really exist in the real content.
if self.cursor < len(self.content) && self.content[self.cursor] != '\n' {
self.cursor--
}
} }
func (self *TextArea) closestNewlineOnRight() int { func (self *TextArea) closestNewlineOnRight() int {
@ -303,6 +297,16 @@ func (self *TextArea) closestNewlineOnRight() int {
return len(self.content) return len(self.content)
} }
func (self *TextArea) moveLeftFromSoftLineBreak() {
// If the end of line is a soft line break, we need to move left by one so
// that we end up at the last whitespace before the line break. Otherwise
// we'd be at the start of the next line, since the newline character
// doesn't really exist in the real content.
if self.cursor < len(self.content) && self.content[self.cursor] != '\n' {
self.cursor--
}
}
func (self *TextArea) atLineStart() bool { func (self *TextArea) atLineStart() bool {
return self.cursor == 0 || return self.cursor == 0 ||
(len(self.content) > self.cursor-1 && self.content[self.cursor-1] == '\n') (len(self.content) > self.cursor-1 && self.content[self.cursor-1] == '\n')
@ -420,12 +424,16 @@ func (self *TextArea) SetCursor2D(x int, y int) {
for _, r := range self.wrappedContent { for _, r := range self.wrappedContent {
if x <= 0 && y == 0 { if x <= 0 && y == 0 {
self.cursor = self.wrappedCursorToOrigCursor(newCursor) self.cursor = self.wrappedCursorToOrigCursor(newCursor)
if self.wrappedContent[newCursor] == '\n' {
self.moveLeftFromSoftLineBreak()
}
return return
} }
if r == '\n' { if r == '\n' {
if y == 0 { if y == 0 {
self.cursor = self.wrappedCursorToOrigCursor(newCursor) self.cursor = self.wrappedCursorToOrigCursor(newCursor)
self.moveLeftFromSoftLineBreak()
return return
} }
y-- y--

2
vendor/modules.txt vendored
View File

@ -172,7 +172,7 @@ github.com/jesseduffield/go-git/v5/utils/merkletrie/filesystem
github.com/jesseduffield/go-git/v5/utils/merkletrie/index github.com/jesseduffield/go-git/v5/utils/merkletrie/index
github.com/jesseduffield/go-git/v5/utils/merkletrie/internal/frame github.com/jesseduffield/go-git/v5/utils/merkletrie/internal/frame
github.com/jesseduffield/go-git/v5/utils/merkletrie/noder github.com/jesseduffield/go-git/v5/utils/merkletrie/noder
# github.com/jesseduffield/gocui v0.3.1-0.20240818082312-49cc572a9ffa # github.com/jesseduffield/gocui v0.3.1-0.20240824081936-a3adeb73f602
## explicit; go 1.12 ## explicit; go 1.12
github.com/jesseduffield/gocui github.com/jesseduffield/gocui
# github.com/jesseduffield/kill v0.0.0-20220618033138-bfbe04675d10 # github.com/jesseduffield/kill v0.0.0-20220618033138-bfbe04675d10