-
-
Notifications
You must be signed in to change notification settings - Fork 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
Default subcommand #975
Comments
This proposal can be extended to something like For this case, it should be noted that the order in which subcommands are merged matters. Otherwise, their descriptions are the same as the one for |
I think this is an interesting concept, but I'd be worried it could create confusion args from the "default" subcommand are intermixed with args from the parent subcommand such as Using
|
FWIW this feature would be useful to me, I'm porting and application from Python's click which supports this feature and |
While |
The thing is default subcommand can be implemented in non clap code by simply running that subcommand logic when no subcommand is found. We do not want add complicated parsing logic when there is an easy and actually better work around. |
@pksunkara I do not completely agree with your statement. A subcommand might have a complex set of arguments. It would be quite complicate to to re-implement the arg parsing and everything clap gives. Or is there an easy way to do so ? To avoid misunderstanding, what I would like is for the user to avoid typing the subcommand's name but clap to parse the subcommand's fields. The difference here is "default subcommand" (what I need) versus "default behavior" (what you suggested). I hope I correctly interpreted your message. |
You don't need to parse it yourself. What you can do is abstract out that subcommand args and use them on both the subcommand and the main app. |
Ok but then, how do you make these args mandatory when no subcommand is given but invalid with the wrong subcommand? Example: |
I am not sure if you have even tried clap, but it is already invalid.
This might be a good argument for needing default subcommand. But an earlier point raised by Kevin still stands:
|
For posterity, For example: #[derive(Parser)]
#[clap(author, version, about)]
#[clap(global_setting(AppSettings::ArgsNegateSubcommands))]
pub struct Arguments {
#[clap(short, long, global(true), parse(from_occurrences))]
/// Make the subcommand more talkative.
pub verbose: usize,
/// The sub-command to execute.
#[clap(subcommand)]
pub command: Option<Commands>,
#[clap(short, long)]
/// The language that the fenced code blocks must match to be included in the output.
pub language: Option<String>,
#[clap(short, long, requires("language"))]
/// Require fenced code blocks have a language to be included in the output.
pub required: bool,
} This allows |
@misalcedo Correct me if I'm wrong, but I think I see what your example does and it doesn't address the original problem statement. What @hcpl is after is something where
I think your approach would disallow the second line. @pksunkara You suggested "abstract out that subcommand args and use them on both the subcommand and the main app." I don't understand what you're describing. If you have time and it's not too much trouble, I wonder if you'd be able to explain more or write out a little example? |
FYI the git cookbook entry includes support for |
Thank you @epage. I have extracted out the minimal parts of the git cookbook entry to answer the original question in this issue:
The solution requires three parts:
It's not an ideal answer because the help text isn't quite right:
In an ideal world, it would only document the "--verbose" flag if you did "cargo run -- info --help". |
I don't think this is universal though: I personally prefer what it currently does as it documents how it can be used without a command. |
Strictly, both options document how it can be used, (1) the message "if no command then info is assumed" and (2) the current behavior. The difference is with (2) the user has no indication what the difference in meaning is between "--verbose" and "info --verbose", or indeed whether there is a difference. (We the programmer know there isn't a difference). Nor does the (2) tell the user what happens when they run the binary on its own without specifying any flags or commands. And (2) gives the impression that options are allowed with the command, while in fact they're not. |
One option is to put the options under a custom help heading so it says "info options" or something like that |
@epage Could you clarify what you mean, please? When I try to add a custom help heading then it gives a build-time message "error: methods are not allowed for flattened entry".
|
We do not yet support iirc you can set it on the |
Setting on the struct gives a build-time error "no method named Setting on each field doesn't give the desired effect because, even though it achieves the desired affect that "mybinary --help" shows the options for the info subcommand in a separate heading, "mybinary info --help" also shows them in a separate heading. https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=fb338e3037a1a00e96e4c3d3ed82b530 I guess I'll wait for #1807. Thank you @epage for your continued assistance - much appreciated. |
This is a convenience optimization for the default user experience, since `jj log` is a frequently run command. Accessing the help information explicitly still follows normal CLI conventions, and instructions are displayed appropriately if the user happens to make a mistake. Discoverability should not be adversely harmed. Since clap does not natively support setting a default subcommand [1], it will only parse global options when invoking `jj` in this way. This limitation is also why we have to create the LogArgs struct literal (with derived default values) to pass through to the cmd_log function. Note that this behavior (and limitation) mirrors what Sapling does [2], where `sl` will display the smartlog by default. [1] clap-rs/clap#975 [2] https://sapling-scm.com/docs/overview/smartlog
This is a convenience optimization to improve the default user experience, since `jj log` is a frequently run command. Accessing the help information explicitly still follows normal CLI conventions, and instructions are displayed appropriately if the user happens to make a mistake. Discoverability should not be adversely harmed. Since clap does not natively support setting a default subcommand [1], it will only parse global options when invoking `jj` in this way. This limitation is also why we have to create the LogArgs struct literal (with derived default values) to pass through to the cmd_log function. Note that this behavior (and limitation) mirrors what Sapling does [2], where `sl` will display the smartlog by default. [1] clap-rs/clap#975 [2] https://sapling-scm.com/docs/overview/smartlog
This is a convenience optimization to improve the default user experience, since `jj log` is a frequently run command. Accessing the help information explicitly still follows normal CLI conventions, and instructions are displayed appropriately if the user happens to make a mistake. Discoverability should not be adversely harmed. Since clap does not natively support setting a default subcommand [1], it will only parse global options when invoking `jj` in this way. This limitation is also why we have to create the LogArgs struct literal (with derived default values) to pass through to the cmd_log function. Note that this behavior (and limitation) mirrors what Sapling does [2], where `sl` will display the smartlog by default. [1] clap-rs/clap#975 [2] https://sapling-scm.com/docs/overview/smartlog
This is a convenience optimization to improve the default user experience, since `jj log` is a frequently run command. Accessing the help information explicitly still follows normal CLI conventions, and instructions are displayed appropriately if the user happens to make a mistake. Discoverability should not be adversely harmed. Since clap does not natively support setting a default subcommand [1], it will only parse global options when invoking `jj` in this way. This limitation is also why we have to create the LogArgs struct literal (with derived default values) to pass through to the cmd_log function. Note that this behavior (and limitation) mirrors what Sapling does [2], where `sl` will display the smartlog by default. [1] clap-rs/clap#975 [2] https://sapling-scm.com/docs/overview/smartlog
This is a convenience optimization to improve the default user experience, since `jj log` is a frequently run command. Accessing the help information explicitly still follows normal CLI conventions, and instructions are displayed appropriately if the user happens to make a mistake. Discoverability should not be adversely harmed. Note that this behavior mirrors what Sapling does [2], where `sl` will display the smartlog by default. [1] clap-rs/clap#975 [2] https://sapling-scm.com/docs/overview/smartlog
This is a convenience optimization to improve the default user experience, since `jj log` is a frequently run command. Accessing the help information explicitly still follows normal CLI conventions, and instructions are displayed appropriately if the user happens to make a mistake. Discoverability should not be adversely harmed. Note that this behavior mirrors what Sapling does [2], where `sl` will display the smartlog by default. [1] clap-rs/clap#975 [2] https://sapling-scm.com/docs/overview/smartlog
This is a convenience optimization to improve the default user experience, since `jj log` is a frequently run command. Accessing the help information explicitly still follows normal CLI conventions, and instructions are displayed appropriately if the user happens to make a mistake. Discoverability should not be adversely harmed. Note that this behavior mirrors what Sapling does [2], where `sl` will display the smartlog by default. [1] clap-rs/clap#975 [2] https://sapling-scm.com/docs/overview/smartlog
This is a convenience optimization to improve the default user experience, since `jj log` is a frequently run command. Accessing the help information explicitly still follows normal CLI conventions, and instructions are displayed appropriately if the user happens to make a mistake. Discoverability should not be adversely harmed. Note that this behavior mirrors what Sapling does [2], where `sl` will display the smartlog by default. [1] clap-rs/clap#975 [2] https://sapling-scm.com/docs/overview/smartlog
This is a convenience optimization to improve the default user experience, since `jj log` is a frequently run command. Accessing the help information explicitly still follows normal CLI conventions, and instructions are displayed appropriately if the user happens to make a mistake. Discoverability should not be adversely harmed. Note that this behavior mirrors what Sapling does [2], where `sl` will display the smartlog by default. [1] clap-rs/clap#975 [2] https://sapling-scm.com/docs/overview/smartlog
This is a convenience optimization to improve the default user experience, since `jj log` is a frequently run command. Accessing the help information explicitly still follows normal CLI conventions, and instructions are displayed appropriately if the user happens to make a mistake. Discoverability should not be adversely harmed. Note that this behavior mirrors what Sapling does [2], where `sl` will display the smartlog by default. [1] clap-rs/clap#975 [2] https://sapling-scm.com/docs/overview/smartlog
This is a convenience optimization to improve the default user experience, since `jj log` is a frequently run command. Accessing the help information explicitly still follows normal CLI conventions, and instructions are displayed appropriately if the user happens to make a mistake. Discoverability should not be adversely harmed. Note that this behavior mirrors what Sapling does [2], where `sl` will display the smartlog by default. [1] clap-rs/clap#975 [2] https://sapling-scm.com/docs/overview/smartlog
This is a convenience optimization to improve the default user experience, since `jj log` is a frequently run command. Accessing the help information explicitly still follows normal CLI conventions, and instructions are displayed appropriately if the user happens to make a mistake. Discoverability should not be adversely harmed. Note that this behavior mirrors what Sapling does [2], where `sl` will display the smartlog by default. [1] clap-rs/clap#975 [2] https://sapling-scm.com/docs/overview/smartlog
This is a convenience optimization to improve the default user experience, since `jj log` is a frequently run command. Accessing the help information explicitly still follows normal CLI conventions, and instructions are displayed appropriately if the user happens to make a mistake. Discoverability should not be adversely harmed. Note that this behavior mirrors what Sapling does [2], where `sl` will display the smartlog by default. [1] clap-rs/clap#975 [2] https://sapling-scm.com/docs/overview/smartlog
I visited this issue earlier but I could seem to get a fix here's what I did. I hope it helps someone in the future Here's the root of my application // mount clap parser here
#[derive(Parser)]
#[command(author, version, about ="Compilation of utility scripts for everyday use", long_about = None)]
#[command(propagate_version = true)]
pub struct Utils {
#[command(subcommand)]
pub command: Commands,
}
impl Utils {
pub async fn run() {
let utils = Utils::parse();
match utils.command {
Commands::Ignore(git_ignore) => git_ignore.parse(),
Commands::Mailto(email) => email.parse().await,
Commands::Readme(readme) => readme.parse(),
Commands::Store(store) => store.parse().await,
// _ => PrintColoredText::error("invalid command"),
}
}
}
#[derive(Subcommand)]
pub enum Commands {
/// store data as key value pair
Store(StoreCommands),
/// generate .gitignore
Ignore(GitIgnoreCommands),
/// send email from the command line
Mailto(EmailCommands),
/// add readme to a git software project
Readme(ReadmeCommands),
} My help script look like this Compilation of utility scripts for everyday use
Usage: utils <COMMAND>
Commands:
store store data as key value pair
ignore generate .gitignore
mailto send email from the command line
readme add a readme to a git software project
help Print this message or the help of the given subcommand(s)
Options:
-h, --help Print help
-V, --version Print version
I wanted to implement a default subcommand for the store subcommand such that I can say
To solve this,
#[derive(Args, Debug, Serialize, Deserialize)]
pub struct StoreCommands {
#[clap(short, long, value_parser)]
pub key: Option<String>,
#[clap(short, long, value_parser)]
pub value: Option<String>,
#[command(subcommand)]
pub subcommands: Option<SubCommands>,
}
pub async fn parse(&self) {
if let Some(command) = &self.subcommands {
match command {
SubCommands::List => Self::list().await,
SubCommands::Delete { key } => Self::delete(key).await,
SubCommands::Clear => Self::clear().await,
SubCommands::Update { key, value } => Self::update(key, value).await,
}
} else {
let Some(key) = &self.key else {
PrintColoredText::error("Invalid key");
return;
};
let Some(value) = &self.value else {
PrintColoredText::error("Invalid value");
return;
};
Store::new(key, value).save().await.unwrap();
let message = format!("{key} successfully stored");
PrintColoredText::success(&message);
}
} The entirety of the source is as follows use clap::{Args, Subcommand};
use serde::{Deserialize, Serialize};
use crate::{database::Store, style::PrintColoredText};
#[derive(Args, Debug, Serialize, Deserialize)]
pub struct StoreCommands {
#[clap(short, long, value_parser)]
pub key: Option<String>,
#[clap(short, long, value_parser)]
pub value: Option<String>,
#[command(subcommand)]
pub subcommands: Option<SubCommands>,
}
#[derive(Debug, Subcommand, Serialize, Deserialize)]
pub enum SubCommands {
/// list the stored data
List,
/// delete a key
Delete { key: String },
/// clear all stored data
Clear,
/// update the value of a key
Update { key: String, value: String },
}
impl StoreCommands {
pub async fn parse(&self) {
if let Some(command) = &self.subcommands {
match command {
SubCommands::List => Self::list().await,
SubCommands::Delete { key } => Self::delete(key).await,
SubCommands::Clear => Self::clear().await,
SubCommands::Update { key, value } => Self::update(key, value).await,
}
} else {
let Some(key) = &self.key else {
PrintColoredText::error("Invalid key");
return;
};
let Some(value) = &self.value else {
PrintColoredText::error("Invalid value");
return;
};
Store::new(key, value).save().await.unwrap();
let message = format!("{key} successfully stored");
PrintColoredText::success(&message);
}
}
async fn list() {
let data = crate::database::Store::find().await;
if data.is_empty() {
PrintColoredText::error("no data found");
return;
}
let data = crate::database::Database(data);
println!("{}", data);
}
async fn delete(key: &str) {
crate::database::Store::remove(key).await;
}
async fn update(key: &str, value: &str) {
let _ = crate::database::Store::update(key, value).await.ok();
let message = format!("{key} successfully updated");
PrintColoredText::success(&message);
}
async fn clear() {
crate::database::Store::clear().await;
}
} I hope this helps someone. the project source code is available at https://github.com/opeolluwa/utils |
While it's possible to mark the subcommand as optional and use pattern matching to use A solution I've found was to keep the #[derive(Subcommand, Clone, Debug)]
pub enum Command {
Compile,
Format
}
#[derive(Parser)]
#[command(author, version, about, long_about = None)]
pub struct Cli {
#[command(subcommand)]
command: Option<Command>,
}
impl Cli {
pub fn command(&self) -> Command {
self.command.clone().unwrap_or(Command::Compile)
}
} |
Feature request
This is a proposal to add a means to reduce verbosity of command-line calls.
The API presented here is
App::default_subcommand()
method. It is used to show how this feature can be employed, so feel free to implement the functionality however you find suitable.Description
Arguments of the default subcommand are merged into arguments of the enclosing app-like entity (subcommands can exploit this behavior regarding inner subcommands too).
Naming conflicts are resolved by preferring the arguments defined in the enclosing entity because otherwise they would be shadowed permanently. In other words, only merge the non-conflicting arguments into the scope, whilst preserving its own conflicting ones.
Inspecting the presence of these arguments is done unambiguously — through the entity where they were defined.
Sample Code
Expected Behavior Summary
The text was updated successfully, but these errors were encountered: