1
0
mirror of https://github.com/jesseduffield/lazygit.git synced 2024-12-02 09:21:40 +02:00

Add key binding for switching from the commit message panel to an editor

This is useful for when you begin to type the message in lazygit's commit panel,
and then realize that you'd rather use your editor's more powerful editing
capabilities. Pressing <c-o> will take you right there.
This commit is contained in:
Stefan Haller 2023-05-18 19:15:23 +02:00
parent 7263630967
commit 61bd3e8dd2
8 changed files with 131 additions and 11 deletions

View File

@ -68,6 +68,19 @@ func (self *CommitCommands) RewordLastCommitInEditorCmdObj() oscommands.ICmdObj
return self.cmd.New(NewGitCmd("commit").Arg("--allow-empty", "--amend", "--only").ToArgv())
}
func (self *CommitCommands) RewordLastCommitInEditorWithMessageFileCmdObj(tmpMessageFile string) oscommands.ICmdObj {
return self.cmd.New(NewGitCmd("commit").
Arg("--allow-empty", "--amend", "--only", "--edit", "--file="+tmpMessageFile).ToArgv())
}
func (self *CommitCommands) CommitInEditorWithMessageFileCmdObj(tmpMessageFile string) oscommands.ICmdObj {
return self.cmd.New(NewGitCmd("commit").
Arg("--edit").
Arg("--file="+tmpMessageFile).
ArgIf(self.signoffFlag() != "", self.signoffFlag()).
ToArgv())
}
// RewordLastCommit rewords the topmost commit with the given message
func (self *CommitCommands) RewordLastCommit(summary string, description string) error {
messageArgs := self.commitMessageArgs(summary, description)

View File

@ -132,16 +132,17 @@ type UpdateConfig struct {
}
type KeybindingConfig struct {
Universal KeybindingUniversalConfig `yaml:"universal"`
Status KeybindingStatusConfig `yaml:"status"`
Files KeybindingFilesConfig `yaml:"files"`
Branches KeybindingBranchesConfig `yaml:"branches"`
Worktrees KeybindingWorktreesConfig `yaml:"worktrees"`
Commits KeybindingCommitsConfig `yaml:"commits"`
Stash KeybindingStashConfig `yaml:"stash"`
CommitFiles KeybindingCommitFilesConfig `yaml:"commitFiles"`
Main KeybindingMainConfig `yaml:"main"`
Submodules KeybindingSubmodulesConfig `yaml:"submodules"`
Universal KeybindingUniversalConfig `yaml:"universal"`
Status KeybindingStatusConfig `yaml:"status"`
Files KeybindingFilesConfig `yaml:"files"`
Branches KeybindingBranchesConfig `yaml:"branches"`
Worktrees KeybindingWorktreesConfig `yaml:"worktrees"`
Commits KeybindingCommitsConfig `yaml:"commits"`
Stash KeybindingStashConfig `yaml:"stash"`
CommitFiles KeybindingCommitFilesConfig `yaml:"commitFiles"`
Main KeybindingMainConfig `yaml:"main"`
Submodules KeybindingSubmodulesConfig `yaml:"submodules"`
CommitMessage KeybindingCommitMessageConfig `yaml:"commitMessage"`
}
// damn looks like we have some inconsistencies here with -alt and -alt1
@ -305,6 +306,10 @@ type KeybindingSubmodulesConfig struct {
BulkMenu string `yaml:"bulkMenu"`
}
type KeybindingCommitMessageConfig struct {
SwitchToEditor string `yaml:"switchToEditor"`
}
// OSConfig contains config on the level of the os
type OSConfig struct {
// Command for editing a file. Should contain "{{filename}}".
@ -652,6 +657,9 @@ func GetDefaultConfig() *UserConfig {
Update: "u",
BulkMenu: "b",
},
CommitMessage: KeybindingCommitMessageConfig{
SwitchToEditor: "<c-o>",
},
},
OS: OSConfig{},
DisableStartupPopups: false,

View File

@ -32,6 +32,8 @@ type CommitMessageViewModel struct {
preservedMessage string
// invoked when pressing enter in the commit message panel
onConfirm func(string, string) error
// invoked when pressing the switch-to-editor key binding
onSwitchToEditor func(string) error
// The message typed in before cycling through history
// We store this separately to 'preservedMessage' because 'preservedMessage'
@ -98,10 +100,12 @@ func (self *CommitMessageContext) SetPanelState(
descriptionTitle string,
preserveMessage bool,
onConfirm func(string, string) error,
onSwitchToEditor func(string) error,
) {
self.viewModel.selectedindex = index
self.viewModel.preserveMessage = preserveMessage
self.viewModel.onConfirm = onConfirm
self.viewModel.onSwitchToEditor = onSwitchToEditor
self.GetView().Title = summaryTitle
self.c.Views().CommitDescription.Title = descriptionTitle
}
@ -117,3 +121,11 @@ func (self *CommitMessageContext) RenderCommitLength() {
func getBufferLength(view *gocui.View) string {
return " " + strconv.Itoa(strings.Count(view.TextArea.GetContent(), "")-1) + " "
}
func (self *CommitMessageContext) SwitchToEditor(message string) error {
return self.viewModel.onSwitchToEditor(message)
}
func (self *CommitMessageContext) CanSwitchToEditor() bool {
return self.viewModel.onSwitchToEditor != nil
}

View File

@ -1,6 +1,7 @@
package controllers
import (
"github.com/jesseduffield/lazygit/pkg/gui/context"
"github.com/jesseduffield/lazygit/pkg/gui/types"
)
@ -34,6 +35,10 @@ func (self *CommitDescriptionController) GetKeybindings(opts types.KeybindingsOp
Key: opts.GetKey(opts.Config.Universal.ConfirmInEditor),
Handler: self.confirm,
},
{
Key: opts.GetKey(opts.Config.CommitMessage.SwitchToEditor),
Handler: self.switchToEditor,
},
}
return bindings
@ -43,7 +48,7 @@ func (self *CommitDescriptionController) Context() types.Context {
return self.context()
}
func (self *CommitDescriptionController) context() types.Context {
func (self *CommitDescriptionController) context() *context.CommitMessageContext {
return self.c.Contexts().CommitMessage
}
@ -58,3 +63,7 @@ func (self *CommitDescriptionController) close() error {
func (self *CommitDescriptionController) confirm() error {
return self.c.Helpers().Commits.HandleCommitConfirm()
}
func (self *CommitDescriptionController) switchToEditor() error {
return self.c.Helpers().Commits.SwitchToEditor()
}

View File

@ -46,6 +46,10 @@ func (self *CommitMessageController) GetKeybindings(opts types.KeybindingsOpts)
Key: opts.GetKey(opts.Config.Universal.TogglePanel),
Handler: self.switchToCommitDescription,
},
{
Key: opts.GetKey(opts.Config.CommitMessage.SwitchToEditor),
Handler: self.switchToEditor,
},
}
return bindings
@ -84,6 +88,10 @@ func (self *CommitMessageController) switchToCommitDescription() error {
return nil
}
func (self *CommitMessageController) switchToEditor() error {
return self.c.Helpers().Commits.SwitchToEditor()
}
func (self *CommitMessageController) handleCommitIndexChange(value int) error {
currentIndex := self.context().GetSelectedIndex()
newIndex := currentIndex + value

View File

@ -1,9 +1,12 @@
package helpers
import (
"path/filepath"
"strings"
"time"
"github.com/jesseduffield/lazygit/pkg/gui/types"
"github.com/samber/lo"
)
type ICommitsHelper interface {
@ -62,6 +65,28 @@ func (self *CommitsHelper) JoinCommitMessageAndDescription() string {
return self.getCommitSummary() + "\n" + self.getCommitDescription()
}
func (self *CommitsHelper) SwitchToEditor() error {
if !self.c.Contexts().CommitMessage.CanSwitchToEditor() {
return nil
}
message := lo.Ternary(len(self.getCommitDescription()) == 0,
self.getCommitSummary(),
self.getCommitSummary()+"\n\n"+self.getCommitDescription())
filepath := filepath.Join(self.c.OS().GetTempDir(), self.c.Git().RepoPaths.RepoName(), time.Now().Format("Jan _2 15.04.05.000000000")+".msg")
err := self.c.OS().CreateFileWithContent(filepath, message)
if err != nil {
return err
}
err = self.CloseCommitMessagePanel()
if err != nil {
return err
}
return self.c.Contexts().CommitMessage.SwitchToEditor(filepath)
}
func (self *CommitsHelper) UpdateCommitPanelView(message string) {
if message != "" {
self.SetMessageAndDescriptionInView(message)
@ -83,6 +108,7 @@ type OpenCommitMessagePanelOpts struct {
DescriptionTitle string
PreserveMessage bool
OnConfirm func(summary string, description string) error
OnSwitchToEditor func(string) error
InitialMessage string
}
@ -101,6 +127,7 @@ func (self *CommitsHelper) OpenCommitMessagePanel(opts *OpenCommitMessagePanelOp
opts.DescriptionTitle,
opts.PreserveMessage,
onConfirm,
opts.OnSwitchToEditor,
)
self.UpdateCommitPanelView(opts.InitialMessage)

View File

@ -104,6 +104,7 @@ func (self *WorkingTreeHelper) HandleCommitPressWithMessage(initialMessage strin
DescriptionTitle: self.c.Tr.CommitDescriptionTitle,
PreserveMessage: true,
OnConfirm: self.handleCommit,
OnSwitchToEditor: self.switchFromCommitMessagePanelToEditor,
},
)
}
@ -117,6 +118,21 @@ func (self *WorkingTreeHelper) handleCommit(summary string, description string)
})
}
func (self *WorkingTreeHelper) switchFromCommitMessagePanelToEditor(filepath string) error {
// We won't be able to tell whether the commit was successful, because
// RunSubprocessAndRefresh doesn't return the error (it opens an error alert
// itself and returns nil on error). But even if we could, we wouldn't have
// access to the last message that the user typed, and it might be very
// different from what was last in the commit panel. So the best we can do
// here is to always clear the remembered commit message.
self.commitsHelper.OnCommitSuccess()
self.c.LogAction(self.c.Tr.Actions.Commit)
return self.c.RunSubprocessAndRefresh(
self.c.Git().Commit.CommitInEditorWithMessageFileCmdObj(filepath),
)
}
// HandleCommitEditorPress - handle when the user wants to commit changes via
// their editor rather than via the popup panel
func (self *WorkingTreeHelper) HandleCommitEditorPress() error {

View File

@ -279,10 +279,37 @@ func (self *LocalCommitsController) reword(commit *models.Commit) error {
DescriptionTitle: self.c.Tr.CommitDescriptionTitle,
PreserveMessage: false,
OnConfirm: self.handleReword,
OnSwitchToEditor: self.switchFromCommitMessagePanelToEditor,
},
)
}
func (self *LocalCommitsController) switchFromCommitMessagePanelToEditor(filepath string) error {
if self.isHeadCommit() {
return self.c.RunSubprocessAndRefresh(
self.c.Git().Commit.RewordLastCommitInEditorWithMessageFileCmdObj(filepath))
}
err := self.c.Git().Rebase.BeginInteractiveRebaseForCommit(self.c.Model().Commits, self.context().GetSelectedLineIdx(), false)
if err != nil {
return err
}
// now the selected commit should be our head so we'll amend it with the new message
err = self.c.RunSubprocessAndRefresh(
self.c.Git().Commit.RewordLastCommitInEditorWithMessageFileCmdObj(filepath))
if err != nil {
return err
}
err = self.c.Git().Rebase.ContinueRebase()
if err != nil {
return err
}
return self.c.Refresh(types.RefreshOptions{Mode: types.ASYNC})
}
func (self *LocalCommitsController) handleReword(summary string, description string) error {
err := self.c.Git().Rebase.RewordCommit(self.c.Model().Commits, self.c.Contexts().LocalCommits.GetSelectedLineIdx(), summary, description)
if err != nil {