From 0aa3d6320f01929cbf42347a9e951682063930c9 Mon Sep 17 00:00:00 2001 From: Martino Facchin Date: Tue, 8 Jan 2019 18:49:01 +0100 Subject: [PATCH 1/4] Initial: provide bash completion To test: arduino-cli generate_autocomplete > arduino-cli.sh source arduino-cli.sh Completion on fqbn is broken and wip --- commands/board/board.go | 1 + commands/board/listall.go | 27 ++++++++++++++ commands/compile/compile.go | 61 +++++++++++++++++++++++-------- commands/completion/completion.go | 44 ++++++++++++++++++++++ commands/root/root.go | 25 ++++++++++--- 5 files changed, 138 insertions(+), 20 deletions(-) create mode 100644 commands/completion/completion.go diff --git a/commands/board/board.go b/commands/board/board.go index 318cd0041e1..aa7278e4154 100644 --- a/commands/board/board.go +++ b/commands/board/board.go @@ -37,5 +37,6 @@ func InitCommand() *cobra.Command { boardCommand.AddCommand(initDetailsCommand()) boardCommand.AddCommand(initListCommand()) boardCommand.AddCommand(initListAllCommand()) + boardCommand.AddCommand(initListAllCommandOnlyFqbn()) return boardCommand } diff --git a/commands/board/listall.go b/commands/board/listall.go index 6c18f0cbc67..00a290fdb91 100644 --- a/commands/board/listall.go +++ b/commands/board/listall.go @@ -18,6 +18,7 @@ package board import ( + "fmt" "sort" "strings" @@ -78,3 +79,29 @@ func runListAllCommand(cmd *cobra.Command, args []string) { sort.Sort(list) formatter.Print(list) } + +func initListAllCommandOnlyFqbn() *cobra.Command { + listAllCommand := &cobra.Command{ + Use: "listallfqbn", + Run: runListAllCommandOnlyFqbn, + Hidden: true, + } + return listAllCommand +} + +// runListAllCommand list all installed boards +func runListAllCommandOnlyFqbn(cmd *cobra.Command, args []string) { + pm := commands.InitPackageManager() + + for _, targetPackage := range pm.GetPackages().Packages { + for _, platform := range targetPackage.Platforms { + platformRelease := pm.GetInstalledPlatformRelease(platform) + if platformRelease == nil { + continue + } + for _, board := range platformRelease.Boards { + fmt.Println(board.FQBN()) + } + } + } +} diff --git a/commands/compile/compile.go b/commands/compile/compile.go index 33c05d75b07..15e4cef2877 100644 --- a/commands/compile/compile.go +++ b/commands/compile/compile.go @@ -35,10 +35,12 @@ import ( properties "github.com/arduino/go-properties-orderedmap" "github.com/sirupsen/logrus" "github.com/spf13/cobra" + "github.com/spf13/pflag" ) // InitCommand prepares the command. func InitCommand() *cobra.Command { + command := &cobra.Command{ Use: "compile", Short: "Compiles Arduino sketches.", @@ -47,9 +49,21 @@ func InitCommand() *cobra.Command { Args: cobra.MaximumNArgs(1), Run: run, } - command.Flags().StringVarP( - &flags.fqbn, "fqbn", "b", "", - "Fully Qualified Board Name, e.g.: arduino:avr:uno") + + annotation := make(map[string][]string) + annotation[cobra.BashCompCustom] = []string{"__arduino_cli_boards_listall_fqbn"} + + fqbn := &pflag.Flag{ + Name: "fqbn", + Shorthand: "b", + DefValue: "", + Value: flags.fqbnWrapper, + Usage: "Fully Qualified Board Name, e.g.: arduino:avr:uno", + Annotations: annotation, + } + command.Flags().AddFlag(fqbn) + command.MarkFlagRequired("fqbn") + command.Flags().BoolVar( &flags.showProperties, "show-properties", false, "Show all build properties used instead of compiling.") @@ -83,18 +97,35 @@ func InitCommand() *cobra.Command { return command } +type localValue struct { +} + +func (r localValue) Set(v string) error { + flags.fqbn = v + return nil +} + +func (r localValue) String() string { + return flags.fqbn +} + +func (r localValue) Type() string { + return "fqbn" +} + var flags struct { - fqbn string // Fully Qualified Board Name, e.g.: arduino:avr:uno. - showProperties bool // Show all build preferences used instead of compiling. - preprocess bool // Print preprocessed code to stdout. - buildCachePath string // Builds of 'core.a' are saved into this path to be cached and reused. - buildPath string // Path where to save compiled files. - buildProperties []string // List of custom build properties separated by commas. Or can be used multiple times for multiple properties. - warnings string // Used to tell gcc which warning level to use. - verbose bool // Turns on verbose mode. - quiet bool // Suppresses almost every output. - vidPid string // VID/PID specific build properties. - exportFile string // The compiled binary is written to this file + fqbnWrapper localValue // Fully Qualified Board Name, e.g.: arduino:avr:uno. + fqbn string // Fully Qualified Board Name, e.g.: arduino:avr:uno. + showProperties bool // Show all build preferences used instead of compiling. + preprocess bool // Print preprocessed code to stdout. + buildCachePath string // Builds of 'core.a' are saved into this path to be cached and reused. + buildPath string // Path where to save compiled files. + buildProperties []string // List of custom build properties separated by commas. Or can be used multiple times for multiple properties. + warnings string // Used to tell gcc which warning level to use. + verbose bool // Turns on verbose mode. + quiet bool // Suppresses almost every output. + vidPid string // VID/PID specific build properties. + exportFile string // The compiled binary is written to this file } func run(cmd *cobra.Command, args []string) { @@ -109,7 +140,7 @@ func run(cmd *cobra.Command, args []string) { os.Exit(commands.ErrGeneric) } - if flags.fqbn == "" && sketch != nil { + if flags.fqbn == "" && sketch != nil && sketch.Metadata != nil { flags.fqbn = sketch.Metadata.CPU.Fqbn } if flags.fqbn == "" { diff --git a/commands/completion/completion.go b/commands/completion/completion.go new file mode 100644 index 00000000000..4f0c6b0ad78 --- /dev/null +++ b/commands/completion/completion.go @@ -0,0 +1,44 @@ +/* + * This file is part of arduino-cli. + * + * Copyright 2018 ARDUINO SA (http://www.arduino.cc/) + * + * This software is released under the GNU General Public License version 3, + * which covers the main part of arduino-cli. + * The terms of this license can be found at: + * https://www.gnu.org/licenses/gpl-3.0.en.html + * + * You can be released from the requirements of the above licenses by purchasing + * a commercial license. Buying such a license is mandatory if you want to modify or + * otherwise use the software for commercial activities involving the Arduino + * software without disclosing the source code of your own applications. To purchase + * a commercial license, send an email to license@arduino.cc. + */ + +package completion + +import ( + "os" + + "github.com/spf13/cobra" +) + +// InitCommand prepares the command. +func InitCommand() *cobra.Command { + // completionCmd represents the completion command + var completionCmd = &cobra.Command{ + Use: "generate_autocomplete", + Short: "Generates bash completion scripts", + Long: `To load completion run + # arduino-cli generate_autocomplete > arduino-cli.sh + and then + # source arduino-cli.sh + or add the script to /etc/bash_completion.d/ + `, + Run: func(cmd *cobra.Command, args []string) { + cmd.Root().GenBashCompletion(os.Stdout) + }, + Hidden: true, + } + return completionCmd +} diff --git a/commands/root/root.go b/commands/root/root.go index 779acddb7b1..1b1502c09b0 100644 --- a/commands/root/root.go +++ b/commands/root/root.go @@ -32,6 +32,7 @@ import ( "github.com/arduino/arduino-cli/commands" "github.com/arduino/arduino-cli/commands/board" "github.com/arduino/arduino-cli/commands/compile" + "github.com/arduino/arduino-cli/commands/completion" "github.com/arduino/arduino-cli/commands/config" "github.com/arduino/arduino-cli/commands/core" "github.com/arduino/arduino-cli/commands/generatedocs" @@ -45,14 +46,27 @@ import ( "github.com/spf13/cobra" ) +const ( + fqbn_bash_completion_func = `__arduino_cli_boards_listall_fqbn() +{ + local arduino_cli_output out + if arduino_cli_output=$(arduino-cli board listallfqbn 2>/dev/null); then + out=($(echo "${arduino_cli_output}" | cut -f1 -d":" | uniq | awk '{print $1}')) + COMPREPLY=( $( compgen -W "${out[*]}" -- "$cur" ) ) + fi +} +` +) + // Init prepares the cobra root command. func Init() *cobra.Command { command := &cobra.Command{ - Use: "arduino-cli", - Short: "Arduino CLI.", - Long: "Arduino Command Line Interface (arduino-cli).", - Example: " " + commands.AppName + " [flags...]", - PersistentPreRun: preRun, + Use: "arduino-cli", + Short: "Arduino CLI.", + Long: "Arduino Command Line Interface (arduino-cli).", + Example: " " + commands.AppName + " [flags...]", + PersistentPreRun: preRun, + BashCompletionFunction: fqbn_bash_completion_func, } command.PersistentFlags().BoolVar(&commands.GlobalFlags.Debug, "debug", false, "Enables debug output (super verbose, used to debug the CLI).") command.PersistentFlags().StringVar(&commands.GlobalFlags.Format, "format", "text", "The output format, can be [text|json].") @@ -69,6 +83,7 @@ func Init() *cobra.Command { command.AddCommand(upload.InitCommand()) // command.AddCommand(validate.InitCommand()) command.AddCommand(version.InitCommand()) + command.AddCommand(completion.InitCommand()) return command } From ee69cf8f90dfa34150db720ce1b915cdf281c961 Mon Sep 17 00:00:00 2001 From: Martino Facchin Date: Mon, 28 Jan 2019 17:57:47 +0100 Subject: [PATCH 2/4] Fix colon separated fqbn completion --- commands/root/root.go | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/commands/root/root.go b/commands/root/root.go index 1b1502c09b0..71977f612f2 100644 --- a/commands/root/root.go +++ b/commands/root/root.go @@ -47,11 +47,12 @@ import ( ) const ( - fqbn_bash_completion_func = `__arduino_cli_boards_listall_fqbn() + fqbn_bash_completion_func = `COMP_WORDBREAKS=" " +__arduino_cli_boards_listall_fqbn() { local arduino_cli_output out if arduino_cli_output=$(arduino-cli board listallfqbn 2>/dev/null); then - out=($(echo "${arduino_cli_output}" | cut -f1 -d":" | uniq | awk '{print $1}')) + out=($(echo "${arduino_cli_output}" | uniq | awk '{print $1}')) COMPREPLY=( $( compgen -W "${out[*]}" -- "$cur" ) ) fi } From 1e7da841f3832e13fb5794d3f0f8dcd4f13b0ea7 Mon Sep 17 00:00:00 2001 From: Martino Facchin Date: Tue, 29 Jan 2019 11:33:35 +0100 Subject: [PATCH 3/4] Use proper COMP_WORDBREAKS --- commands/root/root.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/commands/root/root.go b/commands/root/root.go index 71977f612f2..f9e11c6e259 100644 --- a/commands/root/root.go +++ b/commands/root/root.go @@ -47,7 +47,7 @@ import ( ) const ( - fqbn_bash_completion_func = `COMP_WORDBREAKS=" " + fqbn_bash_completion_func = `COMP_WORDBREAKS="\"'><;|&( " __arduino_cli_boards_listall_fqbn() { local arduino_cli_output out From 2885b10466ec16ccbe093a5b5b13f11ffd42aa49 Mon Sep 17 00:00:00 2001 From: Martino Facchin Date: Mon, 4 Feb 2019 11:49:29 +0100 Subject: [PATCH 4/4] Expand fqbn arguments on autocomplete Should help discovering features "inline" (see #138) --- commands/board/listall.go | 21 ++++++++++++++++++++- commands/root/root.go | 2 +- 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/commands/board/listall.go b/commands/board/listall.go index 00a290fdb91..e972dbf2f5b 100644 --- a/commands/board/listall.go +++ b/commands/board/listall.go @@ -85,10 +85,19 @@ func initListAllCommandOnlyFqbn() *cobra.Command { Use: "listallfqbn", Run: runListAllCommandOnlyFqbn, Hidden: true, + Args: cobra.ArbitraryArgs, } return listAllCommand } +func userAskForOptions(str string) bool { + // one arg must contain 3 or more colons + if strings.Count(str, ":") >= 3 { + return true + } + return false +} + // runListAllCommand list all installed boards func runListAllCommandOnlyFqbn(cmd *cobra.Command, args []string) { pm := commands.InitPackageManager() @@ -100,7 +109,17 @@ func runListAllCommandOnlyFqbn(cmd *cobra.Command, args []string) { continue } for _, board := range platformRelease.Boards { - fmt.Println(board.FQBN()) + boardname := board.FQBN() + if board.GetConfigOptions() != nil && len(args) > 0 && userAskForOptions(args[0]) && strings.Contains(args[0], boardname) { + for _, option := range board.GetConfigOptions().FirstLevelKeys() { + str := boardname + ":" + option + "=" + for _, value := range board.GetConfigOptionValues(option).FirstLevelKeys() { + fmt.Println(str + value) + } + } + } else { + fmt.Println(boardname) + } } } } diff --git a/commands/root/root.go b/commands/root/root.go index f9e11c6e259..1def378978a 100644 --- a/commands/root/root.go +++ b/commands/root/root.go @@ -51,7 +51,7 @@ const ( __arduino_cli_boards_listall_fqbn() { local arduino_cli_output out - if arduino_cli_output=$(arduino-cli board listallfqbn 2>/dev/null); then + if arduino_cli_output=$(arduino-cli board listallfqbn $cur 2>/dev/null); then out=($(echo "${arduino_cli_output}" | uniq | awk '{print $1}')) COMPREPLY=( $( compgen -W "${out[*]}" -- "$cur" ) ) fi