Skip to content

Commit 4a5330a

Browse files
umbynosper1234
andcommitted
add basic implementation of tab completion (#663)
* add basic implementation of bash completion * update cobra to 1.0.0 because of spf13/cobra#1048 * add support for zsh and fish, improved help messages * add flag ´--no-descriptions´ to disable automatic command description (for shells that supports it) * fix fish not supporting env variables with dash in the name * fixed zsh completion not working * revert "#compdef" patch * add check on --no-description flag add comments regarding "hacks" change Replacer with ReplaceAll (for readability) * add docs * Apply suggestions from code review fix typos and corrections Co-authored-by: per1234 <[email protected]> * forgot a space * fix fish docs * add test for completion Co-authored-by: per1234 <[email protected]>
1 parent 3b18571 commit 4a5330a

File tree

8 files changed

+199
-2
lines changed

8 files changed

+199
-2
lines changed

Diff for: cli/cli.go

+2
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ import (
2424
"github.com/arduino/arduino-cli/cli/board"
2525
"github.com/arduino/arduino-cli/cli/cache"
2626
"github.com/arduino/arduino-cli/cli/compile"
27+
"github.com/arduino/arduino-cli/cli/completion"
2728
"github.com/arduino/arduino-cli/cli/config"
2829
"github.com/arduino/arduino-cli/cli/core"
2930
"github.com/arduino/arduino-cli/cli/daemon"
@@ -77,6 +78,7 @@ func createCliCommandTree(cmd *cobra.Command) {
7778
cmd.AddCommand(board.NewCommand())
7879
cmd.AddCommand(cache.NewCommand())
7980
cmd.AddCommand(compile.NewCommand())
81+
cmd.AddCommand(completion.NewCommand())
8082
cmd.AddCommand(config.NewCommand())
8183
cmd.AddCommand(core.NewCommand())
8284
cmd.AddCommand(daemon.NewCommand())

Diff for: cli/completion/completion.go

+76
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
// This file is part of arduino-cli.
2+
//
3+
// Copyright 2020 ARDUINO SA (http://www.arduino.cc/)
4+
//
5+
// This software is released under the GNU General Public License version 3,
6+
// which covers the main part of arduino-cli.
7+
// The terms of this license can be found at:
8+
// https://www.gnu.org/licenses/gpl-3.0.en.html
9+
//
10+
// You can be released from the requirements of the above licenses by purchasing
11+
// a commercial license. Buying such a license is mandatory if you want to
12+
// modify or otherwise use the software for commercial activities involving the
13+
// Arduino software without disclosing the source code of your own applications.
14+
// To purchase a commercial license, send an email to [email protected].
15+
16+
package completion
17+
18+
import (
19+
"bytes"
20+
"os"
21+
"strings"
22+
23+
"github.com/arduino/arduino-cli/cli/errorcodes"
24+
"github.com/arduino/arduino-cli/cli/feedback"
25+
"github.com/spf13/cobra"
26+
)
27+
28+
var (
29+
completionNoDesc bool //Disable completion description for shells that support it
30+
)
31+
32+
// NewCommand created a new `version` command
33+
func NewCommand() *cobra.Command {
34+
command := &cobra.Command{
35+
Use: "completion [bash|zsh|fish] [--no-descriptions]",
36+
ValidArgs: []string{"bash", "zsh", "fish"},
37+
Args: cobra.ExactArgs(1),
38+
Short: "Generates completion scripts",
39+
Long: "Generates completion scripts for various shells",
40+
Example: " " + os.Args[0] + " completion bash > completion.sh\n" +
41+
" " + "source completion.sh",
42+
Run: run,
43+
}
44+
command.Flags().BoolVar(&completionNoDesc, "no-descriptions", false, "Disable completion description for shells that support it")
45+
46+
return command
47+
}
48+
49+
func run(cmd *cobra.Command, args []string) {
50+
if completionNoDesc && (args[0] == "bash" || args[0] == "zsh") {
51+
feedback.Errorf("Error: command description is not supported by %v", args[0])
52+
os.Exit(errorcodes.ErrGeneric)
53+
}
54+
switch args[0] {
55+
case "bash":
56+
cmd.Root().GenBashCompletion(os.Stdout)
57+
break
58+
case "zsh":
59+
buf := new(bytes.Buffer)
60+
cmd.Root().GenZshCompletion(buf)
61+
// Next 3 lines are Hack, we'll wait new version of cobra with ZshV2Completion https://github.com/spf13/cobra/pull/1070
62+
//insert escaping before [ and ]
63+
s := strings.ReplaceAll(buf.String(), "[", "\\[")
64+
s = strings.ReplaceAll(s, "]", "\\]")
65+
s = strings.ReplaceAll(s, "\\[1\\]", "[1]") // revert the case
66+
os.Stdout.WriteString(s)
67+
break
68+
case "fish":
69+
buf := new(bytes.Buffer)
70+
cmd.Root().GenFishCompletion(buf, !completionNoDesc)
71+
// Next 2 lines are Hack, fixed here https://github.com/spf13/cobra/pull/1122
72+
s := strings.ReplaceAll(buf.String(), "arduino-cli_comp", "arduino_cli_comp") //required because fish does not support env variables with "-" in the name
73+
os.Stdout.WriteString(s)
74+
break
75+
}
76+
}

Diff for: docs/command-line-completion.md

+45
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
`arduino-cli` supports command-line completion (also known as *tab completion*) for basic commands.
2+
Currently only `bash`, `zsh`, `fish` shells are supported
3+
4+
### Before you start
5+
In order to generate the file required to make the completion work you have to [install](installation.md) Arduino CLI first.
6+
7+
### Generate the completion file
8+
To generate the completion file you can use `arduino-cli completion [bash|zsh|fish] [--no-descriptions]`.
9+
By default this command will print on the standard output (the shell window) the content of the completion file. To save to an actual file use the `>` redirect symbol.
10+
11+
### Bash
12+
Use `arduino-cli completion bash > arduino-cli.sh` to generate the completion file.
13+
At this point you can move that file in `/etc/bash_completion.d/` (root access is required) with `sudo mv arduino-cli.sh /etc/bash_completion.d/`.
14+
15+
A not recommended alternative is to source the completion file in `.bashrc`.
16+
17+
Remember to open a new shell to test the functionality
18+
19+
### Zsh
20+
Use `arduino-cli completion zsh > _arduino-cli` to generate the completion file.
21+
At this point you can place the file in a directory listed in your `fpath` if you have already created a directory to store your completion.
22+
23+
Or if you want you can create a directory, add it to your `fpath` and copy the file in it:
24+
25+
1. `mkdir ~/completion_zsh`
26+
2. add `fpath=($HOME/completion_zsh $fpath)` at the beginning of your `.zshrc` file
27+
3. `mv _arduino-cli ~/completion_zsh/`
28+
29+
Remember to open a new shell to test the functionality
30+
31+
*N.B.*
32+
The Zsh completion is working with [Oh-My-Zsh](https://ohmyz.sh/) but not with [Prezto](https://github.com/sorin-ionescu/prezto) (the zsh completion system is working in a different way than classic zsh). But hopefully it will be fixed in the future
33+
34+
### Fish
35+
Use `arduino-cli completion fish > arduino-cli.fish` to generate the completion file.
36+
At this point you can place the file in `~/.config/fish/completions` as stated in the [official documentation](http://fishshell.com/docs/current/index.html#where-to-put-completions).
37+
Remember to create the directory if it's not already there `mkdir -p ~/.config/fish/completions/` and then place the completion file in there with `mv arduino-cli.fish ~/.config/fish/completions/`
38+
39+
Remember to open a new shell to test the functionality
40+
41+
#### Disabling command and flag descriptions
42+
By default fish completion has command and flag description enabled by default. If you want to disable this behaviour you can simply pass the `--no-descriptions` flag when calling `completion` command and the generated file will not have descriptions
43+
44+
*N.B.*
45+
This flag is not compatible with bash or zsh

Diff for: docsgen/go.mod

+1-1
Original file line numberDiff line numberDiff line change
@@ -6,5 +6,5 @@ replace github.com/arduino/arduino-cli => ../
66

77
require (
88
github.com/arduino/arduino-cli v0.0.0
9-
github.com/spf13/cobra v0.0.6
9+
github.com/spf13/cobra v1.0.0
1010
)

Diff for: go.mod

+1-1
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ require (
3636
github.com/schollz/closestmatch v2.1.0+incompatible
3737
github.com/segmentio/stats/v4 v4.5.3
3838
github.com/sirupsen/logrus v1.4.2
39-
github.com/spf13/cobra v0.0.5
39+
github.com/spf13/cobra v1.0.0
4040
github.com/spf13/jwalterweatherman v1.0.0
4141
github.com/spf13/viper v1.6.2
4242
github.com/stretchr/testify v1.4.0

Diff for: go.sum

+9
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,8 @@ github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7
4444
github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
4545
github.com/cpuguy83/go-md2man v1.0.10 h1:BSKMNlYxDvnunlTymqtgONjNnaRV1sTpcovwwjF22jk=
4646
github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE=
47+
github.com/cpuguy83/go-md2man/v2 v2.0.0 h1:EoUDS0afbrsXAZ9YQ9jdu/mZ2sXgT1/2yyNng4PGlyM=
48+
github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
4749
github.com/creack/goselect v0.1.1 h1:tiSSgKE1eJtxs1h/VgGQWuXUP0YS4CDIFMp6vaI1ls0=
4850
github.com/creack/goselect v0.1.1/go.mod h1:a/NhLweNvqIYMuxcMOuWY516Cimucms3DglDzQP3hKY=
4951
github.com/daaku/go.zipexe v1.0.0 h1:VSOgZtH418pH9L16hC/JrgSNJbbAL26pj7lmD1+CGdY=
@@ -175,6 +177,8 @@ github.com/rifflock/lfshook v0.0.0-20180920164130-b9218ef580f5/go.mod h1:GEXHk5H
175177
github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
176178
github.com/russross/blackfriday v1.5.2 h1:HyvC0ARfnZBqnXwABFeSZHpKvJHJJfPz81GNueLj0oo=
177179
github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=
180+
github.com/russross/blackfriday/v2 v2.0.1 h1:lPqVAte+HuHNfhJ/0LC98ESWRz8afy9tM/0RK8m9o+Q=
181+
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
178182
github.com/schollz/closestmatch v2.1.0+incompatible h1:Uel2GXEpJqOWBrlyI+oY9LTiyyjYS17cCYRqP13/SHk=
179183
github.com/schollz/closestmatch v2.1.0+incompatible/go.mod h1:RtP1ddjLong6gTkbtmuhtR2uUrrJOpYzYRvbcPAid+g=
180184
github.com/segmentio/fasthash v0.0.0-20180216231524-a72b379d632e h1:uO75wNGioszjmIzcY/tvdDYKRLVvzggtAmmJkn9j4GQ=
@@ -183,6 +187,8 @@ github.com/segmentio/objconv v1.0.1 h1:QjfLzwriJj40JibCV3MGSEiAoXixbp4ybhwfTB8RX
183187
github.com/segmentio/objconv v1.0.1/go.mod h1:auayaH5k3137Cl4SoXTgrzQcuQDmvuVtZgS0fb1Ahys=
184188
github.com/segmentio/stats/v4 v4.5.3 h1:Y/DSUWZ4c8ICgqJ9rQohzKvGqGWbLPWad5zmxVoKN+Y=
185189
github.com/segmentio/stats/v4 v4.5.3/go.mod h1:LsaahUJR7iiSs8mnkvQvdQ/RLHAS5adGLxuntg0ydGo=
190+
github.com/shurcooL/sanitized_anchor_name v1.0.0 h1:PdmoCO6wvbs+7yrJyMORt4/BmY5IYyJwS/kOiWx8mHo=
191+
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
186192
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
187193
github.com/sirupsen/logrus v1.4.2 h1:SPIRibHv4MatM3XXNO2BJeFLZwZ2LvZgfQ5+UNI2im4=
188194
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
@@ -198,12 +204,15 @@ github.com/spf13/cast v1.3.0 h1:oget//CVOEoFewqQxwr0Ej5yjygnqGkvggSE/gB35Q8=
198204
github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
199205
github.com/spf13/cobra v0.0.5 h1:f0B+LkLX6DtmRH1isoNA9VTtNUK9K8xYd28JNNfOv/s=
200206
github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU=
207+
github.com/spf13/cobra v1.0.0 h1:6m/oheQuQ13N9ks4hubMG6BnvwOeaJrqSPLahSnczz8=
208+
github.com/spf13/cobra v1.0.0/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHNrgE=
201209
github.com/spf13/jwalterweatherman v1.0.0 h1:XHEdyB+EcvlqZamSM4ZOMGlc93t6AcsBEu9Gc1vn7yk=
202210
github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo=
203211
github.com/spf13/pflag v1.0.3 h1:zPAT6CGy6wXeQ7NtTnaTerfKOsV6V6F8agHXFiazDkg=
204212
github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
205213
github.com/spf13/viper v1.3.2 h1:VUFqw5KcqRf7i70GOzW7N+Q7+gxVBkSSqiXB12+JQ4M=
206214
github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s=
215+
github.com/spf13/viper v1.4.0/go.mod h1:PTJ7Z/lr49W6bUbkmS1V3by4uWynFiR9p7+dSq/yZzE=
207216
github.com/spf13/viper v1.6.2 h1:7aKfF+e8/k68gda3LOjo5RxiUqddoFxVq4BKBPrxk5E=
208217
github.com/spf13/viper v1.6.2/go.mod h1:t3iDnF5Jlj76alVNuyFBk5oUMCvsrkbvZK0WQdfDi5k=
209218
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=

Diff for: mkdocs.yml

+2
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ nav:
5656
- Documentation Home: index.md
5757
- installation.md
5858
- getting-started.md
59+
- command-line-completion.md
5960
- CONTRIBUTING.md
6061
- FAQ.md
6162
- Command reference:
@@ -68,6 +69,7 @@ nav:
6869
- cache: commands/arduino-cli_cache.md
6970
- cache clean: commands/arduino-cli_cache_clean.md
7071
- compile: commands/arduino-cli_compile.md
72+
- completion: commands/arduino-cli_completion.md
7173
- config: commands/arduino-cli_config.md
7274
- config dump: commands/arduino-cli_config_dump.md
7375
- config init: commands/arduino-cli_config_init.md

Diff for: test/test_completion.py

+63
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
# This file is part of arduino-cli.
2+
#
3+
# Copyright 2020 ARDUINO SA (http://www.arduino.cc/)
4+
#
5+
# This software is released under the GNU General Public License version 3,
6+
# which covers the main part of arduino-cli.
7+
# The terms of this license can be found at:
8+
# https://www.gnu.org/licenses/gpl-3.0.en.html
9+
#
10+
# You can be released from the requirements of the above licenses by purchasing
11+
# a commercial license. Buying such a license is mandatory if you want to modify or
12+
# otherwise use the software for commercial activities involving the Arduino
13+
# software without disclosing the source code of your own applications. To purchase
14+
# a commercial license, send an email to [email protected].
15+
16+
import pytest
17+
18+
def test_completion_no_args(run_command):
19+
result = run_command("completion")
20+
assert not result.ok
21+
assert "Error: accepts 1 arg(s), received 0" in result.stderr
22+
assert result.stdout == ""
23+
24+
def test_completion_bash(run_command):
25+
result = run_command("completion bash")
26+
assert result.ok
27+
assert result.stderr == ""
28+
assert "_arduino-cli_root_command()" in result.stdout
29+
assert "__start_arduino-cli()" in result.stdout
30+
31+
def test_completion_zsh(run_command):
32+
result = run_command("completion zsh")
33+
assert result.ok
34+
assert result.stderr == ""
35+
assert "#compdef _arduino-cli arduino-cli" in result.stdout
36+
assert "function _arduino-cli" in result.stdout
37+
38+
def test_completion_fish(run_command):
39+
result = run_command("completion fish")
40+
assert result.ok
41+
assert result.stderr == ""
42+
assert "# fish completion for arduino-cli" in result.stdout
43+
assert "function __arduino-cli_perform_completion" in result.stdout
44+
45+
def test_completion_bash_no_desc(run_command):
46+
result = run_command("completion bash --no-descriptions")
47+
assert not result.ok
48+
assert result.stdout == ""
49+
assert "Error: command description is not supported by bash" in result.stderr
50+
51+
def test_completion_zsh_no_desc(run_command):
52+
result = run_command("completion zsh --no-descriptions")
53+
assert not result.ok
54+
assert result.stdout == ""
55+
assert "Error: command description is not supported by zsh" in result.stderr
56+
57+
def test_completion_fish_no_desc(run_command):
58+
result = run_command("completion fish --no-descriptions")
59+
assert result.ok
60+
assert result.stderr == ""
61+
assert "# fish completion for arduino-cli" in result.stdout
62+
assert "function __arduino-cli_perform_completion" in result.stdout
63+
assert "__completeNoDesc" in result.stdout

0 commit comments

Comments
 (0)