1
0
mirror of https://github.com/jesseduffield/lazygit.git synced 2025-07-30 03:23:08 +03:00

Support using command output directly in menuFromCommand custom command prompt

The menuFromCommand option is a little complicated, so I'm adding an easy way to just use the command output directly,
where each line becomes a suggestion, as-is.

Now that we support suggestions in the input prompt, there's less of a need for menuFromCommand, but it probably still
serves some purpose.

In future I want to support this filter/valueFormat/labelFormat thing for suggestions too. I would like to think a little more
about the interface though: is using a regex like we currently do really the simplest approach?
This commit is contained in:
Jesse Duffield
2023-05-29 22:52:16 +10:00
parent 036a1ea519
commit 1de876ed4d
4 changed files with 80 additions and 25 deletions

View File

@ -210,7 +210,7 @@ func (self *HandlerCreator) menuPromptFromCommand(prompt *config.CustomCommandPr
return self.c.Error(err)
}
menuItems := slices.Map(candidates, func(candidate *commandMenuEntry) *types.MenuItem {
menuItems := slices.Map(candidates, func(candidate *commandMenuItem) *types.MenuItem {
return &types.MenuItem{
LabelColumns: []string{candidate.label},
OnPress: func() error {

View File

@ -22,12 +22,41 @@ func NewMenuGenerator(c *common.Common) *MenuGenerator {
return &MenuGenerator{c: c}
}
type commandMenuEntry struct {
type commandMenuItem struct {
label string
value string
}
func (self *MenuGenerator) call(commandOutput, filter, valueFormat, labelFormat string) ([]*commandMenuEntry, error) {
func (self *MenuGenerator) call(commandOutput, filter, valueFormat, labelFormat string) ([]*commandMenuItem, error) {
menuItemFromLine, err := self.getMenuItemFromLinefn(filter, valueFormat, labelFormat)
if err != nil {
return nil, err
}
menuItems := []*commandMenuItem{}
for _, line := range strings.Split(commandOutput, "\n") {
if line == "" {
continue
}
menuItem, err := menuItemFromLine(line)
if err != nil {
return nil, err
}
menuItems = append(menuItems, menuItem)
}
return menuItems, nil
}
func (self *MenuGenerator) getMenuItemFromLinefn(filter string, valueFormat string, labelFormat string) (func(line string) (*commandMenuItem, error), error) {
if filter == "" && valueFormat == "" && labelFormat == "" {
// showing command output lines as-is in suggestions panel
return func(line string) (*commandMenuItem, error) {
return &commandMenuItem{label: line, value: line}, nil
}, nil
}
regex, err := regexp.Compile(filter)
if err != nil {
return nil, errors.New("unable to parse filter regex, error: " + err.Error())
@ -51,37 +80,25 @@ func (self *MenuGenerator) call(commandOutput, filter, valueFormat, labelFormat
labelTemplate = valueTemplate
}
candidates := []*commandMenuEntry{}
for _, line := range strings.Split(commandOutput, "\n") {
if line == "" {
continue
}
candidate, err := self.generateMenuCandidate(
return func(line string) (*commandMenuItem, error) {
return self.generateMenuItem(
line,
regex,
valueTemplate,
labelTemplate,
)
if err != nil {
return nil, err
}
candidates = append(candidates, candidate)
}
return candidates, err
}, nil
}
func (self *MenuGenerator) generateMenuCandidate(
func (self *MenuGenerator) generateMenuItem(
line string,
regex *regexp.Regexp,
valueTemplate *TrimmerTemplate,
labelTemplate *TrimmerTemplate,
) (*commandMenuEntry, error) {
) (*commandMenuItem, error) {
tmplData := self.parseLine(line, regex)
entry := &commandMenuEntry{}
entry := &commandMenuItem{}
var err error
entry.value, err = valueTemplate.execute(tmplData)

View File

@ -14,7 +14,7 @@ func TestMenuGenerator(t *testing.T) {
filter string
valueFormat string
labelFormat string
test func([]*commandMenuEntry, error)
test func([]*commandMenuItem, error)
}
scenarios := []scenario{
@ -24,7 +24,7 @@ func TestMenuGenerator(t *testing.T) {
"(?P<remote>[a-z_]+)/(?P<branch>.*)",
"{{ .branch }}",
"Remote: {{ .remote }}",
func(actualEntry []*commandMenuEntry, err error) {
func(actualEntry []*commandMenuItem, err error) {
assert.NoError(t, err)
assert.EqualValues(t, "pr-1", actualEntry[0].value)
assert.EqualValues(t, "Remote: upstream", actualEntry[0].label)
@ -36,7 +36,7 @@ func TestMenuGenerator(t *testing.T) {
"(?P<remote>[a-z]*)/(?P<branch>.*)",
"{{ .branch }}|{{ .remote }}",
"",
func(actualEntry []*commandMenuEntry, err error) {
func(actualEntry []*commandMenuItem, err error) {
assert.NoError(t, err)
assert.EqualValues(t, "pr-1|upstream", actualEntry[0].value)
assert.EqualValues(t, "pr-1|upstream", actualEntry[0].label)
@ -48,12 +48,36 @@ func TestMenuGenerator(t *testing.T) {
"(?P<remote>[a-z]*)/(?P<branch>.*)",
"{{ .group_2 }}|{{ .group_1 }}",
"Remote: {{ .group_1 }}",
func(actualEntry []*commandMenuEntry, err error) {
func(actualEntry []*commandMenuItem, err error) {
assert.NoError(t, err)
assert.EqualValues(t, "pr-1|upstream", actualEntry[0].value)
assert.EqualValues(t, "Remote: upstream", actualEntry[0].label)
},
},
{
"No named groups",
"upstream/pr-1",
"([a-z]*)/(.*)",
"{{ .group_2 }}|{{ .group_1 }}",
"Remote: {{ .group_1 }}",
func(actualEntry []*commandMenuItem, err error) {
assert.NoError(t, err)
assert.EqualValues(t, "pr-1|upstream", actualEntry[0].value)
assert.EqualValues(t, "Remote: upstream", actualEntry[0].label)
},
},
{
"No filter",
"upstream/pr-1",
"",
"",
"",
func(actualEntry []*commandMenuItem, err error) {
assert.NoError(t, err)
assert.EqualValues(t, "upstream/pr-1", actualEntry[0].value)
assert.EqualValues(t, "upstream/pr-1", actualEntry[0].label)
},
},
}
for _, s := range scenarios {