Repository: jesseduffield/lazygit
File: pkg/gui/custom_commands.go (Go)

Code before:

		value, err := gui.resolveTemplate(option.Value, promptResponses)
		if err != nil {
			return gui.surfaceError(err)
		}

		menuItems[i] = &menuItem{
			displayStrings: []string{name, style.FgYellow.Sprint(description)},
			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, tFormat string, dFormat string) ([]string, []string, error) {
	candidates := []string{}
	descriptions := []string{}
	reg, err := regexp.Compile(filter)
	if err != nil {
		return candidates, descriptions, gui.surfaceError(errors.New("unable to parse filter regex, error: " + err.Error()))
	}
	buffTitle := bytes.NewBuffer(nil)
	tempTitle, err := template.New("format").Parse(tFormat)
	if err != nil {
		return candidates, descriptions, gui.surfaceError(errors.New("unable to parse item format, error: " + err.Error()))
	}
	buffDescr := bytes.NewBuffer(nil)
	tempDescr, err := template.New("format").Parse(dFormat)
	if err != nil {
		return candidates, descriptions, gui.surfaceError(errors.New("unable to parse item description 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] = out[0][groupIdx]

Review comment (bug):
Having every menu entry represented in 2 arrays seems wrong to me.  

What about this function returning `[]*menuItem`?  
Maybe you'll need to add a callback as function argument to this function that itself has one argument of the selected value.

Or we have a struct with the label and value inside of it
```
type commandMenuEntry struct {
  label string
  value string
}
```
And return that
```
entries := []commandMenuEntry{}
```

Code after:

		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, style.FgYellow.Sprint(description)},
			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, filter, valueFormat, labelFormat string) ([]commandMenuEntry, error) {
	reg, err := regexp.Compile(filter)
	if err != nil {
		return nil, gui.surfaceError(errors.New("unable to parse filter regex, error: " + err.Error()))
	}

	buff := bytes.NewBuffer(nil)

	valueTemp, err := template.New("format").Parse(valueFormat)
	if err != nil {
		return nil, gui.surfaceError(errors.New("unable to parse value format, error: " + err.Error()))
	}

	descTemp, err := template.New("format").Parse(labelFormat)
	if err != nil {
		return nil, gui.surfaceError(errors.New("unable to parse label format, error: " + err.Error()))
	}

	candidates := []commandMenuEntry{}
	for _, str := range strings.Split(string(commandOutput), "\n") {
		if str == "" {
			continue
		}