summaryrefslogtreecommitdiff
path: root/complete.go
diff options
context:
space:
mode:
Diffstat (limited to 'complete.go')
-rw-r--r--complete.go222
1 files changed, 222 insertions, 0 deletions
diff --git a/complete.go b/complete.go
new file mode 100644
index 0000000..72f964d
--- /dev/null
+++ b/complete.go
@@ -0,0 +1,222 @@
+package arg
+
+import (
+ "fmt"
+ "io"
+ "os"
+ "strings"
+)
+
+// has the variables for autocomplete
+type Complete struct {
+ Subcommand []string // this will be sent from the shell autocomplete scheme
+ Partial string // whatever the user has partially entered on the commandline
+ Stderr io.Writer // this is where Stderr
+ Stdout io.Writer // this is where Stdout
+}
+
+// same as WriteHelpForSubcommand above, but can flip to STDERR and STDOUT
+// most shell autocomplete behavior usually wants things that way
+func (p *Parser) WriteHelpForAutocomplete(stderr io.Writer, stdout io.Writer, partial string, subcommand ...string) error {
+ var automatch []string
+ if stderr == nil {
+ stderr = os.Stderr
+ }
+ cmd, err := p.lookupCommand(subcommand...)
+ if err != nil {
+ return err
+ }
+
+ var positionals, longOptions, shortOptions, envOnlyOptions []*spec
+ var hasVersionOption bool
+ for _, spec := range cmd.specs {
+ switch {
+ case spec.positional:
+ positionals = append(positionals, spec)
+ case spec.long != "":
+ longOptions = append(longOptions, spec)
+ if spec.long == "version" {
+ hasVersionOption = true
+ }
+ case spec.short != "":
+ shortOptions = append(shortOptions, spec)
+ case spec.short == "" && spec.long == "":
+ envOnlyOptions = append(envOnlyOptions, spec)
+ }
+ }
+
+ // obtain a flattened list of options from all ancestors
+ // also determine if any ancestor has a version option spec
+ var globals []*spec
+ ancestor := cmd.parent
+ for ancestor != nil {
+ for _, spec := range ancestor.specs {
+ if spec.long == "version" {
+ hasVersionOption = true
+ break
+ }
+ }
+ globals = append(globals, ancestor.specs...)
+ ancestor = ancestor.parent
+ }
+
+ if p.description != "" {
+ fmt.Fprintln(stderr, p.description)
+ }
+
+ if !hasVersionOption && p.version != "" {
+ fmt.Fprintln(stderr, p.version)
+ }
+
+ p.WriteUsageForSubcommand(stderr, subcommand...)
+
+ // write the list of positionals
+ if len(positionals) > 0 {
+ fmt.Fprint(stderr, "\nPositional arguments:\n")
+ for _, spec := range positionals {
+ print(stderr, spec.placeholder, spec.help, withDefault(spec.defaultString), withEnv(spec.env))
+ }
+ }
+
+ // write the list of options with the short-only ones first to match the usage string
+ if len(shortOptions)+len(longOptions) > 0 || cmd.parent == nil {
+ fmt.Fprint(stderr, "\nOptions:\n")
+ for _, spec := range shortOptions {
+ p.printOption(stderr, spec)
+ }
+ for _, spec := range longOptions {
+ p.printOption(stderr, spec)
+ //jwc
+ if strings.HasPrefix(spec.long, partial) {
+ automatch = append(automatch, "--"+spec.long)
+ }
+ }
+ }
+
+ // write the list of global options
+ if len(globals) > 0 {
+ fmt.Fprint(stderr, "\nGlobal options:\n")
+ for _, spec := range globals {
+ p.printOption(stderr, spec)
+ }
+ }
+
+ // write the list of built in options
+ p.printOption(stderr, &spec{
+ cardinality: zero,
+ long: "help",
+ short: "h",
+ help: "display this help and exit",
+ })
+ if !hasVersionOption && p.version != "" {
+ p.printOption(stderr, &spec{
+ cardinality: zero,
+ long: "version",
+ help: "display version and exit",
+ })
+ }
+
+ // write the list of environment only variables
+ if len(envOnlyOptions) > 0 {
+ fmt.Fprint(stderr, "\nEnvironment variables:\n")
+ for _, spec := range envOnlyOptions {
+ p.printEnvOnlyVar(stderr, spec)
+ }
+ }
+
+ // write the list of subcommands
+ if len(cmd.subcommands) > 0 {
+ fmt.Fprint(stderr, "\nCommands:\n")
+ for _, subcmd := range cmd.subcommands {
+ names := append([]string{subcmd.name}, subcmd.aliases...)
+ print(stderr, strings.Join(names, ", "), subcmd.help)
+ if strings.HasPrefix(subcmd.name, partial) {
+ automatch = append(automatch, subcmd.name)
+ }
+ }
+ }
+
+ if p.epilogue != "" {
+ fmt.Fprintln(stderr, "\n"+p.epilogue)
+ }
+
+ if stdout == nil {
+ fmt.Fprintf(os.Stdout, "err foo")
+ } else {
+ // writes out the shell autocomplete matches
+ if len(automatch) > 0 {
+ fmt.Fprintf(stdout, "%s", strings.Join(automatch, " "))
+ }
+ }
+ return nil
+}
+
+// GetUsageForSubcommand gets the commands for bash shell completetion
+func (p *Parser) GetUsageForSubcommand(stdout io.Writer, stderr io.Writer, partial string, s string) (string, error) {
+ var log []string
+ var final []string
+ cmd, err := p.lookupCommand(s)
+ if err != nil {
+ return "", err
+ }
+
+ var positionals, longOptions, shortOptions []*spec
+ for _, spec := range cmd.specs {
+ switch {
+ case spec.positional:
+ positionals = append(positionals, spec)
+ case spec.long != "":
+ longOptions = append(longOptions, spec)
+ case spec.short != "":
+ shortOptions = append(shortOptions, spec)
+ }
+ }
+
+ // write the option component of the usage message
+ for _, spec := range shortOptions {
+ // prefix with a space
+ log = append(log, fmt.Sprintf(" "))
+ if !spec.required {
+ // log = append(log, fmt.Sprintf("["))
+ }
+ log = append(log, synopsis(spec, "-"+spec.short))
+ if !spec.required {
+ // log = append(log, fmt.Sprintf("]"))
+ }
+ }
+
+ for _, spec := range longOptions {
+ // prefix with a space
+ if !spec.required {
+ // log = append(log, fmt.Sprintf("["))
+ }
+ log = append(log, synopsis(spec, "--"+spec.long))
+ if !spec.required {
+ // log = append(log, fmt.Sprintf("]"))
+ }
+ }
+
+ for _, spec := range positionals {
+ if !spec.required {
+ // log = append(log, fmt.Sprintf("["))
+ }
+ if spec.cardinality == multiple {
+ log = append(log, fmt.Sprintf("%s [%s ...]", spec.placeholder, spec.placeholder))
+ } else {
+ log = append(log, spec.placeholder)
+ }
+ }
+ for _, subcmd := range cmd.subcommands {
+ names := append([]string{subcmd.name}, subcmd.aliases...)
+ if strings.HasPrefix(subcmd.name, partial) {
+ final = append(final, subcmd.name)
+ }
+ log = append(log, strings.Join(names, ", "), subcmd.help)
+ if stderr != nil {
+ print(stderr, strings.Join(names, ", "), subcmd.help)
+ }
+ }
+ fmt.Fprintf(stdout, "%s", strings.Join(final, " "))
+
+ return strings.Join(final, " "), nil
+}