1
0
mirror of https://github.com/jesseduffield/lazygit.git synced 2024-11-28 09:08:41 +02:00

Refactor code around handleCustomCommandKeybinding

This commit is contained in:
Elwardi 2021-07-20 20:59:03 +01:00
parent f70435a20f
commit edfb0a26b2

View File

@ -54,6 +54,149 @@ func (gui *Gui) resolveTemplate(templateStr string, promptResponses []string) (s
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 {
return func() error {
promptResponses := make([]string, len(customCommand.Prompts))
@ -94,144 +237,15 @@ func (gui *Gui) handleCustomCommandKeybinding(customCommand config.CustomCommand
switch prompt.Type {
case "input":
f = func() 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[idx] = str
return wrappedF()
},
})
return gui.inputPrompt(prompt, promptResponses, idx, wrappedF)
}
case "menu":
f = func() 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[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})
return gui.menuPrompt(prompt, promptResponses, idx, wrappedF)
}
case "menuFromCommand":
f = func() 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)
}
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})
return gui.menuPromptFromCommand(prompt, promptResponses, idx, wrappedF)
}
default:
return gui.createErrorPanel("custom command prompt must have a type of 'input', 'menu' or 'menuFromCommand'")