package cli import ( "fmt" "io" "strings" ) // Version is the program version, overridable at build time via -ldflags. var Version = "0.1.0" // PrintVersion writes the version banner. func PrintVersion(w io.Writer) { fmt.Fprintf(w, "got %s — a Rob-Pike-style command-line downloader in Go\n", Version) } // PrintHelp writes usage. A bare -h/--help (empty tag) shows only the Basic // group, keeping the default terse; --help=all shows every group and // --help= (basic/http/bittorrent/advanced) filters to one. func PrintHelp(w io.Writer, tag string) { all := tag == "all" // Empty tag means a bare -h/--help: default to the Basic group only. bare := tag == "" want, filtered := tagByName(tag) if bare { want, filtered = Basic, true } if !all && !bare && !filtered { fmt.Fprintf(w, "got: unknown help tag %q (use all|basic|http|bittorrent|advanced)\n\n", tag) } fmt.Fprint(w, `Usage: got [OPTIONS] URI | magnet:... | file.torrent ... A multi-protocol download tool: segmented HTTP(S) and BitTorrent. `) for _, group := range []Tag{Basic, HTTP, BitTorrent, Advanced} { if filtered && !all && group != want { continue } fmt.Fprintf(w, "%s options:\n", title(group.String())) for i := range options { o := &options[i] if o.Tag != group { continue } fmt.Fprintf(w, " %s %s\n", flagLabel(o), o.Help) } fmt.Fprintln(w) } // Only the full listing (all groups) repeats the meta flags. if all || !filtered { fmt.Fprint(w, " -h, --help[=TAG] show help (TAG: all|basic|http|bittorrent|advanced)\n") fmt.Fprint(w, " -v, --version show version\n\n") } if bare { fmt.Fprint(w, "Showing basic options. Use --help=all for every option, or --help=advanced for advanced ones.\n") } } // title upper-cases the first letter of a single word. func title(s string) string { if s == "" { return s } return strings.ToUpper(s[:1]) + s[1:] } func tagByName(name string) (Tag, bool) { switch name { case "basic": return Basic, true case "http": return HTTP, true case "bittorrent", "bt": return BitTorrent, true case "advanced": return Advanced, true default: return Basic, false } } // flagLabel renders the "-x, --long=ARG" column for one option. func flagLabel(o *Opt) string { var b strings.Builder if o.Short != 0 { fmt.Fprintf(&b, "-%c, ", o.Short) } else { b.WriteString(" ") } b.WriteString("--" + o.Long) if m := metavar(o); m != "" { b.WriteString("=" + m) } return b.String() } // metavar is the placeholder shown after a value-taking flag, e.g. the "N" in // "--split=N". An explicit Opt.Metavar wins; otherwise it derives from the Kind. // Bool takes no value, so its metavar is empty and no "=ARG" is printed. func metavar(o *Opt) string { if o.Metavar != "" { return o.Metavar } switch o.Kind { case Bool: return "" case Size: return "SIZE" case Int: return "N" case Float: return "RATIO" case Enum: return strings.Join(o.Enum, "|") default: return "VAL" } }