From a8ec044f0e52bff8921592fb4d334a4d6f4c7468 Mon Sep 17 00:00:00 2001 From: Elwardi Date: Thu, 5 Aug 2021 15:24:17 +0100 Subject: [PATCH 1/4] Make menuFromCommand format menu items and their description --- docs/Custom_Command_Keybindings.md | 34 ++++++++++++++++----------- pkg/config/user_config.go | 3 ++- pkg/gui/custom_commands.go | 37 ++++++++++++++++++++---------- pkg/gui/gui_test.go | 29 ++++++++++++++--------- 4 files changed, 65 insertions(+), 38 deletions(-) diff --git a/docs/Custom_Command_Keybindings.md b/docs/Custom_Command_Keybindings.md index 9dc42a9da..c167309f8 100644 --- a/docs/Custom_Command_Keybindings.md +++ b/docs/Custom_Command_Keybindings.md @@ -47,7 +47,8 @@ customCommands: title: 'Remote branch:' command: 'git branch -r --list {{index .PromptResponses 0}}/*' filter: '.*{{index .PromptResponses 0}}/(?P.*)' - format: '{{ .branch }}' + itemFormat: '{{ .branch }}' + descriptionFormat: '' ``` Looking at the command assigned to the 'n' key, here's what the result looks like: @@ -92,19 +93,24 @@ The permitted contexts are: The permitted prompt fields are: -| _field_ | _description_ | _required_ | -| ------------ | -------------------------------------------------------------------------------- | ---------- | -| type | one of 'input' or 'menu' | yes | -| title | the title to display in the popup panel | no | -| initialValue | (only applicable to 'input' prompts) the initial value to appear in the text box | no | -| options | (only applicable to 'menu' prompts) the options to display in the menu | no | -| command | (only applicable to 'menuFromCommand' prompts) the command to run to generate | yes | -| | menu options | | -| filter | (only applicable to 'menuFromCommand' prompts) the regexp to run specifying | yes | -| | groups which are going to be kept from the command's output | | -| format | (only applicable to 'menuFromCommand' prompts) how to format matched groups from | yes | -| | the filter. You can use named groups, or `{{ .group_GROUPID }}`. | yes | -| | PS: named groups keep first match only | yes | +| _field_ | _description_ | _required_ | +| ------------ | -------------------------------------------------------------------------------- | ---------- | +| type | one of 'input' or 'menu' | yes | +| title | the title to display in the popup panel | no | +| initialValue | (only applicable to 'input' prompts) the initial value to appear in the text box | no | +| options | (only applicable to 'menu' prompts) the options to display in the menu | no | +| command | (only applicable to 'menuFromCommand' prompts) the command to run to generate | yes | +| | menu options | | +| filter | (only applicable to 'menuFromCommand' prompts) the regexp to run specifying | yes | +| | groups which are going to be kept from the command's output | | +| itemFormat | (only applicable to 'menuFromCommand' prompts) how to format matched groups from | yes | +| | the filter to construct a menu item. You can use named groups, | yes | +| | or `{{ .group_GROUPID }}`. | | +| | PS: named groups keep first match only | yes | +| descriptionFormat | (only applicable to 'menuFromCommand' prompts) how to format matched groups from | yes | +| | the filter to construct a menu item's description. You can use named groups, | yes | +| | or `{{ .group_GROUPID }}`. | | +| | PS: named groups keep first match only | yes | The permitted option fields are: | _field_ | _description_ | _required_ | diff --git a/pkg/config/user_config.go b/pkg/config/user_config.go index 38259f6f2..239a79acf 100644 --- a/pkg/config/user_config.go +++ b/pkg/config/user_config.go @@ -285,7 +285,8 @@ type CustomCommandPrompt struct { // this only applies to menuFromCommand Command string `yaml:"command"` Filter string `yaml:"filter"` - Format string `yaml:"format"` + TFormat string `yaml:"itemFormat"` + DFormat string `yaml:"descriptionFormat"` } type CustomCommandMenuOption struct { diff --git a/pkg/gui/custom_commands.go b/pkg/gui/custom_commands.go index 2fb17049f..080831aa0 100644 --- a/pkg/gui/custom_commands.go +++ b/pkg/gui/custom_commands.go @@ -118,16 +118,22 @@ func (gui *Gui) menuPrompt(prompt config.CustomCommandPrompt, promptResponses [] return gui.createMenu(title, menuItems, createMenuOptions{showCancel: true}) } -func (gui *Gui) GenerateMenuCandidates(commandOutput string, filter string, format string) ([]string, error) { +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, gui.surfaceError(errors.New("unable to parse filter regex, error: " + err.Error())) + return candidates, descriptions, gui.surfaceError(errors.New("unable to parse filter regex, error: " + err.Error())) } - buff := bytes.NewBuffer(nil) - temp, err := template.New("format").Parse(format) + buffTitle := bytes.NewBuffer(nil) + tempTitle, err := template.New("format").Parse(tFormat) if err != nil { - return candidates, gui.surfaceError(errors.New("unable to parse format, error: " + err.Error())) + 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 == "" { @@ -146,15 +152,21 @@ func (gui *Gui) GenerateMenuCandidates(commandOutput string, filter string, form } } } - err = temp.Execute(buff, tmplData) + err = tempTitle.Execute(buffTitle, tmplData) if err != nil { - return candidates, gui.surfaceError(err) + return candidates, descriptions, gui.surfaceError(err) + } + err = tempDescr.Execute(buffDescr, tmplData) + if err != nil { + return candidates, descriptions, gui.surfaceError(err) } - candidates = append(candidates, strings.TrimSpace(buff.String())) - buff.Reset() + candidates = append(candidates, strings.TrimSpace(buffTitle.String())) + descriptions = append(descriptions, strings.TrimSpace(buffDescr.String())) + buffTitle.Reset() + buffDescr.Reset() } - return candidates, err + return candidates, descriptions, err } func (gui *Gui) menuPromptFromCommand(prompt config.CustomCommandPrompt, promptResponses []string, responseIdx int, wrappedF func() error) error { @@ -177,7 +189,7 @@ func (gui *Gui) menuPromptFromCommand(prompt config.CustomCommandPrompt, promptR } // Need to make a menu out of what the cmd has displayed - candidates, err := gui.GenerateMenuCandidates(message, filter, prompt.Format) + candidates, descriptions, err := gui.GenerateMenuCandidates(message, filter, prompt.TFormat, prompt.DFormat) if err != nil { return gui.surfaceError(err) } @@ -185,7 +197,8 @@ func (gui *Gui) menuPromptFromCommand(prompt config.CustomCommandPrompt, promptR menuItems := make([]*menuItem, len(candidates)) for i := range candidates { menuItems[i] = &menuItem{ - displayStrings: []string{candidates[i]}, + // Put in candidate and its description + displayStrings: []string{candidates[i], style.FgYellow.Sprint(descriptions[i])}, onPress: func() error { promptResponses[responseIdx] = candidates[i] return wrappedF() diff --git a/pkg/gui/gui_test.go b/pkg/gui/gui_test.go index ec1279608..f3f798d03 100644 --- a/pkg/gui/gui_test.go +++ b/pkg/gui/gui_test.go @@ -86,29 +86,34 @@ func TestGuiGenerateMenuCandidates(t *testing.T) { testName string cmdOut string filter string - format string - test func([]string, error) + tFormat string + dFormat string + test func([]string, []string, error) } scenarios := []scenario{ { "Extract remote branch name", "upstream/pr-1", - "upstream/(?P.*)", + "(?P[a-z_]+)/(?P.*)", "{{ .branch }}", - func(actual []string, err error) { + "Remote: {{ .remote }}", + func(actualCandidate []string, actualDescr []string, err error) { assert.NoError(t, err) - assert.EqualValues(t, "pr-1", actual[0]) + assert.EqualValues(t, "pr-1", actualCandidate[0]) + assert.EqualValues(t, "Remote: upstream", actualDescr[0]) }, }, { - "Multiple named groups", + "Multiple named groups with empty description", "upstream/pr-1", "(?P[a-z]*)/(?P.*)", "{{ .branch }}|{{ .remote }}", - func(actual []string, err error) { + "", + func(actualCandidate []string, actualDescr []string, err error) { assert.NoError(t, err) - assert.EqualValues(t, "pr-1|upstream", actual[0]) + assert.EqualValues(t, "pr-1|upstream", actualCandidate[0]) + assert.EqualValues(t, "", actualDescr[0]) }, }, { @@ -116,16 +121,18 @@ func TestGuiGenerateMenuCandidates(t *testing.T) { "upstream/pr-1", "(?P[a-z]*)/(?P.*)", "{{ .group_2 }}|{{ .group_1 }}", - func(actual []string, err error) { + "Remote: {{ .group_1 }}", + func(actualCandidate []string, actualDescr []string, err error) { assert.NoError(t, err) - assert.EqualValues(t, "pr-1|upstream", actual[0]) + assert.EqualValues(t, "pr-1|upstream", actualCandidate[0]) + assert.EqualValues(t, "Remote: upstream", actualDescr[0]) }, }, } for _, s := range scenarios { t.Run(s.testName, func(t *testing.T) { - s.test(NewDummyGui().GenerateMenuCandidates(s.cmdOut, s.filter, s.format)) + s.test(NewDummyGui().GenerateMenuCandidates(s.cmdOut, s.filter, s.tFormat, s.dFormat)) }) } } From 906ec30cac9ea632006b295b30bca732498f81bc Mon Sep 17 00:00:00 2001 From: Elwardi Date: Fri, 6 Aug 2021 10:53:32 +0100 Subject: [PATCH 2/4] Minor changes to menuFromCommand prompts --- docs/Custom_Command_Keybindings.md | 8 ++--- pkg/config/user_config.go | 8 ++--- pkg/gui/custom_commands.go | 49 ++++++++++++++++++------------ pkg/gui/gui_test.go | 32 +++++++++---------- 4 files changed, 54 insertions(+), 43 deletions(-) diff --git a/docs/Custom_Command_Keybindings.md b/docs/Custom_Command_Keybindings.md index c167309f8..9a5c89609 100644 --- a/docs/Custom_Command_Keybindings.md +++ b/docs/Custom_Command_Keybindings.md @@ -47,8 +47,8 @@ customCommands: title: 'Remote branch:' command: 'git branch -r --list {{index .PromptResponses 0}}/*' filter: '.*{{index .PromptResponses 0}}/(?P.*)' - itemFormat: '{{ .branch }}' - descriptionFormat: '' + valueFormat: '{{ .branch }}' + labelFormat: '' ``` Looking at the command assigned to the 'n' key, here's what the result looks like: @@ -103,11 +103,11 @@ The permitted prompt fields are: | | menu options | | | filter | (only applicable to 'menuFromCommand' prompts) the regexp to run specifying | yes | | | groups which are going to be kept from the command's output | | -| itemFormat | (only applicable to 'menuFromCommand' prompts) how to format matched groups from | yes | +| valueFormat | (only applicable to 'menuFromCommand' prompts) how to format matched groups from | yes | | | the filter to construct a menu item. You can use named groups, | yes | | | or `{{ .group_GROUPID }}`. | | | | PS: named groups keep first match only | yes | -| descriptionFormat | (only applicable to 'menuFromCommand' prompts) how to format matched groups from | yes | +| labelFormat | (only applicable to 'menuFromCommand' prompts) how to format matched groups from | yes | | | the filter to construct a menu item's description. You can use named groups, | yes | | | or `{{ .group_GROUPID }}`. | | | | PS: named groups keep first match only | yes | diff --git a/pkg/config/user_config.go b/pkg/config/user_config.go index 239a79acf..2f435f066 100644 --- a/pkg/config/user_config.go +++ b/pkg/config/user_config.go @@ -283,10 +283,10 @@ type CustomCommandPrompt struct { Options []CustomCommandMenuOption // this only applies to menuFromCommand - Command string `yaml:"command"` - Filter string `yaml:"filter"` - TFormat string `yaml:"itemFormat"` - DFormat string `yaml:"descriptionFormat"` + Command string `yaml:"command"` + Filter string `yaml:"filter"` + ValueFormat string `yaml:"valueFormat"` + LabelFormat string `yaml:"labelFormat"` } type CustomCommandMenuOption struct { diff --git a/pkg/gui/custom_commands.go b/pkg/gui/custom_commands.go index 080831aa0..bad6f3c36 100644 --- a/pkg/gui/custom_commands.go +++ b/pkg/gui/custom_commands.go @@ -33,6 +33,11 @@ type CustomCommandObjects struct { PromptResponses []string } +type CommandMenuEntry struct { + label string + value string +} + func (gui *Gui) resolveTemplate(templateStr string, promptResponses []string) (string, error) { objects := CustomCommandObjects{ SelectedFile: gui.getSelectedFile(), @@ -118,22 +123,21 @@ func (gui *Gui) menuPrompt(prompt config.CustomCommandPrompt, promptResponses [] 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{} +func (gui *Gui) GenerateMenuCandidates(commandOutput, filter, valueFormat, labelFormat string) ([]CommandMenuEntry, error) { + candidates := []CommandMenuEntry{} reg, err := regexp.Compile(filter) if err != nil { - return candidates, descriptions, gui.surfaceError(errors.New("unable to parse filter regex, error: " + err.Error())) + return candidates, gui.surfaceError(errors.New("unable to parse filter regex, error: " + err.Error())) } - buffTitle := bytes.NewBuffer(nil) - tempTitle, err := template.New("format").Parse(tFormat) + buffItem := bytes.NewBuffer(nil) + tempItem, err := template.New("format").Parse(valueFormat) if err != nil { - return candidates, descriptions, gui.surfaceError(errors.New("unable to parse item format, error: " + err.Error())) + return candidates, gui.surfaceError(errors.New("unable to parse item format, error: " + err.Error())) } buffDescr := bytes.NewBuffer(nil) - tempDescr, err := template.New("format").Parse(dFormat) + tempDescr, err := template.New("format").Parse(labelFormat) if err != nil { - return candidates, descriptions, gui.surfaceError(errors.New("unable to parse item description format, error: " + err.Error())) + return candidates, gui.surfaceError(errors.New("unable to parse item description format, error: " + err.Error())) } for _, str := range strings.Split(string(commandOutput), "\n") { if str == "" { @@ -152,21 +156,28 @@ func (gui *Gui) GenerateMenuCandidates(commandOutput string, filter string, tFor } } } - err = tempTitle.Execute(buffTitle, tmplData) + err = tempItem.Execute(buffItem, tmplData) if err != nil { - return candidates, descriptions, gui.surfaceError(err) + return candidates, gui.surfaceError(err) } err = tempDescr.Execute(buffDescr, tmplData) if err != nil { - return candidates, descriptions, gui.surfaceError(err) + return candidates, gui.surfaceError(err) } - candidates = append(candidates, strings.TrimSpace(buffTitle.String())) - descriptions = append(descriptions, strings.TrimSpace(buffDescr.String())) - buffTitle.Reset() + // Populate menu entry + // label formatted as labelFormat + // value as valueFormat + entry := CommandMenuEntry{ + strings.TrimSpace(buffDescr.String()), + //"Description", + strings.TrimSpace(buffItem.String()), + } + candidates = append(candidates, entry) + buffItem.Reset() buffDescr.Reset() } - return candidates, descriptions, err + return candidates, err } func (gui *Gui) menuPromptFromCommand(prompt config.CustomCommandPrompt, promptResponses []string, responseIdx int, wrappedF func() error) error { @@ -189,7 +200,7 @@ func (gui *Gui) menuPromptFromCommand(prompt config.CustomCommandPrompt, promptR } // Need to make a menu out of what the cmd has displayed - candidates, descriptions, err := gui.GenerateMenuCandidates(message, filter, prompt.TFormat, prompt.DFormat) + candidates, err := gui.GenerateMenuCandidates(message, filter, prompt.ValueFormat, prompt.LabelFormat) if err != nil { return gui.surfaceError(err) } @@ -198,9 +209,9 @@ func (gui *Gui) menuPromptFromCommand(prompt config.CustomCommandPrompt, promptR for i := range candidates { menuItems[i] = &menuItem{ // Put in candidate and its description - displayStrings: []string{candidates[i], style.FgYellow.Sprint(descriptions[i])}, + displayStrings: []string{candidates[i].value, style.FgYellow.Sprint(candidates[i].label)}, onPress: func() error { - promptResponses[responseIdx] = candidates[i] + promptResponses[responseIdx] = candidates[i].value return wrappedF() }, } diff --git a/pkg/gui/gui_test.go b/pkg/gui/gui_test.go index f3f798d03..d4e0415c7 100644 --- a/pkg/gui/gui_test.go +++ b/pkg/gui/gui_test.go @@ -83,12 +83,12 @@ func runCmdHeadless(cmd *exec.Cmd) error { func TestGuiGenerateMenuCandidates(t *testing.T) { type scenario struct { - testName string - cmdOut string - filter string - tFormat string - dFormat string - test func([]string, []string, error) + testName string + cmdOut string + filter string + valueFormat string + labelFormat string + test func([]CommandMenuEntry, error) } scenarios := []scenario{ @@ -98,10 +98,10 @@ func TestGuiGenerateMenuCandidates(t *testing.T) { "(?P[a-z_]+)/(?P.*)", "{{ .branch }}", "Remote: {{ .remote }}", - func(actualCandidate []string, actualDescr []string, err error) { + func(actualEntry []CommandMenuEntry, err error) { assert.NoError(t, err) - assert.EqualValues(t, "pr-1", actualCandidate[0]) - assert.EqualValues(t, "Remote: upstream", actualDescr[0]) + assert.EqualValues(t, "pr-1", actualEntry[0].value) + assert.EqualValues(t, "Remote: upstream", actualEntry[0].label) }, }, { @@ -110,10 +110,10 @@ func TestGuiGenerateMenuCandidates(t *testing.T) { "(?P[a-z]*)/(?P.*)", "{{ .branch }}|{{ .remote }}", "", - func(actualCandidate []string, actualDescr []string, err error) { + func(actualEntry []CommandMenuEntry, err error) { assert.NoError(t, err) - assert.EqualValues(t, "pr-1|upstream", actualCandidate[0]) - assert.EqualValues(t, "", actualDescr[0]) + assert.EqualValues(t, "pr-1|upstream", actualEntry[0].value) + assert.EqualValues(t, "", actualEntry[0].label) }, }, { @@ -122,17 +122,17 @@ func TestGuiGenerateMenuCandidates(t *testing.T) { "(?P[a-z]*)/(?P.*)", "{{ .group_2 }}|{{ .group_1 }}", "Remote: {{ .group_1 }}", - func(actualCandidate []string, actualDescr []string, err error) { + func(actualEntry []CommandMenuEntry, err error) { assert.NoError(t, err) - assert.EqualValues(t, "pr-1|upstream", actualCandidate[0]) - assert.EqualValues(t, "Remote: upstream", actualDescr[0]) + assert.EqualValues(t, "pr-1|upstream", actualEntry[0].value) + assert.EqualValues(t, "Remote: upstream", actualEntry[0].label) }, }, } for _, s := range scenarios { t.Run(s.testName, func(t *testing.T) { - s.test(NewDummyGui().GenerateMenuCandidates(s.cmdOut, s.filter, s.tFormat, s.dFormat)) + s.test(NewDummyGui().GenerateMenuCandidates(s.cmdOut, s.filter, s.valueFormat, s.labelFormat)) }) } } From dcd3b7c058f9c1289234c2ec174d6dd9802e96e2 Mon Sep 17 00:00:00 2001 From: Elwardi Date: Fri, 6 Aug 2021 18:38:26 +0100 Subject: [PATCH 3/4] Show only labels in menuFromCommand prompts --- docs/Custom_Command_Keybindings.md | 16 +++++----- pkg/gui/custom_commands.go | 48 +++++++++++++++++------------- pkg/gui/gui_test.go | 4 +-- 3 files changed, 38 insertions(+), 30 deletions(-) diff --git a/docs/Custom_Command_Keybindings.md b/docs/Custom_Command_Keybindings.md index 9a5c89609..c48442362 100644 --- a/docs/Custom_Command_Keybindings.md +++ b/docs/Custom_Command_Keybindings.md @@ -103,14 +103,16 @@ The permitted prompt fields are: | | menu options | | | filter | (only applicable to 'menuFromCommand' prompts) the regexp to run specifying | yes | | | groups which are going to be kept from the command's output | | -| valueFormat | (only applicable to 'menuFromCommand' prompts) how to format matched groups from | yes | -| | the filter to construct a menu item. You can use named groups, | yes | +| valueFormat | (only applicable to 'menuFromCommand' prompts) how to format matched groups from | yes | +| | the filter to construct a menu item's value (What gets appended to prompt | | +| | responses when the item is selected). You can use named groups, | | | | or `{{ .group_GROUPID }}`. | | -| | PS: named groups keep first match only | yes | -| labelFormat | (only applicable to 'menuFromCommand' prompts) how to format matched groups from | yes | -| | the filter to construct a menu item's description. You can use named groups, | yes | -| | or `{{ .group_GROUPID }}`. | | -| | PS: named groups keep first match only | yes | +| | PS: named groups keep first match only | | +| labelFormat | (only applicable to 'menuFromCommand' prompts) how to format matched groups from | no | +| | the filter to construct the item's label (What's shown on screen). You can use | | +| | named groups, or `{{ .group_GROUPID }}`. If this is not specified, `valueFormat` | | +| | is shown instead. | | +| | PS: named groups keep first match only | | The permitted option fields are: | _field_ | _description_ | _required_ | diff --git a/pkg/gui/custom_commands.go b/pkg/gui/custom_commands.go index bad6f3c36..bac65801d 100644 --- a/pkg/gui/custom_commands.go +++ b/pkg/gui/custom_commands.go @@ -125,20 +125,24 @@ func (gui *Gui) menuPrompt(prompt config.CustomCommandPrompt, promptResponses [] func (gui *Gui) GenerateMenuCandidates(commandOutput, filter, valueFormat, labelFormat string) ([]CommandMenuEntry, error) { candidates := []CommandMenuEntry{} + reg, err := regexp.Compile(filter) if err != nil { return candidates, gui.surfaceError(errors.New("unable to parse filter regex, error: " + err.Error())) } - buffItem := bytes.NewBuffer(nil) - tempItem, err := template.New("format").Parse(valueFormat) + + valueBuff := bytes.NewBuffer(nil) + valueTemp, err := template.New("format").Parse(valueFormat) if err != nil { - return candidates, gui.surfaceError(errors.New("unable to parse item format, error: " + err.Error())) + return candidates, gui.surfaceError(errors.New("unable to parse value format, error: " + err.Error())) } - buffDescr := bytes.NewBuffer(nil) - tempDescr, err := template.New("format").Parse(labelFormat) + + descBuff := bytes.NewBuffer(nil) + descTemp, err := template.New("format").Parse(labelFormat) if err != nil { - return candidates, gui.surfaceError(errors.New("unable to parse item description format, error: " + err.Error())) + return candidates, gui.surfaceError(errors.New("unable to parse label format, error: " + err.Error())) } + for _, str := range strings.Split(string(commandOutput), "\n") { if str == "" { continue @@ -156,26 +160,29 @@ func (gui *Gui) GenerateMenuCandidates(commandOutput, filter, valueFormat, label } } } - err = tempItem.Execute(buffItem, tmplData) - if err != nil { - return candidates, gui.surfaceError(err) - } - err = tempDescr.Execute(buffDescr, tmplData) + + err = valueTemp.Execute(valueBuff, tmplData) if err != nil { return candidates, gui.surfaceError(err) } - // Populate menu entry - // label formatted as labelFormat - // value as valueFormat + if labelFormat != "" { + err = descTemp.Execute(descBuff, tmplData) + if err != nil { + return candidates, gui.surfaceError(err) + } + } else { + descBuff.Write(valueBuff.Bytes()) + } + entry := CommandMenuEntry{ - strings.TrimSpace(buffDescr.String()), - //"Description", - strings.TrimSpace(buffItem.String()), + strings.TrimSpace(descBuff.String()), + strings.TrimSpace(valueBuff.String()), } candidates = append(candidates, entry) - buffItem.Reset() - buffDescr.Reset() + + valueBuff.Reset() + descBuff.Reset() } return candidates, err } @@ -208,8 +215,7 @@ func (gui *Gui) menuPromptFromCommand(prompt config.CustomCommandPrompt, promptR menuItems := make([]*menuItem, len(candidates)) for i := range candidates { menuItems[i] = &menuItem{ - // Put in candidate and its description - displayStrings: []string{candidates[i].value, style.FgYellow.Sprint(candidates[i].label)}, + displayStrings: []string{candidates[i].label}, onPress: func() error { promptResponses[responseIdx] = candidates[i].value return wrappedF() diff --git a/pkg/gui/gui_test.go b/pkg/gui/gui_test.go index d4e0415c7..e3989ba24 100644 --- a/pkg/gui/gui_test.go +++ b/pkg/gui/gui_test.go @@ -105,7 +105,7 @@ func TestGuiGenerateMenuCandidates(t *testing.T) { }, }, { - "Multiple named groups with empty description", + "Multiple named groups with empty labelFormat", "upstream/pr-1", "(?P[a-z]*)/(?P.*)", "{{ .branch }}|{{ .remote }}", @@ -113,7 +113,7 @@ func TestGuiGenerateMenuCandidates(t *testing.T) { func(actualEntry []CommandMenuEntry, err error) { assert.NoError(t, err) assert.EqualValues(t, "pr-1|upstream", actualEntry[0].value) - assert.EqualValues(t, "", actualEntry[0].label) + assert.EqualValues(t, "pr-1|upstream", actualEntry[0].label) }, }, { From ea136e4e77259e27db0b89a88d7d57cad6062d1e Mon Sep 17 00:00:00 2001 From: mjarkk Date: Fri, 6 Aug 2021 21:50:53 +0200 Subject: [PATCH 4/4] Improve code quality - Make CommandMenuEntry private - create candidates only once we really need it - Use only 1 buffer - Clearify CommandMenuEntry creation fields --- pkg/gui/custom_commands.go | 36 ++++++++++++++++++------------------ pkg/gui/gui_test.go | 8 ++++---- 2 files changed, 22 insertions(+), 22 deletions(-) diff --git a/pkg/gui/custom_commands.go b/pkg/gui/custom_commands.go index bac65801d..a9795f7b6 100644 --- a/pkg/gui/custom_commands.go +++ b/pkg/gui/custom_commands.go @@ -33,7 +33,7 @@ type CustomCommandObjects struct { PromptResponses []string } -type CommandMenuEntry struct { +type commandMenuEntry struct { label string value string } @@ -123,30 +123,30 @@ func (gui *Gui) menuPrompt(prompt config.CustomCommandPrompt, promptResponses [] return gui.createMenu(title, menuItems, createMenuOptions{showCancel: true}) } -func (gui *Gui) GenerateMenuCandidates(commandOutput, filter, valueFormat, labelFormat string) ([]CommandMenuEntry, error) { - candidates := []CommandMenuEntry{} - +func (gui *Gui) GenerateMenuCandidates(commandOutput, filter, valueFormat, labelFormat string) ([]commandMenuEntry, error) { reg, err := regexp.Compile(filter) if err != nil { - return candidates, gui.surfaceError(errors.New("unable to parse filter regex, error: " + err.Error())) + return nil, gui.surfaceError(errors.New("unable to parse filter regex, error: " + err.Error())) } - valueBuff := bytes.NewBuffer(nil) + buff := bytes.NewBuffer(nil) + valueTemp, err := template.New("format").Parse(valueFormat) if err != nil { - return candidates, gui.surfaceError(errors.New("unable to parse value format, error: " + err.Error())) + return nil, gui.surfaceError(errors.New("unable to parse value format, error: " + err.Error())) } - descBuff := bytes.NewBuffer(nil) descTemp, err := template.New("format").Parse(labelFormat) if err != nil { - return candidates, gui.surfaceError(errors.New("unable to parse label format, error: " + err.Error())) + 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 { @@ -161,28 +161,28 @@ func (gui *Gui) GenerateMenuCandidates(commandOutput, filter, valueFormat, label } } - err = valueTemp.Execute(valueBuff, tmplData) + err = valueTemp.Execute(buff, tmplData) if err != nil { return candidates, gui.surfaceError(err) } + entry := commandMenuEntry{ + value: strings.TrimSpace(buff.String()), + } if labelFormat != "" { - err = descTemp.Execute(descBuff, tmplData) + buff.Reset() + err = descTemp.Execute(buff, tmplData) if err != nil { return candidates, gui.surfaceError(err) } + entry.label = strings.TrimSpace(buff.String()) } else { - descBuff.Write(valueBuff.Bytes()) + entry.label = entry.value } - entry := CommandMenuEntry{ - strings.TrimSpace(descBuff.String()), - strings.TrimSpace(valueBuff.String()), - } candidates = append(candidates, entry) - valueBuff.Reset() - descBuff.Reset() + buff.Reset() } return candidates, err } diff --git a/pkg/gui/gui_test.go b/pkg/gui/gui_test.go index e3989ba24..a50f093be 100644 --- a/pkg/gui/gui_test.go +++ b/pkg/gui/gui_test.go @@ -88,7 +88,7 @@ func TestGuiGenerateMenuCandidates(t *testing.T) { filter string valueFormat string labelFormat string - test func([]CommandMenuEntry, error) + test func([]commandMenuEntry, error) } scenarios := []scenario{ @@ -98,7 +98,7 @@ func TestGuiGenerateMenuCandidates(t *testing.T) { "(?P[a-z_]+)/(?P.*)", "{{ .branch }}", "Remote: {{ .remote }}", - func(actualEntry []CommandMenuEntry, err error) { + func(actualEntry []commandMenuEntry, err error) { assert.NoError(t, err) assert.EqualValues(t, "pr-1", actualEntry[0].value) assert.EqualValues(t, "Remote: upstream", actualEntry[0].label) @@ -110,7 +110,7 @@ func TestGuiGenerateMenuCandidates(t *testing.T) { "(?P[a-z]*)/(?P.*)", "{{ .branch }}|{{ .remote }}", "", - func(actualEntry []CommandMenuEntry, err error) { + func(actualEntry []commandMenuEntry, err error) { assert.NoError(t, err) assert.EqualValues(t, "pr-1|upstream", actualEntry[0].value) assert.EqualValues(t, "pr-1|upstream", actualEntry[0].label) @@ -122,7 +122,7 @@ func TestGuiGenerateMenuCandidates(t *testing.T) { "(?P[a-z]*)/(?P.*)", "{{ .group_2 }}|{{ .group_1 }}", "Remote: {{ .group_1 }}", - func(actualEntry []CommandMenuEntry, err error) { + func(actualEntry []commandMenuEntry, err error) { assert.NoError(t, err) assert.EqualValues(t, "pr-1|upstream", actualEntry[0].value) assert.EqualValues(t, "Remote: upstream", actualEntry[0].label)