mirror of
https://github.com/jesseduffield/lazygit.git
synced 2025-06-21 00:30:00 +02:00
Refactor code around handleCustomCommandKeybinding
This commit is contained in:
@ -54,6 +54,149 @@ func (gui *Gui) resolveTemplate(templateStr string, promptResponses []string) (s
|
|||||||
return utils.ResolveTemplate(templateStr, objects)
|
return utils.ResolveTemplate(templateStr, objects)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (gui *Gui) inputPrompt(prompt config.CustomCommandPrompt, promptResponses []string, responseIdx int, wrappedF func() error) error {
|
||||||
|
title, err := gui.resolveTemplate(prompt.Title, promptResponses)
|
||||||
|
if err != nil {
|
||||||
|
return gui.surfaceError(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
initialValue, err := gui.resolveTemplate(prompt.InitialValue, promptResponses)
|
||||||
|
if err != nil {
|
||||||
|
return gui.surfaceError(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return gui.prompt(promptOpts{
|
||||||
|
title: title,
|
||||||
|
initialContent: initialValue,
|
||||||
|
handleConfirm: func(str string) error {
|
||||||
|
promptResponses[responseIdx] = str
|
||||||
|
return wrappedF()
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (gui *Gui) menuPrompt(prompt config.CustomCommandPrompt, promptResponses []string, responseIdx int, wrappedF func() error) error {
|
||||||
|
// need to make a menu here some how
|
||||||
|
menuItems := make([]*menuItem, len(prompt.Options))
|
||||||
|
for i, option := range prompt.Options {
|
||||||
|
option := option
|
||||||
|
|
||||||
|
nameTemplate := option.Name
|
||||||
|
if nameTemplate == "" {
|
||||||
|
// this allows you to only pass values rather than bother with names/descriptions
|
||||||
|
nameTemplate = option.Value
|
||||||
|
}
|
||||||
|
name, err := gui.resolveTemplate(nameTemplate, promptResponses)
|
||||||
|
if err != nil {
|
||||||
|
return gui.surfaceError(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
description, err := gui.resolveTemplate(option.Description, promptResponses)
|
||||||
|
if err != nil {
|
||||||
|
return gui.surfaceError(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
value, err := gui.resolveTemplate(option.Value, promptResponses)
|
||||||
|
if err != nil {
|
||||||
|
return gui.surfaceError(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
menuItems[i] = &menuItem{
|
||||||
|
displayStrings: []string{name, utils.ColoredString(description, color.FgYellow)},
|
||||||
|
onPress: func() error {
|
||||||
|
promptResponses[responseIdx] = value
|
||||||
|
return wrappedF()
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
title, err := gui.resolveTemplate(prompt.Title, promptResponses)
|
||||||
|
if err != nil {
|
||||||
|
return gui.surfaceError(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return gui.createMenu(title, menuItems, createMenuOptions{showCancel: true})
|
||||||
|
}
|
||||||
|
func (gui *Gui) generateMenuCandidates(commandOutput string, filter string, format string) ([]string, error) {
|
||||||
|
candidates := []string{}
|
||||||
|
reg, err := regexp.Compile(filter)
|
||||||
|
if err != nil {
|
||||||
|
return candidates, gui.surfaceError(errors.New("unable to parse filter regex, error: " + err.Error()))
|
||||||
|
}
|
||||||
|
buff := bytes.NewBuffer(nil)
|
||||||
|
temp, err := template.New("format").Parse(format)
|
||||||
|
if err != nil {
|
||||||
|
return candidates, gui.surfaceError(errors.New("unable to parse format, error: " + err.Error()))
|
||||||
|
}
|
||||||
|
for _, str := range strings.Split(string(commandOutput), "\n") {
|
||||||
|
if str == "" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
tmplData := map[string]string{}
|
||||||
|
out := reg.FindAllStringSubmatch(str, -1)
|
||||||
|
if len(out) > 0 {
|
||||||
|
for groupIdx, group := range reg.SubexpNames() {
|
||||||
|
// Record matched group with group ids
|
||||||
|
matchName := "group_" + strconv.Itoa(groupIdx)
|
||||||
|
tmplData[matchName] = group
|
||||||
|
// Record last named group non-empty matches as group matches
|
||||||
|
if group != "" {
|
||||||
|
tmplData[group] = out[0][groupIdx]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
err = temp.Execute(buff, tmplData)
|
||||||
|
if err != nil {
|
||||||
|
return candidates, gui.surfaceError(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
candidates = append(candidates, strings.TrimSpace(buff.String()))
|
||||||
|
buff.Reset()
|
||||||
|
}
|
||||||
|
return candidates, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (gui *Gui) menuPromptFromCommand(prompt config.CustomCommandPrompt, promptResponses []string, responseIdx int, wrappedF func() error) error {
|
||||||
|
// Collect cmd to run from config
|
||||||
|
cmdStr, err := gui.resolveTemplate(prompt.Command, promptResponses)
|
||||||
|
if err != nil {
|
||||||
|
return gui.surfaceError(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Collect Filter regexp
|
||||||
|
filter, err := gui.resolveTemplate(prompt.Filter, promptResponses)
|
||||||
|
if err != nil {
|
||||||
|
return gui.surfaceError(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Run and save output
|
||||||
|
message, err := gui.GitCommand.RunCommandWithOutput(cmdStr)
|
||||||
|
if err != nil {
|
||||||
|
return gui.surfaceError(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Need to make a menu out of what the cmd has displayed
|
||||||
|
candidates, err := gui.generateMenuCandidates(message, filter, prompt.Format)
|
||||||
|
|
||||||
|
menuItems := make([]*menuItem, len(candidates))
|
||||||
|
for i := range candidates {
|
||||||
|
menuItems[i] = &menuItem{
|
||||||
|
displayStrings: []string{candidates[i]},
|
||||||
|
onPress: func() error {
|
||||||
|
promptResponses[responseIdx] = candidates[i]
|
||||||
|
return wrappedF()
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
title, err := gui.resolveTemplate(prompt.Title, promptResponses)
|
||||||
|
if err != nil {
|
||||||
|
return gui.surfaceError(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return gui.createMenu(title, menuItems, createMenuOptions{showCancel: true})
|
||||||
|
}
|
||||||
|
|
||||||
func (gui *Gui) handleCustomCommandKeybinding(customCommand config.CustomCommand) func() error {
|
func (gui *Gui) handleCustomCommandKeybinding(customCommand config.CustomCommand) func() error {
|
||||||
return func() error {
|
return func() error {
|
||||||
promptResponses := make([]string, len(customCommand.Prompts))
|
promptResponses := make([]string, len(customCommand.Prompts))
|
||||||
@ -94,144 +237,15 @@ func (gui *Gui) handleCustomCommandKeybinding(customCommand config.CustomCommand
|
|||||||
switch prompt.Type {
|
switch prompt.Type {
|
||||||
case "input":
|
case "input":
|
||||||
f = func() error {
|
f = func() error {
|
||||||
title, err := gui.resolveTemplate(prompt.Title, promptResponses)
|
return gui.inputPrompt(prompt, promptResponses, idx, wrappedF)
|
||||||
if err != nil {
|
|
||||||
return gui.surfaceError(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
initialValue, err := gui.resolveTemplate(prompt.InitialValue, promptResponses)
|
|
||||||
if err != nil {
|
|
||||||
return gui.surfaceError(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return gui.prompt(promptOpts{
|
|
||||||
title: title,
|
|
||||||
initialContent: initialValue,
|
|
||||||
handleConfirm: func(str string) error {
|
|
||||||
promptResponses[idx] = str
|
|
||||||
|
|
||||||
return wrappedF()
|
|
||||||
},
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
case "menu":
|
case "menu":
|
||||||
f = func() error {
|
f = func() error {
|
||||||
// need to make a menu here some how
|
return gui.menuPrompt(prompt, promptResponses, idx, wrappedF)
|
||||||
menuItems := make([]*menuItem, len(prompt.Options))
|
|
||||||
for i, option := range prompt.Options {
|
|
||||||
option := option
|
|
||||||
|
|
||||||
nameTemplate := option.Name
|
|
||||||
if nameTemplate == "" {
|
|
||||||
// this allows you to only pass values rather than bother with names/descriptions
|
|
||||||
nameTemplate = option.Value
|
|
||||||
}
|
|
||||||
name, err := gui.resolveTemplate(nameTemplate, promptResponses)
|
|
||||||
if err != nil {
|
|
||||||
return gui.surfaceError(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
description, err := gui.resolveTemplate(option.Description, promptResponses)
|
|
||||||
if err != nil {
|
|
||||||
return gui.surfaceError(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
value, err := gui.resolveTemplate(option.Value, promptResponses)
|
|
||||||
if err != nil {
|
|
||||||
return gui.surfaceError(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
menuItems[i] = &menuItem{
|
|
||||||
displayStrings: []string{name, utils.ColoredString(description, color.FgYellow)},
|
|
||||||
onPress: func() error {
|
|
||||||
promptResponses[idx] = value
|
|
||||||
|
|
||||||
return wrappedF()
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
title, err := gui.resolveTemplate(prompt.Title, promptResponses)
|
|
||||||
if err != nil {
|
|
||||||
return gui.surfaceError(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return gui.createMenu(title, menuItems, createMenuOptions{showCancel: true})
|
|
||||||
}
|
}
|
||||||
case "menuFromCommand":
|
case "menuFromCommand":
|
||||||
f = func() error {
|
f = func() error {
|
||||||
// Collect cmd to run from config
|
return gui.menuPromptFromCommand(prompt, promptResponses, idx, wrappedF)
|
||||||
cmdStr, err := gui.resolveTemplate(prompt.Command, promptResponses)
|
|
||||||
if err != nil {
|
|
||||||
return gui.surfaceError(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Collect Filter regexp
|
|
||||||
filter, err := gui.resolveTemplate(prompt.Filter, promptResponses)
|
|
||||||
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)
|
|
||||||
if err != nil {
|
|
||||||
return gui.surfaceError(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Need to make a menu out of what the cmd has displayed
|
|
||||||
candidates := []string{}
|
|
||||||
buff := bytes.NewBuffer(nil)
|
|
||||||
temp, err := template.New("format").Parse(prompt.Format)
|
|
||||||
if err != nil {
|
|
||||||
return gui.surfaceError(errors.New("unable to parse format, error: " + err.Error()))
|
|
||||||
}
|
|
||||||
for _, str := range strings.Split(string(message), "\n") {
|
|
||||||
if str == "" {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
tmplData := map[string]string{}
|
|
||||||
out := reg.FindAllStringSubmatch(str, -1)
|
|
||||||
if len(out) > 0 {
|
|
||||||
for groupIdx, group := range reg.SubexpNames() {
|
|
||||||
// Record matched group with group ids
|
|
||||||
matchName := "group_" + strconv.Itoa(groupIdx)
|
|
||||||
tmplData[matchName] = group
|
|
||||||
// Record last named group non-empty matches as group matches
|
|
||||||
if group != "" {
|
|
||||||
tmplData[group] = out[0][idx]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
err = temp.Execute(buff, tmplData)
|
|
||||||
if err != nil {
|
|
||||||
return gui.surfaceError(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
candidates = append(candidates, strings.TrimSpace(buff.String()))
|
|
||||||
buff.Reset()
|
|
||||||
}
|
|
||||||
|
|
||||||
menuItems := make([]*menuItem, len(candidates))
|
|
||||||
for i := range candidates {
|
|
||||||
menuItems[i] = &menuItem{
|
|
||||||
displayStrings: []string{candidates[i]},
|
|
||||||
onPress: func() error {
|
|
||||||
promptResponses[idx] = candidates[i]
|
|
||||||
return wrappedF()
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
title, err := gui.resolveTemplate(prompt.Title, promptResponses)
|
|
||||||
if err != nil {
|
|
||||||
return gui.surfaceError(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return gui.createMenu(title, menuItems, createMenuOptions{showCancel: true})
|
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
return gui.createErrorPanel("custom command prompt must have a type of 'input', 'menu' or 'menuFromCommand'")
|
return gui.createErrorPanel("custom command prompt must have a type of 'input', 'menu' or 'menuFromCommand'")
|
||||||
|
Reference in New Issue
Block a user