-
-
Notifications
You must be signed in to change notification settings - Fork 1.1k
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
Allow accepting an argument by position and by flag #1820
Comments
I am really hesitant about making this part of clap itself. Clap gives users the tools to do this themselves and I think that is enough for the scope of Clap. Relevant discussion in #1818 |
I'll go ahead an close this because the described use case is already possible - and not too complicated - with two args and |
I don't see why this can't be a part of clap. Keeping it open for future exploration |
If I get it right, this snipped is exactly what @casey wants: App::new("app")
.arg(
// deprecated optional option
Arg::with_name("input_opt")
.hidden(true)
.long("--input")
.takes_value(true)
)
.arg(
// new positional arg
Arg::with_name("input_pos")
.takes_value(true)
.required_unless("input_pos")
) This is done already, what's left to explore? |
Thanks for the workaround, I'll do that for now. I'm not so much thinking of it as deprecating the option for the positional, since options can be more readable, for example in shell scripts. There are some negatives to using two args. One is that because I'm calling a number of additional methods, those need to be duplicated. Using structopt, but would likely be similar with clap-derive:
I had to factor out the help message into a constant, Also, I have
And then to actually access the value, since it's now an
All in all this isn't too bad, since I'm able to get the CLI that I wanted, but it could be made a little less verbose if it was supported directly. Edit: Actually, using |
You can use an arg group for that.
You would be adding just one more condition to check if the argument is present or not. You wouldn't be needing anymore duplication. Please give some example if I am wrong. I am still not convinced that this is needed to be handled by clap. Let's leave this open and see if more people ask for this. |
I should have been more clear, what I was referring to was the additional configuration of each arg that needs to be duplicated and now kept in sync, in this case |
This is totally expected when you want to use the same message for different args. For example, consider this // we want to pass the very same value to multiple fns
// Option 1 - duplicate
func1(&get_val());
func2(&get_val());
// Option 2 - factor out
let val = get_val;
func1(&val);
func2(&val);
Yeah,
I believe this is intentional design of Keeping args in sync might be a problem indeed, but you current proposal is pretty much irrelevant here, no offense. I'd like to get back to your proposal - Personally I think that the only real problem here is keeping args in sync, but I also think that |
Can he do |
He can't since the flags are not *the same*. And even if he could, I hardly see a point.
|
Right, but with access to
None taken! I think the proposal is relevant, because if you could do
Here's a concrete example:
Then, the following would both be the same, giving the arg
|
@casey Sorry for the delay. The whole point of "different types - different arg" is that we want to keep it simple. In clap, an arg defines one entity, whether it's an option or a positional arg. Your proposal introduces a magical switch that goes against this unspoken policy (I repeat, I might have got it wrong), and what's more, a switch for a thing that does something that is already doable with a combination of existing switches. I see you called My opinion is that your CLI is suffering from "multiple ways to do the same thing" syndrome. You probably don't need it, and if you believe you do, be ready to embrace the complexity it brings in. |
No worries!
I think that part of the issue is that that's not how my mental model of clap works. I think of args as being the same kind of thing, whether by position, by long flag, or by short flag, and that in the same way that the same arg can have both a long flag and a short flag, they should also be able to be positional as well. |
Our mental models of clap - and perhaps mindsets - are different, indeed. Let me try to explain it to you (and let's hope you're into math 🙏 ). A developer comes up with a set of command line options ( Your mental model is surjective mapping: My mental model is bijective mapping: The reasons I prefer bijection over everything else:
Anyway, I really don't think this option has any value. The thing you want to do is doable with current If many people come here with similar requests I might become open to it, but until then, I'm totally against the inconsistency the proposed option drags along. |
I think it's mostly a matter of perspective: Clap already supports mapping short flags, long flags, and aliases, which could be be considered to be a surjective mapping. |
@casey I'm sympathetic to your situation, but I'm afraid it will create some additional confusion and complicate the parsing rules for what subjectively is a niche problem set. I can see where you come from about all arguments being simply "arguments" and the way they're accessed (via short, long, or position) is just an implementation detail. I'd submit that both you and @CreepySkeleton are correct in your assumptions. All arguments are just arguments, and can pretty easily float between the ways they're accessed (short, long, position, etc.) depending on configuration, however @CreepySkeleton is correct in that internally clap handles these as very distinct types, which allows certain optimizations and rule simplification when parsing. The three "types" for clap are:
Clap makes the determination as to which type an argument is early on based on the supplied configuration. Having one argument be multiple types could be rather large internal change. Also, aliases are not related to this discussion as they're just additional shorts/longs and don't change the base type of the argument. I.e. they're not additional arguments from claps point of view (even if it appears so from the users point of view). To solve your case, I would suggest two things and I know they're not exactly what you're looking for but in the long run I think its a better solution:
Reason being, you are essentially phasing out the old argument. Then on next major version release, you can remove the old option. If you want to go the extra mile, you could first set the option's help message to a deprecation warning, and hide later, or even print a deprecation warning manually if they use the old option. Essentially you're trying to move your CLI to something more consistent in the future instead of fixing the problem for now but leaving it complicated indefinitely. |
That all makes sense, although even considering the maintenance burden of keeping two arguments in sync, I think I probably won't deprecate the option:
I'm not sure that deprecating the option would benefit the end user. |
100% agree. A good general rule of thumb is to have no more than two positional arguments per command or subcommand for exactly that reason. |
Here's a somewhat minimal (was too lazy to remove some glif2svg options lol) example of how you can hack this together with clap 2.3x despite developers not wanting to add it: https://gist.github.com/ctrlcctrlv/bd0ba2d2a9eb638eec5b5f9dd0ec671e |
So don't implement it that way. Implement it as |
I think at this point, this is too specialized to have native support in clap but instead we offer the tools to be able to do it. I have created #3146 to track experiments with multiple arguments mapping to one I'm going to go ahead and close this. If there are any concerns that are remaining, feel free to speak up! |
It would be nice to allow CLIs to a single argument both by position, and by flag.
A possible API for this would be to add
Arg::positional(bool)
, that when passedtrue
makes an arg be accepted by position, even if it already has a long or short flag.The reason this came up is that wrote a CLI with Clap that takes all of it arguments by flag. After releasing the binary, it's clear that one of the flags is always going to be present, so I'd like to "promote" it to a positional argument, so the flag isn't required. However, I'd like to avoid breaking existing usage, so it would be ideal to make it both a flag and a positional argument.
Allowing seamless promotion from flag to flag + positional would have the nice bonus of encouraging conservative design of CLIs.
Positional arguments are the most scarce, since using more than two or three becomes unwieldy. Short flags are the next most scarce, since there are < 100 possible short flags. Long flags are essentially unlimited. So it would nice to enable the pattern of giving everything long flags initially, and then "upgradiing" commonly used arguments to short flags and positional over time.
The text was updated successfully, but these errors were encountered: