Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for subcommands #102

Open
nicoulaj opened this issue Aug 29, 2016 · 5 comments
Open

Add support for subcommands #102

nicoulaj opened this issue Aug 29, 2016 · 5 comments

Comments

@nicoulaj
Copy link

nicoulaj commented Aug 29, 2016

It looks from the comments in #49 that subcommands support has been considered at some point, but I am not sure what is the current status.

By subcommand support, I mean this type of syntax:

program [global options] <subcommand> [subcommand specific options/args]

It seems to me it could be done without changing the whole API:

  • Add support to differentiate positional arguments (be able to get an OptionSpec for argument 0)
  • Improve availableIf() so that it can take an OptionSpec and a value

This way we could use the API this way (pseudo-code):

OptionParser parser = new OptionParser();

// Register global options
OptionSpec<Void> helpOption = parser.acceptsAll(asList("h", "help"), "Show this help screen and exit.").forHelp();
OptionSpec<Void> versionOption = parser.acceptsAll(asList("v", "version"), "Show version and exit.").forHelp();
OptionSpec<Void> verboseOption = parser.accepts("verbose");

// Register first argument
OptionSpec<SubCommandEnum> firstArgument = parser.argument(0)
                                                  .ofType(SubCommandEnum.class)
                                                  .withValuesConvertedBy(StringToSubCommandEnum.class);

// Register subcommand1 options
OptionSpec<Void> command1Option1 = parser.accepts("option1")
                                          .availableIf(firstArgument, SubCommandEnum.SUBCOMMAND1);

// Register subcommand2 options
OptionSpec<Void> command2Option1 = parser.accepts("option1")
                                          .availableIf(firstArgument, SubCommandEnum.SUBCOMMAND2);

Or maybe I am missing something in the API ?

@pholser
Copy link
Collaborator

pholser commented Aug 30, 2016

@nicoulaj Thanks for this! Support for subcommands will get very quickly complex. I'm open to implementing something, but I want to make sure it's as simple and intuitive to grasp as possible -- otherwise, we might need to change the name of the library. 8^)

Maybe can further discuss on the Google group -- I'd be interested to hear other opinions/proposals for tweaking the API to handle subcommands.

@nicoulaj
Copy link
Author

@pholser yes, I understand your point. This is why I wanted to suggest something simple, but I already see some problems with this approach, for instance help will be poorly formatted.

BTW I tried to join the Google group, but it's private.

@nicoulaj
Copy link
Author

Nevermind, I can access it now.

@lbergelson
Copy link
Contributor

What about implementing subcommands as recursive sub-parsers? An OptionParser could accept a new type of OptionSpec that pairs a sub command with an OptionParser. Going from right to left, the top level parser would accept input, if it reaches one of the special subcommands, the rest of the input would be handed to the associated sub parser to complete parsing. If the sub-parser completes successfully it would return it's results to the parser that called it.

It would be nicely modular, so it would be easy to add or edit a subcommand without affecting the remaining commands, even if there were redundant option names between them.

@Querela
Copy link

Querela commented Apr 12, 2024

Maybe similar to Python's ArgumentParser which almost seems to function like nesting parsers.

It could be implemented as having a parser for each subcommands and a root parser that bundles them and just needs to evaluate the CLI arguments/flags until it encounters the sub command name/key. Then the sub command parser takes over.
I'm unsure if you can't already somewhat simulate this with parser.nonOptions() and "trying" to evaluate the first token as sub command identifier? And then invoking the specific sub command parser with the remaining nonOptions tokens?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants