Skip to content

Commit

Permalink
Update README
Browse files Browse the repository at this point in the history
  • Loading branch information
DavidGamba committed Jan 5, 2024
1 parent 023a4a9 commit aa4632a
Showing 1 changed file with 184 additions and 182 deletions.
366 changes: 184 additions & 182 deletions README.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -330,9 +330,9 @@ Only the last two versions of Go will be supported.

NOTE: For a <<quick_overview>>, jump to that section in the TOC or review the http://godoc.org/github.com/DavidGamba/go-getoptions[GoDoc Documentation].

Option parsing is the act of taking command line arguments and converting them into meaningful structures within the program.
Option parsing is the act of taking command line (CLI) arguments and converting them into meaningful structures within the program.

First declare a getoptions instance:
First declare a `getoptions` instance:

[source, go]
----
Expand Down Expand Up @@ -472,6 +472,187 @@ func Name(ctx context.Context, opt *getoptions.GetOpt, args []string) error {
}
----

== Automatically generate help

For a proper extended 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]
----
fmt.Fprintf(os.Stderr, "%s", opt.Help(getoptions.HelpSynopsis))
----

Or through a helper:

[source, go]
----
func ForceUnlock(ctx context.Context, opt *getoptions.GetOpt, args []string) error {
lockID, args, err := opt.GetRequiredArg(args)
if err != nil {
return err
}
----

In the code above, if there is no argument passed, the `GetRequiredArg` will print an error plus the synopsis:

----
ERROR: Missing <lock-id>
SYNOPSIS:
program [--help] <lock-id>
----

The error 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.


[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
----

Another helpful error to check for is `getoptions.ErrorParsing`, as shown above, which indicates there was a problem parsing the CLI arguments.
This can be used, to print the help only in cases where the user didn't enter valid CLI options or arguments.

The built in help shows default values and environment variables when available.

It separates _ARGUMENTS_, _REQUIRED PARAMETERS_ and _OPTIONS_ into separate sections.

For example, the following is a script using the built in help:

----
$ bt terraform force-unlock help
NAME:
bt terraform force-unlock
SYNOPSIS:
bt terraform force-unlock [--help|-?] [--profile <string>] [--quiet]
[--ws <string>] <lock-id>
ARGUMENTS:
<lock-id> Lock ID
OPTIONS:
--help|-? (default: false)
--profile <string> BT Terraform Profile to use (default: "default", env: AWS_PROFILE)
--quiet (default: false, env: QUIET)
--ws <string> Workspace to use (default: "")
----

And below is the output of the automated help of a program with multiple commands:

----
$ tz help
SYNOPSIS:
tz [--config|-c <string>] [--format-standard|--format-12-hour|--format-12h]
[--group <string>] [--help|-?] [--short|-s] [--verbose] <command> [<args>]
COMMANDS:
cities filter cities list
list list all timezones
version show version
OPTIONS:
--config|-c <string> Config file (default: "")
--format-standard|--format-12-hour|--format-12h Use standard 12 hour AM/PM time format (default: false)
--group <string> Group to show (default: "")
--help|-? (default: false)
--short|-s Don't show timezone bars (default: false)
--verbose Enable logging (default: false, env: TZ_VERBOSE)
Use 'tz help <command>' 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.

== Options

=== Boolean options

Opposite of default when passed on the command line.
Expand Down Expand Up @@ -744,7 +925,7 @@ When calling `CommandFn` directly, it is sometimes useful to set the option as c
Use cases are for testing and wrappers.

[[operation_modes]]
== Operation Modes
== Operation Modes: How to handle single dash '-' options

Notice how so far only long options (options starting with double dash `--`) have been mentioned.
There are 3 main ways to handle short options (options starting with only one dash `-`).
Expand Down Expand Up @@ -818,185 +999,6 @@ a|option: `"o"`, argument: `"pt=arg"` footnote:[Argument gets type casted depend

|===

== Automatically generate help

For a proper extended 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]
----
fmt.Fprintf(os.Stderr, "%s", opt.Help(getoptions.HelpSynopsis))
----

Or through a helper:

[source, go]
----
func ForceUnlock(ctx context.Context, opt *getoptions.GetOpt, args []string) error {
lockID, args, err := opt.GetRequiredArg(args)
if err != nil {
return err
}
----

In the code above, if there is no argument passed, the `GetRequiredArg` will print an error plus the synopsis:

----
ERROR: Missing <lock-id>
SYNOPSIS:
program [--help] <lock-id>
----

The error 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.


[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
----

Another helpful error to check for is `getoptions.ErrorParsing`, as shown above, which indicates there was a problem parsing the CLI arguments.
This can be used, to print the help only in cases where the user didn't enter valid CLI options or arguments.

The built in help shows default values and environment variables when available.

It separates required parameters from options.

For example, the following is a script using the built in help:

----
$ bt terraform force-unlock help
NAME:
bt terraform force-unlock
SYNOPSIS:
bt terraform force-unlock [--help|-?] [--profile <string>] [--quiet]
[--ws <string>] <lock-id>
ARGUMENTS:
<lock-id> Lock ID
OPTIONS:
--help|-? (default: false)
--profile <string> BT Terraform Profile to use (default: "default", env: AWS_PROFILE)
--quiet (default: false, env: QUIET)
--ws <string> Workspace to use (default: "")
----

And below is the output of the automated help of a program with multiple commands:

----
$ tz help
SYNOPSIS:
tz [--config|-c <string>] [--format-standard|--format-12-hour|--format-12h]
[--group <string>] [--help|-?] [--short|-s] [--verbose] <command> [<args>]
COMMANDS:
cities filter cities list
list list all timezones
version show version
OPTIONS:
--config|-c <string> Config file (default: "")
--format-standard|--format-12-hour|--format-12h Use standard 12 hour AM/PM time format (default: false)
--group <string> Group to show (default: "")
--help|-? (default: false)
--short|-s Don't show timezone bars (default: false)
--verbose Enable logging (default: false, env: TZ_VERBOSE)
Use 'tz help <command>' 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.
Expand Down

0 comments on commit aa4632a

Please sign in to comment.