diff --git a/pkg/gui/controllers/confirmation_controller.go b/pkg/gui/controllers/confirmation_controller.go index 97754655f..1e4e5cd46 100644 --- a/pkg/gui/controllers/confirmation_controller.go +++ b/pkg/gui/controllers/confirmation_controller.go @@ -47,6 +47,13 @@ func (self *ConfirmationController) GetKeybindings(opts types.KeybindingsOpts) [ return nil }, }, + { + Key: opts.GetKey(opts.Config.Universal.CopyToClipboard), + Handler: self.handleCopyToClipboard, + Description: self.c.Tr.CopyToClipboardMenu, + DisplayOnScreen: true, + GetDisabledReason: self.copyToClipboardEnabled, + }, } return bindings @@ -93,3 +100,23 @@ func (self *ConfirmationController) switchToSuggestions() { self.c.Views().Suggestions.Subtitle = subtitle self.c.Context().Replace(self.c.Contexts().Suggestions) } + +func (self *ConfirmationController) handleCopyToClipboard() error { + confirmationView := self.c.Views().Confirmation + text := confirmationView.Buffer() + if err := self.c.OS().CopyToClipboard(text); err != nil { + return err + } + + self.c.Toast(self.c.Tr.MessageCopiedToClipboard) + return nil +} + +func (self *ConfirmationController) copyToClipboardEnabled() *types.DisabledReason { + if self.c.Views().Confirmation.Editable { + // The empty text is intentional. We don't want to get a toast when invoking this, we only + // want to prevent it from showing up in the options bar. + return &types.DisabledReason{Text: ""} + } + return nil +} diff --git a/pkg/i18n/english.go b/pkg/i18n/english.go index 24e428142..ee3c11dea 100644 --- a/pkg/i18n/english.go +++ b/pkg/i18n/english.go @@ -723,6 +723,7 @@ type TranslationSet struct { CommitHasNoTags string CommitHasNoMessageBody string PatchCopiedToClipboard string + MessageCopiedToClipboard string CopiedToClipboard string ErrCannotEditDirectory string ErrCannotCopyContentOfDirectory string @@ -1800,6 +1801,7 @@ func EnglishTranslationSet() *TranslationSet { CommitHasNoTags: "Commit has no tags", CommitHasNoMessageBody: "Commit has no message body", PatchCopiedToClipboard: "Patch copied to clipboard", + MessageCopiedToClipboard: "Message copied to clipboard", CopiedToClipboard: "copied to clipboard", ErrCannotEditDirectory: "Cannot edit directories: you can only edit individual files", ErrCannotCopyContentOfDirectory: "Cannot copy content of directories: you can only copy content of individual files", diff --git a/pkg/integration/components/popup.go b/pkg/integration/components/popup.go index 46df83e23..aa80770b2 100644 --- a/pkg/integration/components/popup.go +++ b/pkg/integration/components/popup.go @@ -36,6 +36,11 @@ func (self *Popup) Alert() *AlertDriver { return &AlertDriver{t: self.t} } +func (self *AlertDriver) Tap(f func()) *AlertDriver { + self.getViewDriver().Tap(f) + return self +} + func (self *Popup) inAlert() { // basically the same thing as a confirmation popup with the current implementation self.t.assertWithRetries(func() (bool, string) { diff --git a/pkg/integration/tests/misc/copy_confirmation_message_to_clipboard.go b/pkg/integration/tests/misc/copy_confirmation_message_to_clipboard.go new file mode 100644 index 000000000..6d98f856a --- /dev/null +++ b/pkg/integration/tests/misc/copy_confirmation_message_to_clipboard.go @@ -0,0 +1,40 @@ +package misc + +import ( + "github.com/jesseduffield/lazygit/pkg/config" + . "github.com/jesseduffield/lazygit/pkg/integration/components" +) + +var CopyConfirmationMessageToClipboard = NewIntegrationTest(NewIntegrationTestArgs{ + Description: "Copy the text of a confirmation popup 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.EmptyCommit("commit") + }, + + Run: func(t *TestDriver, keys config.KeybindingConfig) { + t.Views().Commits(). + Focus(). + Lines( + Contains("commit").IsSelected(), + ). + Press(keys.Universal.Remove) + + t.ExpectPopup().Alert(). + Title(Equals("Drop commit")). + Content(Equals("Are you sure you want to drop the selected commit(s)?")). + Tap(func() { + t.GlobalPress(keys.Universal.CopyToClipboard) + t.ExpectToast(Equals("Message copied to clipboard")) + }). + Confirm() + + t.FileSystem().FileContent("clipboard", + Equals("Are you sure you want to drop the selected commit(s)?")) + }, +}) diff --git a/pkg/integration/tests/test_list.go b/pkg/integration/tests/test_list.go index 000b21339..3fc314d10 100644 --- a/pkg/integration/tests/test_list.go +++ b/pkg/integration/tests/test_list.go @@ -299,6 +299,7 @@ var tests = []*components.IntegrationTest{ interactive_rebase.SwapWithConflict, interactive_rebase.ViewFilesOfTodoEntries, misc.ConfirmOnQuit, + misc.CopyConfirmationMessageToClipboard, misc.CopyToClipboard, misc.DisabledKeybindings, misc.InitialOpen,