Skip to content

Commit

Permalink
fix: improve completion cmd handling (#290)
Browse files Browse the repository at this point in the history
* fix: improve completion cmd handling

The way it works today, its not possible to install the completions
automatically on Nix, as the build needs to be pure.

This is kinda hacky, but I think it'll work: we only allow the
completion cmd to run if there is good evidence that it is a completion
command, and not a prompt that happens to start with completion.

refs #287

* docs: update

* docs: wording
  • Loading branch information
caarlos0 authored Jun 18, 2024
1 parent bf1dab7 commit 5722fe6
Show file tree
Hide file tree
Showing 3 changed files with 87 additions and 11 deletions.
10 changes: 5 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -83,18 +83,18 @@ go install github.com/charmbracelet/mods@latest
```

<details>
<summary>Completions</summary>
<summary>Shell Completions</summary>

All the packages and archives come with pre-generated completion files for Bash,
ZSH, Fish, and PowerShell.

If you built it from source, you can generate them with:

```bash
__MODS_CMP_ENABLED=1 mods completion bash -h
__MODS_CMP_ENABLED=1 mods completion zsh -h
__MODS_CMP_ENABLED=1 mods completion fish -h
__MODS_CMP_ENABLED=1 mods completion powershell -h
mods completion bash -h
mods completion zsh -h
mods completion fish -h
mods completion powershell -h
```

If you use a package (like Homebrew, Debs, etc), the completions should be set
Expand Down
47 changes: 41 additions & 6 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -322,12 +322,15 @@ func main() {
// XXX: this must come after creating the config.
initFlags()

// XXX: since mods doesn't have any subcommands, Cobra won't create the
// default `completion` command.
// Forcefully create the completion related subcommands by adding a fake
// command when completions are being used.
if os.Getenv("__MODS_CMP_ENABLED") == "1" || (len(os.Args) > 1 && os.Args[1] == "__complete") {
rootCmd.AddCommand(&cobra.Command{Use: "____fake_command_to_enable_completions"})
if isCompletionCmd(os.Args) {
// XXX: since mods doesn't have any sub-commands, Cobra won't create
// the default `completion` command. Forcefully create the completion
// related sub-commands by adding a fake command when completions are
// being used.
rootCmd.AddCommand(&cobra.Command{
Use: "____fake_command_to_enable_completions",
Hidden: true,
})
rootCmd.InitDefaultCompletionCmd()
}

Expand Down Expand Up @@ -722,3 +725,35 @@ func newModelSelect() *huh.Select[string] {
Options(opts...).
Value(&config.Model)
}

func isCompletionCmd(args []string) bool {
if len(args) <= 1 {
return false
}
if args[1] == "__complete" {
return true
}
if args[1] != "completion" {
return false
}
if len(args) == 3 {

Check failure on line 739 in main.go

View workflow job for this annotation

GitHub Actions / lint-soft

Magic number: 3, in <condition> detected (mnd)
_, ok := map[string]any{
"bash": nil,
"fish": nil,
"zsh": nil,
"powershell": nil,
"-h": nil,
"--help": nil,
"help": nil,
}[args[2]]
return ok
}
if len(args) == 4 {

Check failure on line 751 in main.go

View workflow job for this annotation

GitHub Actions / lint-soft

Magic number: 4, in <condition> detected (mnd)
_, ok := map[string]any{
"-h": nil,
"--help": nil,
}[args[3]]
return ok
}
return false
}
41 changes: 41 additions & 0 deletions main_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package main

import (
"strings"
"testing"
)

func TestIsCompletionCmd(t *testing.T) {
for args, is := range map[string]bool{
"": false,
"something": false,
"something something": false,
"completion for my bash script how to": false,
"completion bash how to": false,
"completion": false,
"completion -h": true,
"completion --help": true,
"completion help": true,
"completion bash": true,
"completion fish": true,
"completion zsh": true,
"completion powershell": true,
"completion bash -h": true,
"completion fish -h": true,
"completion zsh -h": true,
"completion powershell -h": true,
"completion bash --help": true,
"completion fish --help": true,
"completion zsh --help": true,
"completion powershell --help": true,
"__complete": true,
"__complete blah blah blah": true,
} {
t.Run(args, func(t *testing.T) {
vargs := append([]string{"mods"}, strings.Fields(args)...)
if b := isCompletionCmd(vargs); b != is {
t.Errorf("%v: expected %v, got %v", vargs, is, b)
}
})
}
}

0 comments on commit 5722fe6

Please sign in to comment.