package arg import ( "fmt" "io" "os" "strings" "go.wit.com/lib/protobuf/argvpb" ) // 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 } func (p *Parser) WriteHelpForAutocompleteArgv() error { argvpb.PB.Stderr += fmt.Sprintln("go-args.WriteHelpForAutocompleteArgv() not finished") return nil } // 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 tmp := "--" + spec.long if strings.HasPrefix(tmp, partial) { automatch = append(automatch, tmp) } } } /* // 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(os.Stderr, "%s\n", strings.Join(automatch, " ")) // fmt.Fprintf(os.Stderr, "%s\n", strings.Join(automatch, " ")) // fmt.Fprintf(os.Stderr, "\n") 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 }