mirror of
https://github.com/jesseduffield/lazygit.git
synced 2024-12-12 11:15:00 +02:00
ef7c4c9ca9
more custom command refactoring
139 lines
3.3 KiB
Go
139 lines
3.3 KiB
Go
package custom_commands
|
|
|
|
import (
|
|
"bytes"
|
|
"errors"
|
|
"regexp"
|
|
"strconv"
|
|
"strings"
|
|
"text/template"
|
|
|
|
"github.com/jesseduffield/lazygit/pkg/common"
|
|
"github.com/jesseduffield/lazygit/pkg/gui/style"
|
|
)
|
|
|
|
type MenuGenerator struct {
|
|
c *common.Common
|
|
}
|
|
|
|
// takes the output of a command and returns a list of menu entries based on a filter
|
|
// and value/label format templates provided by the user
|
|
func NewMenuGenerator(c *common.Common) *MenuGenerator {
|
|
return &MenuGenerator{c: c}
|
|
}
|
|
|
|
type commandMenuEntry struct {
|
|
label string
|
|
value string
|
|
}
|
|
|
|
func (self *MenuGenerator) call(commandOutput, filter, valueFormat, labelFormat string) ([]*commandMenuEntry, error) {
|
|
regex, err := regexp.Compile(filter)
|
|
if err != nil {
|
|
return nil, errors.New("unable to parse filter regex, error: " + err.Error())
|
|
}
|
|
|
|
valueTemplateAux, err := template.New("format").Parse(valueFormat)
|
|
if err != nil {
|
|
return nil, errors.New("unable to parse value format, error: " + err.Error())
|
|
}
|
|
valueTemplate := NewTrimmerTemplate(valueTemplateAux)
|
|
|
|
var labelTemplate *TrimmerTemplate
|
|
if labelFormat != "" {
|
|
colorFuncMap := style.TemplateFuncMapAddColors(template.FuncMap{})
|
|
labelTemplateAux, err := template.New("format").Funcs(colorFuncMap).Parse(labelFormat)
|
|
if err != nil {
|
|
return nil, errors.New("unable to parse label format, error: " + err.Error())
|
|
}
|
|
labelTemplate = NewTrimmerTemplate(labelTemplateAux)
|
|
} else {
|
|
labelTemplate = valueTemplate
|
|
}
|
|
|
|
candidates := []*commandMenuEntry{}
|
|
for _, line := range strings.Split(commandOutput, "\n") {
|
|
if line == "" {
|
|
continue
|
|
}
|
|
|
|
candidate, err := self.generateMenuCandidate(
|
|
line,
|
|
regex,
|
|
valueTemplate,
|
|
labelTemplate,
|
|
)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
candidates = append(candidates, candidate)
|
|
}
|
|
|
|
return candidates, err
|
|
}
|
|
|
|
func (self *MenuGenerator) generateMenuCandidate(
|
|
line string,
|
|
regex *regexp.Regexp,
|
|
valueTemplate *TrimmerTemplate,
|
|
labelTemplate *TrimmerTemplate,
|
|
) (*commandMenuEntry, error) {
|
|
tmplData := self.parseLine(line, regex)
|
|
|
|
entry := &commandMenuEntry{}
|
|
|
|
var err error
|
|
entry.value, err = valueTemplate.execute(tmplData)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
entry.label, err = labelTemplate.execute(tmplData)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return entry, nil
|
|
}
|
|
|
|
func (self *MenuGenerator) parseLine(line string, regex *regexp.Regexp) map[string]string {
|
|
tmplData := map[string]string{}
|
|
out := regex.FindAllStringSubmatch(line, -1)
|
|
if len(out) > 0 {
|
|
for groupIdx, group := range regex.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]
|
|
}
|
|
}
|
|
}
|
|
|
|
return tmplData
|
|
}
|
|
|
|
// wrapper around a template which trims the output
|
|
type TrimmerTemplate struct {
|
|
template *template.Template
|
|
buffer *bytes.Buffer
|
|
}
|
|
|
|
func NewTrimmerTemplate(template *template.Template) *TrimmerTemplate {
|
|
return &TrimmerTemplate{
|
|
template: template,
|
|
buffer: bytes.NewBuffer(nil),
|
|
}
|
|
}
|
|
|
|
func (self *TrimmerTemplate) execute(tmplData map[string]string) (string, error) {
|
|
self.buffer.Reset()
|
|
err := self.template.Execute(self.buffer, tmplData)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
return strings.TrimSpace(self.buffer.String()), nil
|
|
}
|