From 279074ca10abd761be2a05833f4748e8b5245cba Mon Sep 17 00:00:00 2001 From: David Gamba Date: Tue, 12 Dec 2023 20:27:26 -0700 Subject: [PATCH] Update README --- README.adoc | 560 +++++++++++++++++++++++++++++++++------------------- 1 file changed, 362 insertions(+), 198 deletions(-) diff --git a/README.adoc b/README.adoc index a074ae2..f2750a1 100644 --- a/README.adoc +++ b/README.adoc @@ -192,14 +192,21 @@ Tab completion without arguments triggers completion for commands, for option co For an overview of the Directed Acyclic Graph Build System see link:./dag/README.adoc[] +NOTE: The DAG code is in a separate package so it is not pulled in by default. + == Features • Built in auto completion. A single line of bash is all it takes. + +[source,bash] +---- +complete -o default -C my-go-program my-go-program +---- ++ Zshell is also supported, by exporting `ZSHELL=true` in your environment and using `bashcompinit`. -• Allow passing options and non-options in any order. +• Allow passing options and non-options (arguments) in any order. • Support for `--long` options. @@ -215,7 +222,7 @@ Zshell is also supported, by exporting `ZSHELL=true` in your environment and usi • `CalledAs()` method indicates what alias was used to call the option on the command line. -• Simple synopsis and option list automated help. +• Synopsis and option list automated help. • Boolean, String, Int, Float64, Slice and Map type options. @@ -284,9 +291,9 @@ For example, you can use `v` to define `verbose` and `V` to define `Version`. • Support indicating if an option is required and allows overriding the default error message. -• Errors exposed as public variables to allow overriding them for internationalization. +• Errors and Help Strings exposed as public variables to allow overriding them for internationalization. -• Supports program commands (when a command is passed a command function is triggered to handle the command logic). +• Supports program commands and subcommands (when a command is passed a command function is triggered to handle the command logic). • Built in `opt.Dispatch` function calls commands and propagates context, options, arguments and cancellation signals. @@ -299,6 +306,7 @@ For example, you can use `v` to define `verbose` and `V` to define `Version`. When mixed with Pass through, it also stops parsing arguments when the first unmatched option is found. • Set options by reading Environment Variables. +Precedence is CLI option over Env Var over Default. == How to install it @@ -314,7 +322,7 @@ When mixed with Pass through, it also stops parsing arguments when the first unm == Dependencies -Go 1.14+ +Go 1.16+ Only the last two versions of Go will be supported. @@ -324,43 +332,155 @@ NOTE: For a <>, jump to that section in the TOC or review the ht Option parsing is the act of taking command line arguments and converting them into meaningful structures within the program. -An option parser should support, at least, the following: +First declare a getoptions instance: -=== Boolean options +[source, go] +---- +opt := getoptions.New() +---- -`True` when passed on the command line. -For example: +Then declare the options you want to parse: -`ls --all` +[source, go] +---- +opt.String("string", "default_value") +---- -In `go-getoptions` this is accomplished with: +Optionally, define option modifiers: + +[source, go] +---- +opt.String("string", "default_value", + + opt.Alias("s"), // Allow -s as an alias for --string + opt.Description("This is a string option"), // Add a description to the option + opt.Required(), // Mark the option as required + opt.GetEnv("STRING"), // Set the environment variable to read the option from + opt.ArgName("mystring"), // Set the argument name for the help output + // The help with show --string instead of --string + opt.ValidValues("value1", "value2"), // Set the valid values for the option, these are used for autocompletion too + opt.SetCalled(true), // Forcefully set the option as if called in the CLI +) +---- -- `ptr := opt.Bool(name, default_value)`. -- `opt.BoolVar(&ptr, name, default_value)`. -- Additionally, if all you want to know is if the option was passed you can use: `opt.Bool(name, default_value)` (without capturing its return value) and then check `opt.Called(name)`. +Define the function for the program: + +---- +opt.SetCommandFn(Run) +---- + +If no function is defined and `opt.Dispatch` is called, the program will show a help message with any commands or subcommands. + +Define any commands and their options and functions: + +[source, go] +---- +cmd := opt.NewCommand("command", "command description") +cmd.String("int", 123) +cmd.SetCommandFn(CommandRun) +---- + +NOTE: Options defined at a parent level will be interited by the command unless `cmd.UnsetOptions()` is called. + +After defining options and commands declare the help command, it must be the last one defined. + +[source, go] +---- +opt.HelpCommand("help", opt.Alias("?")) +---- + +Parse the CLI arguments (or any `[]string`): + +[source, go] +---- +remaining, err := opt.Parse(os.Args[1:]) +---- + +Finally, call dispatch which will call the proper command function for the given arguments: + +[source, go] +---- +err = opt.Dispatch(ctx, remaining) +---- + +Dispatch requires a `context.Context` to be passed which can be used to propagate cancellation signals or configuration values. + +A built in helper to create a context with cancellation support is provided: + +[source, go] +---- +ctx, cancel, done := getoptions.InterruptContext() +defer func() { cancel(); <-done }() + +err = opt.Dispatch(ctx, remaining) +---- + +The actual functions running the business logic are the `CommandFn` functions set with the `SetCommandFn`. + +The `CommandFn` function signature is: + +[source, go] +---- +func Name(ctx context.Context, opt *getoptions.GetOpt, args []string) error { + return nil +} +---- + +This function will receive the context, the parsed options and the remaining arguments. + +Read the received options from the `opt` variable. + +[source, go] +---- +func Name(ctx context.Context, opt *getoptions.GetOpt, args []string) error { + file := opt.Value("file").(string) + count := opt.Value("count").(int) + tags := opt.Value("tags").(map[string]string) + + // logic + + return nil +} +---- + +NOTE: The `opt.Value` function returns an `interface{}` so it needs to be type casted to the proper type. +The type cast will panic if trying to read an option that is not defined. + +=== Boolean options + +Opposite of default when passed on the command line. + +- `ptr := opt.Bool(name, false)` +- `opt.BoolVar(&ptr, name, false)` +- Additionally, if all you want to know is if the option was passed you can use: `opt.Bool(name, false)` (without capturing its return value) and then check `opt.Called(name)`. - Also, you can get the value with `v, ok := opt.Value(name).(bool)`. +For example: + +`ls --all` + === Options with String arguments The option will accept a string argument. + +- `ptr := opt.String(name, "default")`. +- `opt.StringVar(&ptr, name, "default")`. + For example: `grepp --ignore .txt` Additionally, arguments to options can be passed with the `=` symbol. -`grepp --ignore=.txt` - -In `go-getoptions` this is accomplished with: - -- `ptr := opt.String(name, default_value)`. -- `opt.StringVar(&ptr, name, default_value)`. - -The features listed above are enough to create basic programs but an option parser should do better: +`grepp --ignore=.txt` or `count --from=-123` === Options with Integer arguments Parse an option string argument into an Integer and provide an user error if the string provided is not an integer. + +- `ptr := opt.Int(name, 0)`. +- `opt.IntVar(&ptr, name, 0)`. + For example: `grepp --contex-lines 3` @@ -371,14 +491,13 @@ and: Error: 'string' is not a valid integer. -In `go-getoptions` this is accomplished with: - -- `ptr := opt.Int(name, default_value)`. -- `opt.IntVar(&ptr, name, default_value)`. - === Options with Floating point arguments Parse an option string argument into a Floating point value and provide an user error if the string provided is not a valid floating point. + +- `ptr := opt.Float64(name, 3.14)`. +- `opt.Float64Var(&ptr, name, 3.14)`. + For example: `program --approximation 3.5` @@ -391,58 +510,25 @@ $ program --approximation string Error: 'string' is not a valid floating point value. ---- -In `go-getoptions` this is accomplished with: - -- `ptr := opt.Float64(name, default_value)`. -- `opt.Float64Var(&ptr, name, default_value)`. - -The features listed above relieve the programmer from the cumbersome task of converting the option argument into the expected type. - -That covers the most basic set of features, but still it is not enough to get past a basic program. -The following features will allow for a more complete interface. - === Options with array arguments This allows the same option to be used multiple times with different arguments. The list of arguments will be saved into a Slice inside the program. -For example: - -`list-files --exclude .txt --exclude .html --exclude .pdf` - -In `go-getoptions` this is accomplished with: - -- `ptr := opt.StringSlice(name, 1, 1)`. -- `opt.StringSliceVar(&ptr, name, 1, 1)`. -- `ptr := opt.IntSlice(name, 1, 1)`. -- `opt.IntSliceVar(&ptr, name, 1, 1)`. -`go-getoptions` has only implemented this feature for string and int. +- `ptr := opt.StringSlice(name, 1, 99)`. +- `opt.StringSliceVar(&ptr, name, 1, 99)`. +- `ptr := opt.IntSlice(name, 1, 99)`. +- `opt.IntSliceVar(&ptr, name, 1, 99)`. +- `ptr := opt.Float64Slice(name, 1, 99)`. +- `opt.Float64SliceVar(&ptr, name, 1, 99)`. -=== Options with Key Value arguments - -This allows the same option to be used multiple times with arguments of key value type. For example: -`rpmbuild --define name=myrpm --define version=123` - -In `go-getoptions` this is accomplished with: - -- `strMap := opt.StringMap(name, 1, 1)`. -- `opt.StringMapVar(&ptr, name, 1, 1)`. - -`go-getoptions` has only implemented this feature for string. - -The features above are useful when you have a variable amount of arguments, but it becomes cumbersome for the user when the number of entries is always the same. -The features described below are meant to handle the cases when each option has a known number of multiple entries. - -=== Options with array arguments and multiple entries - -This allows the user to save typing. -For example: +`list-files --exclude .txt --exclude .html --exclude .pdf` -Instead of writing: `color --r 10 --g 20 --b 30 --next-option` or `color --rgb 10 --rgb 20 --rgb 30 --next-option` +or: -The input could be: `color --rgb 10 20 30 --next-option`. +`list-files --exclude .txt .html .pdf` The setup for this feature should allow for the user to continue using both versions of the input, that is passing one argument at a time or passing the 3 arguments at once, or allow the setup to force the user to have to use the 3 arguments at once version. This is accomplished with the minimum and maximum setup parameters. @@ -454,12 +540,7 @@ When set to 1, the user will be able to pass a single parameter per option call. The maximum setup parameter indicates the maximum amount of parameters the user can pass at a time. The option parser will leave any non option argument after the maximum in the `remaining` slice. -In `go-getoptions` this is accomplished with: - -- `strSlice := opt.StringSlice(name, minArgs, maxArgs)`. -- `opt.StringSliceVar(&ptr, name, minArgs, maxArgs)`. -- `intSlice := opt.IntSlice(name, minArgs, maxArgs)`. -- `opt.IntSliceVar(&ptr, name, minArgs, maxArgs)`. +Good defaults are `1` and `99`. Additionally, in the case of integers, positive integer ranges are allowed. For example: @@ -468,72 +549,76 @@ Instead of writing: `csv --columns 1 2 3` or `csv --columns 1 --columns 2 --colu The input could be: `csv --columns 1..3`. -In `go-getoptions` this is currently enabled by default when using: +=== Options with Key Value arguments -- `intSlice := opt.IntSlice(name, minArgs, maxArgs)` -- `opt.IntSliceVar(&ptr, name, minArgs, maxArgs)`. +This allows the same option to be used multiple times with arguments of key value type. -=== Options with key value arguments and multiple entries +- `strMap := opt.StringMap(name, 1, 99)`. +- `opt.StringMapVar(&ptr, name, 1, 99)`. -This allows the user to save typing. For example: -Instead of writing: `connection --server hostname=serverIP --server port=123 --client hostname=localhost --client port=456` +`rpmbuild --define name=myrpm --define version=123` -The input could be: `connection --server hostname=serverIP port=123 --client hostname=localhost port=456` +or: -In `go-getoptions` this is accomplished with: +`rpmbuild --define name=myrpm version=123` -- `strMap := opt.StringMap(name, minArgs, maxArgs)`. -- `opt.StringMapVar(&ptr, name, minArgs, maxArgs)`. +Also, instead of writing: `connection --server hostname=serverIP --server port=123 --client hostname=localhost --client port=456` -That covers a complete user interface that is flexible enough to accommodate most programs. -The following are advanced features: +The input could be: `connection --server hostname=serverIP port=123 --client hostname=localhost port=456` -=== Stop parsing options when `--` is passed +=== Incremental option -Useful when arguments start with dash `-` and you don't want them interpreted as options. +- `ptr := opt.Increment(name, default_value)`. +- `opt.IncrementVar(&ptr, name, default_value)`. -In `go-getoptions` this is the default behaviour. +Some options can be passed more than once to increment an internal counter. +For example: -=== Stop parsing options when a command is passed +`command --v --v --v` -A command is assumed to be the first argument that is not an option or an argument to an option. -When a command is found, stop parsing arguments and let a command handler handle the remaining arguments. -For example: +Could increase the verbosity level each time the option is passed. -`program --opt arg command --subopt subarg` +=== Options with optional arguments -In the example above, `--opt` is an option and `arg` is an argument to an option, making `command` the first non option argument. +- `ptr := opt.StringOptional(name, default_value)`. +- `ptr := opt.IntOptional(name, default_value)`. +- `ptr := opt.Float64Optional(name, default_value)`. +- The above should be used in combination with `opt.Called(name)`. -Additionally, when mixed with _pass through_, it will also stop parsing arguments when it finds the first unmatched option. +With regular options, when the argument is not passed (for example: `--level` instead of `--level=debug`) you will get a _Missing argument_ error. +When using options with optional arguments, If the argument is not passed, the option will set the default value for the option type. +For this feature to be fully effective in strong typed languages where types have defaults, there must be a means to query the option parser to determine whether or not the option was called. -In `go-getoptions` this is accomplished with: +For example, for the following definition: -- `opt.SetUnknownMode(getoptions.Pass)`. +`ptr := opt.StringOptional("level", "info")` -And can be combined with: +* If the option `level` is called with just `--level`, the value of `*ptr` is the default `"info"` and querying `opt.Called("level")` returns `true`. +* If the option `level` is called with `--level=debug`, the value of `*ptr` is `"debug"` and querying `opt.Called("level")` returns `true`. +* Finally, If the option `level` is not called, the value of `*ptr` is the default `"info"` and querying `opt.Called("level")` returns `false`. + +=== Stop parsing options when `--` is passed -- `opt.SetRequireOrder()`. +Useful when arguments start with dash `-` and you don't want them interpreted as options. === Allow passing options and non-options in any order Some option parsers force you to put the options before or after the arguments. That is really annoying! -In `go-getoptions` this is the default behaviour. +The `go-getoptions` parser knows when to expect arguments for an option so they can be intermixed with arguments without issues. === Allow pass through +- `opt.SetUnknownMode(getoptions.Pass)`. + Have an option to pass through unmatched options. Useful when writing programs with multiple options depending on the main arguments. The initial parser will only capture the help or global options and pass through everything else. Additional argument parsing calls are invoked on the remaining arguments based on the initial input. -In `go-getoptions` this is accomplished with: - -- `opt.SetUnknownMode(getoptions.Pass)`. - === Fail on unknown The opposite of the above option. @@ -554,80 +639,77 @@ In `go-getoptions` this is accomplished with: - `opt.SetUnknownMode(getoptions.Warn)`. -=== Option aliases +=== Option Modifiers (ModifyFn) -Options should be allowed to have different aliases. -For example, the same option could be invoked with `--address` or `--hostname`. - -In `go-getoptions`, pass `opt.Alias("my-alias")` to any option. -For example: +==== Aliases `opt.BoolVar(&flag, "flag", false, opt.Alias("alias", "alias-2"))` -Finally, to know with what alias an option was called with used `opt.CalledAs()`. +Use `opt.CalledAs()` to determine the alias used to call the option. -=== Required options +==== Description -Mark an option as required. -Return an error if the option is not called. +`opt.BoolVar(&flag, "flag", false, opt.Description("This is a flag"))` -In `go-getoptions`, pass `opt.Required()` to any option. -For example: +Add a description to the option. + +==== Required options `opt.BoolVar(&flag, "flag", false, opt.Required())` +Mark an option as required. +Return an error if the option is not called. + Optionally, override the default error message with `opt.Required(msg)`. For example: `opt.BoolVar(&flag, "flag", false, opt.Required("Missing --flag!"))` -=== Incremental option - -Some options can be passed more than once to increment an internal counter. -For example: +==== Read option value from environment variable -`command --v --v --v` +`opt.BoolVar(&flag, "flag", false, opt.GetEnv("FLAG"))` -Could increase the verbosity level each time the option is passed. +Precedence is CLI option over Env Var over Default. -In `go-getoptions` this is accomplished with: +Supported for the following types: +- `opt.Bool` and `opt.BoolVar` +- `opt.String`, `opt.StringVar`, `opt.StringOptional`, and `opt.StringVarOptional` +- `opt.Int`, `opt.IntVar`, `opt.IntOptional`, and `opt.IntVarOptional` +- `opt.Float64`, `opt.Float64Var`, `opt.Float64Optional`, and `opt.Float64VarOptional` -- `ptr := opt.Increment(name, default_value)`. -- `opt.IncrementVar(&ptr, name, default_value)`. +NOTE: Non supported option types behave with a No-Op when `opt.GetEnv` is defined. -=== Additional types +When using `opt.GetEnv` with `opt.Bool` or `opt.BoolVar`, only the words "true" or "false" are valid. +They can be provided in any casing, for example: "true", "True" or "TRUE". -The option parser could provide converters to additional types. -The disadvantage of providing non basic types is that the option parser grows in size. +NOTE: For numeric values, `opt.Int` and `opt.Float64` and their derivatives, environment variable string conversion errors are ignored and the default value is assigned. -Not yet implemented in `go-getoptions`. +==== Help argument name hint -=== Options with optional arguments +`opt.StringVar(&str, "str", false, opt.ArgName("my_arg_name"))` -With regular options, when the argument is not passed (for example: `--level` instead of `--level=debug`) you will get a _Missing argument_ error. -When using options with optional arguments, If the argument is not passed, the option will set the default value for the option type. -For this feature to be fully effective in strong typed languages where types have defaults, there must be a means to query the option parser to determine whether or not the option was called or not. +The default help string for an option is: -In `go-getoptions` this is accomplished with: +- string: "" +- int: "" +- float64: "" - - `ptr := opt.StringOptional(name, default_value)`. - - `ptr := opt.IntOptional(name, default_value)`. - - `ptr := opt.Float64Optional(name, default_value)`. - - The above should be used in combination with `opt.Called(name)`. +Override it with `opt.ArgName("my_arg_name")`. +It additionally shows in the autocompletion hints. -For example, for the following definition: +==== Valid values -`ptr := opt.StringOptional("level", "info")` +`opt.StringVar(&str, "str", false, opt.ValidValues("value1", "value2"))` -* If the option `level` is called with just `--level`, the value of `*ptr` is the default `"info"` and querying `opt.Called("level")` returns `true`. -* If the option `level` is called with `--level=debug`, the value of `*ptr` is `"debug"` and querying `opt.Called("level")` returns `true`. -* Finally, If the option `level` is not called, the value of `*ptr` is the default `"info"` and querying `opt.Called("level")` returns `false`. +Limit the list of valid values for the option. +This list will be added to the autocompletion engine. -=== Option flags that call a method internally +==== Set option as called -If all the flag is doing is call a method or function when present, then having a way to call that function directly saves the programmer some time. +`opt.StringVar(&str, "str", false, opt.SetCalled(true))` -Not yet implemented in `go-getoptions`. +When calling `CommandFn` directly, it is sometimes useful to set the option as called. +Use cases are for testing and wrappers. [[operation_modes]] == Operation Modes @@ -704,16 +786,64 @@ a|option: `"o"`, argument: `"pt=arg"` footnote:[Argument gets type casted depend |=== -== Biggest option parser misfeature - Automatically generate help +== Automatically generate help + +For a proper man page for your program consider link:http://asciidoctor.org/[asciidoctor] that can generate manpages written in the Asciidoc markup. + +For the built-in help, you can add a description to your program: + +- `opt.Self("", "This is a program description")` + +NOTE: When the first argument is empty, it will use the program name from `os.Args[0]`. + +For options help ensure you add option descriptions and argument names. + +- `opt.Description("This is a string option")` +- `opt.ArgName("mystring")` + +The help command needs to be defined after all options, commands and subcommands. + +`opt.HelpCommand("help", opt.Alias("?"))` + +When calling the help command, you get the full help. +Optionally you can print only given sections of the Help. + +For example: + +[source, go] +---- +func ForceUnlock(ctx context.Context, opt *getoptions.GetOpt, args []string) error { + if len(args) < 1 { + fmt.Fprintf(os.Stderr, "ERROR: missing \n") + fmt.Fprintf(os.Stderr, "%s", opt.Help(getoptions.HelpSynopsis)) + return getoptions.ErrorHelpCalled + } + lockID := args[0] + args = slices.Delete(args, 0, 1) +---- + +In the code above, the return is `getoptions.ErrorHelpCalled` which signals the help is already printed. +The dispatch error handling can handle this error and not print and additional error message. -The biggest misfeature an option parser can have is to automatically generate the help message for the programmer. -This seemingly helpful feature has caused most tools not to have proper man pages anymore and to have all verbose descriptions mixed in the help synopsis. +[source, go] +---- + err = opt.Dispatch(ctx, remaining) + if err != nil { + if errors.Is(err, getoptions.ErrorHelpCalled) { + return 1 + } + fmt.Fprintf(os.Stderr, "ERROR: %s\n", err) + if errors.Is(err, getoptions.ErrorParsing) { + fmt.Fprintf(os.Stderr, "\n"+opt.Help()) + } + return 1 + } + return 0 +---- -If you are writing a mid to large tool, don't be lazy, write a man page for your program! -If you are looking for options, link:http://asciidoctor.org/[asciidoctor] has a manpage backend that can generate manpages written in the Asciidoc markup. +The built in help shows default values and environment variables when available. -For the help synopsis, however, use the automated help. -It even shows when an option can be set with environment variables. +It separates required options from normal options. For example, the following is a script using the built in help: @@ -783,12 +913,65 @@ OPTIONS: Use 'menu help ' for extra details. ---- +Any built-in string in `go-getoptions`, like titles, is exposed as a public variable so it can be overridden for internationalization. + +== Autocompletion + +To enable bash autocompletion, add the following line to your bash profile: + +[source,bash] +---- +complete -o default -C my-go-program my-go-program +---- + +For the above to work, the program must be in the PATH. +Otherwise: + +[source,bash] +---- +complete -o default -C "$HOME/go/bin/my-go-program" my-go-program +---- + +To enable zsh autocompletion, add the following line to your zsh profile: + +[source,zsh] +---- +export ZSHELL="true" +autoload -U +X compinit && compinit +autoload -U +X bashcompinit && bashcompinit +complete -o default -C my-go-program my-go-program +---- + +The `ZSHELL="true"` export is required because bash and zsh have different ways of handling autocompletion and there is no reliable way to detect which shell is being used. + +If testing completion in the CLI, you might require to first clean the completion entry that `complete` auto generates when hitting `Tab` twice: + +`complete -r ./my-go-program 2>/dev/null` + +When providing these as scripts that users source but not add into their profile you can use the following `sourceme.bash` script: + +. sourceme.bash +[source,bash] +---- +#!/bin/bash + +# Remove existing entries to ensure the right one is loaded +# This is not required when the completion one liner is loaded in your bashrc. +complete -r ./my-go-program 2>/dev/null + +complete -o default -C "$PWD/my-go-program" my-go-program +---- + +Then when the users go into the directory and run `source sourceme.bash` the autocompletion will be enabled. + == Command behaviour This section describes how the parser resolves ambiguities between the program and the command. Given a definition like: +[source, go] +---- func main() { var profile, password string opt := New() @@ -807,6 +990,7 @@ Given a definition like: args, err := opt.Parse(remaining) ... } +---- There is an option at the parent, `profile` and one at the command, `password`. Passing `--p ` is ambiguous and results in an error. @@ -814,6 +998,8 @@ At minimum, `--pr ` and `--pa ` are required. Given a definition like: +[source, go] +---- func main() { var profile, password string opt := New() @@ -832,6 +1018,7 @@ Given a definition like: args, err := opt.Parse(remaining) ... } +---- There is an option at the parent, `profile` and one at the command, `password` with alias `p`. Passing `--p ` at the parent results in the parent `opt.Parse` call to leave the `--p ` option unhandled and leave it in the remaining slice. @@ -848,38 +1035,35 @@ But the following one is incorrect: ./program -pr -p command -== Environment Variables Support +[[roadmap]] +== ROADMAP -Initial support for environment variables has been added. +* Generate compilation errors for commands without a defined `CommandFn`. -Currently, only: -- `opt.Bool` and `opt.BoolVar` -- `opt.String`, `opt.StringVar`, `opt.StringOptional`, and `opt.StringVarOptional` -- `opt.Int`, `opt.IntVar`, `opt.IntOptional`, and `opt.IntVarOptional` -- `opt.Float64`, `opt.Float64Var`, `opt.Float64Optional`, and `opt.Float64VarOptional` +* Create new error description for errors when parsing integer ranges (`1..3`). -To use it, set the option modify function to opt.GetEnv. -For example: +* Case insensitive matching. -[source, go] ----- -var profile string -opt.StringVar(&profile, "profile", "default", opt.GetEnv("AWS_PROFILE")) ----- +* prefix and prefix_pattern. +The string that starts options. +Defaults to "--" and "-" but could include "/" to support Win32 style argument handling. -Or: +* Allow grouping commands so they can have a different order other than alphabetical in the help output. -[source, go] ----- -profile := opt.String("profile", "default", opt.GetEnv("AWS_PROFILE")) ----- +* Some Windows tests fail because the binary name includes .exe at the end. +Update test suite to accommodate for Windows. -NOTE: Non supported option types behave with a No-Op when `opt.GetEnv` is defined. +* Introduce a `opt.NoArgs` so there are no `[]` listed in the help output. -When using `opt.GetEnv` with `opt.Bool` or `opt.BoolVar`, only the words "true" or "false" are valid. -They can be provided in any casing, for example: "true", "True" or "TRUE". +* Add `CustomCompletionFn` before release figure out how to have ways to have custom completions with different engines for arg1 and arg2. -NOTE: For numeric values, `opt.Int` and `opt.Float64` and their derivatives, environment variable string conversion errors are ignored and the default value is assigned. +* Figure out how to have custom completions for option values. + +* Add SuggestedValues as an alternative to ValidValues. + +* Add OptionGroup to allow grouping options in the help output. + +* Helper function to parse required arguments and return ErrorHelpCalled. === Possible Env Variable Roadmap @@ -896,26 +1080,6 @@ IntSlice and IntSliceVar:: Comma separated? StringMap and StringMapVar:: Comma separated key=value? -[[roadmap]] -== ROADMAP - -* Generate compilation errors for commands without a defined `CommandFn`. - -* Create new error description for errors when parsing integer ranges (`1..3`). - -* Case insensitive matching. - -* prefix and prefix_pattern. -The string that starts options. -Defaults to "--" and "-" but could include "/" to support Win32 style argument handling. - -* Allow grouping commands so they can have a different order other than alphabetical in the help output. - -* Some Windows tests fail because the binary name includes .exe at the end. -Update test suite to accommodate for Windows. - -* Introduce a opt.NoArgs so there are no `[]` listed in the help output. - == License This file is part of go-getoptions.