diff --git a/docs/Custom_Command_Keybindings.md b/docs/Custom_Command_Keybindings.md index 7a9f1bc0d..77fb90be5 100644 --- a/docs/Custom_Command_Keybindings.md +++ b/docs/Custom_Command_Keybindings.md @@ -46,7 +46,8 @@ customCommands: - type: 'menuFromCommand' title: 'Remote branch:' command: 'git branch -r --list {{index .PromptResponses 0}}/*' - filter: '.*{{index .PromptResponses 0}}/(.*)' + filter: '.*{{index .PromptResponses 0}}/(?P.*)' + format: '{{ .branch }}' ``` Looking at the command assigned to the 'n' key, here's what the result looks like: @@ -99,8 +100,11 @@ The permitted prompt fields are: | options | (only applicable to 'menu' prompts) the options to display in the menu | no | | command | (only applicable to 'menuFromCommand' prompts) the command to run to generate | yes | | | menu options | | -| filter | (only applicable to 'menuFromCommand' prompts) the regexp to run specify groups | yes | -| | which are going to be kept from the command's output | | +| filter | (only applicable to 'menuFromCommand' prompts) the regexp to run specifying | yes | +| | groups which are going to be kept from the command's output | | +| format | (only applicable to 'menuFromCommand' prompts) how to format matched groups from | yes | +| | the filter. You can use named groups, or `{{ .group_GROUPID_MATCHID }}`. | yes | +| | PS: named groups keep last non-empty match | yes | The permitted option fields are: | _field_ | _description_ | _required_ | diff --git a/pkg/config/user_config.go b/pkg/config/user_config.go index f98bde28e..d373b74f1 100644 --- a/pkg/config/user_config.go +++ b/pkg/config/user_config.go @@ -284,6 +284,7 @@ type CustomCommandPrompt struct { // this only applies to menuFromCommand Command string `yaml:"command"` Filter string `yaml:"filter"` + Format string `yaml:"format"` } type CustomCommandMenuOption struct { diff --git a/pkg/gui/custom_commands.go b/pkg/gui/custom_commands.go index 7a70eeb95..fbe92a72f 100644 --- a/pkg/gui/custom_commands.go +++ b/pkg/gui/custom_commands.go @@ -1,10 +1,13 @@ package gui import ( + "bytes" + "errors" "log" "regexp" "strconv" "strings" + "text/template" "github.com/fatih/color" "github.com/jesseduffield/gocui" @@ -168,6 +171,10 @@ func (gui *Gui) handleCustomCommandKeybinding(customCommand config.CustomCommand if err != nil { return gui.surfaceError(err) } + reg, err := regexp.Compile(filter) + if err != nil { + return gui.surfaceError(errors.New("unable to parse filter regex, error: " + err.Error())) + } // Run and save output message, err := gui.GitCommand.RunCommandWithOutput(cmdStr) @@ -177,17 +184,31 @@ func (gui *Gui) handleCustomCommandKeybinding(customCommand config.CustomCommand // Need to make a menu out of what the cmd has displayed candidates := []string{} - reg := regexp.MustCompile(filter) + temp := template.Must(template.New("format").Parse(prompt.Format)) for _, str := range strings.Split(string(message), "\n") { - cand := "" if str == "" { continue } - for i := 1; i < (reg.NumSubexp() + 1); i++ { - keep := reg.ReplaceAllString(str, "${"+strconv.Itoa(i)+"}") - cand += keep + buff := bytes.NewBuffer(nil) + groupNames := reg.SubexpNames() + tmplData := map[string]string{} + for matchNum, match := range reg.FindAllStringSubmatch(str, -1) { + if len(match) > 0 { + for groupIdx, group := range match { + // Record matched group with group and match ids + matchName := "group_" + strconv.Itoa(groupIdx) + "_" + strconv.Itoa(matchNum) + tmplData[matchName] = group + // Record last named group non-empty matches as group matches + name := groupNames[groupIdx] + _, ok := tmplData[name] + if name != "" && group != "" && !ok { + tmplData[name] = group + } + } + } } - candidates = append(candidates, cand) + temp.Execute(buff, tmplData) + candidates = append(candidates, strings.TrimSpace(buff.String())) } menuItems := make([]*menuItem, len(candidates))