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鈥檒l occasionally send you account related emails.

Already on GitHub? Sign in to your account

Options shown in Global section can include unreachable alternatives. #461

Open
ChrisPenner opened this issue Sep 19, 2022 · 4 comments
Open

Comments

@ChrisPenner
Copy link

Hello 馃憢馃徏

The CLI for Unison has one very common use-case (launching the unison shell) and several other 'utility' commands. The way we have things set up right now is as follows:

  • ucm without any subcommand runs the 'launch' behaviour
  • ucm run defers to the run subcommand.

The way we've implemented this is by using our launch option parser as a fallback for our subcommand parser:

topLevelParser =
  hsubparser subcommands <|> launchCommand

Meaning that if the user doesn't provide a command, we interpret it as a 'launch'.

The issue is that currently optparse-applicative interprets all of the options of launch as global options, even though all of those options will fail if passed to the run subcommand for example.

Is there any way to indicate options as being only relevant if no subcommand is provided, rather than showing them as global?

Effectively I want the empty command to just be treated as another subcommand.

This may not be the most common setup, but if you can think of a way to make this work I'd love to hear it 馃槃

Thank you for maintaining such an awesome tool, it saves us a lot of time :D

@HuwCampbell
Copy link
Collaborator

The parser you mentioned should just work and be pretty intuitive. An option passed for the launch command will lock in one side alternative. Indeed everything should be wrapped parenthetically with an alternative marker.

Can you give me an example of what the help looks like and what you think it should look like? Or some CLI examples with desired vs current behaviour given a particular parser?

@ChrisPenner
Copy link
Author

The executable itself works as expected, it seems to be just the help messages that are out of whack; The issue is that currently optparse-applicative interprets all of the options of launch as global options, even though all of those options will fail if passed to the run subcommand for example.

So, for example, for the unison executable, launch has a --port flag, but run does not.

If I get the help for run, it shows ALL of the options for launch under "Global options" even though some of them only work for the launch command specifically (or the empty top-level command which ends up calling launch)

$ ucm run --help
Usage: unison-trunk run SYMBOL [RUN-ARGS]
  Execute a definition from the codebase, passing on the provided arguments. To pass flags to your
  program, use `run <symbol> -- --my-flag`

Available options:
  -h,--help                Show this help text

Global options:
  -v,--version             Show version
  -c,--codebase CODEBASE/PATH
                           The path to an existing codebase
  -C,--codebase-create CODEBASE/PATH
                           The path to a new or existing codebase (one will be created if there
                           isn't one)
  --exit                   Exit repl after the command.
  --token STRING           API auth token
  --host STRING            Codebase server host
  --port NUMBER            Codebase server port
  --ui DIR                 Path to codebase ui root
  --no-base                if set, a new codebase will be created without downloading the base
                           library, otherwise the new codebase will download base

Notice that --port is listed here as a global option, but it's not actually a valid option for the run command; and opt-parse applicative will correctly show an error if we try to use it (although the option still incorrectly appears in the global options of the usage info):

$ ucm run --port 5050
Invalid option `--port'

Usage: unison-trunk run SYMBOL [RUN-ARGS]
  Execute a definition from the codebase, passing on the provided arguments. To pass flags to your
  program, use `run <symbol> -- --my-flag`

Available options:
  -h,--help                Show this help text

Global options:
  -v,--version             Show version
  -c,--codebase CODEBASE/PATH
                           The path to an existing codebase
  -C,--codebase-create CODEBASE/PATH
                           The path to a new or existing codebase (one will be created if there
                           isn't one)
  --exit                   Exit repl after the command.
  --token STRING           API auth token
  --host STRING            Codebase server host
  --port NUMBER            Codebase server port
  --ui DIR                 Path to codebase ui root
  --no-base                if set, a new codebase will be created without downloading the base
                           library, otherwise the new codebase will download base

Hopefully that helps clear up the issue; it's really just a matter of things showing up in global options that aren't actually global :)

Let me know if any further clarification would help!

@HuwCampbell
Copy link
Collaborator

Ok I see.

The issue is that global options can appear in the help text which are invalid when an alternative is taken which includes a subparser. And yes, that's not ideal.

The globals are pulled in from the parent parsers as they were before any data was parsed, so they don't "know" about any alternatives accepted. I did this so that you'd still see the help text for options which were provided as well.

Workarounds:

If you don't actually have global options, the simplest thing to do is just not include helpShowGlobals when building the parser. In general that flag works best with subparserInline anyway, as then the global ones can actually mix in with the child ones during use.

Alternatively, you can use the noGlobal modifier to suppress individual options which you don't want to bubble into the subparsers.

I'll leave this issue open (and maybe rename it) as there is an underlying bug there.

@HuwCampbell HuwCampbell changed the title How can I mix subcommand parsers with a top-level command? Options show in Global section can include unreachable alternatives. Sep 23, 2022
@HuwCampbell HuwCampbell changed the title Options show in Global section can include unreachable alternatives. Options shown in Global section can include unreachable alternatives. Sep 23, 2022
@ChrisPenner
Copy link
Author

Manually adding noGlobal seems to do the trick for now, thanks for the tip!

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

2 participants