aboutsummaryrefslogtreecommitdiff
path: root/structopt/structopt-derive
diff options
context:
space:
mode:
Diffstat (limited to 'structopt/structopt-derive')
-rw-r--r--structopt/structopt-derive/Cargo.toml27
-rw-r--r--structopt/structopt-derive/LICENSE-APACHE201
-rw-r--r--structopt/structopt-derive/LICENSE-MIT21
-rw-r--r--structopt/structopt-derive/src/attrs.rs620
-rw-r--r--structopt/structopt-derive/src/doc_comments.rs103
-rw-r--r--structopt/structopt-derive/src/lib.rs667
-rw-r--r--structopt/structopt-derive/src/parse.rs304
-rw-r--r--structopt/structopt-derive/src/spanned.rs101
-rw-r--r--structopt/structopt-derive/src/ty.rs108
9 files changed, 0 insertions, 2152 deletions
diff --git a/structopt/structopt-derive/Cargo.toml b/structopt/structopt-derive/Cargo.toml
deleted file mode 100644
index ad547af..0000000
--- a/structopt/structopt-derive/Cargo.toml
+++ /dev/null
@@ -1,27 +0,0 @@
-[package]
-name = "structopt-derive"
-version = "0.4.0"
-edition = "2018"
-authors = ["Guillaume Pinot <texitoi@texitoi.eu>"]
-description = "Parse command line argument by defining a struct, derive crate."
-documentation = "https://docs.rs/structopt-derive"
-repository = "https://github.com/TeXitoi/structopt"
-keywords = ["clap", "cli", "derive", "docopt"]
-categories = ["command-line-interface"]
-license = "Apache-2.0/MIT"
-
-[badges]
-travis-ci = { repository = "TeXitoi/structopt" }
-
-[dependencies]
-syn = { version = "1", features = ["full"] }
-quote = "1"
-proc-macro2 = "1"
-heck = "0.3.0"
-proc-macro-error = "0.4.3"
-
-[features]
-paw = []
-
-[lib]
-proc-macro = true
diff --git a/structopt/structopt-derive/LICENSE-APACHE b/structopt/structopt-derive/LICENSE-APACHE
deleted file mode 100644
index 261eeb9..0000000
--- a/structopt/structopt-derive/LICENSE-APACHE
+++ /dev/null
@@ -1,201 +0,0 @@
- Apache License
- Version 2.0, January 2004
- http://www.apache.org/licenses/
-
- TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
-
- 1. Definitions.
-
- "License" shall mean the terms and conditions for use, reproduction,
- and distribution as defined by Sections 1 through 9 of this document.
-
- "Licensor" shall mean the copyright owner or entity authorized by
- the copyright owner that is granting the License.
-
- "Legal Entity" shall mean the union of the acting entity and all
- other entities that control, are controlled by, or are under common
- control with that entity. For the purposes of this definition,
- "control" means (i) the power, direct or indirect, to cause the
- direction or management of such entity, whether by contract or
- otherwise, or (ii) ownership of fifty percent (50%) or more of the
- outstanding shares, or (iii) beneficial ownership of such entity.
-
- "You" (or "Your") shall mean an individual or Legal Entity
- exercising permissions granted by this License.
-
- "Source" form shall mean the preferred form for making modifications,
- including but not limited to software source code, documentation
- source, and configuration files.
-
- "Object" form shall mean any form resulting from mechanical
- transformation or translation of a Source form, including but
- not limited to compiled object code, generated documentation,
- and conversions to other media types.
-
- "Work" shall mean the work of authorship, whether in Source or
- Object form, made available under the License, as indicated by a
- copyright notice that is included in or attached to the work
- (an example is provided in the Appendix below).
-
- "Derivative Works" shall mean any work, whether in Source or Object
- form, that is based on (or derived from) the Work and for which the
- editorial revisions, annotations, elaborations, or other modifications
- represent, as a whole, an original work of authorship. For the purposes
- of this License, Derivative Works shall not include works that remain
- separable from, or merely link (or bind by name) to the interfaces of,
- the Work and Derivative Works thereof.
-
- "Contribution" shall mean any work of authorship, including
- the original version of the Work and any modifications or additions
- to that Work or Derivative Works thereof, that is intentionally
- submitted to Licensor for inclusion in the Work by the copyright owner
- or by an individual or Legal Entity authorized to submit on behalf of
- the copyright owner. For the purposes of this definition, "submitted"
- means any form of electronic, verbal, or written communication sent
- to the Licensor or its representatives, including but not limited to
- communication on electronic mailing lists, source code control systems,
- and issue tracking systems that are managed by, or on behalf of, the
- Licensor for the purpose of discussing and improving the Work, but
- excluding communication that is conspicuously marked or otherwise
- designated in writing by the copyright owner as "Not a Contribution."
-
- "Contributor" shall mean Licensor and any individual or Legal Entity
- on behalf of whom a Contribution has been received by Licensor and
- subsequently incorporated within the Work.
-
- 2. Grant of Copyright License. Subject to the terms and conditions of
- this License, each Contributor hereby grants to You a perpetual,
- worldwide, non-exclusive, no-charge, royalty-free, irrevocable
- copyright license to reproduce, prepare Derivative Works of,
- publicly display, publicly perform, sublicense, and distribute the
- Work and such Derivative Works in Source or Object form.
-
- 3. Grant of Patent License. Subject to the terms and conditions of
- this License, each Contributor hereby grants to You a perpetual,
- worldwide, non-exclusive, no-charge, royalty-free, irrevocable
- (except as stated in this section) patent license to make, have made,
- use, offer to sell, sell, import, and otherwise transfer the Work,
- where such license applies only to those patent claims licensable
- by such Contributor that are necessarily infringed by their
- Contribution(s) alone or by combination of their Contribution(s)
- with the Work to which such Contribution(s) was submitted. If You
- institute patent litigation against any entity (including a
- cross-claim or counterclaim in a lawsuit) alleging that the Work
- or a Contribution incorporated within the Work constitutes direct
- or contributory patent infringement, then any patent licenses
- granted to You under this License for that Work shall terminate
- as of the date such litigation is filed.
-
- 4. Redistribution. You may reproduce and distribute copies of the
- Work or Derivative Works thereof in any medium, with or without
- modifications, and in Source or Object form, provided that You
- meet the following conditions:
-
- (a) You must give any other recipients of the Work or
- Derivative Works a copy of this License; and
-
- (b) You must cause any modified files to carry prominent notices
- stating that You changed the files; and
-
- (c) You must retain, in the Source form of any Derivative Works
- that You distribute, all copyright, patent, trademark, and
- attribution notices from the Source form of the Work,
- excluding those notices that do not pertain to any part of
- the Derivative Works; and
-
- (d) If the Work includes a "NOTICE" text file as part of its
- distribution, then any Derivative Works that You distribute must
- include a readable copy of the attribution notices contained
- within such NOTICE file, excluding those notices that do not
- pertain to any part of the Derivative Works, in at least one
- of the following places: within a NOTICE text file distributed
- as part of the Derivative Works; within the Source form or
- documentation, if provided along with the Derivative Works; or,
- within a display generated by the Derivative Works, if and
- wherever such third-party notices normally appear. The contents
- of the NOTICE file are for informational purposes only and
- do not modify the License. You may add Your own attribution
- notices within Derivative Works that You distribute, alongside
- or as an addendum to the NOTICE text from the Work, provided
- that such additional attribution notices cannot be construed
- as modifying the License.
-
- You may add Your own copyright statement to Your modifications and
- may provide additional or different license terms and conditions
- for use, reproduction, or distribution of Your modifications, or
- for any such Derivative Works as a whole, provided Your use,
- reproduction, and distribution of the Work otherwise complies with
- the conditions stated in this License.
-
- 5. Submission of Contributions. Unless You explicitly state otherwise,
- any Contribution intentionally submitted for inclusion in the Work
- by You to the Licensor shall be under the terms and conditions of
- this License, without any additional terms or conditions.
- Notwithstanding the above, nothing herein shall supersede or modify
- the terms of any separate license agreement you may have executed
- with Licensor regarding such Contributions.
-
- 6. Trademarks. This License does not grant permission to use the trade
- names, trademarks, service marks, or product names of the Licensor,
- except as required for reasonable and customary use in describing the
- origin of the Work and reproducing the content of the NOTICE file.
-
- 7. Disclaimer of Warranty. Unless required by applicable law or
- agreed to in writing, Licensor provides the Work (and each
- Contributor provides its Contributions) on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
- implied, including, without limitation, any warranties or conditions
- of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
- PARTICULAR PURPOSE. You are solely responsible for determining the
- appropriateness of using or redistributing the Work and assume any
- risks associated with Your exercise of permissions under this License.
-
- 8. Limitation of Liability. In no event and under no legal theory,
- whether in tort (including negligence), contract, or otherwise,
- unless required by applicable law (such as deliberate and grossly
- negligent acts) or agreed to in writing, shall any Contributor be
- liable to You for damages, including any direct, indirect, special,
- incidental, or consequential damages of any character arising as a
- result of this License or out of the use or inability to use the
- Work (including but not limited to damages for loss of goodwill,
- work stoppage, computer failure or malfunction, or any and all
- other commercial damages or losses), even if such Contributor
- has been advised of the possibility of such damages.
-
- 9. Accepting Warranty or Additional Liability. While redistributing
- the Work or Derivative Works thereof, You may choose to offer,
- and charge a fee for, acceptance of support, warranty, indemnity,
- or other liability obligations and/or rights consistent with this
- License. However, in accepting such obligations, You may act only
- on Your own behalf and on Your sole responsibility, not on behalf
- of any other Contributor, and only if You agree to indemnify,
- defend, and hold each Contributor harmless for any liability
- incurred by, or claims asserted against, such Contributor by reason
- of your accepting any such warranty or additional liability.
-
- END OF TERMS AND CONDITIONS
-
- APPENDIX: How to apply the Apache License to your work.
-
- To apply the Apache License to your work, attach the following
- boilerplate notice, with the fields enclosed by brackets "[]"
- replaced with your own identifying information. (Don't include
- the brackets!) The text should be enclosed in the appropriate
- comment syntax for the file format. We also recommend that a
- file or class name and description of purpose be included on the
- same "printed page" as the copyright notice for easier
- identification within third-party archives.
-
- Copyright [yyyy] [name of copyright owner]
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
diff --git a/structopt/structopt-derive/LICENSE-MIT b/structopt/structopt-derive/LICENSE-MIT
deleted file mode 100644
index e931b83..0000000
--- a/structopt/structopt-derive/LICENSE-MIT
+++ /dev/null
@@ -1,21 +0,0 @@
-MIT License
-
-Copyright (c) 2018 Guillaume Pinot (@TeXitoi) <texitoi@texitoi.eu>
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in all
-copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-SOFTWARE.
diff --git a/structopt/structopt-derive/src/attrs.rs b/structopt/structopt-derive/src/attrs.rs
deleted file mode 100644
index ce684a2..0000000
--- a/structopt/structopt-derive/src/attrs.rs
+++ /dev/null
@@ -1,620 +0,0 @@
-// Copyright 2018 Guillaume Pinot (@TeXitoi) <texitoi@texitoi.eu>
-//
-// 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.
-
-use crate::doc_comments::process_doc_comment;
-use crate::{parse::*, spanned::Sp, ty::Ty};
-
-use std::env;
-
-use heck::{CamelCase, KebabCase, MixedCase, ShoutySnakeCase, SnakeCase};
-use proc_macro2::{Span, TokenStream};
-use proc_macro_error::abort;
-use quote::{quote, quote_spanned, ToTokens};
-use syn::{self, ext::IdentExt, spanned::Spanned, Attribute, Expr, Ident, LitStr, MetaNameValue};
-
-#[derive(Clone)]
-pub enum Kind {
- Arg(Sp<Ty>),
- Subcommand(Sp<Ty>),
- FlattenStruct,
- Skip(Option<Expr>),
-}
-
-#[derive(Clone)]
-pub struct Method {
- name: Ident,
- args: TokenStream,
-}
-
-#[derive(Clone)]
-pub struct Parser {
- pub kind: Sp<ParserKind>,
- pub func: TokenStream,
-}
-
-#[derive(Debug, PartialEq, Clone)]
-pub enum ParserKind {
- FromStr,
- TryFromStr,
- FromOsStr,
- TryFromOsStr,
- FromOccurrences,
- FromFlag,
-}
-
-/// Defines the casing for the attributes long representation.
-#[derive(Copy, Clone, Debug, PartialEq)]
-pub enum CasingStyle {
- /// Indicate word boundaries with uppercase letter, excluding the first word.
- Camel,
- /// Keep all letters lowercase and indicate word boundaries with hyphens.
- Kebab,
- /// Indicate word boundaries with uppercase letter, including the first word.
- Pascal,
- /// Keep all letters uppercase and indicate word boundaries with underscores.
- ScreamingSnake,
- /// Keep all letters lowercase and indicate word boundaries with underscores.
- Snake,
- /// Use the original attribute name defined in the code.
- Verbatim,
-}
-
-#[derive(Clone)]
-pub enum Name {
- Derived(Ident),
- Assigned(LitStr),
-}
-
-#[derive(Clone)]
-pub struct Attrs {
- name: Name,
- casing: Sp<CasingStyle>,
- env_casing: Sp<CasingStyle>,
- doc_comment: Vec<Method>,
- methods: Vec<Method>,
- parser: Sp<Parser>,
- author: Option<Method>,
- about: Option<Method>,
- version: Option<Method>,
- no_version: Option<Ident>,
- verbatim_doc_comment: Option<Ident>,
- has_custom_parser: bool,
- kind: Sp<Kind>,
-}
-
-impl Method {
- pub fn new(name: Ident, args: TokenStream) -> Self {
- Method { name, args }
- }
-
- fn from_lit_or_env(ident: Ident, lit: Option<LitStr>, env_var: &str) -> Option<Self> {
- let mut lit = match lit {
- Some(lit) => lit,
-
- None => match env::var(env_var) {
- Ok(val) => LitStr::new(&val, ident.span()),
- Err(_) => {
- abort!(ident.span(),
- "cannot derive `{}` from Cargo.toml", ident;
- note = "`{}` environment variable is not set", env_var;
- help = "use `{} = \"...\"` to set {} manually", ident, ident;
- );
- }
- },
- };
-
- if ident == "author" {
- let edited = process_author_str(&lit.value());
- lit = LitStr::new(&edited, lit.span());
- }
-
- Some(Method::new(ident, quote!(#lit)))
- }
-}
-
-impl ToTokens for Method {
- fn to_tokens(&self, ts: &mut TokenStream) {
- let Method { ref name, ref args } = self;
- quote!(.#name(#args)).to_tokens(ts);
- }
-}
-
-impl Parser {
- fn default_spanned(span: Span) -> Sp<Self> {
- let kind = Sp::new(ParserKind::TryFromStr, span);
- let func = quote_spanned!(span=> ::std::str::FromStr::from_str);
- Sp::new(Parser { kind, func }, span)
- }
-
- fn from_spec(parse_ident: Ident, spec: ParserSpec) -> Sp<Self> {
- use ParserKind::*;
-
- let kind = match &*spec.kind.to_string() {
- "from_str" => FromStr,
- "try_from_str" => TryFromStr,
- "from_os_str" => FromOsStr,
- "try_from_os_str" => TryFromOsStr,
- "from_occurrences" => FromOccurrences,
- "from_flag" => FromFlag,
- s => abort!(spec.kind.span(), "unsupported parser `{}`", s),
- };
-
- let func = match spec.parse_func {
- None => match kind {
- FromStr | FromOsStr => {
- quote_spanned!(spec.kind.span()=> ::std::convert::From::from)
- }
- TryFromStr => quote_spanned!(spec.kind.span()=> ::std::str::FromStr::from_str),
- TryFromOsStr => abort!(
- spec.kind.span(),
- "you must set parser for `try_from_os_str` explicitly"
- ),
- FromOccurrences => quote_spanned!(spec.kind.span()=> { |v| v as _ }),
- FromFlag => quote_spanned!(spec.kind.span()=> ::std::convert::From::from),
- },
-
- Some(func) => match func {
- syn::Expr::Path(_) => quote!(#func),
- _ => abort!(func.span(), "`parse` argument must be a function path"),
- },
- };
-
- let kind = Sp::new(kind, spec.kind.span());
- let parser = Parser { kind, func };
- Sp::new(parser, parse_ident.span())
- }
-}
-
-impl CasingStyle {
- fn from_lit(name: LitStr) -> Sp<Self> {
- use CasingStyle::*;
-
- let normalized = name.value().to_camel_case().to_lowercase();
- let cs = |kind| Sp::new(kind, name.span());
-
- match normalized.as_ref() {
- "camel" | "camelcase" => cs(Camel),
- "kebab" | "kebabcase" => cs(Kebab),
- "pascal" | "pascalcase" => cs(Pascal),
- "screamingsnake" | "screamingsnakecase" => cs(ScreamingSnake),
- "snake" | "snakecase" => cs(Snake),
- "verbatim" | "verbatimcase" => cs(Verbatim),
- s => abort!(name.span(), "unsupported casing: `{}`", s),
- }
- }
-}
-
-impl Name {
- pub fn translate(self, style: CasingStyle) -> LitStr {
- use CasingStyle::*;
-
- match self {
- Name::Assigned(lit) => lit,
- Name::Derived(ident) => {
- let s = ident.unraw().to_string();
- let s = match style {
- Pascal => s.to_camel_case(),
- Kebab => s.to_kebab_case(),
- Camel => s.to_mixed_case(),
- ScreamingSnake => s.to_shouty_snake_case(),
- Snake => s.to_snake_case(),
- Verbatim => s,
- };
- LitStr::new(&s, ident.span())
- }
- }
- }
-}
-
-impl Attrs {
- fn new(
- default_span: Span,
- name: Name,
- casing: Sp<CasingStyle>,
- env_casing: Sp<CasingStyle>,
- ) -> Self {
- Self {
- name,
- casing,
- env_casing,
- doc_comment: vec![],
- methods: vec![],
- parser: Parser::default_spanned(default_span),
- about: None,
- author: None,
- version: None,
- no_version: None,
- verbatim_doc_comment: None,
-
- has_custom_parser: false,
- kind: Sp::new(Kind::Arg(Sp::new(Ty::Other, default_span)), default_span),
- }
- }
-
- /// push `.method("str literal")`
- fn push_str_method(&mut self, name: Sp<String>, arg: Sp<String>) {
- if *name == "name" {
- self.name = Name::Assigned(arg.as_lit());
- } else {
- self.methods
- .push(Method::new(name.as_ident(), quote!(#arg)))
- }
- }
-
- fn push_attrs(&mut self, attrs: &[Attribute]) {
- use crate::parse::StructOptAttr::*;
-
- for attr in parse_structopt_attributes(attrs) {
- match attr {
- Short(ident) | Long(ident) => {
- self.push_str_method(
- ident.into(),
- self.name.clone().translate(*self.casing).into(),
- );
- }
-
- Env(ident) => {
- self.push_str_method(
- ident.into(),
- self.name.clone().translate(*self.env_casing).into(),
- );
- }
-
- Subcommand(ident) => {
- let ty = Sp::call_site(Ty::Other);
- let kind = Sp::new(Kind::Subcommand(ty), ident.span());
- self.set_kind(kind);
- }
-
- Flatten(ident) => {
- let kind = Sp::new(Kind::FlattenStruct, ident.span());
- self.set_kind(kind);
- }
-
- Skip(ident, expr) => {
- let kind = Sp::new(Kind::Skip(expr), ident.span());
- self.set_kind(kind);
- }
-
- NoVersion(ident) => self.no_version = Some(ident),
-
- VerbatimDocComment(ident) => self.verbatim_doc_comment = Some(ident),
-
- About(ident, about) => {
- self.about = Method::from_lit_or_env(ident, about, "CARGO_PKG_DESCRIPTION");
- }
-
- Author(ident, author) => {
- self.author = Method::from_lit_or_env(ident, author, "CARGO_PKG_AUTHORS");
- }
-
- Version(ident, version) => {
- self.version = Some(Method::new(ident, quote!(#version)))
- }
-
- NameLitStr(name, lit) => {
- self.push_str_method(name.into(), lit.into());
- }
-
- NameExpr(name, expr) => self.methods.push(Method::new(name, quote!(#expr))),
-
- MethodCall(name, args) => self.methods.push(Method::new(name, quote!(#(#args),*))),
-
- RenameAll(_, casing_lit) => {
- self.casing = CasingStyle::from_lit(casing_lit);
- }
-
- RenameAllEnv(_, casing_lit) => {
- self.env_casing = CasingStyle::from_lit(casing_lit);
- }
-
- Parse(ident, spec) => {
- self.has_custom_parser = true;
- self.parser = Parser::from_spec(ident, spec);
- }
- }
- }
- }
-
- fn push_doc_comment(&mut self, attrs: &[Attribute], name: &str) {
- use crate::Lit::*;
- use crate::Meta::*;
-
- let comment_parts: Vec<_> = attrs
- .iter()
- .filter(|attr| attr.path.is_ident("doc"))
- .filter_map(|attr| {
- if let Ok(NameValue(MetaNameValue { lit: Str(s), .. })) = attr.parse_meta() {
- Some(s.value())
- } else {
- // non #[doc = "..."] attributes are not our concern
- // we leave them for rustc to handle
- None
- }
- })
- .collect();
-
- self.doc_comment =
- process_doc_comment(comment_parts, name, self.verbatim_doc_comment.is_none());
- }
-
- pub fn from_struct(
- span: Span,
- attrs: &[Attribute],
- name: Name,
- argument_casing: Sp<CasingStyle>,
- env_casing: Sp<CasingStyle>,
- ) -> Self {
- let mut res = Self::new(span, name, argument_casing, env_casing);
- res.push_attrs(attrs);
- res.push_doc_comment(attrs, "about");
-
- if res.has_custom_parser {
- abort!(
- res.parser.span(),
- "`parse` attribute is only allowed on fields"
- );
- }
- match &*res.kind {
- Kind::Subcommand(_) => abort!(res.kind.span(), "subcommand is only allowed on fields"),
- Kind::FlattenStruct => abort!(res.kind.span(), "flatten is only allowed on fields"),
- Kind::Skip(_) => abort!(res.kind.span(), "skip is only allowed on fields"),
- Kind::Arg(_) => res,
- }
- }
-
- pub fn from_field(
- field: &syn::Field,
- struct_casing: Sp<CasingStyle>,
- env_casing: Sp<CasingStyle>,
- ) -> Self {
- let name = field.ident.clone().unwrap();
- let mut res = Self::new(
- field.span(),
- Name::Derived(name.clone()),
- struct_casing,
- env_casing,
- );
- res.push_doc_comment(&field.attrs, "help");
- res.push_attrs(&field.attrs);
-
- match &*res.kind {
- Kind::FlattenStruct => {
- if res.has_custom_parser {
- abort!(
- res.parser.span(),
- "parse attribute is not allowed for flattened entry"
- );
- }
- if res.has_explicit_methods() || res.has_doc_methods() {
- abort!(
- res.kind.span(),
- "methods and doc comments are not allowed for flattened entry"
- );
- }
- }
- Kind::Subcommand(_) => {
- if res.has_custom_parser {
- abort!(
- res.parser.span(),
- "parse attribute is not allowed for subcommand"
- );
- }
- if res.has_explicit_methods() {
- abort!(
- res.kind.span(),
- "methods in attributes are not allowed for subcommand"
- );
- }
-
- let ty = Ty::from_syn_ty(&field.ty);
- match *ty {
- Ty::OptionOption => {
- abort!(
- ty.span(),
- "Option<Option<T>> type is not allowed for subcommand"
- );
- }
- Ty::OptionVec => {
- abort!(
- ty.span(),
- "Option<Vec<T>> type is not allowed for subcommand"
- );
- }
- _ => (),
- }
-
- res.kind = Sp::new(Kind::Subcommand(ty), res.kind.span());
- }
- Kind::Skip(_) => {
- if res.has_explicit_methods() {
- abort!(
- res.kind.span(),
- "methods are not allowed for skipped fields"
- );
- }
- }
- Kind::Arg(orig_ty) => {
- let mut ty = Ty::from_syn_ty(&field.ty);
- if res.has_custom_parser {
- match *ty {
- Ty::Option | Ty::Vec | Ty::OptionVec => (),
- _ => ty = Sp::new(Ty::Other, ty.span()),
- }
- }
-
- match *ty {
- Ty::Bool => {
- if res.is_positional() && !res.has_custom_parser {
- abort!(ty.span(),
- "`bool` cannot be used as positional parameter with default parser";
- help = "if you want to create a flag add `long` or `short`";
- help = "If you really want a boolean parameter \
- add an explicit parser, for example `parse(try_from_str)`";
- note = "see also https://github.com/TeXitoi/structopt/tree/master/examples/true_or_false.rs";
- )
- }
- if let Some(m) = res.find_method("default_value") {
- abort!(m.name.span(), "default_value is meaningless for bool")
- }
- if let Some(m) = res.find_method("required") {
- abort!(m.name.span(), "required is meaningless for bool")
- }
- }
- Ty::Option => {
- if let Some(m) = res.find_method("default_value") {
- abort!(m.name.span(), "default_value is meaningless for Option")
- }
- if let Some(m) = res.find_method("required") {
- abort!(m.name.span(), "required is meaningless for Option")
- }
- }
- Ty::OptionOption => {
- if res.is_positional() {
- abort!(
- ty.span(),
- "Option<Option<T>> type is meaningless for positional argument"
- )
- }
- }
- Ty::OptionVec => {
- if res.is_positional() {
- abort!(
- ty.span(),
- "Option<Vec<T>> type is meaningless for positional argument"
- )
- }
- }
-
- _ => (),
- }
- res.kind = Sp::new(Kind::Arg(ty), orig_ty.span());
- }
- }
-
- res
- }
-
- fn set_kind(&mut self, kind: Sp<Kind>) {
- if let Kind::Arg(_) = *self.kind {
- self.kind = kind;
- } else {
- abort!(
- kind.span(),
- "subcommand, flatten and skip cannot be used together"
- );
- }
- }
-
- pub fn has_method(&self, name: &str) -> bool {
- self.find_method(name).is_some()
- }
-
- pub fn find_method(&self, name: &str) -> Option<&Method> {
- self.methods.iter().find(|m| m.name == name)
- }
-
- /// generate methods from attributes on top of struct or enum
- pub fn top_level_methods(&self) -> TokenStream {
- let version = match (&self.no_version, &self.version) {
- (Some(no_version), Some(_)) => abort!(
- no_version.span(),
- "`no_version` and `version = \"version\"` can't be used together"
- ),
-
- (None, Some(m)) => m.to_token_stream(),
-
- (None, None) => std::env::var("CARGO_PKG_VERSION")
- .map(|version| quote!( .version(#version) ))
- .unwrap_or_default(),
-
- (Some(_), None) => quote!(),
- };
-
- let author = &self.author;
- let about = &self.about;
- let methods = &self.methods;
- let doc_comment = &self.doc_comment;
-
- quote!( #(#doc_comment)* #author #version #about #(#methods)* )
- }
-
- /// generate methods on top of a field
- pub fn field_methods(&self) -> TokenStream {
- let methods = &self.methods;
- let doc_comment = &self.doc_comment;
- quote!( #(#doc_comment)* #(#methods)* )
- }
-
- pub fn cased_name(&self) -> LitStr {
- self.name.clone().translate(*self.casing)
- }
-
- pub fn parser(&self) -> &Sp<Parser> {
- &self.parser
- }
-
- pub fn kind(&self) -> Sp<Kind> {
- self.kind.clone()
- }
-
- pub fn casing(&self) -> Sp<CasingStyle> {
- self.casing.clone()
- }
-
- pub fn env_casing(&self) -> Sp<CasingStyle> {
- self.env_casing.clone()
- }
-
- pub fn is_positional(&self) -> bool {
- self.methods
- .iter()
- .all(|m| m.name != "long" && m.name != "short")
- }
-
- pub fn has_explicit_methods(&self) -> bool {
- self.methods
- .iter()
- .any(|m| m.name != "help" && m.name != "long_help")
- }
-
- pub fn has_doc_methods(&self) -> bool {
- !self.doc_comment.is_empty()
- || self.methods.iter().any(|m| {
- m.name == "help"
- || m.name == "long_help"
- || m.name == "about"
- || m.name == "long_about"
- })
- }
-}
-
-/// replace all `:` with `, ` when not inside the `<>`
-///
-/// `"author1:author2:author3" => "author1, author2, author3"`
-/// `"author1 <http://website1.com>:author2" => "author1 <http://website1.com>, author2"
-fn process_author_str(author: &str) -> String {
- let mut res = String::with_capacity(author.len());
- let mut inside_angle_braces = 0usize;
-
- for ch in author.chars() {
- if inside_angle_braces > 0 && ch == '>' {
- inside_angle_braces -= 1;
- res.push(ch);
- } else if ch == '<' {
- inside_angle_braces += 1;
- res.push(ch);
- } else if inside_angle_braces == 0 && ch == ':' {
- res.push_str(", ");
- } else {
- res.push(ch);
- }
- }
-
- res
-}
diff --git a/structopt/structopt-derive/src/doc_comments.rs b/structopt/structopt-derive/src/doc_comments.rs
deleted file mode 100644
index 06e1b14..0000000
--- a/structopt/structopt-derive/src/doc_comments.rs
+++ /dev/null
@@ -1,103 +0,0 @@
-//! The preprocessing we apply to doc comments.
-//!
-//! structopt works in terms of "paragraphs". Paragraph is a sequence of
-//! non-empty adjacent lines, delimited by sequences of blank (whitespace only) lines.
-
-use crate::attrs::Method;
-use quote::{format_ident, quote};
-use std::iter;
-
-pub fn process_doc_comment(lines: Vec<String>, name: &str, preprocess: bool) -> Vec<Method> {
- // multiline comments (`/** ... */`) may have LFs (`\n`) in them,
- // we need to split so we could handle the lines correctly
- //
- // we also need to remove leading and trailing blank lines
- let mut lines: Vec<&str> = lines
- .iter()
- .skip_while(|s| is_blank(s))
- .flat_map(|s| s.split('\n'))
- .collect();
-
- while let Some(true) = lines.last().map(|s| is_blank(s)) {
- lines.pop();
- }
-
- // remove one leading space no matter what
- for line in lines.iter_mut() {
- if line.starts_with(' ') {
- *line = &line[1..];
- }
- }
-
- if lines.is_empty() {
- return vec![];
- }
-
- let short_name = format_ident!("{}", name);
- let long_name = format_ident!("long_{}", name);
-
- if let Some(first_blank) = lines.iter().position(|s| is_blank(s)) {
- let (short, long) = if preprocess {
- let paragraphs = split_paragraphs(&lines);
- let short = paragraphs[0].clone();
- let long = paragraphs.join("\n\n");
- (remove_period(short), long)
- } else {
- let short = lines[..first_blank].join("\n");
- let long = lines.join("\n");
- (short, long)
- };
-
- vec![
- Method::new(short_name, quote!(#short)),
- Method::new(long_name, quote!(#long)),
- ]
- } else {
- let short = if preprocess {
- let s = merge_lines(&lines);
- remove_period(s)
- } else {
- lines.join("\n")
- };
-
- vec![Method::new(short_name, quote!(#short))]
- }
-}
-
-fn split_paragraphs(lines: &[&str]) -> Vec<String> {
- let mut last_line = 0;
- iter::from_fn(|| {
- let slice = &lines[last_line..];
- let start = slice.iter().position(|s| !is_blank(s)).unwrap_or(0);
-
- let slice = &slice[start..];
- let len = slice
- .iter()
- .position(|s| is_blank(s))
- .unwrap_or(slice.len());
-
- last_line += start + len;
-
- if len != 0 {
- Some(merge_lines(&slice[..len]))
- } else {
- None
- }
- })
- .collect()
-}
-
-fn remove_period(mut s: String) -> String {
- if s.ends_with('.') && !s.ends_with("..") {
- s.pop();
- }
- s
-}
-
-fn is_blank(s: &str) -> bool {
- s.trim().is_empty()
-}
-
-fn merge_lines(lines: &[&str]) -> String {
- lines.iter().map(|s| s.trim()).collect::<Vec<_>>().join(" ")
-}
diff --git a/structopt/structopt-derive/src/lib.rs b/structopt/structopt-derive/src/lib.rs
deleted file mode 100644
index 87eaf1f..0000000
--- a/structopt/structopt-derive/src/lib.rs
+++ /dev/null
@@ -1,667 +0,0 @@
-// Copyright 2018 Guillaume Pinot (@TeXitoi) <texitoi@texitoi.eu>
-//
-// 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 crate is custom derive for `StructOpt`. It should not be used
-//! directly. See [structopt documentation](https://docs.rs/structopt)
-//! for the usage of `#[derive(StructOpt)]`.
-
-#![allow(clippy::large_enum_variant)]
-
-extern crate proc_macro;
-
-mod attrs;
-mod doc_comments;
-mod parse;
-mod spanned;
-mod ty;
-
-use crate::{
- attrs::{Attrs, CasingStyle, Kind, Name, ParserKind},
- spanned::Sp,
- ty::{sub_type, Ty},
-};
-
-use proc_macro2::{Span, TokenStream};
-use proc_macro_error::{abort, abort_call_site, proc_macro_error, set_dummy};
-use quote::{quote, quote_spanned};
-use syn::{punctuated::Punctuated, spanned::Spanned, token::Comma, *};
-
-/// Default casing style for generated arguments.
-const DEFAULT_CASING: CasingStyle = CasingStyle::Kebab;
-
-/// Default casing style for environment variables
-const DEFAULT_ENV_CASING: CasingStyle = CasingStyle::ScreamingSnake;
-
-/// Output for the `gen_xxx()` methods were we need more than a simple stream of tokens.
-///
-/// The output of a generation method is not only the stream of new tokens but also the attribute
-/// information of the current element. These attribute information may contain valuable information
-/// for any kind of child arguments.
-struct GenOutput {
- tokens: TokenStream,
- attrs: Attrs,
-}
-
-/// Generates the `StructOpt` impl.
-#[proc_macro_derive(StructOpt, attributes(structopt))]
-#[proc_macro_error]
-pub fn structopt(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
- let input: DeriveInput = syn::parse(input).unwrap();
- let gen = impl_structopt(&input);
- gen.into()
-}
-
-/// Generate a block of code to add arguments/subcommands corresponding to
-/// the `fields` to an app.
-fn gen_augmentation(
- fields: &Punctuated<Field, Comma>,
- app_var: &Ident,
- parent_attribute: &Attrs,
-) -> TokenStream {
- let mut subcmds = fields.iter().filter_map(|field| {
- let attrs = Attrs::from_field(
- field,
- parent_attribute.casing(),
- parent_attribute.env_casing(),
- );
- let kind = attrs.kind();
- if let Kind::Subcommand(ty) = &*kind {
- let subcmd_type = match (**ty, sub_type(&field.ty)) {
- (Ty::Option, Some(sub_type)) => sub_type,
- _ => &field.ty,
- };
- let required = if **ty == Ty::Option {
- quote!()
- } else {
- quote_spanned! { kind.span()=>
- let #app_var = #app_var.setting(
- ::structopt::clap::AppSettings::SubcommandRequiredElseHelp
- );
- }
- };
-
- let span = field.span();
- let ts = quote! {
- let #app_var = <#subcmd_type as ::structopt::StructOptInternal>::augment_clap(
- #app_var
- );
- #required
- };
- Some((span, ts))
- } else {
- None
- }
- });
-
- let subcmd = subcmds.next().map(|(_, ts)| ts);
- if let Some((span, _)) = subcmds.next() {
- abort!(
- span,
- "multiple subcommand sets are not allowed, that's the second"
- );
- }
-
- let args = fields.iter().filter_map(|field| {
- let attrs = Attrs::from_field(
- field,
- parent_attribute.casing(),
- parent_attribute.env_casing(),
- );
- let kind = attrs.kind();
- match &*kind {
- Kind::Subcommand(_) | Kind::Skip(_) => None,
- Kind::FlattenStruct => {
- let ty = &field.ty;
- Some(quote_spanned! { kind.span()=>
- let #app_var = <#ty as ::structopt::StructOptInternal>::augment_clap(#app_var);
- let #app_var = if <#ty as ::structopt::StructOptInternal>::is_subcommand() {
- #app_var.setting(::structopt::clap::AppSettings::SubcommandRequiredElseHelp)
- } else {
- #app_var
- };
- })
- }
- Kind::Arg(ty) => {
- let convert_type = match **ty {
- Ty::Vec | Ty::Option => sub_type(&field.ty).unwrap_or(&field.ty),
- Ty::OptionOption | Ty::OptionVec => {
- sub_type(&field.ty).and_then(sub_type).unwrap_or(&field.ty)
- }
- _ => &field.ty,
- };
-
- let occurrences = *attrs.parser().kind == ParserKind::FromOccurrences;
- let flag = *attrs.parser().kind == ParserKind::FromFlag;
-
- let parser = attrs.parser();
- let func = &parser.func;
- let validator = match *parser.kind {
- ParserKind::TryFromStr => quote_spanned! { func.span()=>
- .validator(|s| {
- #func(s.as_str())
- .map(|_: #convert_type| ())
- .map_err(|e| e.to_string())
- })
- },
- ParserKind::TryFromOsStr => quote_spanned! { func.span()=>
- .validator_os(|s| #func(&s).map(|_: #convert_type| ()))
- },
- _ => quote!(),
- };
-
- let modifier = match **ty {
- Ty::Bool => quote_spanned! { ty.span()=>
- .takes_value(false)
- .multiple(false)
- },
-
- Ty::Option => quote_spanned! { ty.span()=>
- .takes_value(true)
- .multiple(false)
- #validator
- },
-
- Ty::OptionOption => quote_spanned! { ty.span()=>
- .takes_value(true)
- .multiple(false)
- .min_values(0)
- .max_values(1)
- #validator
- },
-
- Ty::OptionVec => quote_spanned! { ty.span()=>
- .takes_value(true)
- .multiple(true)
- .min_values(0)
- #validator
- },
-
- Ty::Vec => quote_spanned! { ty.span()=>
- .takes_value(true)
- .multiple(true)
- #validator
- },
-
- Ty::Other if occurrences => quote_spanned! { ty.span()=>
- .takes_value(false)
- .multiple(true)
- },
-
- Ty::Other if flag => quote_spanned! { ty.span()=>
- .takes_value(false)
- .multiple(false)
- },
-
- Ty::Other => {
- let required = !attrs.has_method("default_value");
- quote_spanned! { ty.span()=>
- .takes_value(true)
- .multiple(false)
- .required(#required)
- #validator
- }
- }
- };
-
- let name = attrs.cased_name();
- let methods = attrs.field_methods();
-
- Some(quote_spanned! { field.span()=>
- let #app_var = #app_var.arg(
- ::structopt::clap::Arg::with_name(#name)
- #modifier
- #methods
- );
- })
- }
- }
- });
-
- let app_methods = parent_attribute.top_level_methods();
- quote! {{
- let #app_var = #app_var#app_methods;
- #( #args )*
- #subcmd
- #app_var
- }}
-}
-
-fn gen_constructor(fields: &Punctuated<Field, Comma>, parent_attribute: &Attrs) -> TokenStream {
- let fields = fields.iter().map(|field| {
- let attrs = Attrs::from_field(
- field,
- parent_attribute.casing(),
- parent_attribute.env_casing(),
- );
- let field_name = field.ident.as_ref().unwrap();
- let kind = attrs.kind();
- match &*kind {
- Kind::Subcommand(ty) => {
- let subcmd_type = match (**ty, sub_type(&field.ty)) {
- (Ty::Option, Some(sub_type)) => sub_type,
- _ => &field.ty,
- };
- let unwrapper = match **ty {
- Ty::Option => quote!(),
- _ => quote_spanned!( ty.span()=> .unwrap() ),
- };
- quote_spanned! { kind.span()=>
- #field_name: <#subcmd_type as ::structopt::StructOptInternal>::from_subcommand(
- matches.subcommand())
- #unwrapper
- }
- }
-
- Kind::FlattenStruct => quote_spanned! { kind.span()=>
- #field_name: ::structopt::StructOpt::from_clap(matches)
- },
-
- Kind::Skip(val) => match val {
- None => quote_spanned!(kind.span()=> #field_name: Default::default()),
- Some(val) => quote_spanned!(kind.span()=> #field_name: (#val).into()),
- },
-
- Kind::Arg(ty) => {
- use crate::attrs::ParserKind::*;
-
- let parser = attrs.parser();
- let func = &parser.func;
- let span = parser.kind.span();
- let (value_of, values_of, parse) = match *parser.kind {
- FromStr => (
- quote_spanned!(span=> value_of),
- quote_spanned!(span=> values_of),
- func.clone(),
- ),
- TryFromStr => (
- quote_spanned!(span=> value_of),
- quote_spanned!(span=> values_of),
- quote_spanned!(func.span()=> |s| #func(s).unwrap()),
- ),
- FromOsStr => (
- quote_spanned!(span=> value_of_os),
- quote_spanned!(span=> values_of_os),
- func.clone(),
- ),
- TryFromOsStr => (
- quote_spanned!(span=> value_of_os),
- quote_spanned!(span=> values_of_os),
- quote_spanned!(func.span()=> |s| #func(s).unwrap()),
- ),
- FromOccurrences => (
- quote_spanned!(span=> occurrences_of),
- quote!(),
- func.clone(),
- ),
- FromFlag => (quote!(), quote!(), func.clone()),
- };
-
- let flag = *attrs.parser().kind == ParserKind::FromFlag;
- let occurrences = *attrs.parser().kind == ParserKind::FromOccurrences;
- let name = attrs.cased_name();
- let field_value = match **ty {
- Ty::Bool => quote_spanned!(ty.span()=> matches.is_present(#name)),
-
- Ty::Option => quote_spanned! { ty.span()=>
- matches.#value_of(#name)
- .map(#parse)
- },
-
- Ty::OptionOption => quote_spanned! { ty.span()=>
- if matches.is_present(#name) {
- Some(matches.#value_of(#name).map(#parse))
- } else {
- None
- }
- },
-
- Ty::OptionVec => quote_spanned! { ty.span()=>
- if matches.is_present(#name) {
- Some(matches.#values_of(#name)
- .map_or_else(Vec::new, |v| v.map(#parse).collect()))
- } else {
- None
- }
- },
-
- Ty::Vec => quote_spanned! { ty.span()=>
- matches.#values_of(#name)
- .map_or_else(Vec::new, |v| v.map(#parse).collect())
- },
-
- Ty::Other if occurrences => quote_spanned! { ty.span()=>
- #parse(matches.#value_of(#name))
- },
-
- Ty::Other if flag => quote_spanned! { ty.span()=>
- #parse(matches.is_present(#name))
- },
-
- Ty::Other => quote_spanned! { ty.span()=>
- matches.#value_of(#name)
- .map(#parse)
- .unwrap()
- },
- };
-
- quote_spanned!(field.span()=> #field_name: #field_value )
- }
- }
- });
-
- quote! {{
- #( #fields ),*
- }}
-}
-
-fn gen_from_clap(
- struct_name: &Ident,
- fields: &Punctuated<Field, Comma>,
- parent_attribute: &Attrs,
-) -> TokenStream {
- let field_block = gen_constructor(fields, parent_attribute);
-
- quote! {
- fn from_clap(matches: &::structopt::clap::ArgMatches) -> Self {
- #struct_name #field_block
- }
- }
-}
-
-fn gen_clap(attrs: &[Attribute]) -> GenOutput {
- let name = std::env::var("CARGO_PKG_NAME").ok().unwrap_or_default();
-
- let attrs = Attrs::from_struct(
- Span::call_site(),
- attrs,
- Name::Assigned(LitStr::new(&name, Span::call_site())),
- Sp::call_site(DEFAULT_CASING),
- Sp::call_site(DEFAULT_ENV_CASING),
- );
- let tokens = {
- let name = attrs.cased_name();
- quote!(::structopt::clap::App::new(#name))
- };
-
- GenOutput { tokens, attrs }
-}
-
-fn gen_clap_struct(struct_attrs: &[Attribute]) -> GenOutput {
- let initial_clap_app_gen = gen_clap(struct_attrs);
- let clap_tokens = initial_clap_app_gen.tokens;
-
- let augmented_tokens = quote! {
- fn clap<'a, 'b>() -> ::structopt::clap::App<'a, 'b> {
- let app = #clap_tokens;
- <Self as ::structopt::StructOptInternal>::augment_clap(app)
- }
- };
-
- GenOutput {
- tokens: augmented_tokens,
- attrs: initial_clap_app_gen.attrs,
- }
-}
-
-fn gen_augment_clap(fields: &Punctuated<Field, Comma>, parent_attribute: &Attrs) -> TokenStream {
- let app_var = Ident::new("app", Span::call_site());
- let augmentation = gen_augmentation(fields, &app_var, parent_attribute);
- quote! {
- fn augment_clap<'a, 'b>(
- #app_var: ::structopt::clap::App<'a, 'b>
- ) -> ::structopt::clap::App<'a, 'b> {
- #augmentation
- }
- }
-}
-
-fn gen_clap_enum(enum_attrs: &[Attribute]) -> GenOutput {
- let initial_clap_app_gen = gen_clap(enum_attrs);
- let clap_tokens = initial_clap_app_gen.tokens;
-
- let tokens = quote! {
- fn clap<'a, 'b>() -> ::structopt::clap::App<'a, 'b> {
- let app = #clap_tokens
- .setting(::structopt::clap::AppSettings::SubcommandRequiredElseHelp);
- <Self as ::structopt::StructOptInternal>::augment_clap(app)
- }
- };
-
- GenOutput {
- tokens,
- attrs: initial_clap_app_gen.attrs,
- }
-}
-
-fn gen_augment_clap_enum(
- variants: &Punctuated<Variant, Comma>,
- parent_attribute: &Attrs,
-) -> TokenStream {
- use syn::Fields::*;
-
- let subcommands = variants.iter().map(|variant| {
- let attrs = Attrs::from_struct(
- variant.span(),
- &variant.attrs,
- Name::Derived(variant.ident.clone()),
- parent_attribute.casing(),
- parent_attribute.env_casing(),
- );
- let app_var = Ident::new("subcommand", Span::call_site());
- let arg_block = match variant.fields {
- Named(ref fields) => gen_augmentation(&fields.named, &app_var, &attrs),
- Unit => quote!( #app_var ),
- Unnamed(FieldsUnnamed { ref unnamed, .. }) if unnamed.len() == 1 => {
- let ty = &unnamed[0];
- quote_spanned! { ty.span()=>
- {
- let #app_var = <#ty as ::structopt::StructOptInternal>::augment_clap(
- #app_var
- );
- if <#ty as ::structopt::StructOptInternal>::is_subcommand() {
- #app_var.setting(
- ::structopt::clap::AppSettings::SubcommandRequiredElseHelp
- )
- } else {
- #app_var
- }
- }
- }
- }
- Unnamed(..) => abort_call_site!("{}: tuple enums are not supported", variant.ident),
- };
-
- let name = attrs.cased_name();
- let from_attrs = attrs.top_level_methods();
-
- quote! {
- .subcommand({
- let #app_var = ::structopt::clap::SubCommand::with_name(#name);
- let #app_var = #arg_block;
- #app_var#from_attrs
- })
- }
- });
-
- let app_methods = parent_attribute.top_level_methods();
-
- quote! {
- fn augment_clap<'a, 'b>(
- app: ::structopt::clap::App<'a, 'b>
- ) -> ::structopt::clap::App<'a, 'b> {
- app #app_methods #( #subcommands )*
- }
- }
-}
-
-fn gen_from_clap_enum(name: &Ident) -> TokenStream {
- quote! {
- fn from_clap(matches: &::structopt::clap::ArgMatches) -> Self {
- <#name as ::structopt::StructOptInternal>::from_subcommand(matches.subcommand())
- .unwrap()
- }
- }
-}
-
-fn gen_from_subcommand(
- name: &Ident,
- variants: &Punctuated<Variant, Comma>,
- parent_attribute: &Attrs,
-) -> TokenStream {
- use syn::Fields::*;
-
- let match_arms = variants.iter().map(|variant| {
- let attrs = Attrs::from_struct(
- variant.span(),
- &variant.attrs,
- Name::Derived(variant.ident.clone()),
- parent_attribute.casing(),
- parent_attribute.env_casing(),
- );
- let sub_name = attrs.cased_name();
- let variant_name = &variant.ident;
- let constructor_block = match variant.fields {
- Named(ref fields) => gen_constructor(&fields.named, &attrs),
- Unit => quote!(),
- Unnamed(ref fields) if fields.unnamed.len() == 1 => {
- let ty = &fields.unnamed[0];
- quote!( ( <#ty as ::structopt::StructOpt>::from_clap(matches) ) )
- }
- Unnamed(..) => abort_call_site!("{}: tuple enums are not supported", variant.ident),
- };
-
- quote! {
- (#sub_name, Some(matches)) =>
- Some(#name :: #variant_name #constructor_block)
- }
- });
-
- quote! {
- fn from_subcommand<'a, 'b>(
- sub: (&'b str, Option<&'b ::structopt::clap::ArgMatches<'a>>)
- ) -> Option<Self> {
- match sub {
- #( #match_arms ),*,
- _ => None
- }
- }
- }
-}
-
-#[cfg(feature = "paw")]
-fn gen_paw_impl(name: &Ident) -> TokenStream {
- quote! {
- impl paw::ParseArgs for #name {
- type Error = std::io::Error;
-
- fn parse_args() -> std::result::Result<Self, Self::Error> {
- Ok(<#name as ::structopt::StructOpt>::from_args())
- }
- }
- }
-}
-#[cfg(not(feature = "paw"))]
-fn gen_paw_impl(_: &Ident) -> TokenStream {
- TokenStream::new()
-}
-
-fn impl_structopt_for_struct(
- name: &Ident,
- fields: &Punctuated<Field, Comma>,
- attrs: &[Attribute],
-) -> TokenStream {
- let basic_clap_app_gen = gen_clap_struct(attrs);
- let augment_clap = gen_augment_clap(fields, &basic_clap_app_gen.attrs);
- let from_clap = gen_from_clap(name, fields, &basic_clap_app_gen.attrs);
- let paw_impl = gen_paw_impl(name);
-
- let clap_tokens = basic_clap_app_gen.tokens;
- quote! {
- #[allow(unused_variables)]
- #[allow(unknown_lints)]
- #[allow(clippy::all)]
- #[allow(dead_code, unreachable_code)]
- impl ::structopt::StructOpt for #name {
- #clap_tokens
- #from_clap
- }
-
- #[allow(unused_variables)]
- #[allow(unknown_lints)]
- #[allow(clippy::all)]
- #[allow(dead_code, unreachable_code)]
- impl ::structopt::StructOptInternal for #name {
- #augment_clap
- fn is_subcommand() -> bool { false }
- }
-
- #paw_impl
- }
-}
-
-fn impl_structopt_for_enum(
- name: &Ident,
- variants: &Punctuated<Variant, Comma>,
- attrs: &[Attribute],
-) -> TokenStream {
- let basic_clap_app_gen = gen_clap_enum(attrs);
-
- let augment_clap = gen_augment_clap_enum(variants, &basic_clap_app_gen.attrs);
- let from_clap = gen_from_clap_enum(name);
- let from_subcommand = gen_from_subcommand(name, variants, &basic_clap_app_gen.attrs);
- let paw_impl = gen_paw_impl(name);
-
- let clap_tokens = basic_clap_app_gen.tokens;
- quote! {
- #[allow(unknown_lints)]
- #[allow(unused_variables, dead_code, unreachable_code)]
- #[allow(clippy)]
- impl ::structopt::StructOpt for #name {
- #clap_tokens
- #from_clap
- }
-
- #[allow(unused_variables)]
- #[allow(unknown_lints)]
- #[allow(clippy::all)]
- #[allow(dead_code, unreachable_code)]
- impl ::structopt::StructOptInternal for #name {
- #augment_clap
- #from_subcommand
- fn is_subcommand() -> bool { true }
- }
-
- #paw_impl
- }
-}
-
-fn impl_structopt(input: &DeriveInput) -> TokenStream {
- use syn::Data::*;
-
- let struct_name = &input.ident;
-
- set_dummy(quote! {
- impl ::structopt::StructOpt for #struct_name {
- fn clap<'a, 'b>() -> ::structopt::clap::App<'a, 'b> {
- unimplemented!()
- }
- fn from_clap(_matches: &::structopt::clap::ArgMatches) -> Self {
- unimplemented!()
- }
- }
- });
-
- match input.data {
- Struct(DataStruct {
- fields: syn::Fields::Named(ref fields),
- ..
- }) => impl_structopt_for_struct(struct_name, &fields.named, &input.attrs),
- Enum(ref e) => impl_structopt_for_enum(struct_name, &e.variants, &input.attrs),
- _ => abort_call_site!("structopt only supports non-tuple structs and enums"),
- }
-}
diff --git a/structopt/structopt-derive/src/parse.rs b/structopt/structopt-derive/src/parse.rs
deleted file mode 100644
index a704742..0000000
--- a/structopt/structopt-derive/src/parse.rs
+++ /dev/null
@@ -1,304 +0,0 @@
-use std::iter::FromIterator;
-
-use proc_macro_error::{abort, ResultExt};
-use quote::ToTokens;
-use syn::{
- self, parenthesized,
- parse::{Parse, ParseBuffer, ParseStream},
- parse2,
- punctuated::Punctuated,
- spanned::Spanned,
- Attribute, Expr, ExprLit, Ident, Lit, LitBool, LitStr, Token,
-};
-
-pub struct StructOptAttributes {
- pub paren_token: syn::token::Paren,
- pub attrs: Punctuated<StructOptAttr, Token![,]>,
-}
-
-impl Parse for StructOptAttributes {
- fn parse(input: ParseStream<'_>) -> syn::Result<Self> {
- let content;
- let paren_token = parenthesized!(content in input);
- let attrs = content.parse_terminated(StructOptAttr::parse)?;
-
- Ok(StructOptAttributes { paren_token, attrs })
- }
-}
-
-pub enum StructOptAttr {
- // single-identifier attributes
- Short(Ident),
- Long(Ident),
- Env(Ident),
- Flatten(Ident),
- Subcommand(Ident),
- NoVersion(Ident),
- VerbatimDocComment(Ident),
-
- // ident [= "string literal"]
- About(Ident, Option<LitStr>),
- Author(Ident, Option<LitStr>),
-
- // ident = "string literal"
- Version(Ident, LitStr),
- RenameAllEnv(Ident, LitStr),
- RenameAll(Ident, LitStr),
- NameLitStr(Ident, LitStr),
-
- // parse(parser_kind [= parser_func])
- Parse(Ident, ParserSpec),
-
- // ident [= arbitrary_expr]
- Skip(Ident, Option<Expr>),
-
- // ident = arbitrary_expr
- NameExpr(Ident, Expr),
-
- // ident(arbitrary_expr,*)
- MethodCall(Ident, Vec<Expr>),
-}
-
-impl Parse for StructOptAttr {
- fn parse(input: ParseStream<'_>) -> syn::Result<Self> {
- use self::StructOptAttr::*;
-
- let name: Ident = input.parse()?;
- let name_str = name.to_string();
-
- if input.peek(Token![=]) {
- // `name = value` attributes.
- let assign_token = input.parse::<Token![=]>()?; // skip '='
-
- if input.peek(LitStr) {
- let lit: LitStr = input.parse()?;
- let lit_str = lit.value();
-
- let check_empty_lit = |s| {
- if lit_str.is_empty() {
- abort!(
- lit.span(),
- "`#[structopt({} = \"\")]` is deprecated in structopt 0.3, \
- now it's default behavior",
- s
- );
- }
- };
-
- match &*name_str.to_string() {
- "rename_all" => Ok(RenameAll(name, lit)),
- "rename_all_env" => Ok(RenameAllEnv(name, lit)),
-
- "version" => {
- check_empty_lit("version");
- Ok(Version(name, lit))
- }
-
- "author" => {
- check_empty_lit("author");
- Ok(Author(name, Some(lit)))
- }
-
- "about" => {
- check_empty_lit("about");
- Ok(About(name, Some(lit)))
- }
-
- "skip" => {
- let expr = ExprLit {
- attrs: vec![],
- lit: Lit::Str(lit),
- };
- let expr = Expr::Lit(expr);
- Ok(Skip(name, Some(expr)))
- }
-
- _ => Ok(NameLitStr(name, lit)),
- }
- } else {
- match input.parse::<Expr>() {
- Ok(expr) => {
- if name_str == "skip" {
- Ok(Skip(name, Some(expr)))
- } else {
- Ok(NameExpr(name, expr))
- }
- }
-
- Err(_) => abort! {
- assign_token.span(),
- "expected `string literal` or `expression` after `=`"
- },
- }
- }
- } else if input.peek(syn::token::Paren) {
- // `name(...)` attributes.
- let nested;
- parenthesized!(nested in input);
-
- match name_str.as_ref() {
- "parse" => {
- let parser_specs: Punctuated<ParserSpec, Token![,]> =
- nested.parse_terminated(ParserSpec::parse)?;
-
- if parser_specs.len() == 1 {
- Ok(Parse(name, parser_specs[0].clone()))
- } else {
- abort!(name.span(), "parse must have exactly one argument")
- }
- }
-
- "raw" => match nested.parse::<LitBool>() {
- Ok(bool_token) => {
- let expr = ExprLit {
- attrs: vec![],
- lit: Lit::Bool(bool_token),
- };
- let expr = Expr::Lit(expr);
- Ok(MethodCall(name, vec![expr]))
- }
-
- Err(_) => {
- abort!(name.span(),
- "`#[structopt(raw(...))` attributes are removed in structopt 0.3, \
- they are replaced with raw methods";
- help = "if you meant to call `clap::Arg::raw()` method \
- you should use bool literal, like `raw(true)` or `raw(false)`";
- note = raw_method_suggestion(nested);
- );
- }
- },
-
- _ => {
- let method_args: Punctuated<_, Token![,]> =
- nested.parse_terminated(Expr::parse)?;
- Ok(MethodCall(name, Vec::from_iter(method_args)))
- }
- }
- } else {
- // Attributes represented with a sole identifier.
- match name_str.as_ref() {
- "long" => Ok(Long(name)),
- "short" => Ok(Short(name)),
- "env" => Ok(Env(name)),
- "flatten" => Ok(Flatten(name)),
- "subcommand" => Ok(Subcommand(name)),
- "no_version" => Ok(NoVersion(name)),
- "verbatim_doc_comment" => Ok(VerbatimDocComment(name)),
-
- "about" => (Ok(About(name, None))),
- "author" => (Ok(Author(name, None))),
-
- "skip" => Ok(Skip(name, None)),
-
- "version" => abort!(
- name.span(),
- "#[structopt(version)] is invalid attribute, \
- structopt 0.3 inherits version from Cargo.toml by default, \
- no attribute needed"
- ),
-
- _ => abort!(name.span(), "unexpected attribute: {}", name_str),
- }
- }
- }
-}
-
-#[derive(Clone)]
-pub struct ParserSpec {
- pub kind: Ident,
- pub eq_token: Option<Token![=]>,
- pub parse_func: Option<Expr>,
-}
-
-impl Parse for ParserSpec {
- fn parse(input: ParseStream<'_>) -> syn::Result<Self> {
- let kind = input
- .parse()
- .map_err(|_| input.error("parser specification must start with identifier"))?;
- let eq_token = input.parse()?;
- let parse_func = match eq_token {
- None => None,
- Some(_) => Some(input.parse()?),
- };
- Ok(ParserSpec {
- kind,
- eq_token,
- parse_func,
- })
- }
-}
-
-struct CommaSeparated<T>(Punctuated<T, Token![,]>);
-
-impl<T: Parse> Parse for CommaSeparated<T> {
- fn parse(input: ParseStream<'_>) -> syn::Result<Self> {
- let res = Punctuated::parse_separated_nonempty(input)?;
- Ok(CommaSeparated(res))
- }
-}
-
-fn raw_method_suggestion(ts: ParseBuffer) -> String {
- let do_parse = move || -> Result<(Ident, CommaSeparated<Expr>), syn::Error> {
- let name = ts.parse()?;
- let _eq: Token![=] = ts.parse()?;
- let val: LitStr = ts.parse()?;
- Ok((name, syn::parse_str(&val.value())?))
- };
-
- fn to_string<T: ToTokens>(val: &T) -> String {
- val.to_token_stream()
- .to_string()
- .replace(" ", "")
- .replace(",", ", ")
- }
-
- if let Ok((name, val)) = do_parse() {
- let exprs = val.0;
- let suggestion = if exprs.len() == 1 {
- let val = to_string(&exprs[0]);
- format!(" = {}", val)
- } else {
- let val = exprs
- .into_iter()
- .map(|expr| to_string(&expr))
- .collect::<Vec<_>>()
- .join(", ");
-
- format!("({})", val)
- };
-
- format!(
- "if you need to call `clap::Arg/App::{}` method you \
- can do it like this: #[structopt({}{})]",
- name, name, suggestion
- )
- } else {
- "if you need to call some method from `clap::Arg/App` \
- you should use raw method, see \
- https://docs.rs/structopt/0.3/structopt/#raw-methods"
- .into()
- }
-}
-
-pub fn parse_structopt_attributes(all_attrs: &[Attribute]) -> Vec<StructOptAttr> {
- all_attrs
- .iter()
- .filter(|attr| attr.path.is_ident("structopt"))
- .flat_map(|attr| {
- let attrs: StructOptAttributes = parse2(attr.tokens.clone())
- .map_err(|e| match &*e.to_string() {
- // this error message is misleading and points to Span::call_site()
- // so we patch it with something meaningful
- "unexpected end of input, expected parentheses" => {
- let span = attr.path.span();
- let patch_msg = "expected parentheses after `structopt`";
- syn::Error::new(span, patch_msg)
- }
- _ => e,
- })
- .unwrap_or_abort();
- attrs.attrs
- })
- .collect()
-}
diff --git a/structopt/structopt-derive/src/spanned.rs b/structopt/structopt-derive/src/spanned.rs
deleted file mode 100644
index 2dd595b..0000000
--- a/structopt/structopt-derive/src/spanned.rs
+++ /dev/null
@@ -1,101 +0,0 @@
-use proc_macro2::{Ident, Span, TokenStream};
-use quote::ToTokens;
-use std::ops::{Deref, DerefMut};
-use syn::LitStr;
-
-/// An entity with a span attached.
-#[derive(Debug, Clone)]
-pub struct Sp<T> {
- span: Span,
- val: T,
-}
-
-impl<T> Sp<T> {
- pub fn new(val: T, span: Span) -> Self {
- Sp { val, span }
- }
-
- pub fn call_site(val: T) -> Self {
- Sp {
- val,
- span: Span::call_site(),
- }
- }
-
- pub fn span(&self) -> Span {
- self.span
- }
-}
-
-impl<T: ToString> Sp<T> {
- pub fn as_ident(&self) -> Ident {
- Ident::new(&self.to_string(), self.span)
- }
-
- pub fn as_lit(&self) -> LitStr {
- LitStr::new(&self.to_string(), self.span)
- }
-}
-
-impl<T> Deref for Sp<T> {
- type Target = T;
-
- fn deref(&self) -> &T {
- &self.val
- }
-}
-
-impl<T> DerefMut for Sp<T> {
- fn deref_mut(&mut self) -> &mut T {
- &mut self.val
- }
-}
-
-impl From<Ident> for Sp<String> {
- fn from(ident: Ident) -> Self {
- Sp {
- val: ident.to_string(),
- span: ident.span(),
- }
- }
-}
-
-impl From<LitStr> for Sp<String> {
- fn from(lit: LitStr) -> Self {
- Sp {
- val: lit.value(),
- span: lit.span(),
- }
- }
-}
-
-impl<'a> From<Sp<&'a str>> for Sp<String> {
- fn from(sp: Sp<&'a str>) -> Self {
- Sp::new(sp.val.into(), sp.span)
- }
-}
-
-impl<U, T: PartialEq<U>> PartialEq<U> for Sp<T> {
- fn eq(&self, other: &U) -> bool {
- self.val == *other
- }
-}
-
-impl<T: AsRef<str>> AsRef<str> for Sp<T> {
- fn as_ref(&self) -> &str {
- self.val.as_ref()
- }
-}
-
-impl<T: ToTokens> ToTokens for Sp<T> {
- fn to_tokens(&self, stream: &mut TokenStream) {
- // this is the simplest way out of correct ones to change span on
- // arbitrary token tree I can come up with
- let tt = self.val.to_token_stream().into_iter().map(|mut tt| {
- tt.set_span(self.span.clone());
- tt
- });
-
- stream.extend(tt);
- }
-}
diff --git a/structopt/structopt-derive/src/ty.rs b/structopt/structopt-derive/src/ty.rs
deleted file mode 100644
index 06eb3ec..0000000
--- a/structopt/structopt-derive/src/ty.rs
+++ /dev/null
@@ -1,108 +0,0 @@
-//! Special types handling
-
-use crate::spanned::Sp;
-
-use syn::{
- spanned::Spanned, GenericArgument, Path, PathArguments, PathArguments::AngleBracketed,
- PathSegment, Type, TypePath,
-};
-
-#[derive(Copy, Clone, PartialEq, Debug)]
-pub enum Ty {
- Bool,
- Vec,
- Option,
- OptionOption,
- OptionVec,
- Other,
-}
-
-impl Ty {
- pub fn from_syn_ty(ty: &syn::Type) -> Sp<Self> {
- use Ty::*;
- let t = |kind| Sp::new(kind, ty.span());
-
- if is_simple_ty(ty, "bool") {
- t(Bool)
- } else if is_generic_ty(ty, "Vec") {
- t(Vec)
- } else if let Some(subty) = subty_if_name(ty, "Option") {
- if is_generic_ty(subty, "Option") {
- t(OptionOption)
- } else if is_generic_ty(subty, "Vec") {
- t(OptionVec)
- } else {
- t(Option)
- }
- } else {
- t(Other)
- }
- }
-}
-
-pub fn sub_type(ty: &syn::Type) -> Option<&syn::Type> {
- subty_if(ty, |_| true)
-}
-
-fn only_last_segment(ty: &syn::Type) -> Option<&PathSegment> {
- match ty {
- Type::Path(TypePath {
- qself: None,
- path:
- Path {
- leading_colon: None,
- segments,
- },
- }) => only_one(segments.iter()),
-
- _ => None,
- }
-}
-
-fn subty_if<F>(ty: &syn::Type, f: F) -> Option<&syn::Type>
-where
- F: FnOnce(&PathSegment) -> bool,
-{
- only_last_segment(ty)
- .filter(|segment| f(segment))
- .and_then(|segment| {
- if let AngleBracketed(args) = &segment.arguments {
- only_one(args.args.iter()).and_then(|genneric| {
- if let GenericArgument::Type(ty) = genneric {
- Some(ty)
- } else {
- None
- }
- })
- } else {
- None
- }
- })
-}
-
-fn subty_if_name<'a>(ty: &'a syn::Type, name: &str) -> Option<&'a syn::Type> {
- subty_if(ty, |seg| seg.ident == name)
-}
-
-fn is_simple_ty(ty: &syn::Type, name: &str) -> bool {
- only_last_segment(ty)
- .map(|segment| {
- if let PathArguments::None = segment.arguments {
- segment.ident == name
- } else {
- false
- }
- })
- .unwrap_or(false)
-}
-
-fn is_generic_ty(ty: &syn::Type, name: &str) -> bool {
- subty_if_name(ty, name).is_some()
-}
-
-fn only_one<I, T>(mut iter: I) -> Option<T>
-where
- I: Iterator<Item = T>,
-{
- iter.next().filter(|_| iter.next().is_none())
-}