// Copyright 2018 Guillaume Pinot (@TeXitoi) <texitoi@texitoi.eu>, // Kevin Knapp (@kbknapp) <kbknapp@gmail.com>, and // Ana Hobden (@hoverbear) <operator@hoverbear.org> // // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your // option. This file may not be copied, modified, or distributed // except according to those terms. // // This work was derived from Structopt (https://github.com/TeXitoi/structopt) // commit#ea76fa1b1b273e65e3b0b1046643715b49bec51f which is licensed under the // MIT/Apache 2.0 license.
use proc_macro2::{Ident, Span, TokenStream}; use quote::{format_ident, quote, quote_spanned}; use syn::{
punctuated::Punctuated, spanned::Spanned, token::Comma, Data, DataStruct, DeriveInput, Field,
Fields, FieldsNamed, Generics,
};
/// Generate a block of code to add arguments/subcommands corresponding to /// the `fields` to an cmd. pub(crate) fn gen_augment(
fields: &[(&Field, Item)],
app_var: &Ident,
parent_item: &Item,
override_required: bool,
) -> Result<TokenStream, syn::Error> { letmut subcommand_specified = false; letmut args = Vec::new(); for (field, item) in fields { let kind = item.kind(); let genned = match &*kind {
Kind::Command(_)
| Kind::Value
| Kind::Skip(_, _)
| Kind::FromGlobal(_)
| Kind::ExternalSubcommand => None,
Kind::Subcommand(ty) => { if subcommand_specified {
abort!(
field.span(), "`#[command(subcommand)]` can only be used once per container"
);
}
subcommand_specified = true;
let subcmd_type = match (**ty, sub_type(&field.ty)) {
(Ty::Option, Some(sub_type)) => sub_type,
_ => &field.ty,
}; let implicit_methods = if **ty == Ty::Option {
quote!()
} else {
quote_spanned! { kind.span()=>
.subcommand_required(true)
.arg_required_else_help(true)
}
};
let override_methods = if override_required {
quote_spanned! { kind.span()=>
.subcommand_required(false)
.arg_required_else_help(false)
}
} else {
quote!()
};
Ty::Other => { let required = item.find_default_method().is_none(); // `ArgAction::takes_values` is assuming `ArgAction::default_value` will be // set though that won't always be true but this should be good enough, // otherwise we'll report an "arg required" error when unwrapping. let action_value = action.args();
quote_spanned! { ty.span()=>
.value_name(#value_name)
.required(#required && #action_value.takes_values()) #value_parser #action
}
}
};
let id = item.id(); let explicit_methods = item.field_methods(); let deprecations = if !override_required {
item.deprecations()
} else {
quote!()
}; let override_methods = if override_required {
quote_spanned! { kind.span()=>
.required(false)
}
} else {
quote!()
};
fn gen_parsers(
item: &Item,
ty: &Sp<Ty>,
field_name: &Ident,
field: &Field,
update: Option<&TokenStream>,
) -> Result<TokenStream, syn::Error> { let span = ty.span(); let convert_type = inner_type(&field.ty); let id = item.id(); let get_one = quote_spanned!(span=> remove_one::<#convert_type>); let get_many = quote_spanned!(span=> remove_many::<#convert_type>); let get_occurrences = quote_spanned!(span=> remove_occurrences::<#convert_type>);
// Give this identifier the same hygiene // as the `arg_matches` parameter definition. This // allows us to refer to `arg_matches` within a `quote_spanned` block let arg_matches = format_ident!("__clap_arg_matches");
let field_value = match **ty {
Ty::Unit => {
quote_spanned! { ty.span()=>
()
}
}
Ty::Other => { // Prefer `concat` where possible for reduced code size but fallback to `format!` to // allow non-literal `id`s match id {
Name::Assigned(_) => {
quote_spanned! { ty.span()=> #arg_matches.#get_one(#id)
.ok_or_else(|| clap::Error::raw(clap::error::ErrorKind::MissingRequiredArgument, format!("The following required argument was not provided: {}", #id)))?
}
}
Name::Derived(_) => {
quote_spanned! { ty.span()=> #arg_matches.#get_one(#id)
.ok_or_else(|| clap::Error::raw(clap::error::ErrorKind::MissingRequiredArgument, concat!("The following required argument was not provided: ", #id)))?
}
}
}
}
};
#[cfg(not(feature = "raw-deprecated"))] pub(crate) fn raw_deprecated() -> TokenStream {
quote! { #![allow(deprecated)] // Assuming any deprecation in here will be related to a deprecation in `Args`
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.