cli icon indicating copy to clipboard operation
cli copied to clipboard

Enhance help text generation

Open S4G4R opened this issue 11 months ago • 5 comments

Printing help text is currently facilitated using functions such as format-opts and format-table, which might suffice for simple applications. But it quickly gets complicated when we have layers of nested commands and subcommands which have their own opts and args.

Given a spec and args, we should be able to generate help text using a single function call.

Additionally, we could consider including --help or -h as implicit opts for every command and subcommand. Running a command with missing opts and/or args could result in automatically printing help text. cli-matic handles this well.

S4G4R avatar Jan 28 '25 10:01 S4G4R

Help for subcommands could e.g. work like this:

$ example
Commands:
cmd1  First command
cmd2  Second command

Use "example help <command>" for more information about a given command.
Use "example options" for a list of global command-line options (applies to all commands).


$ example options
The following options can be passed to any command:
  --foo:
      Description
      spanning multiple lines.


$ example help cmd1
Short description

More details
on multiple lines.

Usage:
  example cmd1 [options] <bar> [baz]

Options:
  bar:
      Required argument description.
  baz:
      Optional argument description.
  --bag='default':
      Option description
      spanning multiple lines.


$ example help cmd2
Description.

Usage:
  example cmd2 [options] [foo]

Options:
  foo:
      Optional argument description.
  --fog=[]:
      Description.

devurandom avatar Mar 11 '25 11:03 devurandom

Using the following function:

(defn format-commands [{:keys [table]}]
  (let [table (mapv (fn [{:keys [cmds desc]}]
                      (cond-> [(str/join " " cmds)]
                        desc (conj desc)))
                    (filter (comp seq :cmds) table))]
    (cli/format-table {:rows table})))

we can produce, from e.g. this table:

(def table
  [{:cmds ["copy"]   :fn copy   :args->opts [:file] :desc "Copy a file"}
   {:cmds ["delete"] :fn delete :args->opts [:file] :desc "Delete a file"}
   {:cmds []         :fn help}])
  copy   Copy a file
  delete Delete a file

borkdude avatar Mar 11 '25 12:03 borkdude

Sorry I wasn't done, but I hit "Comment" accidentally.

The options can already be formatted using format-opts. Honestly the rest of the proposition is too opiniated in my opinion. So it seems to be that just adding the function format-commands (or perhaps format-table is a better name) would help a bit?

borkdude avatar Mar 11 '25 12:03 borkdude

Some prior art here as well:

https://github.com/nextjournal/garden-cli/blob/8cbd0a719c7d0999dee93cb1e9e5387cb5e9ab1a/src/nextjournal/garden_cli.clj#L866-L916

borkdude avatar Mar 11 '25 12:03 borkdude

So it seems to be that just adding the function format-commands (or perhaps format-table is a better name) would help a bit?

Sounds great and is probably good enough for most. Thanks for considering this topic!

devurandom avatar Mar 11 '25 13:03 devurandom