|
| 1 | +/* |
| 2 | +This package contains our custom help text generators, |
| 3 | +and wires them into `urfave/cli` at package init time. |
| 4 | +
|
| 5 | +We use templates which emit markdown. |
| 6 | +Optionally, this can be subsequently post-processed to be |
| 7 | +converted to nicer terminal rendering using ANSI codes -- |
| 8 | +this feature is in another package, so you can disable it. |
| 9 | +
|
| 10 | +(The use of package init time is unfortunate, |
| 11 | +but package sideeffects cannot be avoided: |
| 12 | +package-scope vars are the only option for customizing help processing |
| 13 | +that the `urfave/cli` package currently makes available.) |
| 14 | +*/ |
| 15 | +package helpgen |
| 16 | + |
| 17 | +import ( |
| 18 | + "bytes" |
| 19 | + "io" |
| 20 | + "strings" |
| 21 | + "text/tabwriter" |
| 22 | + "text/template" |
| 23 | + |
| 24 | + "github.com/urfave/cli/v2" |
| 25 | + "github.com/warptools/warpforge/app/base/render" |
| 26 | +) |
| 27 | + |
| 28 | +/* |
| 29 | + A guide to how to use the various docs strings in a cli.Command in our system: |
| 30 | +
|
| 31 | + - Usage -- this should be a one-liner, used to describe this command in the parent command's overview of its children. |
| 32 | + - UsageText -- this should contain a synopsys, with examples of how to use the command and its flags. May be multi-line. |
| 33 | + - Description -- freetext prose; may be multi-line. Shows up in the `-h` for that command. |
| 34 | + - ArgsUsage -- UNUSED. (TODO:CONSIDER: maybe use this for synopsys, and repurpose UsageText for bighelp? Or otherwise shuffle the deck chairs.) |
| 35 | +
|
| 36 | + And outside of this: |
| 37 | +
|
| 38 | + - longer helptext for the `{appname} help {subcommandname}` feature -- that isn't actually a feature we've implemented yet. |
| 39 | + If it comes, it might be based on munging the Description field. (e.g., peeking for "---" or similar, on the assumption that isn't actually needed in real content.) |
| 40 | +
|
| 41 | + For documenting cli.Flag: |
| 42 | +
|
| 43 | + - there's really only the Usage fields, per type. |
| 44 | + - Short and long isn't disambiguated here either. |
| 45 | + (As with commands, if we introduce this, it might be possibly to do it by munging format cues in-band.) |
| 46 | +*/ |
| 47 | + |
| 48 | +// printHelpCustom is the entrypoint for `urfave/cli`'s customization. |
| 49 | +// |
| 50 | +// See the function of the same name upstream for reference. |
| 51 | +// This function is considerably derived from it. |
| 52 | +func printHelpCustom(out io.Writer, tmpl string, data interface{}, customFuncs map[string]interface{}) { |
| 53 | + |
| 54 | + const hardwrap = 10000 |
| 55 | + |
| 56 | + funcMap := template.FuncMap{ |
| 57 | + "join": strings.Join, |
| 58 | + "subtract": subtract, |
| 59 | + "indent": indent, |
| 60 | + "nindent": nindent, |
| 61 | + "trim": strings.TrimSpace, |
| 62 | + "wrap": func(input string, offset int) string { return wrap(input, offset, hardwrap) }, |
| 63 | + "offset": offset, |
| 64 | + "offsetCommands": offsetCommands, |
| 65 | + } |
| 66 | + for key, value := range customFuncs { |
| 67 | + funcMap[key] = value |
| 68 | + } |
| 69 | + |
| 70 | + var buf bytes.Buffer |
| 71 | + w := tabwriter.NewWriter(&buf, 1, 8, 4, ' ', 0) |
| 72 | + t := template.Must(template.New("help").Funcs(funcMap).Parse(tmpl)) |
| 73 | + template.Must(t.New("helpNameTemplate").Parse(helpNameTemplate)) |
| 74 | + template.Must(t.New("usageTemplate").Parse(usageTemplate)) |
| 75 | + template.Must(t.New("visibleCommandTemplate").Parse(visibleCommandTemplate)) |
| 76 | + template.Must(t.New("visibleFlagCategoryTemplate").Parse(visibleFlagCategoryTemplate)) |
| 77 | + template.Must(t.New("visibleFlagTemplate").Parse(visibleFlagTemplate)) |
| 78 | + template.Must(t.New("visibleGlobalFlagCategoryTemplate").Parse(strings.Replace(visibleFlagCategoryTemplate, "OPTIONS", "GLOBAL OPTIONS", -1))) |
| 79 | + template.Must(t.New("authorsTemplate").Parse(authorsTemplate)) |
| 80 | + template.Must(t.New("visibleCommandCategoryTemplate").Parse(visibleCommandCategoryTemplate)) |
| 81 | + |
| 82 | + err := t.Execute(w, data) |
| 83 | + if err != nil { |
| 84 | + panic(err) |
| 85 | + } |
| 86 | + _ = w.Flush() |
| 87 | + |
| 88 | + if err := render.Render(buf.Bytes(), out, Mode); err != nil { |
| 89 | + panic(err) |
| 90 | + } |
| 91 | +} |
| 92 | + |
| 93 | +var Mode = render.Mode_ANSIdown |
| 94 | + |
| 95 | +func init() { |
| 96 | + cli.HelpPrinterCustom = printHelpCustom |
| 97 | +} |
0 commit comments