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

fix(derive): Replace clap attributes with command, arg, and value #4180

Merged
merged 5 commits into from Sep 2, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Expand Up @@ -66,6 +66,7 @@ Deprecated
- `Arg::number_of_values` in favor of `Arg::num_args`
- `default_value_os`, `default_values_os`, `default_value_if_os`, and `default_value_ifs_os` as the non `_os` variants now accept either a `str` or an `OsStr`
- `Command::dont_collapse_args_in_usage` is now the default and is deprecated
- *(derive)* `structopt` and `clap` attributes in favor of the more specific `command`, `arg`, and `value`

### Features

Expand Down
30 changes: 15 additions & 15 deletions clap_complete/examples/completion-derive.rs
Expand Up @@ -19,41 +19,41 @@ use std::io;
use std::path::PathBuf;

#[derive(Parser, Debug, PartialEq)]
#[clap(
#[command(
name = "value_hints_derive",
// Command::trailing_var_ar is required to use ValueHint::CommandWithArguments
trailing_var_arg = true,
)]
struct Opt {
/// If provided, outputs the completion file for given shell
#[clap(long = "generate", value_enum)]
#[arg(long = "generate", value_enum)]
generator: Option<Shell>,
// Showcasing all possible ValueHints:
#[clap(long, value_hint = ValueHint::Unknown)]
#[arg(long, value_hint = ValueHint::Unknown)]
unknown: Option<String>,
#[clap(long, value_hint = ValueHint::Other)]
#[arg(long, value_hint = ValueHint::Other)]
other: Option<String>,
#[clap(short, long, value_hint = ValueHint::AnyPath)]
#[arg(short, long, value_hint = ValueHint::AnyPath)]
path: Option<PathBuf>,
#[clap(short, long, value_hint = ValueHint::FilePath)]
#[arg(short, long, value_hint = ValueHint::FilePath)]
file: Option<PathBuf>,
#[clap(short, long, value_hint = ValueHint::DirPath)]
#[arg(short, long, value_hint = ValueHint::DirPath)]
dir: Option<PathBuf>,
#[clap(short, long, value_hint = ValueHint::ExecutablePath)]
#[arg(short, long, value_hint = ValueHint::ExecutablePath)]
exe: Option<PathBuf>,
#[clap(long, value_hint = ValueHint::CommandName)]
#[arg(long, value_hint = ValueHint::CommandName)]
cmd_name: Option<OsString>,
#[clap(short, long, value_hint = ValueHint::CommandString)]
#[arg(short, long, value_hint = ValueHint::CommandString)]
cmd: Option<String>,
#[clap(value_hint = ValueHint::CommandWithArguments)]
#[arg(value_hint = ValueHint::CommandWithArguments)]
command_with_args: Vec<String>,
#[clap(short, long, value_hint = ValueHint::Username)]
#[arg(short, long, value_hint = ValueHint::Username)]
user: Option<String>,
#[clap(short, long, value_hint = ValueHint::Hostname)]
#[arg(short, long, value_hint = ValueHint::Hostname)]
host: Option<String>,
#[clap(long, value_hint = ValueHint::Url)]
#[arg(long, value_hint = ValueHint::Url)]
url: Option<String>,
#[clap(long, value_hint = ValueHint::EmailAddress)]
#[arg(long, value_hint = ValueHint::EmailAddress)]
email: Option<String>,
}

Expand Down
18 changes: 9 additions & 9 deletions clap_complete/src/dynamic.rs
Expand Up @@ -8,7 +8,7 @@ pub mod bash {
use unicode_xid::UnicodeXID;

#[derive(clap::Subcommand)]
#[clap(hide = true)]
#[command(hide = true)]
#[allow(missing_docs)]
#[derive(Clone, Debug)]
pub enum CompleteCommand {
Expand All @@ -17,15 +17,15 @@ pub mod bash {
}

#[derive(clap::Args)]
#[clap(group = clap::ArgGroup::new("complete").multiple(true).conflicts_with("register"))]
#[command(group = clap::ArgGroup::new("complete").multiple(true).conflicts_with("register"))]
#[allow(missing_docs)]
#[derive(Clone, Debug)]
pub struct CompleteArgs {
/// Path to write completion-registration to
#[clap(long, required = true)]
#[arg(long, required = true)]
register: Option<std::path::PathBuf>,

#[clap(
#[arg(
long,
required = true,
value_name = "COMP_CWORD",
Expand All @@ -34,29 +34,29 @@ pub mod bash {
)]
index: Option<usize>,

#[clap(long, hide_short_help = true, group = "complete")]
#[arg(long, hide_short_help = true, group = "complete")]
ifs: Option<String>,

#[clap(
#[arg(
long = "type",
required = true,
hide_short_help = true,
group = "complete"
)]
comp_type: Option<CompType>,

#[clap(long, hide_short_help = true, group = "complete")]
#[arg(long, hide_short_help = true, group = "complete")]
space: bool,

#[clap(
#[arg(
long,
conflicts_with = "space",
hide_short_help = true,
group = "complete"
)]
no_space: bool,

#[clap(raw = true, hide_short_help = true, group = "complete")]
#[arg(raw = true, hide_short_help = true, group = "complete")]
comp_words: Vec<OsString>,
}

Expand Down
12 changes: 12 additions & 0 deletions clap_derive/src/attr.rs
Expand Up @@ -32,6 +32,12 @@ impl ClapAttr {
Some(Sp::new(AttrKind::Clap, attr.path.span()))
} else if attr.path.is_ident("structopt") {
Some(Sp::new(AttrKind::StructOpt, attr.path.span()))
} else if attr.path.is_ident("command") {
Some(Sp::new(AttrKind::Command, attr.path.span()))
} else if attr.path.is_ident("arg") {
Some(Sp::new(AttrKind::Arg, attr.path.span()))
} else if attr.path.is_ident("value") {
Some(Sp::new(AttrKind::Value, attr.path.span()))
} else {
None
};
Expand Down Expand Up @@ -194,13 +200,19 @@ impl ToTokens for AttrValue {
pub enum AttrKind {
Clap,
StructOpt,
Command,
Arg,
Value,
}

impl AttrKind {
pub fn as_str(&self) -> &'static str {
match self {
Self::Clap => "clap",
Self::StructOpt => "structopt",
Self::Command => "command",
Self::Arg => "arg",
Self::Value => "value",
}
}
}
6 changes: 3 additions & 3 deletions clap_derive/src/derives/args.rs
Expand Up @@ -204,7 +204,7 @@ pub fn gen_augment(
Kind::Command(_)
| Kind::Value(_)
| Kind::Subcommand(_)
| Kind::Skip(_)
| Kind::Skip(_, _)
| Kind::FromGlobal(_)
| Kind::ExternalSubcommand => None,
Kind::Flatten => {
Expand Down Expand Up @@ -384,7 +384,7 @@ pub fn gen_constructor(fields: &[(&Field, Item)]) -> TokenStream {
#field_name: clap::FromArgMatches::from_arg_matches_mut(#arg_matches)?
},

Kind::Skip(val) => match val {
Kind::Skip(val, _) => match val {
None => quote_spanned!(kind.span()=> #field_name: Default::default()),
Some(val) => quote_spanned!(kind.span()=> #field_name: (#val).into()),
},
Expand Down Expand Up @@ -463,7 +463,7 @@ pub fn gen_updater(fields: &[(&Field, Item)], use_self: bool) -> TokenStream {
}
},

Kind::Skip(_) => quote!(),
Kind::Skip(_, _) => quote!(),

Kind::Arg(ty) | Kind::FromGlobal(ty) => gen_parsers(item, ty, field_name, field, Some(&access)),
}
Expand Down
2 changes: 1 addition & 1 deletion clap_derive/src/derives/subcommand.rs
Expand Up @@ -137,7 +137,7 @@ fn gen_augment(
let kind = item.kind();

match &*kind {
Kind::Skip(_) => None,
Kind::Skip(_, _) => None,

Kind::ExternalSubcommand => {
let ty = match variant.fields {
Expand Down
2 changes: 1 addition & 1 deletion clap_derive/src/derives/value_enum.rs
Expand Up @@ -78,7 +78,7 @@ fn lits(variants: &[(&Variant, Item)]) -> Vec<(TokenStream, Ident)> {
variants
.iter()
.filter_map(|(variant, item)| {
if let Kind::Skip(_) = &*item.kind() {
if let Kind::Skip(_, _) = &*item.kind() {
None
} else {
if !matches!(variant.fields, Fields::Unit) {
Expand Down
70 changes: 49 additions & 21 deletions clap_derive/src/item.rs
Expand Up @@ -197,7 +197,7 @@ impl Item {

Kind::ExternalSubcommand
| Kind::FromGlobal(_)
| Kind::Skip(_)
| Kind::Skip(_, _)
| Kind::Command(_)
| Kind::Value(_)
| Kind::Arg(_) => (),
Expand Down Expand Up @@ -321,7 +321,7 @@ impl Item {

res.kind = Sp::new(Kind::Subcommand(ty), res.kind.span());
}
Kind::Skip(_) => {
Kind::Skip(_, _) => {
if res.has_explicit_methods() {
abort!(
res.kind.span(),
Expand Down Expand Up @@ -463,7 +463,10 @@ impl Item {
}
Some(MagicAttrName::Skip) => {
let expr = attr.value.clone();
let kind = Sp::new(Kind::Skip(expr), attr.name.clone().span());
let kind = Sp::new(
Kind::Skip(expr, self.kind.attr_kind()),
attr.name.clone().span(),
);
Some(kind)
}
_ => None,
Expand All @@ -475,16 +478,28 @@ impl Item {
}

for attr in &parsed {
match attr.kind.get() {
AttrKind::Clap => {}
AttrKind::StructOpt => {
let actual_attr_kind = *attr.kind.get();
let expected_attr_kind = self.kind.attr_kind();
match (actual_attr_kind, expected_attr_kind) {
(AttrKind::Clap, _) | (AttrKind::StructOpt, _) => {
self.deprecations.push(Deprecation::attribute(
"4.0.0",
*attr.kind.get(),
AttrKind::Clap,
actual_attr_kind,
expected_attr_kind,
attr.kind.span(),
));
}

_ if attr.kind != expected_attr_kind => {
abort!(
attr.kind.span(),
"Expected `{}` attribute instead of `{}`",
expected_attr_kind.as_str(),
actual_attr_kind.as_str()
);
}

_ => {}
}

if let Some(AttrValue::Call(tokens)) = &attr.value {
Expand All @@ -511,7 +526,7 @@ impl Item {
span: attr.name.span(),
id: "bare_value_parser",
version: "4.0.0",
description: "`#[clap(value_parser)]` is now the default and is no longer needed`".to_owned(),
description: "`#[arg(value_parser)]` is now the default and is no longer needed`".to_owned(),
});
self.value_parser = Some(ValueParser::Implicit(attr.name.clone()));
}
Expand All @@ -522,7 +537,7 @@ impl Item {
span: attr.name.span(),
id: "bare_action",
version: "4.0.0",
description: "`#[clap(action)]` is now the default and is no longer needed`".to_owned(),
description: "`#[arg(action)]` is now the default and is no longer needed`".to_owned(),
});
self.action = Some(Action::Implicit(attr.name.clone()));
}
Expand Down Expand Up @@ -568,7 +583,7 @@ impl Item {
} else {
abort!(
attr.name.clone(),
"#[clap(default_value_t)] (without an argument) can be used \
"#[arg(default_value_t)] (without an argument) can be used \
only on field level";

note = "see \
Expand Down Expand Up @@ -610,7 +625,7 @@ impl Item {
} else {
abort!(
attr.name.clone(),
"#[clap(default_values_t)] (without an argument) can be used \
"#[arg(default_values_t)] (without an argument) can be used \
only on field level";

note = "see \
Expand All @@ -622,7 +637,7 @@ impl Item {
if *container_type != Ty::Vec {
abort!(
attr.name.clone(),
"#[clap(default_values_t)] can be used only on Vec types";
"#[arg(default_values_t)] can be used only on Vec types";

note = "see \
https://github.com/clap-rs/clap/blob/master/examples/derive_ref/README.md#magic-attributes")
Expand Down Expand Up @@ -679,7 +694,7 @@ impl Item {
} else {
abort!(
attr.name.clone(),
"#[clap(default_value_os_t)] (without an argument) can be used \
"#[arg(default_value_os_t)] (without an argument) can be used \
only on field level";

note = "see \
Expand Down Expand Up @@ -721,7 +736,7 @@ impl Item {
} else {
abort!(
attr.name.clone(),
"#[clap(default_values_os_t)] (without an argument) can be used \
"#[arg(default_values_os_t)] (without an argument) can be used \
only on field level";

note = "see \
Expand All @@ -733,7 +748,7 @@ impl Item {
if *container_type != Ty::Vec {
abort!(
attr.name.clone(),
"#[clap(default_values_os_t)] can be used only on Vec types";
"#[arg(default_values_os_t)] can be used only on Vec types";

note = "see \
https://github.com/clap-rs/clap/blob/master/examples/derive_ref/README.md#magic-attributes")
Expand Down Expand Up @@ -868,12 +883,12 @@ impl Item {
(Kind::Arg(_), Kind::FromGlobal(_))
| (Kind::Arg(_), Kind::Subcommand(_))
| (Kind::Arg(_), Kind::Flatten)
| (Kind::Arg(_), Kind::Skip(_))
| (Kind::Arg(_), Kind::Skip(_, _))
| (Kind::Command(_), Kind::Subcommand(_))
| (Kind::Command(_), Kind::Flatten)
| (Kind::Command(_), Kind::Skip(_))
| (Kind::Command(_), Kind::Skip(_, _))
| (Kind::Command(_), Kind::ExternalSubcommand)
| (Kind::Value(_), Kind::Skip(_)) => {
| (Kind::Value(_), Kind::Skip(_, _)) => {
self.kind = kind;
}

Expand Down Expand Up @@ -1117,7 +1132,7 @@ pub enum Kind {
FromGlobal(Sp<Ty>),
Subcommand(Sp<Ty>),
Flatten,
Skip(Option<AttrValue>),
Skip(Option<AttrValue>, AttrKind),
ExternalSubcommand,
}

Expand All @@ -1130,10 +1145,23 @@ impl Kind {
Self::FromGlobal(_) => "from_global",
Self::Subcommand(_) => "subcommand",
Self::Flatten => "flatten",
Self::Skip(_) => "skip",
Self::Skip(_, _) => "skip",
Self::ExternalSubcommand => "external_subcommand",
}
}

pub fn attr_kind(&self) -> AttrKind {
match self {
Self::Arg(_) => AttrKind::Arg,
Self::Command(_) => AttrKind::Command,
Self::Value(_) => AttrKind::Value,
Self::FromGlobal(_) => AttrKind::Arg,
Self::Subcommand(_) => AttrKind::Command,
Self::Flatten => AttrKind::Command,
Self::Skip(_, kind) => *kind,
Self::ExternalSubcommand => AttrKind::Command,
}
}
}

#[derive(Clone)]
Expand Down