Skip to content

Commit 2503227

Browse files
committedMar 11, 2025··
fix: shell completions
- disables default `completion` cobra sub-command - adds a `--completion [bash|zsh|fish]` flag which will generate shell completions using cobra's built-in support - adds `installShellCompletion` to the `treefmt` package (this will need added to the nixpkgs entry after release) The completions are static and address the first half of #529. Signed-off-by: Brian McGee <[email protected]>
1 parent 2449507 commit 2503227

File tree

4 files changed

+82
-14
lines changed

4 files changed

+82
-14
lines changed
 

‎cmd/completions.go

+29
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
package cmd
2+
3+
import (
4+
"fmt"
5+
"os"
6+
7+
"github.com/spf13/cobra"
8+
)
9+
10+
func generateShellCompletions(cmd *cobra.Command, args []string) error {
11+
var err error
12+
13+
switch args[0] {
14+
case "bash":
15+
err = cmd.Root().GenBashCompletion(os.Stdout)
16+
case "zsh":
17+
err = cmd.Root().GenZshCompletion(os.Stdout)
18+
case "fish":
19+
err = cmd.Root().GenFishCompletion(os.Stdout, true)
20+
default:
21+
err = fmt.Errorf("unsupported shell: %s", args[0])
22+
}
23+
24+
if err != nil {
25+
err = fmt.Errorf("failed to generate shell completions: %w", err)
26+
}
27+
28+
return err
29+
}

‎cmd/root.go

+29-13
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,6 @@ import (
1616
)
1717

1818
func NewRoot() (*cobra.Command, *stats.Stats) {
19-
var (
20-
treefmtInit bool
21-
configFile string
22-
)
23-
2419
// create a viper instance for reading in config
2520
v, err := config.NewViper()
2621
if err != nil {
@@ -35,6 +30,9 @@ func NewRoot() (*cobra.Command, *stats.Stats) {
3530
Use: build.Name + " <paths...>",
3631
Short: "The formatter multiplexer",
3732
Version: build.Version,
33+
CompletionOptions: cobra.CompletionOptions{
34+
DisableDefaultCmd: true,
35+
},
3836
RunE: func(cmd *cobra.Command, args []string) error {
3937
return runE(v, &statz, cmd, args)
4038
},
@@ -53,17 +51,25 @@ func NewRoot() (*cobra.Command, *stats.Stats) {
5351

5452
cmd.HelpTemplate()
5553

56-
// add a couple of special flags which don't have a corresponding entry in treefmt.toml
57-
fs.StringVar(
58-
&configFile, "config-file", "",
54+
// add a config file flag and some others for special subcommands
55+
fs.String(
56+
"config-file", "",
5957
"Load the config file from the given path (defaults to searching upwards for treefmt.toml or "+
6058
".treefmt.toml).",
6159
)
62-
fs.BoolVarP(
63-
&treefmtInit, "init", "i", false,
60+
61+
// add a flag for the init sub command
62+
fs.BoolP(
63+
"init", "i", false,
6464
"Create a treefmt.toml file in the current directory.",
6565
)
6666

67+
// add a flag for generating shell completions
68+
fs.String(
69+
"completion", "",
70+
"[bash|zsh|fish] Generate shell completion scripts for the specified shell.",
71+
)
72+
6773
// bind our command's flags to viper
6874
if err := v.BindPFlags(fs); err != nil {
6975
cobra.CheckErr(fmt.Errorf("failed to bind global config to viper: %w", err))
@@ -91,9 +97,19 @@ func runE(v *viper.Viper, statz *stats.Stats, cmd *cobra.Command, args []string)
9197
if init, err := flags.GetBool("init"); err != nil {
9298
return fmt.Errorf("failed to read init flag: %w", err)
9399
} else if init {
94-
err := _init.Run()
95-
if err != nil {
96-
return fmt.Errorf("failed to run init command: %w", err)
100+
if initErr := _init.Run(); initErr != nil {
101+
return fmt.Errorf("failed to run init command: %w", initErr)
102+
}
103+
104+
return nil
105+
}
106+
107+
// check if we are running the completion command
108+
if shell, err := flags.GetString("completion"); err != nil {
109+
return fmt.Errorf("failed to read completion flag: %w", err)
110+
} else if shell != "" {
111+
if completionsErr := generateShellCompletions(cmd, []string{shell}); completionsErr != nil {
112+
return fmt.Errorf("failed to generate shell completions: %w", completionsErr)
97113
}
98114

99115
return nil

‎docs/content/getting-started/usage.md

+11
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ Flags:
1414
--allow-missing-formatter Do not exit with error if a configured formatter is missing. (env $TREEFMT_ALLOW_MISSING_FORMATTER)
1515
--ci Runs treefmt in a CI mode, enabling --no-cache, --fail-on-change and adjusting some other settings best suited to a CI use case. (env $TREEFMT_CI)
1616
-c, --clear-cache Reset the evaluation cache. Use in case the cache is not precise enough. (env $TREEFMT_CLEAR_CACHE)
17+
--completion string [bash|zsh|fish] Generate shell completion scripts for the specified shell.
1718
--config-file string Load the config file from the given path (defaults to searching upwards for treefmt.toml or .treefmt.toml).
1819
--cpu-profile string The file into which a cpu profile will be written. (env $TREEFMT_CPU_PROFILE)
1920
--excludes strings Exclude files or directories matching the specified globs. (env $TREEFMT_EXCLUDES)
@@ -126,6 +127,16 @@ in
126127
flake.defaultNix
127128
```
128129

130+
## Shell Completion
131+
132+
To generate completions for your preferred shell:
133+
134+
```console
135+
treefmt --completion bash
136+
treefmt --completion fish
137+
treefmt --completion zsh
138+
```
139+
129140
## CI integration
130141

131142
We recommend using the [CI option](./configure.md#ci) in continuous integration environments.

‎nix/packages/treefmt/default.nix

+13-1
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,10 @@ in
4747
];
4848

4949
nativeBuildInputs =
50-
[pkgs.git]
50+
(with pkgs; [
51+
git
52+
installShellFiles
53+
])
5154
++
5255
# we need some formatters available for the tests
5356
import ./formatters.nix pkgs;
@@ -63,6 +66,15 @@ in
6366
git config --global user.name "Treefmt Test"
6467
'';
6568

69+
postInstall = ''
70+
export HOME=$PWD
71+
72+
installShellCompletion --cmd treefmt \
73+
--bash <($out/bin/treefmt --completion bash) \
74+
--fish <($out/bin/treefmt --completion fish) \
75+
--zsh <($out/bin/treefmt --completion zsh)
76+
'';
77+
6678
passthru = let
6779
inherit (perSystem.self) treefmt;
6880
in {

0 commit comments

Comments
 (0)
Please sign in to comment.