arcanis / clipanion

Type-safe CLI library / framework with no runtime dependencies
https://mael.dev/clipanion/
1.12k stars 65 forks source link

Group options into categories #35

Open cspotcode opened 4 years ago

cspotcode commented 4 years ago

Pending implementation of #12

Just as commands can be grouped into categories, options/flags should be groupable as well. Groups have some sort of ordering, with more commonly-used groups at the top, and more niche options further down, so there should be a way to specify the ordering of groups in the output.

To get an idea of what the output might look like, I threw together this yargs demo:

$ yarn ts-node ./src/index.ts exec --help
bin.js exec <args...>

Run external commands within our administrative environment

Positionals:
  args  Command to run.  Will be executed as an external process.
                                                [array] [required] [default: []]

Options:
  --swallow-exit-code, -s  a silly flag which swallows exit codes for some
                           reason                                      [boolean]

Credentials:
  --foo  authenticate against the foo environment                      [boolean]
  --bar  authenticate against the bar environment                      [boolean]
  --env  authenticate against a custom environment declared in your rc file
                                                                        [string]

Misc:
  --version  Show version number                                       [boolean]
  --help     Show help                                                 [boolean]

The yargs source code is below:

yargs demo ```typescript import type _yargs from 'yargs/yargs'; const yargs: typeof _yargs = require('yargs/yargs'); const credentialsGroup = 'Credentials:'; yargs(process.argv.slice(2)) .strict() .help() // Global options available to all commands .options({ foo: { group: credentialsGroup, type: 'boolean', describe: 'authenticate against the foo environment' }, bar: { group: credentialsGroup, type: 'boolean', describe: 'authenticate against the bar environment' }, env: { group: credentialsGroup, type: 'string', describe: 'authenticate against a custom environment declared in your rc file' } }) .group('version', 'Misc:') .group('help', 'Misc:') .command('exec ', 'Run external commands within our administrative environment', { builder(yargs) { return yargs .positional('args', { describe: 'Command to run. Will be executed as an external process.' }) .options({ 'swallow-exit-code': { type: 'boolean', alias: 's', group: 'Options:', describe: 'a silly flag which swallows exit codes for some reason' } }).help(); }, handler(args) { } }) .parse(); ```
cspotcode commented 3 years ago

I've started implementing this and I have a question about the headers used for categories.

Here is the current output of option categories. Each gets a header at the same level as "Usage" and "Details."

Should option categories appear as sub-headings of the "Options" heading?


━━━ Usage ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

$ binname other-a

━━━ Options ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

  -v,--verbose    foo

━━━ Credentials ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

  --prod          bar
  --staging       bar
  --qa            bar

━━━ Details ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

This is amulti-line description.