diff --git a/pkg/gui/controllers/custom_patch_options_menu_action.go b/pkg/gui/controllers/custom_patch_options_menu_action.go index 7930484291e..e6e79cc2b7b 100644 --- a/pkg/gui/controllers/custom_patch_options_menu_action.go +++ b/pkg/gui/controllers/custom_patch_options_menu_action.go @@ -3,6 +3,8 @@ package controllers import ( "errors" "fmt" + "path/filepath" + "strings" "github.com/jesseduffield/generics/set" "github.com/jesseduffield/gocui" @@ -104,6 +106,12 @@ func (self *CustomPatchOptionsMenuAction) Call() error { } menuItems = append(menuItems, []*types.MenuItem{ + { + Label: self.c.Tr.SavePatch, + Tooltip: self.c.Tr.SavePatchTooltip, + OnPress: self.handleSavePatchToFile, + Key: 's', + }, { Label: self.c.Tr.CopyPatchToClipboard, OnPress: func() error { return self.copyPatchToClipboard() }, @@ -290,6 +298,31 @@ func (self *CustomPatchOptionsMenuAction) handleApplyPatch(reverse bool) error { }) } +func (self *CustomPatchOptionsMenuAction) handleSavePatchToFile() error { + patch := self.c.Git().Patch.PatchBuilder.RenderAggregatedPatch(true) + + self.c.Prompt(types.PromptOpts{ + Title: self.c.Tr.SavePatchTitle, + HandleConfirm: func(path string) error { + path = strings.TrimSpace(path) + if !filepath.IsAbs(path) { + path = filepath.Join(self.c.Git().RepoPaths.WorktreePath(), path) + } + path = filepath.Clean(path) + + self.c.LogAction(self.c.Tr.Actions.SavePatchToFile) + if err := self.c.OS().CreateFileWithContent(path, patch); err != nil { + return err + } + + self.c.Toast(fmt.Sprintf(self.c.Tr.PatchSavedToFile, path)) + return nil + }, + }) + + return nil +} + func (self *CustomPatchOptionsMenuAction) copyPatchToClipboard() error { patch := self.c.Git().Patch.PatchBuilder.RenderAggregatedPatch(true) diff --git a/pkg/i18n/english.go b/pkg/i18n/english.go index 75391a2c1f2..af1e5c0115b 100644 --- a/pkg/i18n/english.go +++ b/pkg/i18n/english.go @@ -826,6 +826,10 @@ type TranslationSet struct { MovePatchIntoNewCommitBeforeTooltip string MovePatchToSelectedCommit string MovePatchToSelectedCommitTooltip string + SavePatch string + SavePatchTooltip string + SavePatchTitle string + PatchSavedToFile string CopyPatchToClipboard string MustStageFilesAffectedByPatchTitle string MustStageFilesAffectedByPatchWarning string @@ -987,6 +991,7 @@ type Actions struct { CopyCommitAttributeToClipboard string CopyCommitTagsToClipboard string CopyPatchToClipboard string + SavePatchToFile string CustomCommand string DiscardAllChangesInFile string DiscardAllUnstagedChangesInFile string @@ -1923,6 +1928,10 @@ func EnglishTranslationSet() *TranslationSet { MovePatchIntoNewCommitBeforeTooltip: "Move the patch out of its commit and into a new commit before the original commit. This works best when the custom patch contains only entire hunks or even entire files; if it contains partial hunks, you are likely to get conflicts.", MovePatchToSelectedCommit: "Move patch to selected commit (%s)", MovePatchToSelectedCommitTooltip: "Move the patch out of its original commit and into the selected commit. This is achieved by starting an interactive rebase at the original commit, applying the patch in reverse, then continuing the rebase up to the selected commit, before applying the patch forward and amending the selected commit. The rebase is then continued to completion. If commits between the source and destination commit depend on the patch, you may need to resolve conflicts.", + SavePatch: "Save patch to file", + SavePatchTooltip: "Write the current patch to a file. Relative paths are resolved from the repository root.", + SavePatchTitle: "Save patch to file", + PatchSavedToFile: "Patch saved to %s", CopyPatchToClipboard: "Copy patch to clipboard", MustStageFilesAffectedByPatchTitle: "Must stage files", MustStageFilesAffectedByPatchWarning: "Applying a patch to the index requires staging the unstaged files that are affected by the patch. Note that you might get conflicts when applying the patch. Continue?", @@ -2045,6 +2054,7 @@ func EnglishTranslationSet() *TranslationSet { CopyCommitAuthorToClipboard: "Copy commit author to clipboard", CopyCommitAttributeToClipboard: "Copy to clipboard", CopyPatchToClipboard: "Copy patch to clipboard", + SavePatchToFile: "Save patch to file", MoveCommitUp: "Move commit up", MoveCommitDown: "Move commit down", CustomCommand: "Custom command",