Skip to content

Commit

Permalink
Switch to editor from commit message panel (#2881)
Browse files Browse the repository at this point in the history
  • Loading branch information
stefanhaller authored Aug 21, 2023
2 parents 16711c6 + 91ec42f commit c31fcb7
Show file tree
Hide file tree
Showing 13 changed files with 203 additions and 20 deletions.
13 changes: 13 additions & 0 deletions pkg/commands/git_commands/commit.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
28 changes: 18 additions & 10 deletions pkg/config/user_config.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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}}".
Expand Down Expand Up @@ -652,6 +657,9 @@ func GetDefaultConfig() *UserConfig {
Update: "u",
BulkMenu: "b",
},
CommitMessage: KeybindingCommitMessageConfig{
SwitchToEditor: "<c-o>",
},
},
OS: OSConfig{},
DisableStartupPopups: false,
Expand Down
22 changes: 22 additions & 0 deletions pkg/gui/context/commit_message_context.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,10 @@ import (
"strings"

"github.com/jesseduffield/gocui"
"github.com/jesseduffield/lazygit/pkg/gui/keybindings"
"github.com/jesseduffield/lazygit/pkg/gui/types"
"github.com/jesseduffield/lazygit/pkg/utils"
"github.com/samber/lo"
)

type CommitMessageContext struct {
Expand All @@ -32,6 +35,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'
Expand Down Expand Up @@ -98,12 +103,21 @@ 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

subtitleTemplate := lo.Ternary(onSwitchToEditor != nil, self.c.Tr.CommitDescriptionSubTitle, self.c.Tr.CommitDescriptionSubTitleNoSwitch)
self.c.Views().CommitDescription.Subtitle = utils.ResolvePlaceholderString(subtitleTemplate,
map[string]string{
"togglePanelKeyBinding": keybindings.Label(self.c.UserConfig.Keybinding.Universal.TogglePanel),
"switchToEditorKeyBinding": keybindings.Label(self.c.UserConfig.Keybinding.CommitMessage.SwitchToEditor),
})
}

func (self *CommitMessageContext) RenderCommitLength() {
Expand All @@ -117,3 +131,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
}
11 changes: 10 additions & 1 deletion pkg/gui/controllers/commit_description_controller.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package controllers

import (
"github.com/jesseduffield/lazygit/pkg/gui/context"
"github.com/jesseduffield/lazygit/pkg/gui/types"
)

Expand Down Expand Up @@ -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
Expand All @@ -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
}

Expand All @@ -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()
}
10 changes: 8 additions & 2 deletions pkg/gui/controllers/commit_message_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,6 @@ func NewCommitMessageController(
}
}

// TODO: merge that commit panel PR because we're not currently showing how to add a newline as it's
// handled by the editor func rather than by the controller here.
func (self *CommitMessageController) GetKeybindings(opts types.KeybindingsOpts) []*types.Binding {
bindings := []*types.Binding{
{
Expand All @@ -48,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
Expand Down Expand Up @@ -86,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
Expand Down
27 changes: 27 additions & 0 deletions pkg/gui/controllers/helpers/commits_helper.go
Original file line number Diff line number Diff line change
@@ -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 {
Expand Down Expand Up @@ -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)
Expand All @@ -83,6 +108,7 @@ type OpenCommitMessagePanelOpts struct {
DescriptionTitle string
PreserveMessage bool
OnConfirm func(summary string, description string) error
OnSwitchToEditor func(string) error
InitialMessage string
}

Expand All @@ -101,6 +127,7 @@ func (self *CommitsHelper) OpenCommitMessagePanel(opts *OpenCommitMessagePanelOp
opts.DescriptionTitle,
opts.PreserveMessage,
onConfirm,
opts.OnSwitchToEditor,
)

self.UpdateCommitPanelView(opts.InitialMessage)
Expand Down
16 changes: 16 additions & 0 deletions pkg/gui/controllers/helpers/working_tree_helper.go
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,7 @@ func (self *WorkingTreeHelper) HandleCommitPressWithMessage(initialMessage strin
DescriptionTitle: self.c.Tr.CommitDescriptionTitle,
PreserveMessage: true,
OnConfirm: self.handleCommit,
OnSwitchToEditor: self.switchFromCommitMessagePanelToEditor,
},
)
}
Expand All @@ -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 {
Expand Down
27 changes: 27 additions & 0 deletions pkg/gui/controllers/local_commits_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
6 changes: 0 additions & 6 deletions pkg/gui/views.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,7 @@ package gui

import (
"github.com/jesseduffield/gocui"
"github.com/jesseduffield/lazygit/pkg/gui/keybindings"
"github.com/jesseduffield/lazygit/pkg/theme"
"github.com/jesseduffield/lazygit/pkg/utils"
"github.com/samber/lo"
)

Expand Down Expand Up @@ -164,10 +162,6 @@ func (gui *Gui) createAllViews() error {

gui.Views.CommitDescription.Visible = false
gui.Views.CommitDescription.Title = gui.c.Tr.CommitDescriptionTitle
gui.Views.CommitDescription.Subtitle = utils.ResolvePlaceholderString(gui.Tr.CommitDescriptionSubTitle,
map[string]string{
"togglePanelKeyBinding": keybindings.Label(gui.UserConfig.Keybinding.Universal.TogglePanel),
})
gui.Views.CommitDescription.FgColor = theme.GocuiDefaultTextColor
gui.Views.CommitDescription.Editable = true
gui.Views.CommitDescription.Editor = gocui.EditorFunc(gui.commitDescriptionEditor)
Expand Down
4 changes: 3 additions & 1 deletion pkg/i18n/english.go
Original file line number Diff line number Diff line change
Expand Up @@ -199,6 +199,7 @@ type TranslationSet struct {
CommitSummaryTitle string
CommitDescriptionTitle string
CommitDescriptionSubTitle string
CommitDescriptionSubTitleNoSwitch string
LocalBranchesTitle string
SearchTitle string
TagsTitle string
Expand Down Expand Up @@ -969,7 +970,8 @@ func EnglishTranslationSet() TranslationSet {
RebaseOptionsTitle: "Rebase options",
CommitSummaryTitle: "Commit summary",
CommitDescriptionTitle: "Commit description",
CommitDescriptionSubTitle: "Press {{.togglePanelKeyBinding}} to toggle focus",
CommitDescriptionSubTitle: "Press {{.togglePanelKeyBinding}} to toggle focus, {{.switchToEditorKeyBinding}} to switch to editor",
CommitDescriptionSubTitleNoSwitch: "Press {{.togglePanelKeyBinding}} to toggle focus",
LocalBranchesTitle: "Local branches",
SearchTitle: "Search",
TagsTitle: "Tags",
Expand Down
4 changes: 4 additions & 0 deletions pkg/integration/components/commit_message_panel_driver.go
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,10 @@ func (self *CommitMessagePanelDriver) Cancel() {
self.getViewDriver().PressEscape()
}

func (self *CommitMessagePanelDriver) SwitchToEditor() {
self.getViewDriver().Press(self.t.keys.CommitMessage.SwitchToEditor)
}

func (self *CommitMessagePanelDriver) SelectPreviousMessage() *CommitMessagePanelDriver {
self.getViewDriver().SelectPreviousItem()
return self
Expand Down
Loading

0 comments on commit c31fcb7

Please sign in to comment.