Skip to content

add dynamic completion #1509

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 22 commits into from
Oct 18, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
9d61a6e
add completion for `-b` or `--fqbn` for every command
umbynos Oct 18, 2021
b7263bf
add completion for `-l` or `--protocol`
umbynos Oct 18, 2021
b6ed62f
the previous implementation was working only with a board connected t…
umbynos Oct 5, 2021
3e57b18
add static completion for `--log-level, `--log-format` and `--format`
umbynos Oct 6, 2021
0c0823f
add completion for `-P` or `--programmer` & fix typo
umbynos Oct 6, 2021
fe4ab51
add completion for `core uninstall`
umbynos Oct 6, 2021
fc82c12
add completion for `core install` and `core download`
umbynos Oct 6, 2021
e79ae01
add completion for `lib uninstall`
umbynos Oct 6, 2021
6d560b2
add completion for `lib install`, `lib download`
umbynos Oct 7, 2021
3486d94
add completion for `lib examples`
umbynos Oct 7, 2021
28dfdc1
add completion for `config add`, `config remove`, `config delete` and…
umbynos Oct 7, 2021
27d300c
add completion for `lib deps`
umbynos Oct 7, 2021
d7be814
add tests
umbynos Oct 12, 2021
4559c25
enhance the completion for `config add` and `config remove`
umbynos Oct 13, 2021
6b1a01c
add description completion suggestion for core, lib, fqbn, programmer
umbynos Oct 13, 2021
5462031
add completion also for `-p` or `--port` flag
umbynos Oct 13, 2021
fe2cf65
remove the `toComplete` parameter from all the completion functions
umbynos Oct 13, 2021
2a953a9
fixes after rebase
umbynos Oct 13, 2021
7235896
update docs
umbynos Oct 13, 2021
d6c4732
add `-b` or `--fqbn` completion for the monitor command and tests
umbynos Oct 14, 2021
c5ee4d0
apply suggestions from code review
umbynos Oct 15, 2021
d6d4502
fixes after rebase
umbynos Oct 18, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
190 changes: 190 additions & 0 deletions cli/arguments/completion.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,190 @@
package arguments

import (
"context"

"github.com/arduino/arduino-cli/arduino/cores"
"github.com/arduino/arduino-cli/cli/instance"
"github.com/arduino/arduino-cli/commands"
"github.com/arduino/arduino-cli/commands/board"
"github.com/arduino/arduino-cli/commands/core"
"github.com/arduino/arduino-cli/commands/lib"
rpc "github.com/arduino/arduino-cli/rpc/cc/arduino/cli/commands/v1"
)

// GetInstalledBoards is an helper function useful to autocomplete.
// It returns a list of fqbn
// it's taken from cli/board/listall.go
func GetInstalledBoards() []string {
inst := instance.CreateAndInit()

list, _ := board.ListAll(context.Background(), &rpc.BoardListAllRequest{
Instance: inst,
SearchArgs: nil,
IncludeHiddenBoards: false,
})
var res []string
// transform the data structure for the completion
for _, i := range list.Boards {
res = append(res, i.Fqbn+"\t"+i.Name)
}
return res
}

// GetInstalledProtocols is an helper function useful to autocomplete.
// It returns a list of protocols available based on the installed boards
func GetInstalledProtocols() []string {
inst := instance.CreateAndInit()
pm := commands.GetPackageManager(inst.Id)
boards := pm.InstalledBoards()

installedProtocols := make(map[string]struct{})
for _, board := range boards {
for _, protocol := range board.Properties.SubTree("upload.tool").FirstLevelKeys() {
if protocol == "default" {
// default is used as fallback when trying to upload to a board
// using a protocol not defined for it, it's useless showing it
// in autocompletion
continue
}
installedProtocols[protocol] = struct{}{}
}
}
res := make([]string, len(installedProtocols))
i := 0
for k := range installedProtocols {
res[i] = k
i++
}
return res
}

// GetInstalledProgrammers is an helper function useful to autocomplete.
// It returns a list of programmers available based on the installed boards
func GetInstalledProgrammers() []string {
inst := instance.CreateAndInit()
pm := commands.GetPackageManager(inst.Id)

// we need the list of the available fqbn in order to get the list of the programmers
list, _ := board.ListAll(context.Background(), &rpc.BoardListAllRequest{
Instance: inst,
SearchArgs: nil,
IncludeHiddenBoards: false,
})

installedProgrammers := make(map[string]string)
for _, board := range list.Boards {
fqbn, _ := cores.ParseFQBN(board.Fqbn)
_, boardPlatform, _, _, _, _ := pm.ResolveFQBN(fqbn)
for programmerID, programmer := range boardPlatform.Programmers {
installedProgrammers[programmerID] = programmer.Name
}
}

res := make([]string, len(installedProgrammers))
i := 0
for programmerID := range installedProgrammers {
res[i] = programmerID + "\t" + installedProgrammers[programmerID]
i++
}
return res
}

// GetUninstallableCores is an helper function useful to autocomplete.
// It returns a list of cores which can be uninstalled
func GetUninstallableCores() []string {
inst := instance.CreateAndInit()

platforms, _ := core.GetPlatforms(&rpc.PlatformListRequest{
Instance: inst,
UpdatableOnly: false,
All: false,
})
var res []string
// transform the data structure for the completion
for _, i := range platforms {
res = append(res, i.Id+"\t"+i.Name)
}
return res
}

// GetInstallableCores is an helper function useful to autocomplete.
// It returns a list of cores which can be installed/downloaded
func GetInstallableCores() []string {
inst := instance.CreateAndInit()

platforms, _ := core.PlatformSearch(&rpc.PlatformSearchRequest{
Instance: inst,
SearchArgs: "",
AllVersions: false,
})
var res []string
// transform the data structure for the completion
for _, i := range platforms.SearchOutput {
res = append(res, i.Id+"\t"+i.Name)
}
return res
}

// GetInstalledLibraries is an helper function useful to autocomplete.
// It returns a list of libs which are currently installed, including the builtin ones
func GetInstalledLibraries() []string {
return getLibraries(true)
}

// GetUninstallableLibraries is an helper function useful to autocomplete.
// It returns a list of libs which can be uninstalled
func GetUninstallableLibraries() []string {
return getLibraries(false)
}

func getLibraries(all bool) []string {
inst := instance.CreateAndInit()
libs, _ := lib.LibraryList(context.Background(), &rpc.LibraryListRequest{
Instance: inst,
All: all,
Updatable: false,
Name: "",
Fqbn: "",
})
var res []string
// transform the data structure for the completion
for _, i := range libs.InstalledLibraries {
res = append(res, i.Library.Name+"\t"+i.Library.Sentence)
}
return res
}

// GetInstallableLibs is an helper function useful to autocomplete.
// It returns a list of libs which can be installed/downloaded
func GetInstallableLibs() []string {
inst := instance.CreateAndInit()

libs, _ := lib.LibrarySearch(context.Background(), &rpc.LibrarySearchRequest{
Instance: inst,
Query: "", // if no query is specified all the libs are returned
})
var res []string
// transform the data structure for the completion
for _, i := range libs.Libraries {
res = append(res, i.Name+"\t"+i.Latest.Sentence)
}
return res
}

// GetConnectedBoards is an helper function useful to autocomplete.
// It returns a list of boards which are currently connected
// Obviously it does not suggests network ports because of the timeout
func GetConnectedBoards() []string {
inst := instance.CreateAndInit()

list, _ := board.List(&rpc.BoardListRequest{
Instance: inst,
})
var res []string
// transform the data structure for the completion
for _, i := range list {
res = append(res, i.Port.Address)
}
return res
}
6 changes: 6 additions & 0 deletions cli/arguments/port.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,13 @@ type Port struct {
// AddToCommand adds the flags used to set port and protocol to the specified Command
func (p *Port) AddToCommand(cmd *cobra.Command) {
cmd.Flags().StringVarP(&p.address, "port", "p", "", tr("Upload port address, e.g.: COM3 or /dev/ttyACM2"))
cmd.RegisterFlagCompletionFunc("port", func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
return GetConnectedBoards(), cobra.ShellCompDirectiveDefault
})
cmd.Flags().StringVarP(&p.protocol, "protocol", "l", "", tr("Upload port protocol, e.g: serial"))
cmd.RegisterFlagCompletionFunc("protocol", func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
return GetInstalledProtocols(), cobra.ShellCompDirectiveDefault
})
cmd.Flags().DurationVar(&p.timeout, "discovery-timeout", 5*time.Second, tr("Max time to wait for port discovery, e.g.: 30s, 1m"))
}

Expand Down
4 changes: 4 additions & 0 deletions cli/board/details.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import (
"fmt"
"os"

"github.com/arduino/arduino-cli/cli/arguments"
"github.com/arduino/arduino-cli/cli/errorcodes"
"github.com/arduino/arduino-cli/cli/feedback"
"github.com/arduino/arduino-cli/cli/instance"
Expand Down Expand Up @@ -48,6 +49,9 @@ func initDetailsCommand() *cobra.Command {

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

Expand Down
6 changes: 6 additions & 0 deletions cli/burnbootloader/burnbootloader.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,10 +51,16 @@ func NewCommand() *cobra.Command {
}

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

Expand Down
17 changes: 14 additions & 3 deletions cli/cli.go
Original file line number Diff line number Diff line change
Expand Up @@ -105,10 +105,21 @@ func createCliCommandTree(cmd *cobra.Command) {
cmd.AddCommand(version.NewCommand())

cmd.PersistentFlags().BoolVarP(&verbose, "verbose", "v", false, tr("Print the logs on the standard output."))
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"))
validLogLevels := []string{"trace", "debug", "info", "warn", "error", "fatal", "panic"}
cmd.PersistentFlags().String("log-level", "", tr("Messages with this level and above will be logged. Valid levels are: %s", strings.Join(validLogLevels, ", ")))
cmd.RegisterFlagCompletionFunc("log-level", func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
return validLogLevels, cobra.ShellCompDirectiveDefault
})
cmd.PersistentFlags().String("log-file", "", tr("Path to the file where logs will be written."))
cmd.PersistentFlags().String("log-format", "", tr("The output format for the logs, can be: %s", "text, json"))
cmd.PersistentFlags().StringVar(&outputFormat, "format", "text", tr("The output format for the logs, can be: %s", "text, json"))
validFormats := []string{"text", "json"}
cmd.PersistentFlags().String("log-format", "", tr("The output format for the logs, can be: %s", strings.Join(validFormats, ", ")))
cmd.RegisterFlagCompletionFunc("log-format", func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
return validFormats, cobra.ShellCompDirectiveDefault
})
cmd.PersistentFlags().StringVar(&outputFormat, "format", "text", tr("The output format for the logs, can be: %s", strings.Join(validFormats, ", ")))
cmd.RegisterFlagCompletionFunc("format", func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
return validFormats, cobra.ShellCompDirectiveDefault
})
cmd.PersistentFlags().StringVar(&configFile, "config-file", "", tr("The custom config file (if not specified the default will be used)."))
cmd.PersistentFlags().StringSlice("additional-urls", []string{}, tr("Comma-separated list of additional URLs for the Boards Manager."))
cmd.PersistentFlags().Bool("no-color", false, "Disable colored output.")
Expand Down
22 changes: 4 additions & 18 deletions cli/compile/compile.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,6 @@ import (

"github.com/arduino/arduino-cli/cli/errorcodes"
"github.com/arduino/arduino-cli/cli/instance"
"github.com/arduino/arduino-cli/commands/board"
"github.com/arduino/arduino-cli/commands/compile"
"github.com/arduino/arduino-cli/commands/upload"
rpc "github.com/arduino/arduino-cli/rpc/cc/arduino/cli/commands/v1"
Expand Down Expand Up @@ -84,7 +83,7 @@ func NewCommand() *cobra.Command {

command.Flags().StringVarP(&fqbn, "fqbn", "b", "", tr("Fully Qualified Board Name, e.g.: arduino:avr:uno"))
command.RegisterFlagCompletionFunc("fqbn", func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
return getBoards(toComplete), cobra.ShellCompDirectiveDefault
return arguments.GetInstalledBoards(), cobra.ShellCompDirectiveDefault
})
command.Flags().BoolVar(&showProperties, "show-properties", false, tr("Show all build properties used instead of compiling."))
command.Flags().BoolVar(&preprocess, "preprocess", false, tr("Print preprocessed code to stdout instead of compiling."))
Expand All @@ -110,6 +109,9 @@ func NewCommand() *cobra.Command {
tr("List of custom libraries dir paths separated by commas. Or can be used multiple times for multiple libraries dir paths."))
command.Flags().BoolVar(&optimizeForDebug, "optimize-for-debug", false, tr("Optional, optimize compile output for debugging, rather than for release."))
command.Flags().StringVarP(&programmer, "programmer", "P", "", tr("Optional, use the specified programmer to upload."))
command.RegisterFlagCompletionFunc("programmer", func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
return arguments.GetInstalledProgrammers(), cobra.ShellCompDirectiveDefault
})
command.Flags().BoolVar(&compilationDatabaseOnly, "only-compilation-database", false, tr("Just produce the compilation database, without actually compiling."))
command.Flags().BoolVar(&clean, "clean", false, tr("Optional, cleanup the build folder and do not use any cached build."))
// We must use the following syntax for this flag since it's also bound to settings.
Expand Down Expand Up @@ -276,19 +278,3 @@ func (r *compileResult) String() string {
// The output is already printed via os.Stdout/os.Stdin
return ""
}

func getBoards(toComplete string) []string {
// from listall.go TODO optimize
inst := instance.CreateAndInit()

list, _ := board.ListAll(context.Background(), &rpc.BoardListAllRequest{
Instance: inst,
SearchArgs: nil,
IncludeHiddenBoards: false,
})
var res []string
for _, i := range list.GetBoards() {
res = append(res, i.Fqbn)
}
return res
}
3 changes: 3 additions & 0 deletions cli/config/add.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,9 @@ func initAddCommand() *cobra.Command {
" " + 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",
Args: cobra.MinimumNArgs(2),
Run: runAddCommand,
ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
return GetConfigurationKeys(), cobra.ShellCompDirectiveDefault
},
}
return addCommand
}
Expand Down
16 changes: 16 additions & 0 deletions cli/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,9 @@ package config

import (
"os"
"reflect"

"github.com/arduino/arduino-cli/configuration"
"github.com/arduino/arduino-cli/i18n"
"github.com/spf13/cobra"
)
Expand All @@ -41,3 +43,17 @@ func NewCommand() *cobra.Command {

return configCommand
}

// GetConfigurationKeys is an helper function useful to autocomplete.
// It returns a list of configuration keys which can be changed
func GetConfigurationKeys() []string {
var res []string
keys := configuration.Settings.AllKeys()
for _, key := range keys {
kind, _ := typeOf(key)
if kind == reflect.Slice {
res = append(res, key)
}
}
return res
}
3 changes: 3 additions & 0 deletions cli/config/delete.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,9 @@ func initDeleteCommand() *cobra.Command {
" " + os.Args[0] + " config delete board_manager.additional_urls",
Args: cobra.ExactArgs(1),
Run: runDeleteCommand,
ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
return configuration.Settings.AllKeys(), cobra.ShellCompDirectiveDefault
},
}
return addCommand
}
Expand Down
3 changes: 3 additions & 0 deletions cli/config/remove.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,9 @@ func initRemoveCommand() *cobra.Command {
" " + 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",
Args: cobra.MinimumNArgs(2),
Run: runRemoveCommand,
ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
return GetConfigurationKeys(), cobra.ShellCompDirectiveDefault
},
}
return addCommand
}
Expand Down
3 changes: 3 additions & 0 deletions cli/config/set.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,9 @@ func initSetCommand() *cobra.Command {
" " + os.Args[0] + " config set board_manager.additional_urls https://example.com/package_example_index.json https://another-url.com/package_another_index.json",
Args: cobra.MinimumNArgs(2),
Run: runSetCommand,
ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
return configuration.Settings.AllKeys(), cobra.ShellCompDirectiveDefault
},
}
return addCommand
}
Expand Down
3 changes: 3 additions & 0 deletions cli/core/download.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,9 @@ func initDownloadCommand() *cobra.Command {
" " + os.Args[0] + " core download arduino:[email protected] # " + tr("download a specific version (in this case 1.6.9)."),
Args: cobra.MinimumNArgs(1),
Run: runDownloadCommand,
ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
return arguments.GetInstallableCores(), cobra.ShellCompDirectiveDefault
},
}
return downloadCommand
}
Expand Down
3 changes: 3 additions & 0 deletions cli/core/install.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,9 @@ func initInstallCommand() *cobra.Command {
" " + os.Args[0] + " core install arduino:[email protected]",
Args: cobra.MinimumNArgs(1),
Run: runInstallCommand,
ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
return arguments.GetInstallableCores(), cobra.ShellCompDirectiveDefault
},
}
AddPostInstallFlagsToCommand(installCommand)
return installCommand
Expand Down
Loading