GithubHelp home page GithubHelp logo

Comments (14)

shadowspawn avatar shadowspawn commented on June 1, 2024 1

The git stash example might be done in Commander as nested commands. Making it look similar:

import { Command } from 'commander';
const program = new Command();
program.configureHelp({ subcommandTerm: (cmd) => cmd.name() + ' ' + cmd.usage() });

const stashCommand = program.command('stash');
stashCommand.command('list').usage('[<log-options>]')
stashCommand.command('show').usage('[-u | --include-untracked | --only-untracked] [<diff-options>] [<stash>]');
stashCommand.command('drop').usage('[-q | --quiet] [<stash>]');

program.parse();
% node git.mjs help stash
Usage: git stash [options] [command]

Options:
  -h, --help                                                                     display help for command

Commands:
  list [<log-options>]
  show [-u | --include-untracked | --only-untracked] [<diff-options>] [<stash>]
  drop [-q | --quiet] [<stash>]
  help [command]                                                                 display help for command

from commander.js.

shadowspawn avatar shadowspawn commented on June 1, 2024 1

This has not had any likes (yet) and neither did #80, but I am impressed by the examples here. Keeping this open for more consideration.

from commander.js.

shadowspawn avatar shadowspawn commented on June 1, 2024

I appreciate the examples and finding previous issue, thanks.

Having more than one usage string or usage example in the synopsis section is a pattern that Commander does not directly support.

from commander.js.

shadowspawn avatar shadowspawn commented on June 1, 2024

The only workaround is to include a newline in the usage string, but successive usages are not correctly indented.

This work-around seems to work reasonably, with manual indentation?

import { Command } from 'commander';
const program = new Command();

program.usage(`[options] [ script.js ] [arguments]
       node inspect [options] [ script.js | host:port ] [arguments]`);

program.parse();
% node node.mjs --help
Usage: node [options] [ script.js ] [arguments]
       node inspect [options] [ script.js | host:port ] [arguments]

Options:
  -h, --help  display help for command

from commander.js.

vassudanagunta avatar vassudanagunta commented on June 1, 2024

This work-around seems to work reasonably, with manual indentation?

Hardcoding a 7 char indent is exactly the workaround I'm using. Sorry I didn't mention that. Smells a wee bit bad, but not a big deal ;)

In my particular use case, nested commands won't work, and in fact Option.conflicts isn't applicable either, as the command has different semantics (and options) depending on whether the first positional arg is a file or directory, similar to cp which I'll add as an example above.

from commander.js.

vassudanagunta avatar vassudanagunta commented on June 1, 2024

Also, is your name an Anglicization of the French so that people pronounce it correctly? I had a friend with that name and hated how it was mispronounced. Feel free to delete this comment! :)

from commander.js.

shadowspawn avatar shadowspawn commented on June 1, 2024

Gee? Scottish origins in my family tree.

from commander.js.

shadowspawn avatar shadowspawn commented on June 1, 2024

Another possible approach is to include text in the long description, which is fairly freeform (and avoid the 7 char indent annoyance):

program.command('stash')
   .description(`Synopsis:
git stash list [<log-options>]
git stash show [-u | --include-untracked | --only-untracked] [<diff-options>] [<stash>]
git stash drop [-q | --quiet] [<stash>]`)
   .summary('Stash the changes in a dirty working directory away');
% node description.mjs stash -h
Usage: description stash [options]

Synopsis:
git stash list [<log-options>]
git stash show [-u | --include-untracked | --only-untracked] [<diff-options>] [<stash>]
git stash drop [-q | --quiet] [<stash>]

Options:
  -h, --help  display help for command

from commander.js.

vassudanagunta avatar vassudanagunta commented on June 1, 2024

Also, is your name an Anglicization of the French so that people pronounce it correctly? I had a friend with that name and hated how it was mispronounced. Feel free to delete this comment! :)

Gee? Scottish origins in my family tree.

So the French name, Jean-Guy, is pronounced like John Ghee. Sadly, most American colleagues of the aforementioned friend pronounced it as the English words, "gene guy".

from commander.js.

vassudanagunta avatar vassudanagunta commented on June 1, 2024

As I hinted before, this isn't a big deal. The workaround is fine.

That said, since this is JS, I think it would be easy enough to support usage accepting a string array and acting accordingly.
Alternatively, allow multiple calls to usage. Or both, as is the case with conflicts.

If you agree with one of the above, I could look into submitting a PR.

from commander.js.

vassudanagunta avatar vassudanagunta commented on June 1, 2024

I thought about this a little trying to work around it for one of my CLIs. It's implicit for all the CLIs that have multiple usages that aren't keyed by subcommands like git stash that there is some way to distinguish which of the usages is in effect.

Looking at git rebase for example:

git rebase [-i | --interactive] [<options>] [--exec <cmd>]
               [--onto <newbase> | --keep-base] [<upstream> [<branch>]]
git rebase [-i | --interactive] [<options>] [--exec <cmd>] [--onto <newbase>]
               --root [<branch>]
git rebase (--continue | --skip | --abort | --quit | --edit-todo | --show-current-patch)
  • --continue, --skip, etc are unique to usage 3.
  • -i narrows it to usage 1 or 2.
    • --keep-base narrows it to usage 1.
    • --root narrows it to usage 2.
    • two non-option arguments narrow it to usage 1.

So one way to implement this:

  1. Start with a list of all usages as candidates.
  2. For each parsed option narrow the candidate list.
  3. If an option isn't valid for any of the remaining candidates, see if it is valid for any of the eliminated usages.
    • If it is, then report it as a conflict
    • If not, report it as an unrecognized option.

In addition, it would be good to have a way to narrow the candidate list by the type of non-option argument. For example, cp as shown earlier has usages based on whether an argument is a file or directory. My personal use case has this as well. So perhaps a way to process non-option arguments (aka "remaining arguments"). For example:

program.
  .argument('<mode>', 'mode to use')
  .argument('<file>', 'string to split', validateCallback)

where the optional validateCallback returns true only if the argument matches whatever is expected of that argument, e.g. in this case that it exists in the file system and that it is a file and not a directory. For single usage cases, this adds a feature that currently does not exist: A way to validate non-option arguments (If you like this idea separate from supporting multiple usages, let me know and I can create a separate feature request). For multi-usage cases, it is also used to narrow the candidate list.

If you find this interesting, happy to iterate an API design with you if that helps.

from commander.js.

shadowspawn avatar shadowspawn commented on June 1, 2024

Note that custom processing of arguments is supported. See: https://github.com/tj/commander.js#custom-argument-processing

Like:

   .argument('<first>', 'integer argument', myParseInt)

from commander.js.

shadowspawn avatar shadowspawn commented on June 1, 2024

Validating the command-line arguments using the usage (strings or otherwise) is an interesting idea, but I think going to be too much work. Your examples and comments show the complicated ways utilities overload their usage, like cp file/directory argument type, or rebase with 7 modes based on the exclusive options.

Simply supporting calling usage multiple times should be technically easy, but the earlier issue got no upvotes in 7 years. Since there are easy work-arounds, I don't think it is worth adding without some upvotes or interest on this issue. (Which is why I haven't closed it yet, giving it a chance to gather some support.)

from commander.js.

shadowspawn avatar shadowspawn commented on June 1, 2024

I thought about this a little trying to work around it for one of my CLIs.

And to be clear, thanks for sharing. Both for explaining some of your own use-case, and the thoughts on possible approaches.

from commander.js.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.