diff --git a/pkg/gui/controllers/helpers/commits_helper.go b/pkg/gui/controllers/helpers/commits_helper.go index 6a9b0861f..601fc45a9 100644 --- a/pkg/gui/controllers/helpers/commits_helper.go +++ b/pkg/gui/controllers/helpers/commits_helper.go @@ -5,6 +5,7 @@ import ( "path/filepath" "strings" "time" + "unicode" "github.com/jesseduffield/lazygit/pkg/commands/git_commands" "github.com/jesseduffield/lazygit/pkg/gocui" @@ -248,6 +249,13 @@ func (self *CommitsHelper) OpenCommitMenu(suggestionFunc func(string) []*types.S }, Keys: menuKey('c'), }, + { + Label: self.c.Tr.CopyCommitMessageToClipboard, + OnPress: func() error { + return self.copyCommitMessageToClipboard() + }, + Keys: menuKey('C'), + }, { Label: self.c.Tr.PasteCommitMessageFromClipboard, OnPress: func() error { @@ -277,6 +285,30 @@ func (self *CommitsHelper) addCoAuthor(suggestionFunc func(string) []*types.Sugg return nil } +func (self *CommitsHelper) copyCommitMessageToClipboard() error { + // The panel keeps the space at the end of each line that it wraps. Git + // strips trailing whitespace when it commits, so do the same here; this + // makes the copied message look like the committed one. + message := stripTrailingWhitespace( + self.joinCommitMessageAndDescription(self.getCommitSummary(), self.getCommitDescription())) + + self.c.LogAction(self.c.Tr.Actions.CopyCommitMessageToClipboard) + if err := self.c.OS().CopyToClipboard(message); err != nil { + return err + } + + self.c.Toast(self.c.Tr.CommitMessageCopiedToClipboard) + return nil +} + +func stripTrailingWhitespace(message string) string { + lines := strings.Split(message, "\n") + for i, line := range lines { + lines[i] = strings.TrimRightFunc(line, unicode.IsSpace) + } + return strings.Join(lines, "\n") +} + func (self *CommitsHelper) pasteCommitMessageFromClipboard() error { message, err := self.c.OS().PasteFromClipboard() if err != nil { diff --git a/pkg/i18n/english.go b/pkg/i18n/english.go index 3d4689d8a..d923c6e3b 100644 --- a/pkg/i18n/english.go +++ b/pkg/i18n/english.go @@ -765,6 +765,7 @@ type TranslationSet struct { CopyCommitHashToClipboard string CommitHash string CommitURL string + CopyCommitMessageToClipboard string PasteCommitMessageFromClipboard string SurePasteCommitMessage string CommitMessage string @@ -2002,6 +2003,7 @@ func EnglishTranslationSet() *TranslationSet { CopyCommitHashToClipboard: "Copy abbreviated commit hash to clipboard", CommitHash: "Commit hash", CommitURL: "Commit URL", + CopyCommitMessageToClipboard: "Copy commit message to clipboard", PasteCommitMessageFromClipboard: "Paste commit message from clipboard", SurePasteCommitMessage: "Pasting will overwrite the current commit message, continue?", CommitMessage: "Commit message (subject and body)", diff --git a/pkg/integration/tests/commit/copy_commit_message_from_panel.go b/pkg/integration/tests/commit/copy_commit_message_from_panel.go new file mode 100644 index 000000000..12da37d46 --- /dev/null +++ b/pkg/integration/tests/commit/copy_commit_message_from_panel.go @@ -0,0 +1,44 @@ +package commit + +import ( + "github.com/jesseduffield/lazygit/pkg/config" + . "github.com/jesseduffield/lazygit/pkg/integration/components" +) + +var CopyCommitMessageFromPanel = NewIntegrationTest(NewIntegrationTestArgs{ + Description: "Copy the commit message from the commit message panel to the clipboard", + ExtraCmdArgs: []string{}, + Skip: false, + SetupConfig: func(config *config.AppConfig) { + config.GetUserConfig().OS.CopyToClipboardCmd = "printf '%s' {{text}} > ../clipboard" + }, + SetupRepo: func(shell *Shell) { + shell.CreateFileAndAdd("file", "file content") + }, + Run: func(t *TestDriver, keys config.KeybindingConfig) { + t.Views().Files(). + Focus(). + Press(keys.Files.CommitChanges) + + t.ExpectPopup().CommitMessagePanel(). + Type("subject"). + SwitchToDescription(). + Type("This line is longer than the auto-wrap width, so the clipboard gets it with a line break"). + AddNewline(). + Type("second line"). + SwitchToSummary(). + OpenCommitMenu() + + t.ExpectPopup().Menu().Title(Equals("Commit Menu")). + Select(Contains("Copy commit message to clipboard")). + Confirm() + + t.ExpectToast(Equals("Commit message copied to clipboard")) + + t.FileSystem().FileContent("../clipboard", Equals( + "subject\n\nThis line is longer than the auto-wrap width, so the clipboard gets it\nwith a line break\nsecond line")) + + t.ExpectPopup().CommitMessagePanel(). + Content(Equals("subject")) + }, +}) diff --git a/pkg/integration/tests/test_list.go b/pkg/integration/tests/test_list.go index 6d66a1080..6c8e83b6a 100644 --- a/pkg/integration/tests/test_list.go +++ b/pkg/integration/tests/test_list.go @@ -156,6 +156,7 @@ var tests = []*components.IntegrationTest{ commit.CommitWithNonMatchingBranchName, commit.CommitWithPrefix, commit.CopyAuthorToClipboard, + commit.CopyCommitMessageFromPanel, commit.CopyMessageBodyToClipboard, commit.CopyTagToClipboard, commit.CreateAmendCommit,