summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJesse Duffield <jessedduffield@gmail.com>2023-05-29 22:46:18 +1000
committerJesse Duffield <jessedduffield@gmail.com>2023-05-29 22:47:35 +1000
commit036a1ea519885ae9962c0ba2d90f642874cabd89 (patch)
tree9c8849aa2e172a3be2d35eb016248035ff80ecf1
parent29c738a88b992bf1ddeb16864767a433e3c464e3 (diff)
Support suggestions generated from command in custom commands
This changes the interface a bit but it was only added earlier today so I doubt anybody is dependent on it yet. I'm also updating the docs.
-rw-r--r--docs/Custom_Command_Keybindings.md281
-rw-r--r--pkg/config/user_config.go17
-rw-r--r--pkg/gui/services/custom_commands/handler_creator.go62
-rw-r--r--pkg/gui/services/custom_commands/resolver.go7
-rw-r--r--pkg/integration/tests/custom_commands/suggestions_command.go66
-rw-r--r--pkg/integration/tests/custom_commands/suggestions_preset.go10
-rw-r--r--pkg/integration/tests/test_list.go1
7 files changed, 341 insertions, 103 deletions
diff --git a/docs/Custom_Command_Keybindings.md b/docs/Custom_Command_Keybindings.md
index af9431d07..d6e796c66 100644
--- a/docs/Custom_Command_Keybindings.md
+++ b/docs/Custom_Command_Keybindings.md
@@ -5,20 +5,22 @@ You can add custom command keybindings in your config.yml (accessible by pressin
```yml
customCommands:
- key: '<c-r>'
- command: 'hub browse -- "commit/{{.SelectedLocalCommit.Sha}}"'
context: 'commits'
+ command: 'hub browse -- "commit/{{.SelectedLocalCommit.Sha}}"'
- key: 'a'
- command: "git {{if .SelectedFile.HasUnstagedChanges}} add {{else}} reset {{end}} {{.SelectedFile.Name | quote}}"
context: 'files'
- description: 'toggle file staged'
+ command: "git {{if .SelectedFile.HasUnstagedChanges}} add {{else}} reset {{end}} {{.SelectedFile.Name | quote}}"
+ description: 'Toggle file staged'
- key: 'C'
- command: "git commit"
context: 'global'
+ command: "git commit"
subprocess: true
- key: 'n'
+ context: 'localBranches'
prompts:
- type: 'menu'
title: 'What kind of branch is it?'
+ key: 'BranchType'
options:
- name: 'feature'
description: 'a feature branch'
@@ -31,111 +33,238 @@ customCommands:
value: 'release'
- type: 'input'
title: 'What is the new branch name?'
+ key: 'BranchName'
initialValue: ''
- command: "git flow {{index .PromptResponses 0}} start {{index .PromptResponses 1}}"
- context: 'localBranches'
- loadingText: 'creating branch'
- - key : 'r'
- description: 'Checkout a remote branch as FETCH_HEAD'
- command: "git fetch {{index .PromptResponses 0}} {{index .PromptResponses 1}} && git checkout FETCH_HEAD"
- context: 'remotes'
- prompts:
- - type: 'input'
- title: 'Remote:'
- initialValue: "{{index .SelectedRemote.Name }}"
- - type: 'menuFromCommand'
- title: 'Remote branch:'
- command: 'git branch -r --list {{index .PromptResponses 0}}/*'
- filter: '.*{{index .PromptResponses 0}}/(?P<branch>.*)'
- valueFormat: '{{ .branch }}'
- labelFormat: '{{ .branch | green }}'
- - key: '<f1>'
- command: 'git reset --soft {{.CheckedOutBranch.UpstreamRemote}}'
- context: 'files'
- prompts:
- - type: 'confirm'
- title: "Confirm:"
- body: "Are you sure you want to reset HEAD to {{.CheckedOutBranch.UpstreamRemote}}?"
+ command: "git flow {{.Form.BranchType}} start {{.Form.BranchName}}"
+ loadingText: 'Creating branch'
```
Looking at the command assigned to the 'n' key, here's what the result looks like:
![](../../assets/custom-command-keybindings.gif)
-Custom command keybindings will appear alongside inbuilt keybindings when you view the options menu by pressing 'x':
+Custom command keybindings will appear alongside inbuilt keybindings when you view the keybindings menu by pressing '?':
![](https://i.imgur.com/QB21FPx.png)
For a given custom command, here are the allowed fields:
| _field_ | _description_ | required |
|-----------------|----------------------|-|
-| key | the key to trigger the command. Use a single letter or one of the values from [here](https://github.com/jesseduffield/lazygit/blob/master/docs/keybindings/Custom_Keybindings.md) | yes |
-| command | the command to run | yes |
-| context | the context in which to listen for the key (see below) | yes |
-| subprocess | whether you want the command to run in a subprocess (necessary if you want to view the output of the command or provide user input) | no |
-| prompts | a list of prompts that will request user input before running the final command | no |
-| loadingText | text to display while waiting for command to finish | no |
-| description | text to display in the keybindings menu that appears when you press 'x' | no |
-| stream | whether you want to stream the command's output to the Command Log panel | no |
-| showOutput | whether you want to show the command's output in a gui prompt | no |
-
-### Contexts
+| key | The key to trigger the command. Use a single letter or one of the values from [here](https://github.com/jesseduffield/lazygit/blob/master/docs/keybindings/Custom_Keybindings.md) | yes |
+| command | The command to run (using Go template syntax for placeholder values) | yes |
+| context | The context in which to listen for the key (see [below](#contexts)) | yes |
+| subprocess | Whether you want the command to run in a subprocess (e.g. if the command requires user input) | no |
+| prompts | A list of prompts that will request user input before running the final command | no |
+| loadingText | Text to display while waiting for command to finish | no |
+| description | Label for the custom command when displayed in the keybindings menu | no |
+| stream | Whether you want to stream the command's output to the Command Log panel | no |
+| showOutput | Whether you want to show the command's output in a popup within Lazygit | no |
+
+## Contexts
The permitted contexts are:
| _context_ | _description_ |
| -------------- | -------------------------------------------------------------------------------------------------------- |
-| status | the 'Status' tab |
-| files | the 'Files' tab |
-| localBranches | the 'Local Branches' tab |
-| remotes | the 'Remotes' tab |
-| remoteBranches | the context you get when pressing enter on a remote in the remotes tab |
-| tags | the 'Tags' tab |
-| commits | the 'Commits' tab |
-| reflogCommits | the 'Reflog' tab |
-| subCommits | the context you see when pressing enter on a branch |
-| commitFiles | the context you see when pressing enter on a commit or stash entry (warning, might be renamed in future) |
-| stash | the 'Stash' tab |
-| global | this keybinding will take affect everywhere |
-
-### Prompts
-
-The permitted prompt fields are:
+| status | The 'Status' tab |
+| files | The 'Files' tab |
+| localBranches | The 'Local Branches' tab |
+| remotes | The 'Remotes' tab |
+| remoteBranches | The context you get when pressing enter on a remote in the remotes tab |
+| tags | The 'Tags' tab |
+| commits | The 'Commits' tab |
+| reflogCommits | The 'Reflog' tab |
+| subCommits | The context you see when pressing enter on a branch |
+| commitFiles | The context you see when pressing enter on a commit or stash entry (warning, might be renamed in future) |
+| stash | The 'Stash' tab |
+| global | This keybinding will take affect everywhere |
+
+## Prompts
+
+### Common fields
+
+These fields are applicable to all prompts.
| _field_ | _description_ | _required_ |
| ------------ | -----------------------------------------------------------------------------------------------| ---------- |
-| type | one of 'input', 'menu', or 'confirm' | 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 |
-| suggestionsPreset | (only applicable to 'input prompts'. Shows suggestions as the value is typed. One of 'files', 'branches', 'remotes', 'remoteBranches', refs'. | no |
-| body | (only applicable to 'confirm' prompts) the immutable body text 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 groups which are going to be kept from the command's output | yes |
-| valueFormat | (only applicable to 'menuFromCommand' prompts) how to format matched groups from 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 the filter to construct the item's label (What's shown on screen). You can use named groups, or `{{ .group_GROUPID }}`. You can also color each match with `{{ .group_GROUPID \| colorname }}` (Color names from [here](https://github.com/jesseduffield/lazygit/blob/master/docs/Config.md)). If `labelFormat` is not specified, `valueFormat` is shown instead. PS: named groups keep first match only | no |
+| type | One of 'input', 'confirm', 'menu', 'menuFromCommand' | yes |
+| title | The title to display in the popup panel | no |
+| key | Used to reference the entered value from within the custom command. E.g. a prompt with `key: 'Branch'` can be referred to as `{{.Form.Branch}}` in the command | yes |
+
+### Input
+
+| _field_ | _description_ | _required_ |
+| ------------ | -----------------------------------------------------------------------------------------------| ---------- |
+| initialValue | The initial value to appear in the text box | no |
+| suggestions | Shows suggestions as the input is entered. See below for details | no |
+
+The permitted suggestions fields are:
+| _field_ | _description_ | _required_ |
+|-----------------|----------------------|-|
+| preset | Uses built-in logic to obtain the suggestions. One of 'files', 'branches', 'remotes', 'remoteBranches', 'refs' | no |
+| command | Command to run such that each line in the output becomes a suggestion. Mutually exclusive with 'preset' field. | no |
+
+Here's an example of passing a preset:
+
+```yml
+customCommands:
+ - key: 'a'
+ command: 'echo {{.Form.Branch | quote}}'
+ context: 'commits'
+ prompts:
+ - type: 'input'
+ title: 'Which branch?'
+ key: 'Branch'
+ suggestions:
+ preset: 'branches' # use built-in logic for obtaining branches
+```
+
+Here's an example of passing a command directly:
+
+```yml
+customCommands:
+ - key: 'a'
+ command: 'echo {{.Form.Branch | quote}}'
+ context: 'commits'
+ prompts:
+ - type: 'input'
+ title: 'Which branch?'
+ key: 'Branch'
+ suggestions:
+ command: "git branch --format='%(refname:short)'"
+```
+
+
+Here's an example of passing an initial value for the input:
+
+```yml
+customCommands:
+ - key: 'a'
+ command: 'echo {{.Form.Remote | quote}}'
+ context: 'commits'
+ prompts:
+ - type: 'input'
+ title: 'Remote:'
+ key: 'Remote'
+ initialValue: "{{.SelectedRemote.Name}}"
+```
+
+### Confirm
+
+| _field_ | _description_ | _required_ |
+| ------------ | -----------------------------------------------------------------------------------------------| ---------- |
+| body | The immutable body text to appear in the text box | no |
+
+Example:
+
+```yml
+customCommands:
+ - key: 'a'
+ command: 'echo "pushing to remote"'
+ context: 'commits'
+ prompts:
+ - type: 'confirm'
+ title: 'Push to remote'
+ body: 'Are you sure you want to push to the remote?'
+```
+
+### Menu
+
+| _field_ | _description_ | _required_ |
+| ------------ | -----------------------------------------------------------------------------------------------| ---------- |
+| options | The options to display in the menu | yes |
The permitted option fields are:
| _field_ | _description_ | _required_ |
|-----------------|----------------------|-|
-| name | the string which will appear first on the line | no |
-| description | the string which will appear second on the line | no |
-| value | the value that will be stored in `.PromptResponses` if the option is selected | yes |
+| name | The first part of the label | no |
+| description | The second part of the label | no |
+| value | the value that will be used in the command | yes |
If an option has no name the value will be displayed to the user in place of the name, so you're allowed to only include the value like so:
```yml
+customCommands:
+ - key: 'a'
+ command: 'echo {{.Form.BranchType | quote}}'
+ context: 'commits'
+ prompts:
+ - type: 'menu'
+ title: 'What kind of branch is it?'
+ key: 'BranchType'
+ options:
+ - value: 'feature'
+ - value: 'hotfix'
+ - value: 'release'
+```
+
+Here's an example of supplying more detail for each option:
+
+```yml
+customCommands:
+ - key: 'a'
+ command: 'echo {{.Form.BranchType | quote}}'
+ context: 'commits'
prompts:
- type: 'menu'
title: 'What kind of branch is it?'
+ key: 'BranchType'
options:
- value: 'feature'
+ name: 'feature branch'
+ description: 'branch based off develop'
- value: 'hotfix'
+ name: 'hotfix branch'
+ description: 'branch based off main for fast bug fixes'
- value: 'release'
+ name: 'release branch'
+ description: 'branch for a release'
+```
+
+### Menu-from-command
+
+| _field_ | _description_ | _required_ |
+| ------------ | -----------------------------------------------------------------------------------------------| ---------- |
+| command | The command to run to generate menu options | yes |
+| filter | The regexp to run specifying groups which are going to be kept from the command's output | no |
+| valueFormat | How to format matched groups from the filter to construct a menu item's value | no |
+| labelFormat | Like valueFormat but for the labels. If `labelFormat` is not specified, `valueFormat` is shown instead. | no |
+
+Here's an example using named groups in the regex. Notice how we can pipe the label to a colour function for coloured output (available colours [here](https://github.com/jesseduffield/lazygit/blob/master/docs/Config.md))
+
+```yml
+ - key : 'a'
+ description: 'Checkout a remote branch as FETCH_HEAD'
+ command: "git fetch {{.Form.Remote}} {{.Form.Branch}} && git checkout FETCH_HEAD"
+ context: 'remotes'
+ prompts:
+ - type: 'menuFromCommand'
+ title: 'Remote branch:'
+ key: 'Branch'
+ command: 'git branch -r --list {{.SelectedRemote.Name }}/*'
+ filter: '.*{{.SelectedRemote.Name }}/(?P<branch>.*)'
+ valueFormat: '{{ .branch }}'
+ labelFormat: '{{ .branch | green }}'
+```
+
+Here's an example using unnamed groups:
+
+```yml
+ - key : 'a'
+ description: 'Checkout a remote branch as FETCH_HEAD'
+ command: "git fetch {{.Form.Remote}} {{.Form.Branch}} && git checkout FETCH_HEAD"
+ context: 'remotes'
+ prompts:
+ - type: 'menuFromCommand'
+ title: 'Remote branch:'
+ key: 'Branch'
+ command: 'git branch -r --list {{.SelectedRemote.Name }}/*'
+ filter: '.*{{.SelectedRemote.Name }}/(.*)'
+ valueFormat: '{{ .group_1 }}'
+ labelFormat: '{{ .group_1 | green }}'
```
-### Placeholder values
+## Placeholder values
Your commands can contain placeholder strings using Go's [template syntax](https://jan.newmarch.name/golang/template/chapter-template.html). The template syntax is pretty powerful, letting you do things like conditionals if you want, but for the most part you'll simply want to be accessing the fields on the following objects:
@@ -154,16 +283,16 @@ SelectedCommitFile
CheckedOutBranch
```
-To see what fields are available on e.g. the `SelectedFile`, see [here](https://github.com/jesseduffield/lazygit/blob/master/pkg/commands/models/file.go) (all the modelling lives in the same directory). Note that the custom commands feature does not guarantee backwards compatibility (until we hit lazygit version 1.0 of course) which means a field you're accessing on an object may no longer be available from one release to the next. Typically however, all you'll need is `{{.SelectedFile.Name}}`, `{{.SelectedLocalCommit.Sha}}` and `{{.SelectedLocalBranch.Name}}`. In the future we will likely introduce a tighter interface that exposes a limited set of fields for each model.
+To see what fields are available on e.g. the `SelectedFile`, see [here](https://github.com/jesseduffield/lazygit/blob/master/pkg/commands/models/file.go) (all the modelling lives in the same directory). Note that the custom commands feature does not guarantee backwards compatibility (until we hit Lazygit version 1.0 of course) which means a field you're accessing on an object may no longer be available from one release to the next. Typically however, all you'll need is `{{.SelectedFile.Name}}`, `{{.SelectedLocalCommit.Sha}}` and `{{.SelectedLocalBranch.Name}}`. In the future we will likely introduce a tighter interface that exposes a limited set of fields for each model.
-### Keybinding collisions
+## Keybinding collisions
If your custom keybinding collides with an inbuilt keybinding that is defined for the same context, only the custom keybinding will be executed. This also applies to the global context. However, one caveat is that if you have a custom keybinding defined on the global context for some key, and there is an in-built keybinding defined for the same key and for a specific context (say the 'files' context), then the in-built keybinding will take precedence. See how to change in-built keybindings [here](https://github.com/jesseduffield/lazygit/blob/master/docs/Config.md#keybindings)
-### Debugging
+## Debugging
-If you want to verify that your command actually does what you expect, you can wrap it in an 'echo' call and set `showOutput: true` so that it doesn't actually execute the command but you can see how the placeholders were resolved. Alternatively you can run lazygit in debug mode with `lazygit --debug` and in another terminal window run `lazygit --logs` to see which commands are actually run
+If you want to verify that your command actually does what you expect, you can wrap it in an 'echo' call and set `showOutput: true` so that it doesn't actually execute the command but you can see how the placeholders were resolved.
-### More Examples
+## More Examples
See the [wiki](https://github.com/jesseduffield/lazygit/wiki/Custom-Commands-Compendium) page for more examples, and feel free to add your own custom commands to this page so others can benefit!
diff --git a/pkg/config/user_config.go b/pkg/config/user_config.go
index 27ae17953..9f46948b5 100644
--- a/pkg/config/user_config.go
+++ b/pkg/config/user_config.go
@@ -358,16 +358,14 @@ type CustomCommand struct {
}
type CustomCommandPrompt struct {
- Key string `yaml:"key"`
-
// one of 'input', 'menu', 'confirm', or 'menuFromCommand'
- Type string `yaml:"type"`
-
+ Type string `yaml:"type"`
+ Key string `yaml:"key"`
Title string `yaml:"title"`
- // this only apply to input prompts
- InitialValue string `yaml:"initialValue"`
- SuggestionsPreset string `yaml:"suggestionsPreset"`
+ // these only apply to input prompts
+ InitialValue string `yaml:"initialValue"`
+ Suggestions CustomCommandSuggestions `yaml:"suggestions"`
// this only applies to confirm prompts
Body string `yaml:"body"`
@@ -382,6 +380,11 @@ type CustomCommandPrompt struct {
LabelFormat string `yaml:"labelFormat"`
}
+type CustomCommandSuggestions struct {
+ Preset string `yaml:"preset"`
+ Command string `yaml:"command"`
+}
+
type CustomCommandMenuOption struct {
Name string `yaml:"name"`
Description string `yaml:"description"`
diff --git a/pkg/gui/services/custom_commands/handler_creator.go b/pkg/gui/services/custom_commands/handler_creator.go
index 2d13a6f55..8e6700f72 100644
--- a/pkg/gui/services/custom_commands/handler_creator.go
+++ b/pkg/gui/services/custom_commands/handler_creator.go
@@ -11,6 +11,7 @@ import (
"github.com/jesseduffield/lazygit/pkg/gui/style"
"github.com/jesseduffield/lazygit/pkg/gui/types"
"github.com/jesseduffield/lazygit/pkg/utils"
+ "github.com/samber/lo"
)
// takes a custom command and returns a function that will be called when the corresponding user-defined keybinding is pressed
@@ -108,13 +109,9 @@ func (self *HandlerCreator) call(customCommand config.CustomCommand) func() erro
}
func (self *HandlerCreator) inputPrompt(prompt *config.CustomCommandPrompt, wrappedF func(string) error) error {
- var findSuggestionsFn func(string) []*types.Suggestion
- if prompt.SuggestionsPreset != "" {
- var err error
- findSuggestionsFn, err = self.getPresetSuggestionsFn(prompt.SuggestionsPreset)
- if err != nil {
- return err
- }
+ findSuggestionsFn, err := self.generateFindSuggestionsFunc(prompt)
+ if err != nil {
+ return self.c.Error(err)
}
return self.c.Prompt(types.PromptOpts{
@@ -127,6 +124,41 @@ func (self *HandlerCreator) inputPrompt(prompt *config.CustomCommandPrompt, wrap
})
}
+func (self *HandlerCreator) generateFindSuggestionsFunc(prompt *config.CustomCommandPrompt) (func(string) []*types.Suggestion, error) {
+ if prompt.Suggestions.Preset != "" && prompt.Suggestions.Command != "" {
+ return nil, fmt.Errorf(
+ fmt.Sprintf(
+ "Custom command prompt cannot have both a preset and a command for suggestions. Preset: '%s', Command: '%s'",
+ prompt.Suggestions.Preset,
+ prompt.Suggestions.Command,
+ ),
+ )
+ } else if prompt.Suggestions.Preset != "" {
+ return self.getPresetSuggestionsFn(prompt.Suggestions.Preset)
+ } else if prompt.Suggestions.Command != "" {
+ return self.getCommandSuggestionsFn(prompt.Suggestions.Command)
+ }
+
+ return nil, nil
+}
+
+func (self *HandlerCreator) getCommandSuggestionsFn(command string) (func(string) []*types.Suggestion, error) {
+ lines := []*types.Suggestion{}
+ err := self.c.OS().Cmd.NewShell(command).RunAndProcessLines(func(line string) (bool, error) {
+ lines = append(lines, &types.Suggestion{Value: line, Label: line})
+ return false, nil
+ })
+ if err != nil {
+ return nil, err
+ }
+
+ return func(currentWord string) []*types.Suggestion {
+ return lo.Filter(lines, func(suggestion *types.Suggestion, _ int) bool {
+ return strings.Contains(strings.ToLower(suggestion.Value), strings.ToLower(currentWord))
+ })
+ }, nil
+}
+
func (self *HandlerCreator) getPresetSuggestionsFn(preset string) (func(string) []*types.Suggestion, error) {
switch preset {
case "files":
@@ -144,6 +176,14 @@ func (self *HandlerCreator) getPresetSuggestionsFn(preset string) (func(string)
}
}
+func (self *HandlerCreator) confirmPrompt(prompt *config.CustomCommandPrompt, handleConfirm func() error) error {
+ return self.c.Confirm(types.ConfirmOpts{
+ Title: prompt.Title,
+ Prompt: prompt.Body,
+ HandleConfirm: handleConfirm,
+ })
+}
+
func (self *HandlerCreator) menuPrompt(prompt *config.CustomCommandPrompt, wrappedF func(string) error) error {
menuItems := slices.Map(prompt.Options, func(option config.CustomCommandMenuOption) *types.MenuItem {
return &types.MenuItem{
@@ -157,14 +197,6 @@ func (self *HandlerCreator) menuPrompt(prompt *config.CustomCommandPrompt, wrapp
return self.c.Menu(types.CreateMenuOptions{Title: prompt.Title, Items: menuItems})
}
-func (self *HandlerCreator) confirmPrompt(prompt *config.CustomCommandPrompt, handleConfirm func() error) error {
- return self.c.Confirm(types.ConfirmOpts{
- Title: prompt.Title,
- Prompt: prompt.Body,
- HandleConfirm: handleConfirm,
- })
-}
-
func (self *HandlerCreator) menuPromptFromCommand(prompt *config.CustomCommandPrompt, wrappedF func(string) error) error {
// Run and save output
message, err := self.c.Git().Custom.RunWithOutput(prompt.Command)
diff --git a/pkg/gui/services/custom_commands/resolver.go b/pkg/gui/services/custom_commands/resolver.go
index 119581bfc..67dd7be2d 100644
--- a/pkg/gui/services/custom_commands/resolver.go
+++ b/pkg/gui/services/custom_commands/resolver.go
@@ -34,7 +34,12 @@ func (self *Resolver) resolvePrompt(
return nil, err
}
- result.SuggestionsPreset, err = resolveTemplate(prompt.SuggestionsPreset)
+ result.Suggestions.Preset, err = resolveTemplate(prompt.Suggestions.Preset)
+ if err != nil {
+ return nil, err
+ }
+
+ result.Suggestions.Command, err = resolveTemplate(prompt.Suggestions.Command)
if err != nil {
return nil, err
}
diff --git a/pkg/integration/tests/custom_commands/suggestions_command.go b/pkg/integration/tests/custom_commands/suggestions_command.go
new file mode 100644
index 000000000..f54ec1bae
--- /dev/null
+++ b/pkg/integration/tests/custom_commands/suggestions_command.go
@@ -0,0 +1,66 @@
+package custom_commands
+
+import (
+ "github.com/jesseduffield/lazygit/pkg/config"
+ . "github.com/jesseduffield/lazygit/pkg/integration/components"
+)
+
+var SuggestionsCommand = NewIntegrationTest(NewIntegrationTestArgs{
+ Description: "Using a custom command that uses a suggestions command in a prompt step",
+ ExtraCmdArgs: []string{},
+ Skip: false,
+ SetupRepo: func(shell *Shell) {
+ shell.NewBranch("branch-one")
+ shell.EmptyCommit("blah")
+ shell.NewBranch("branch-two")
+ shell.EmptyCommit("blah")
+ shell.NewBranch("branch-three")
+ shell.EmptyCommit("blah")
+ shell.NewBranch("branch-four")
+ shell.EmptyCommit("blah")
+ },
+ SetupConfig: func(cfg *config.AppConfig) {
+ cfg.UserConfig.CustomCommands = []config.CustomCommand{
+ {
+ Key: "a",
+ Context: "localBranches",
+ Command: `git checkout {{.Form.Branch}}`,
+ Prompts: []config.CustomCommandPrompt{
+ {
+ Key: "Branch",
+ Type: "input",
+ Title: "Enter a branch name",
+ Suggestions: config.CustomCommandSuggestions{
+ Command: "git branch --format='%(refname:short)'",
+ },
+ },
+ },
+ },
+ }
+ },
+ Run: func(t *TestDriver, keys config.KeybindingConfig) {
+ t.Views().Branches().
+ Focus().
+ Lines(
+ Contains("branch-four").IsSelected(),
+ Contains("branch-three"),
+ Contains("branch-two"),
+ Contains("branch-one"),
+ ).
+ Press("a")
+
+ t.ExpectPopup().Prompt().
+ Title(Equals("Enter a branch name")).
+ Type("three").
+ SuggestionLines(Contains("branch-three")).
+ ConfirmFirstSuggestion()
+
+ t.Views().Branches().
+ Lines(
+ Contains("branch-three").IsSelected(),
+ Contains("branch-four"),
+ Contains("branch-two"),
+ Contains("branch-one"),
+ )
+ },
+})
diff --git a/pkg/integration/tests/custom_commands/suggestions_preset.go b/pkg/integration/tests/custom_commands/suggestions_preset.go
index 894e3b1fe..40c888625 100644
--- a/pkg/integration/tests/custom_commands/suggestions_preset.go
+++ b/pkg/integration/tests/custom_commands/suggestions_preset.go
@@ -27,10 +27,12 @@ var SuggestionsPreset = NewIntegrationTest(NewIntegrationTestArgs{
Command: `git checkout {{.Form.Branch}}`,
Prompts: []config.CustomCommandPrompt{
{
- Key: "Branch",
- Type: "input",
- Title: "Enter a branch name",
- SuggestionsPreset: "branches",
+ Key: "Branch",
+ Type: "input",
+ Title: "Enter a branch name",
+ Suggestions: config.CustomCommandSuggestions{
+ Preset: "branches",
+ },
},
},
},
diff --git a/pkg/integration/tests/test_list.go b/pkg/integration/tests/test_list.go
index e0800f7bd..50377f101 100644
--- a/pkg/integration/tests/test_list.go
+++ b/pkg/integration/tests/test_list.go
@@ -77,6 +77,7 @@ var tests = []*components.IntegrationTest{
custom_commands.MenuFromCommandsOutput,
custom_commands.MultiplePrompts,
custom_commands.OmitFromHistory,
+ custom_commands.SuggestionsCommand,
custom_commands.SuggestionsPreset,
diff.Diff,
diff.DiffAndApplyPatch,