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

Code before:

	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()))
	}

	colorFuncMap := template.FuncMap{}
	for k, v := range style.ColorMap {
		colorFuncMap[k] = v.Foreground.Sprint
	}

	descTemp, err := template.New("format").Funcs(colorFuncMap).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
		}

		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]
				// Record last named group non-empty matches as group matches
				if group != "" {
					tmplData[group] = out[0][groupIdx]
				}
			}
		}

Review comment (refactor):
Maybe it's better to abstract this logic into `pkg/gui/style/basic_styles.go`

In `basic_styles.go`:
```go
func TemplateFuncMapAddColors(m template.FuncMap) template.FuncMap {
	for k, v := range ColorMap {
		m[k] = v.Foreground.Sprint
	}
	m["underline"] = color.OpUnderscore.Sprint
	m["bold"] = color.OpBold.Sprint
	return m
}
```

And then in this file:
```suggestion
	colorFuncMap := style.TemplateFuncMapAddColors(template.FuncMap{})
```


Code after:

	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()))
	}

	colorFuncMap := style.TemplateFuncMapAddColors(template.FuncMap{})

	descTemp, err := template.New("format").Funcs(colorFuncMap).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
		}

		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]
				// Record last named group non-empty matches as group matches
				if group != "" {
					tmplData[group] = out[0][groupIdx]
				}
			}
		}

		err = valueTemp.Execute(buff, tmplData)
		if err != nil {