diff --git a/pkg/gui/custom_commands.go b/pkg/gui/custom_commands.go index 7181ec2e2..8af82e123 100644 --- a/pkg/gui/custom_commands.go +++ b/pkg/gui/custom_commands.go @@ -21,57 +21,104 @@ type CustomCommandObjects struct { SelectedStashEntry *commands.StashEntry SelectedCommitFile *commands.CommitFile CheckedOutBranch *commands.Branch + PromptResponses []string +} + +func (gui *Gui) resolveTemplate(templateStr string, promptResponses []string) (string, error) { + objects := CustomCommandObjects{ + SelectedFile: gui.getSelectedFile(), + SelectedLocalCommit: gui.getSelectedLocalCommit(), + SelectedReflogCommit: gui.getSelectedReflogCommit(), + SelectedLocalBranch: gui.getSelectedBranch(), + SelectedRemoteBranch: gui.getSelectedRemoteBranch(), + SelectedRemote: gui.getSelectedRemote(), + SelectedTag: gui.getSelectedTag(), + SelectedStashEntry: gui.getSelectedStashEntry(), + SelectedCommitFile: gui.getSelectedCommitFile(), + SelectedSubCommit: gui.getSelectedSubCommit(), + CheckedOutBranch: gui.currentBranch(), + PromptResponses: promptResponses, + } + + tmpl, err := template.New("template").Parse(templateStr) + if err != nil { + return "", err + } + + var buf bytes.Buffer + if err := tmpl.Execute(&buf, objects); err != nil { + return "", err + } + + cmdStr := buf.String() + + return cmdStr, nil } func (gui *Gui) handleCustomCommandKeybinding(customCommand CustomCommand) func() error { return func() error { - objects := CustomCommandObjects{ - SelectedFile: gui.getSelectedFile(), - SelectedLocalCommit: gui.getSelectedLocalCommit(), - SelectedReflogCommit: gui.getSelectedReflogCommit(), - SelectedLocalBranch: gui.getSelectedBranch(), - SelectedRemoteBranch: gui.getSelectedRemoteBranch(), - SelectedRemote: gui.getSelectedRemote(), - SelectedTag: gui.getSelectedTag(), - SelectedStashEntry: gui.getSelectedStashEntry(), - SelectedCommitFile: gui.getSelectedCommitFile(), - SelectedSubCommit: gui.getSelectedSubCommit(), - CheckedOutBranch: gui.currentBranch(), - } + promptResponses := make([]string, len(customCommand.Prompts)) - tmpl, err := template.New("custom command template").Parse(customCommand.Command) - if err != nil { - return gui.surfaceError(err) - } - - var buf bytes.Buffer - if err := tmpl.Execute(&buf, objects); err != nil { - return gui.surfaceError(err) - } - - cmdStr := buf.String() - - if customCommand.Subprocess { - gui.PrepareSubProcess(cmdStr) - return nil - } - - return gui.WithWaitingStatus(gui.Tr.SLocalize("runningCustomCommandStatus"), func() error { - gui.OSCommand.PrepareSubProcess(cmdStr) - - if err := gui.OSCommand.RunCommand(cmdStr); err != nil { + f := func() error { + cmdStr, err := gui.resolveTemplate(customCommand.Command, promptResponses) + if err != nil { return gui.surfaceError(err) } - return gui.refreshSidePanels(refreshOptions{}) - }) + + if customCommand.Subprocess { + gui.PrepareSubProcess(cmdStr) + return nil + } + + return gui.WithWaitingStatus(gui.Tr.SLocalize("runningCustomCommandStatus"), func() error { + gui.OSCommand.PrepareSubProcess(cmdStr) + + if err := gui.OSCommand.RunCommand(cmdStr); err != nil { + return gui.surfaceError(err) + } + return gui.refreshSidePanels(refreshOptions{}) + }) + } + + // if we have prompts we'll recursively wrap our confirm handlers with more prompts + // until we reach the actual command + for reverseIdx := range customCommand.Prompts { + idx := len(customCommand.Prompts) - 1 - reverseIdx + + // going backwards so the outermost prompt is the first one + prompt := customCommand.Prompts[idx] + + gui.Log.Warn(prompt.Title) + + wrappedF := f // need to do this because f's value will change with each iteration + f = func() error { + return gui.prompt( + prompt.Title, + prompt.InitialValue, + func(str string) error { + promptResponses[idx] = str + + return wrappedF() + }, + ) + } + } + + return f() } } +type CustomCommandPrompt struct { + Title string `yaml:"title"` + InitialValue string `yaml:"initialValue"` +} + type CustomCommand struct { - Key string `yaml:"key"` - Context string `yaml:"context"` - Command string `yaml:"command"` - Subprocess bool `yaml:"subprocess"` + Key string `yaml:"key"` + Context string `yaml:"context"` + Command string `yaml:"command"` + Subprocess bool `yaml:"subprocess"` + Prompts []CustomCommandPrompt `yaml:"prompts"` } func (gui *Gui) GetCustomCommandKeybindings() []*Binding {