Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit 10beac7

Browse files
authored
add dynamic completion (#1509)
* add completion for `-b` or `--fqbn` for every command * add completion for `-l` or `--protocol` But does only work for connected boards and do not list every protocol installed * the previous implementation was working only with a board connected to the pc RPC was not exposing that functionality * add static completion for `--log-level, `--log-format` and `--format` * add completion for `-P` or `--programmer` & fix typo * add completion for `core uninstall` maybe could be done better (filter and remove the manually installed ones) * add completion for `core install` and `core download` * add completion for `lib uninstall` * add completion for `lib install`, `lib download` * add completion for `lib examples` * add completion for `config add`, `config remove`, `config delete` and `config set` * add completion for `lib deps` * add tests * enhance the completion for `config add` and `config remove` * add description completion suggestion for core, lib, fqbn, programmer * add completion also for `-p` or `--port` flag * remove the `toComplete` parameter from all the completion functions as of now this parameter is useless because if a string is typed in the terminal it cannot be swapped with a different one. For example if I write `arduino-cli compile -b avr<TAB><TAB>` the completion function returns all elements starting with `arduino:avr...`. So the completions are not showed because they cannot be swapped with a string that starts differently. The only shell which seems to support this seems to be zsh * fixes after rebase * update docs * add `-b` or `--fqbn` completion for the monitor command and tests * apply suggestions from code review * fixes after rebase
1 parent 6c3c864 commit 10beac7

File tree

25 files changed

+609
-217
lines changed

25 files changed

+609
-217
lines changed

‎cli/arguments/completion.go‎

Lines changed: 190 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,190 @@
1+
package arguments
2+
3+
import (
4+
"context"
5+
6+
"github.com/arduino/arduino-cli/arduino/cores"
7+
"github.com/arduino/arduino-cli/cli/instance"
8+
"github.com/arduino/arduino-cli/commands"
9+
"github.com/arduino/arduino-cli/commands/board"
10+
"github.com/arduino/arduino-cli/commands/core"
11+
"github.com/arduino/arduino-cli/commands/lib"
12+
rpc "github.com/arduino/arduino-cli/rpc/cc/arduino/cli/commands/v1"
13+
)
14+
15+
// GetInstalledBoards is an helper function useful to autocomplete.
16+
// It returns a list of fqbn
17+
// it's taken from cli/board/listall.go
18+
func GetInstalledBoards() []string {
19+
inst := instance.CreateAndInit()
20+
21+
list, _ := board.ListAll(context.Background(), &rpc.BoardListAllRequest{
22+
Instance: inst,
23+
SearchArgs: nil,
24+
IncludeHiddenBoards: false,
25+
})
26+
var res []string
27+
// transform the data structure for the completion
28+
for _, i := range list.Boards {
29+
res = append(res, i.Fqbn+"\t"+i.Name)
30+
}
31+
return res
32+
}
33+
34+
// GetInstalledProtocols is an helper function useful to autocomplete.
35+
// It returns a list of protocols available based on the installed boards
36+
func GetInstalledProtocols() []string {
37+
inst := instance.CreateAndInit()
38+
pm := commands.GetPackageManager(inst.Id)
39+
boards := pm.InstalledBoards()
40+
41+
installedProtocols := make(map[string]struct{})
42+
for _, board := range boards {
43+
for _, protocol := range board.Properties.SubTree("upload.tool").FirstLevelKeys() {
44+
if protocol == "default" {
45+
// default is used as fallback when trying to upload to a board
46+
// using a protocol not defined for it, it's useless showing it
47+
// in autocompletion
48+
continue
49+
}
50+
installedProtocols[protocol] = struct{}{}
51+
}
52+
}
53+
res := make([]string, len(installedProtocols))
54+
i := 0
55+
for k := range installedProtocols {
56+
res[i] = k
57+
i++
58+
}
59+
return res
60+
}
61+
62+
// GetInstalledProgrammers is an helper function useful to autocomplete.
63+
// It returns a list of programmers available based on the installed boards
64+
func GetInstalledProgrammers() []string {
65+
inst := instance.CreateAndInit()
66+
pm := commands.GetPackageManager(inst.Id)
67+
68+
// we need the list of the available fqbn in order to get the list of the programmers
69+
list, _ := board.ListAll(context.Background(), &rpc.BoardListAllRequest{
70+
Instance: inst,
71+
SearchArgs: nil,
72+
IncludeHiddenBoards: false,
73+
})
74+
75+
installedProgrammers := make(map[string]string)
76+
for _, board := range list.Boards {
77+
fqbn, _ := cores.ParseFQBN(board.Fqbn)
78+
_, boardPlatform, _, _, _, _ := pm.ResolveFQBN(fqbn)
79+
for programmerID, programmer := range boardPlatform.Programmers {
80+
installedProgrammers[programmerID] = programmer.Name
81+
}
82+
}
83+
84+
res := make([]string, len(installedProgrammers))
85+
i := 0
86+
for programmerID := range installedProgrammers {
87+
res[i] = programmerID + "\t" + installedProgrammers[programmerID]
88+
i++
89+
}
90+
return res
91+
}
92+
93+
// GetUninstallableCores is an helper function useful to autocomplete.
94+
// It returns a list of cores which can be uninstalled
95+
func GetUninstallableCores() []string {
96+
inst := instance.CreateAndInit()
97+
98+
platforms, _ := core.GetPlatforms(&rpc.PlatformListRequest{
99+
Instance: inst,
100+
UpdatableOnly: false,
101+
All: false,
102+
})
103+
var res []string
104+
// transform the data structure for the completion
105+
for _, i := range platforms {
106+
res = append(res, i.Id+"\t"+i.Name)
107+
}
108+
return res
109+
}
110+
111+
// GetInstallableCores is an helper function useful to autocomplete.
112+
// It returns a list of cores which can be installed/downloaded
113+
func GetInstallableCores() []string {
114+
inst := instance.CreateAndInit()
115+
116+
platforms, _ := core.PlatformSearch(&rpc.PlatformSearchRequest{
117+
Instance: inst,
118+
SearchArgs: "",
119+
AllVersions: false,
120+
})
121+
var res []string
122+
// transform the data structure for the completion
123+
for _, i := range platforms.SearchOutput {
124+
res = append(res, i.Id+"\t"+i.Name)
125+
}
126+
return res
127+
}
128+
129+
// GetInstalledLibraries is an helper function useful to autocomplete.
130+
// It returns a list of libs which are currently installed, including the builtin ones
131+
func GetInstalledLibraries() []string {
132+
return getLibraries(true)
133+
}
134+
135+
// GetUninstallableLibraries is an helper function useful to autocomplete.
136+
// It returns a list of libs which can be uninstalled
137+
func GetUninstallableLibraries() []string {
138+
return getLibraries(false)
139+
}
140+
141+
func getLibraries(all bool) []string {
142+
inst := instance.CreateAndInit()
143+
libs, _ := lib.LibraryList(context.Background(), &rpc.LibraryListRequest{
144+
Instance: inst,
145+
All: all,
146+
Updatable: false,
147+
Name: "",
148+
Fqbn: "",
149+
})
150+
var res []string
151+
// transform the data structure for the completion
152+
for _, i := range libs.InstalledLibraries {
153+
res = append(res, i.Library.Name+"\t"+i.Library.Sentence)
154+
}
155+
return res
156+
}
157+
158+
// GetInstallableLibs is an helper function useful to autocomplete.
159+
// It returns a list of libs which can be installed/downloaded
160+
func GetInstallableLibs() []string {
161+
inst := instance.CreateAndInit()
162+
163+
libs, _ := lib.LibrarySearch(context.Background(), &rpc.LibrarySearchRequest{
164+
Instance: inst,
165+
Query: "", // if no query is specified all the libs are returned
166+
})
167+
var res []string
168+
// transform the data structure for the completion
169+
for _, i := range libs.Libraries {
170+
res = append(res, i.Name+"\t"+i.Latest.Sentence)
171+
}
172+
return res
173+
}
174+
175+
// GetConnectedBoards is an helper function useful to autocomplete.
176+
// It returns a list of boards which are currently connected
177+
// Obviously it does not suggests network ports because of the timeout
178+
func GetConnectedBoards() []string {
179+
inst := instance.CreateAndInit()
180+
181+
list, _ := board.List(&rpc.BoardListRequest{
182+
Instance: inst,
183+
})
184+
var res []string
185+
// transform the data structure for the completion
186+
for _, i := range list {
187+
res = append(res, i.Port.Address)
188+
}
189+
return res
190+
}

‎cli/arguments/port.go‎

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,13 @@ type Port struct {
4242
// AddToCommand adds the flags used to set port and protocol to the specified Command
4343
func (p *Port) AddToCommand(cmd *cobra.Command) {
4444
cmd.Flags().StringVarP(&p.address, "port", "p", "", tr("Upload port address, e.g.: COM3 or /dev/ttyACM2"))
45+
cmd.RegisterFlagCompletionFunc("port", func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
46+
return GetConnectedBoards(), cobra.ShellCompDirectiveDefault
47+
})
4548
cmd.Flags().StringVarP(&p.protocol, "protocol", "l", "", tr("Upload port protocol, e.g: serial"))
49+
cmd.RegisterFlagCompletionFunc("protocol", func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
50+
return GetInstalledProtocols(), cobra.ShellCompDirectiveDefault
51+
})
4652
cmd.Flags().DurationVar(&p.timeout, "discovery-timeout", 5*time.Second, tr("Max time to wait for port discovery, e.g.: 30s, 1m"))
4753
}
4854

‎cli/board/details.go‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import (
2020
"fmt"
2121
"os"
2222

23+
"github.com/arduino/arduino-cli/cli/arguments"
2324
"github.com/arduino/arduino-cli/cli/errorcodes"
2425
"github.com/arduino/arduino-cli/cli/feedback"
2526
"github.com/arduino/arduino-cli/cli/instance"
@@ -48,6 +49,9 @@ func initDetailsCommand() *cobra.Command {
4849

4950
detailsCommand.Flags().BoolVarP(&showFullDetails, "full", "f", false, tr("Show full board details"))
5051
detailsCommand.Flags().StringVarP(&fqbn, "fqbn", "b", "", tr("Fully Qualified Board Name, e.g.: arduino:avr:uno"))
52+
detailsCommand.RegisterFlagCompletionFunc("fqbn", func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
53+
return arguments.GetInstalledBoards(), cobra.ShellCompDirectiveDefault
54+
})
5155
detailsCommand.Flags().BoolVarP(&listProgrammers, "list-programmers", "", false, tr("Show list of available programmers"))
5256
// detailsCommand.MarkFlagRequired("fqbn") // enable once `board details <fqbn>` is removed
5357

‎cli/burnbootloader/burnbootloader.go‎

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,10 +51,16 @@ func NewCommand() *cobra.Command {
5151
}
5252

5353
burnBootloaderCommand.Flags().StringVarP(&fqbn, "fqbn", "b", "", tr("Fully Qualified Board Name, e.g.: arduino:avr:uno"))
54+
burnBootloaderCommand.RegisterFlagCompletionFunc("fqbn", func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
55+
return arguments.GetInstalledBoards(), cobra.ShellCompDirectiveDefault
56+
})
5457
port.AddToCommand(burnBootloaderCommand)
5558
burnBootloaderCommand.Flags().BoolVarP(&verify, "verify", "t", false, tr("Verify uploaded binary after the upload."))
5659
burnBootloaderCommand.Flags().BoolVarP(&verbose, "verbose", "v", false, tr("Turns on verbose mode."))
5760
burnBootloaderCommand.Flags().StringVarP(&programmer, "programmer", "P", "", tr("Use the specified programmer to upload."))
61+
burnBootloaderCommand.RegisterFlagCompletionFunc("programmer", func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
62+
return arguments.GetInstalledProgrammers(), cobra.ShellCompDirectiveDefault
63+
})
5864
burnBootloaderCommand.Flags().BoolVar(&dryRun, "dry-run", false, tr("Do not perform the actual upload, just log out actions"))
5965
burnBootloaderCommand.Flags().MarkHidden("dry-run")
6066

‎cli/cli.go‎

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -105,10 +105,21 @@ func createCliCommandTree(cmd *cobra.Command) {
105105
cmd.AddCommand(version.NewCommand())
106106

107107
cmd.PersistentFlags().BoolVarP(&verbose, "verbose", "v", false, tr("Print the logs on the standard output."))
108-
cmd.PersistentFlags().String("log-level", "", tr("Messages with this level and above will be logged. Valid levels are: %s", "trace, debug, info, warn, error, fatal, panic"))
108+
validLogLevels := []string{"trace", "debug", "info", "warn", "error", "fatal", "panic"}
109+
cmd.PersistentFlags().String("log-level", "", tr("Messages with this level and above will be logged. Valid levels are: %s", strings.Join(validLogLevels, ", ")))
110+
cmd.RegisterFlagCompletionFunc("log-level", func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
111+
return validLogLevels, cobra.ShellCompDirectiveDefault
112+
})
109113
cmd.PersistentFlags().String("log-file", "", tr("Path to the file where logs will be written."))
110-
cmd.PersistentFlags().String("log-format", "", tr("The output format for the logs, can be: %s", "text, json"))
111-
cmd.PersistentFlags().StringVar(&outputFormat, "format", "text", tr("The output format for the logs, can be: %s", "text, json"))
114+
validFormats := []string{"text", "json"}
115+
cmd.PersistentFlags().String("log-format", "", tr("The output format for the logs, can be: %s", strings.Join(validFormats, ", ")))
116+
cmd.RegisterFlagCompletionFunc("log-format", func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
117+
return validFormats, cobra.ShellCompDirectiveDefault
118+
})
119+
cmd.PersistentFlags().StringVar(&outputFormat, "format", "text", tr("The output format for the logs, can be: %s", strings.Join(validFormats, ", ")))
120+
cmd.RegisterFlagCompletionFunc("format", func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
121+
return validFormats, cobra.ShellCompDirectiveDefault
122+
})
112123
cmd.PersistentFlags().StringVar(&configFile, "config-file", "", tr("The custom config file (if not specified the default will be used)."))
113124
cmd.PersistentFlags().StringSlice("additional-urls", []string{}, tr("Comma-separated list of additional URLs for the Boards Manager."))
114125
cmd.PersistentFlags().Bool("no-color", false, "Disable colored output.")

‎cli/compile/compile.go‎

Lines changed: 4 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,6 @@ import (
3131

3232
"github.com/arduino/arduino-cli/cli/errorcodes"
3333
"github.com/arduino/arduino-cli/cli/instance"
34-
"github.com/arduino/arduino-cli/commands/board"
3534
"github.com/arduino/arduino-cli/commands/compile"
3635
"github.com/arduino/arduino-cli/commands/upload"
3736
rpc "github.com/arduino/arduino-cli/rpc/cc/arduino/cli/commands/v1"
@@ -84,7 +83,7 @@ func NewCommand() *cobra.Command {
8483

8584
command.Flags().StringVarP(&fqbn, "fqbn", "b", "", tr("Fully Qualified Board Name, e.g.: arduino:avr:uno"))
8685
command.RegisterFlagCompletionFunc("fqbn", func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
87-
return getBoards(toComplete), cobra.ShellCompDirectiveDefault
86+
return arguments.GetInstalledBoards(), cobra.ShellCompDirectiveDefault
8887
})
8988
command.Flags().BoolVar(&showProperties, "show-properties", false, tr("Show all build properties used instead of compiling."))
9089
command.Flags().BoolVar(&preprocess, "preprocess", false, tr("Print preprocessed code to stdout instead of compiling."))
@@ -110,6 +109,9 @@ func NewCommand() *cobra.Command {
110109
tr("List of custom libraries dir paths separated by commas. Or can be used multiple times for multiple libraries dir paths."))
111110
command.Flags().BoolVar(&optimizeForDebug, "optimize-for-debug", false, tr("Optional, optimize compile output for debugging, rather than for release."))
112111
command.Flags().StringVarP(&programmer, "programmer", "P", "", tr("Optional, use the specified programmer to upload."))
112+
command.RegisterFlagCompletionFunc("programmer", func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
113+
return arguments.GetInstalledProgrammers(), cobra.ShellCompDirectiveDefault
114+
})
113115
command.Flags().BoolVar(&compilationDatabaseOnly, "only-compilation-database", false, tr("Just produce the compilation database, without actually compiling."))
114116
command.Flags().BoolVar(&clean, "clean", false, tr("Optional, cleanup the build folder and do not use any cached build."))
115117
// We must use the following syntax for this flag since it's also bound to settings.
@@ -276,19 +278,3 @@ func (r *compileResult) String() string {
276278
// The output is already printed via os.Stdout/os.Stdin
277279
return ""
278280
}
279-
280-
func getBoards(toComplete string) []string {
281-
// from listall.go TODO optimize
282-
inst := instance.CreateAndInit()
283-
284-
list, _ := board.ListAll(context.Background(), &rpc.BoardListAllRequest{
285-
Instance: inst,
286-
SearchArgs: nil,
287-
IncludeHiddenBoards: false,
288-
})
289-
var res []string
290-
for _, i := range list.GetBoards() {
291-
res = append(res, i.Fqbn)
292-
}
293-
return res
294-
}

‎cli/config/add.go‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,9 @@ func initAddCommand() *cobra.Command {
3535
" " + os.Args[0] + " config add board_manager.additional_urls https://example.com/package_example_index.json https://another-url.com/package_another_index.json\n",
3636
Args: cobra.MinimumNArgs(2),
3737
Run: runAddCommand,
38+
ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
39+
return GetConfigurationKeys(), cobra.ShellCompDirectiveDefault
40+
},
3841
}
3942
return addCommand
4043
}

‎cli/config/config.go‎

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,9 @@ package config
1717

1818
import (
1919
"os"
20+
"reflect"
2021

22+
"github.com/arduino/arduino-cli/configuration"
2123
"github.com/arduino/arduino-cli/i18n"
2224
"github.com/spf13/cobra"
2325
)
@@ -41,3 +43,17 @@ func NewCommand() *cobra.Command {
4143

4244
return configCommand
4345
}
46+
47+
// GetConfigurationKeys is an helper function useful to autocomplete.
48+
// It returns a list of configuration keys which can be changed
49+
func GetConfigurationKeys() []string {
50+
var res []string
51+
keys := configuration.Settings.AllKeys()
52+
for _, key := range keys {
53+
kind, _ := typeOf(key)
54+
if kind == reflect.Slice {
55+
res = append(res, key)
56+
}
57+
}
58+
return res
59+
}

‎cli/config/delete.go‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,9 @@ func initDeleteCommand() *cobra.Command {
3636
" " + os.Args[0] + " config delete board_manager.additional_urls",
3737
Args: cobra.ExactArgs(1),
3838
Run: runDeleteCommand,
39+
ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
40+
return configuration.Settings.AllKeys(), cobra.ShellCompDirectiveDefault
41+
},
3942
}
4043
return addCommand
4144
}

‎cli/config/remove.go‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,9 @@ func initRemoveCommand() *cobra.Command {
3535
" " + os.Args[0] + " config remove board_manager.additional_urls https://example.com/package_example_index.json https://another-url.com/package_another_index.json\n",
3636
Args: cobra.MinimumNArgs(2),
3737
Run: runRemoveCommand,
38+
ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
39+
return GetConfigurationKeys(), cobra.ShellCompDirectiveDefault
40+
},
3841
}
3942
return addCommand
4043
}

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /