Repository: clap-rs/clap
Pull request #1638 (2020-01-18 13:24:13)

Subtree merge clap_derive into this repo
I have used git subtree merge to merge clap_derive into this repo thus making sure we don't lose history of clap_derive.

To check that the repo is merged correctly, we compare the hashes. The last non-merge commit here is https://github.com/clap-rs/clap/commit/0352bb30c897b00af88ad240e8e6f4aaf1855d05 where as the last commit in clap_derive is https://github.com/clap-rs/clap_derive/commit/0352bb30c897b00af88ad240e8e6f4aaf1855d05. As you can see, they are both the same.

https://github.com/clap-rs/clap/commit/5e8f424dfeef9c6dbd9c267dee323b8009e9a98b is the merge commit.

And then https://github.com/clap-rs/clap/commit/398e71fcd95eec09404f454beb1e95f8bcfb7232 is the commit which integrates both the repos together and sets up CI.

/cc @Dylan-DPC @CreepySkeleton

### Make sure you use the `merge` option instead of `squash` when merging this PR. Otherwise, all this git history would be lost.


Patch:
diff --git a/.appveyor.yml b/.appveyor.yml
index 247a550d..94e4b56d 100644
--- a/.appveyor.yml
+++ b/.appveyor.yml
@@ -13,5 +13,5 @@ install:
   - cargo -vV
 build: false
 test_script:
-  - cargo build --verbose --features yaml
-  - cargo test --verbose --features yaml
+  - cargo build --all --verbose --features yaml
+  - cargo test --all --verbose --features yaml
diff --git a/.travis.yml b/.travis.yml
index 5d697832..a4271992 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -15,8 +15,11 @@ rust:
 matrix:
     allow_failures:
         - rust: nightly
-    nightly-2019-06-18:
-        - script: cargo clippy
+    include:
+      - rust: nightly-2019-06-18
+        before_script:
+          - rustup component add clippy
+        script: cargo clippy
 before_script:
   - |
     pip install git+git://github.com/kbknapp/travis-cargo.git --user &&
@@ -29,7 +32,8 @@ before_script:
     fi
 script:
   - |
-    travis-cargo test -- --verbose --no-default-features &&
+    travis-cargo --skip nightly test -- --all --verbose --no-default-features &&
+    travis-cargo --only nightly test -- --verbose --no-default-features &&
     travis-cargo --skip nightly test -- --verbose --features "yaml unstable" &&
     travis-cargo --only nightly test -- --verbose --features "yaml unstable nightly" &&
     travis-cargo --only nightly bench
diff --git a/Cargo.toml b/Cargo.toml
index d0ea231e..ecfd51a6 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -57,7 +57,7 @@ yaml-rust = { version = "0.4",  optional = true }
 atty      = { version = "0.2.2",  optional = true }
 vec_map   = { version = "0.8", optional = true }
 term_size = { version = "1.0.0-beta1", optional = true }
-clap_derive = { git = "https://github.com/clap-rs/clap_derive", optional = true }
+clap_derive = { path = "./clap_derive", version = "3.0.0-beta.1", optional = true }
 
 [target.'cfg(not(windows))'.dependencies]
 ansi_term = { version = "0.12.1", optional = true }
@@ -106,3 +106,8 @@ codegen-units = 1
 
 [package.metadata.docs.rs]
 features = ["doc"]
+
+[workspace]
+members = [
+	"clap_derive",
+]
diff --git a/clap_derive/.clog.toml b/clap_derive/.clog.toml
new file mode 100644
index 00000000..b22f0d85
--- /dev/null
+++ b/clap_derive/.clog.toml
@@ -0,0 +1,13 @@
+[clog]
+repository = "https://github.com/kbknapp/clap_derive"
+outfile = "CHANGELOG.md"
+from-latest-tag = true
+
+[sections]
+Performance = ["perf"]
+Improvements = ["impr", "im", "imp"]
+Documentation = ["docs"]
+Deprecations = ["depr"]
+Examples = ["examples"]
+"New Settings" = ["setting", "settings"]
+"API Additions" = ["add", "api"]
diff --git a/clap_derive/Cargo.toml b/clap_derive/Cargo.toml
new file mode 100644
index 00000000..48f462a1
--- /dev/null
+++ b/clap_derive/Cargo.toml
@@ -0,0 +1,38 @@
+[package]
+name = "clap_derive"
+version = "3.0.0-beta.1"
+edition = "2018"
+authors = [
+    "Guillaume Pinot <texitoi@texitoi.eu>",
+    "Kevin K. <kbknapp@gmail.com>",
+    "hoverbear <andrew@hoverbear.org>"
+]
+description = "Parse command line argument by defining a struct, derive crate."
+documentation = "https://docs.rs/clap_derive"
+repository = "https://github.com/clap-rs/clap_derive"
+keywords = ["clap", "cli", "derive", "proc_macro", "parse"]
+categories = ["command-line-interface", "development-tools::procedural-macro-helpers"]
+license = "Apache-2.0/MIT"
+readme = "README.md"
+
+[lib]
+proc-macro = true
+
+[dependencies]
+syn = { version = "1", features = ["full"] }
+quote = "1"
+proc-macro2 = "1"
+heck = "0.3.0"
+proc-macro-error = "0.4.3"
+
+[dev-dependencies]
+clap = { path = "../", version = "3.0.0-beta.1" }
+trybuild = "1.0.5"
+rustversion = "0.1"
+
+[features]
+default = []
+nightly = []
+lints = []
+debug = []
+doc = []
diff --git a/clap_derive/README.md b/clap_derive/README.md
new file mode 100644
index 00000000..ff89f477
--- /dev/null
+++ b/clap_derive/README.md
@@ -0,0 +1,169 @@
+# Work in Progress
+
+This crate is currently a work in progress and not meant to be used. Please use [`structopt`](https://github.com/TeXitoi/structopt)
+while this crate is being built.
+
+# clap_derive[![Build status](https://travis-ci.org/clap-rs/clap_derive.svg?branch=master)](https://travis-ci.org/clap-rs/clap_derive) [![](https://img.shields.io/crates/v/clap_derive.svg)](https://crates.io/crates/clap_derive) [![](https://docs.rs/clap_derive/badge.svg)](https://docs.rs/clap_derive)
+
+Parse command line argument by defining a struct.  It combines [structopt](https://github.com/TeXitoi/structopt) and [clap](https://crates.io/crates/clap) into a single experience. This crate is used by clap, and not meant to be used directly by
+consumers.
+
+## Documentation
+
+Find it on [Docs.rs](https://docs.rs/clap_derive).  You can also check the [examples](https://github.com/clap-rs/clap_derive/tree/master/examples) and the [changelog](https://github.com/clap-rs/clap_derive/blob/master/CHANGELOG.md).
+
+## Example
+
+Add `clap` to your dependencies of your `Cargo.toml`:
+
+```toml
+[dependencies]
+clap = "3"
+```
+
+And then, in your rust file:
+```rust
+#[macro_use]
+extern crate clap;
+
+use std::path::PathBuf;
+use clap::Clap;
+
+/// A basic example
+#[derive(Clap, Debug)]
+#[clap(name = "basic")]
+struct Opt {
+    // A flag, true if used in the command line. Note doc comment will
+    // be used for the help message of the flag. The name of the
+    // argument will be, by default, based on the name of the field.
+    /// Activate debug mode
+    #[clap(short, long)]
+    debug: bool,
+
+    // The number of occurrences of the `v/verbose` flag
+    /// Verbose mode (-v, -vv, -vvv, etc.)
+    #[clap(short, long, parse(from_occurrences))]
+    verbose: u8,
+
+    /// Set speed
+    #[clap(short, long, default_value = "42")]
+    speed: f64,
+
+    /// Output file
+    #[clap(short, long, parse(from_os_str))]
+    output: PathBuf,
+
+    // the long option will be translated by default to kebab case,
+    // i.e. `--nb-cars`.
+    /// Number of cars
+    #[clap(short = "c", long)]
+    nb_cars: Option<i32>,
+
+    /// admin_level to consider
+    #[clap(short, long)]
+    level: Vec<String>,
+
+    /// Files to process
+    #[clap(name = "FILE", parse(from_os_str))]
+    files: Vec<PathBuf>,
+}
+
+fn main() {
+    let opt = Opt::parse();
+    println!("{:#?}", opt);
+}
+```
+
+Using this example:
+```
+$ ./basic
+error: The following required arguments were not provided:
+    --output <output>
+
+USAGE:
+    basic --output <output> --speed <speed>
+
+For more information try --help
+$ ./basic --help
+basic 0.3.0
+Guillaume Pinot <texitoi@texitoi.eu>, others
+A basic example
+
+USAGE:
+    basic [FLAGS] [OPTIONS] --output <output> [--] [file]...
+
+ARGS:
+    <FILE>...    Files to process
+
+FLAGS:
+    -d, --debug      Activate debug mode
+    -h, --help       Prints help information
+    -V, --version    Prints version information
+    -v, --verbose    Verbose mode (-v, -vv, -vvv, etc.)
+
+OPTIONS:
+    -l, --level <level>...     admin_level to consider
+    -c, --nb-cars <nb-cars>    Number of cars
+    -o, --output <output>      Output file
+    -s, --speed <speed>        Set speed [default: 42]
+
+ARGS:
+    <file>...    Files to process
+$ ./basic -o foo.txt
+Opt {
+    debug: false,
+    verbose: 0,
+    speed: 42.0,
+    output: "foo.txt",
+    nb_cars: None,
+    level: [],
+    files: [],
+}
+$ ./basic -o foo.txt -dvvvs 1337 -l alice -l bob --nb-cars 4 bar.txt baz.txt
+Opt {
+    debug: true,
+    verbose: 3,
+    speed: 1337.0,
+    output: "foo.txt",
+    nb_cars: Some(
+        4,
+    ),
+    level: [
+        "alice",
+        "bob",
+    ],
+    files: [
+        "bar.txt",
+        "baz.txt",
+    ],
+}
+```
+
+## clap_derive rustc version policy
+
+- Minimum rustc version modification must be specified in the [changelog](https://github.com/clap-rs/clap_derive/blob/master/CHANGELOG.md) and in the [travis configuration](https://github.com/clap-rs/clap_derive/blob/master/.travis.yml).
+- Contributors can increment minimum rustc version without any justification if the new version is required by the latest version of one of clap_derive's depedencies (`cargo update` will not fail on clap_derive).
+- Contributors can increment minimum rustc version if the library user experience is improved.
+
+## Why
+
+I've (@TeXitoi) used [docopt](https://crates.io/crates/docopt) for a long time (pre rust 1.0). I really like the fact that you have a structure with the parsed argument: no need to convert `String` to `f64`, no useless `unwrap`. But on the other hand, I don't like to write by hand the usage string. That's like going back to the golden age of WYSIWYG editors.  Field naming is also a bit artificial.
+
+Today, the new standard to read command line arguments in Rust is [clap](https://crates.io/crates/clap).  This library is so feature full! But I think there is one downside: even if you can validate argument and expressing that an argument is required, you still need to transform something looking like a hashmap of string vectors to something useful for your application.
+
+Now, there is stable custom derive. Thus I can add to clap the automatic conversion that I miss. Here is the result.
+
+## License
+
+Licensed under either of
+
+- Apache License, Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE) or <https://www.apache.org/licenses/LICENSE-2.0>)
+- MIT license ([LICENSE-MIT](LICENSE-MIT) or <https://opensource.org/licenses/MIT>)
+
+at your option.
+
+### Contribution
+
+Unless you explicitly state otherwise, any contribution intentionally submitted
+for inclusion in the work by you, as defined in the Apache-2.0 license, shall be
+dual licensed as above, without any additional terms or conditions.
diff --git a/clap_derive/examples/README.md b/clap_derive/examples/README.md
new file mode 100644
index 00000000..496cf9fb
--- /dev/null
+++ b/clap_derive/examples/README.md
@@ -0,0 +1,78 @@
+# Collection of examples "how to use `clap_derive`"
+
+### [Help on the bottom](after_help.rs)
+
+How to append a postscript to the help message generated.
+
+### [At least N](at_least_two.rs)
+
+How to require presence of at least N values, like `val1 val2 ... valN ... valM`.
+
+### [Basic](basic.rs)
+
+A basic example how to use `clap_derive`.
+
+### [Deny missing docs](deny_missing_docs.rs)
+
+**This is not an example but a test**, it should be moved to `tests` folder
+as soon as [this](https://github.com/rust-lang/rust/issues/24584) is fixed (if ever).
+
+### [Doc comments](doc_comments.rs)
+
+How to use doc comments in place of `help/long_help`.
+
+### [Enums as arguments](enum_in_args.rs)
+
+How to use `arg_enum!` with `clap_derive`.
+
+### [Arguments of subcommands in separate `struct`](enum_tuple.rs)
+
+How to extract subcommands' args into external structs.
+
+### [Environment variables](env.rs)
+
+How to use environment variable fallback an how it interacts with `default_value`.
+
+### [Advanced](example.rs)
+
+Somewhat complex example of usage of `clap_derive`.
+
+### [Flatten](flatten.rs)
+
+How to use `#[clap(flatten)]`
+
+### [Git](git.rs)
+
+Pseudo-`git` example, shows how to use subcommands and how to document them.
+
+### [Groups](group.rs)
+
+Using `clap::Arg::group` with `clap`.
+
+### [`key=value` pairs](keyvalue.rs)
+
+How to parse `key=value` pairs.
+
+### [`--no-*` flags](negative_flag.rs)
+
+How to add `no-thing` flag which is `true` by default and `false` if passed.
+
+### [No version](no_version.rs)
+
+How to completely remove version.
+
+### [Rename all](rename_all.rs)
+
+How `#[clap(rename_all)]` works.
+
+### [Skip](skip.rs)
+
+How to use `#[clap(skip)]`.
+
+### [Aliases](subcommand_aliases.rs)
+
+How to use aliases
+
+### [`true` or `false`](true_or_false.rs)
+
+How to express "`"true"` or `"false"` argument.
diff --git a/clap_derive/examples/after_help.rs b/clap_derive/examples/after_help.rs
new file mode 100644
index 00000000..38c0bef3
--- /dev/null
+++ b/clap_derive/examples/after_help.rs
@@ -0,0 +1,19 @@
+//! How to append a postscript to the help message generated.
+
+use clap::Clap;
+
+/// I am a program and I do things.
+///
+/// Sometimes they even work.
+#[derive(Clap, Debug)]
+#[clap(after_help = "Beware `-d`, dragons be here")]
+struct Opt {
+    /// Release the dragon.
+    #[clap(short)]
+    dragon: bool,
+}
+
+fn main() {
+    let opt = Opt::parse();
+    println!("{:?}", opt);
+}
diff --git a/clap_derive/examples/arg_enum_basic.rs b/clap_derive/examples/arg_enum_basic.rs
new file mode 100644
index 00000000..d691ca39
--- /dev/null
+++ b/clap_derive/examples/arg_enum_basic.rs
@@ -0,0 +1,28 @@
+// #[macro_use]
+// extern crate clap;
+
+// use clap::{App, Arg};
+
+fn main() {}
+
+// #[derive(ArgEnum, Debug)]
+// enum ArgChoice {
+//     Foo,
+//     Bar,
+//     Baz,
+// }
+
+// fn main() {
+//     let matches = App::new(env!("CARGO_PKG_NAME"))
+//         .arg(
+//             Arg::with_name("arg")
+//                 .required(true)
+//                 .takes_value(true)
+//                 .possible_values(&ArgChoice::variants()),
+//         )
+//         .get_matches();
+
+//     let t = value_t!(matches.value_of("arg"), ArgChoice).unwrap_or_else(|e| e.exit());
+
+//     println!("{:?}", t);
+// }
diff --git a/clap_derive/examples/arg_enum_case_sensitive.rs b/clap_derive/examples/arg_enum_case_sensitive.rs
new file mode 100644
index 00000000..2e3e2f5d
--- /dev/null
+++ b/clap_derive/examples/arg_enum_case_sensitive.rs
@@ -0,0 +1,28 @@
+fn main() {}
+// #[macro_use]
+// extern crate clap;
+
+// use clap::{App, Arg};
+
+// #[derive(ArgEnum, Debug)]
+// #[case_sensitive]
+// enum ArgChoice {
+//     Foo,
+//     Bar,
+//     Baz,
+// }
+
+// fn main() {
+//     let matches = App::new(env!("CARGO_PKG_NAME"))
+//         .arg(
+//             Arg::with_name("arg")
+//                 .required(true)
+//                 .takes_value(true)
+//                 .possible_values(&ArgChoice::variants()),
+//         )
+//         .get_matches();
+
+//     let t = value_t!(matches.value_of("arg"), ArgChoice).unwrap_or_else(|e| e.exit());
+
+//     println!("{:?}", t);
+// }
diff --git a/clap_derive/examples/at_least_two.rs b/clap_derive/examples/at_least_two.rs
new file mode 100644
index 00000000..12c6f24a
--- /dev/null
+++ b/clap_derive/examples/at_least_two.rs
@@ -0,0 +1,15 @@
+//! How to require presence of at least N values,
+//! like `val1 val2 ... valN ... valM`.
+
+use clap::Clap;
+
+#[derive(Clap, Debug)]
+struct Opt {
+    #[clap(required = true, min_values = 2)]
+    foos: Vec<String>,
+}
+
+fn main() {
+    let opt = Opt::parse();
+    println!("{:?}", opt);
+}
diff --git a/clap_derive/examples/basic.rs b/clap_derive/examples/basic.rs
new file mode 100644
index 00000000..d8df8ebe
--- /dev/null
+++ b/clap_derive/examples/basic.rs
@@ -0,0 +1,48 @@
+//! A somewhat comprehensive example of a typical `StructOpt` usage.use
+
+use clap::Clap;
+use std::path::PathBuf;
+
+/// A basic example
+#[derive(Clap, Debug)]
+#[clap(name = "basic")]
+struct Opt {
+    // A flag, true if used in the command line. Note doc comment will
+    // be used for the help message of the flag. The name of the
+    // argument will be, by default, based on the name of the field.
+    /// Activate debug mode
+    #[clap(short, long)]
+    debug: bool,
+
+    // The number of occurrences of the `v/verbose` flag
+    /// Verbose mode (-v, -vv, -vvv, etc.)
+    #[clap(short, long, parse(from_occurrences))]
+    verbose: u8,
+
+    /// Set speed
+    #[clap(short, long, default_value = "42")]
+    speed: f64,
+
+    /// Output file
+    #[clap(short, long, parse(from_os_str))]
+    output: PathBuf,
+
+    // the long option will be translated by default to kebab case,
+    // i.e. `--nb-cars`.
+    /// Number of cars
+    #[clap(short = "c", long)]
+    nb_cars: Option<i32>,
+
+    /// admin_level to consider
+    #[clap(short, long)]
+    level: Vec<String>,
+
+    /// Files to process
+    #[clap(name = "FILE", parse(from_os_str))]
+    files: Vec<PathBuf>,
+}
+
+fn main() {
+    let opt = Opt::parse();
+    println!("{:#?}", opt);
+}
diff --git a/clap_derive/examples/deny_missing_docs.rs b/clap_derive/examples/deny_missing_docs.rs
new file mode 100644
index 00000000..a4f5a204
--- /dev/null
+++ b/clap_derive/examples/deny_missing_docs.rs
@@ -0,0 +1,54 @@
+// Copyright 2018 Guillaume Pinot (@TeXitoi) <texitoi@texitoi.eu>,
+// Kevin Knapp (@kbknapp) <kbknapp@gmail.com>, and
+// Andrew Hobden (@hoverbear) <andrew@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.
+
+//! A test to check that clap_derive compiles with deny(missing_docs)
+
+#![deny(missing_docs)]
+
+use clap::Clap;
+
+/// The options
+#[derive(Clap, Debug, PartialEq)]
+pub struct Opt {
+    #[clap(short)]
+    verbose: bool,
+    #[clap(subcommand)]
+    cmd: Option<Cmd>,
+}
+
+/// Some subcommands
+#[derive(Clap, Debug, PartialEq)]
+pub enum Cmd {
+    /// command A
+    A,
+    /// command B
+    B {
+        /// Alice?
+        #[clap(short)]
+        alice: bool,
+    },
+    /// command C
+    C(COpt),
+}
+
+/// The options for C
+#[derive(Clap, Debug, PartialEq)]
+pub struct COpt {
+    #[clap(short)]
+    bob: bool,
+}
+
+fn main() {
+    println!("{:?}", Opt::parse());
+}
diff --git a/clap_derive/examples/doc_comments.rs b/clap_derive/examples/doc_comments.rs
new file mode 100644
index 00000000..a39c5953
--- /dev/null
+++ b/clap_derive/examples/doc_comments.rs
@@ -0,0 +1,74 @@
+//! How to use doc comments in place of `help/long_help`.
+
+use clap::Clap;
+
+/// A basic example for the usage of doc comments as replacement
+/// of the arguments `help`, `long_help`, `about` and `long_about`.
+#[derive(Clap, Debug)]
+#[clap(name = "basic")]
+struct Opt {
+    /// Just use doc comments to replace `help`, `long_help`,
+    /// `about` or `long_about` input.
+    #[clap(short, long)]
+    first_flag: bool,
+
+    /// Split between `help` and `long_help`.
+    ///
+    /// In the previous case clap is going to present
+    /// the whole comment both as text for the `help` and the
+    /// `long_help` argument.
+    ///
+    /// But if the doc comment is formatted like this example
+    /// -- with an empty second line splitting the heading and
+    /// the rest of the comment -- only the first line is used
+    /// as `help` argument. The `long_help` argument will still
+    /// contain the whole comment.
+    ///
+    /// ## Attention
+    ///
+    /// Any formatting next to empty lines that could be used
+    /// inside a doc comment is currently not preserved. If
+    /// lists or other well formatted content is required it is
+    /// necessary to use the related clap argument with a
+    /// raw string as shown on the `third_flag` description.
+    #[clap(short, long)]
+    second_flag: bool,
+
+    #[clap(
+        short,
+        long,
+        long_help = r"This is a raw string.
+
+It can be used to pass well formatted content (e.g. lists or source
+code) in the description:
+
+ - first example list entry
+ - second example list entry
+ "
+    )]
+    third_flag: bool,
+
+    #[clap(subcommand)]
+    sub_command: SubCommand,
+}
+
+#[derive(Clap, Debug)]
+#[clap()]
+enum SubCommand {
+    /// The same rules described previously for flags. Are
+    /// also true for in regards of sub-commands.
+    First,
+
+    /// Applicable for both `about` an `help`.
+    ///
+    /// The formatting rules described in the comment of the
+    /// `second_flag` also apply to the description of
+    /// sub-commands which is normally given through the `about`
+    /// and `long_about` arguments.
+    Second,
+}
+
+fn main() {
+    let opt = Opt::parse();
+    println!("{:?}", opt);
+}
diff --git a/clap_derive/examples/enum_in_args.rs b/clap_derive/examples/enum_in_args.rs
new file mode 100644
index 00000000..98d581f4
--- /dev/null
+++ b/clap_derive/examples/enum_in_args.rs
@@ -0,0 +1,25 @@
+//! How to use `arg_enum!` with `StructOpt`.
+// TODO: make it work
+fn main() {}
+// use clap::Clap;
+
+// arg_enum! {
+//     #[derive(Debug)]
+//     enum Baz {
+//         Foo,
+//         Bar,
+//         FooBar
+//     }
+// }
+
+// #[derive(Clap, Debug)]
+// struct Opt {
+//     /// Important argument.
+//     #[clap(possible_values = &Baz::variants(), case_insensitive = true)]
+//     i: Baz,
+// }
+
+// fn main() {
+//     let opt = Opt::parse();
+//     println!("{:?}", opt);
+// }
diff --git a/clap_derive/examples/enum_tuple.rs b/clap_derive/examples/enum_tuple.rs
new file mode 100644
index 00000000..6f5db2fb
--- /dev/null
+++ b/clap_derive/examples/enum_tuple.rs
@@ -0,0 +1,26 @@
+//! How to extract subcommands' args into external structs.
+
+use clap::Clap;
+
+#[derive(Debug, Clap)]
+pub struct Foo {
+    pub bar: Option<String>,
+}
+
+#[derive(Debug, Clap)]
+pub enum Command {
+    #[clap(name = "foo")]
+    Foo(Foo),
+}
+
+#[derive(Debug, Clap)]
+#[clap(name = "classify")]
+pub struct ApplicationArguments {
+    #[clap(subcommand)]
+    pub command: Command,
+}
+
+fn main() {
+    let opt = ApplicationArguments::parse();
+    println!("{:?}", opt);
+}
diff --git a/clap_derive/examples/env.rs b/clap_derive/examples/env.rs
new file mode 100644
index 00000000..38ba425e
--- /dev/null
+++ b/clap_derive/examples/env.rs
@@ -0,0 +1,26 @@
+//! How to use environment variable fallback an how it
+//! interacts with `default_value`.
+
+use clap::Clap;
+
+/// Example for allowing to specify options via environment variables.
+#[derive(Clap, Debug)]
+#[clap(name = "env")]
+struct Opt {
+    // Use `env` to enable specifying the option with an environment
+    // variable. Command line arguments take precedence over env.
+    /// URL for the API server
+    #[clap(long, env = "API_URL")]
+    api_url: String,
+
+    // The default value is used if neither argument nor environment
+    // variable is specified.
+    /// Number of retries
+    #[clap(long, env = "RETRIES", default_value = "5")]
+    retries: u32,
+}
+
+fn main() {
+    let opt = Opt::parse();
+    println!("{:#?}", opt);
+}
diff --git a/clap_derive/examples/example.rs b/clap_derive/examples/example.rs
new file mode 100644
index 00000000..3b2e0142
--- /dev/null
+++ b/clap_derive/examples/example.rs
@@ -0,0 +1,54 @@
+//! Somewhat complex example of usage of structopt.
+
+use clap::Clap;
+
+#[derive(Clap, Debug)]
+#[clap(name = "example")]
+/// An example of clap_derive usage.
+struct Opt {
+    // A flag, true if used in the command line.
+    #[clap(short, long)]
+    /// Activate debug mode
+    debug: bool,
+
+    // An argument of type float, with a default value.
+    #[clap(short, long, default_value = "42")]
+    /// Set speed
+    speed: f64,
+
+    // Needed parameter, the first on the command line.
+    /// Input file
+    input: String,
+
+    // An optional parameter, will be `None` if not present on the
+    // command line.
+    /// Output file, stdout if not present
+    output: Option<String>,
+
+    // An optional parameter with optional value, will be `None` if
+    // not present on the command line, will be `Some(None)` if no
+    // argument is provided (i.e. `--log`) and will be
+    // `Some(Some(String))` if argument is provided (e.g. `--log
+    // log.txt`).
+    #[clap(long)]
+    #[allow(clippy::option_option)]
+    /// Log file, stdout if no file, no logging if not present
+    log: Option<Option<String>>,
+
+    // An optional list of values, will be `None` if not present on
+    // the command line, will be `Some(vec![])` if no argument is
+    // provided (i.e. `--optv`) and will be `Some(Some(String))` if
+    // argument list is provided (e.g. `--optv a b c`).
+    #[clap(long)]
+    optv: Option<Vec<String>>,
+
+    // Skipped option: it won't be parsed and will be filled with the
+    // default value for its type (in this case it'll be an empty string).
+    #[clap(skip)]
+    skipped: String,
+}
+
+fn main() {
+    let opt = Opt::parse();
+    println!("{:?}", opt);
+}
diff --git a/clap_derive/examples/flatten.rs b/clap_derive/examples/flatten.rs
new file mode 100644
index 00000000..5a6cfc35
--- /dev/null
+++ b/clap_derive/examples/flatten.rs
@@ -0,0 +1,29 @@
+//! How to use flattening.
+
+use clap::Clap;
+
+#[derive(Clap, Debug)]
+struct Cmdline {
+    /// switch verbosity on
+    #[clap(short)]
+    verbose: bool,
+
+    #[clap(flatten)]
+    daemon_opts: DaemonOpts,
+}
+
+#[derive(Clap, Debug)]
+struct DaemonOpts {
+    /// daemon user
+    #[clap(short)]
+    user: String,
+
+    /// daemon group
+    #[clap(short)]
+    group: String,
+}
+
+fn main() {
+    let opt = Cmdline::parse();
+    println!("{:?}", opt);
+}
diff --git a/clap_derive/examples/git.rs b/clap_derive/examples/git.rs
new file mode 100644
index 00000000..3889a428
--- /dev/null
+++ b/clap_derive/examples/git.rs
@@ -0,0 +1,35 @@
+//! `git.rs` serves as a demonstration of how to use subcommands,
+//! as well as a demonstration of adding documentation to subcommands.
+//! Documentation can be added either through doc comments or
+//! `help`/`about` attributes.
+
+use clap::Clap;
+
+#[derive(Clap, Debug)]
+#[clap(name = "git")]
+/// the stupid content tracker
+enum Opt {
+    /// fetch branches from remote repository
+    Fetch {
+        #[clap(long)]
+        dry_run: bool,
+        #[clap(long)]
+        all: bool,
+        #[clap(default_value = "origin")]
+        repository: String,
+    },
+    #[clap(override_help = "add files to the staging area")]
+    Add {
+        #[clap(short)]
+        interactive: bool,
+        #[clap(short)]
+        all: bool,
+        files: Vec<String>,
+    },
+}
+
+fn main() {
+    let matches = Opt::parse();
+
+    println!("{:?}", matches);
+}
diff --git a/clap_derive/examples/group.rs b/clap_derive/examples/group.rs
new file mode 100644
index 00000000..6ed40b40
--- /dev/null
+++ b/clap_derive/examples/group.rs
@@ -0,0 +1,31 @@
+//! How to use `clap::Arg::group`
+
+use clap::{ArgGroup, Clap};
+
+#[derive(Clap, Debug)]
+#[clap(group = ArgGroup::with_name("verb").required(true))]
+struct Opt {
+    /// Set a custom HTTP verb
+    #[clap(long, group = "verb")]
+    method: Option<String>,
+    /// HTTP GET
+    #[clap(long, group = "verb")]
+    get: bool,
+    /// HTTP HEAD
+    #[clap(long, group = "verb")]
+    head: bool,
+    /// HTTP POST
+    #[clap(long, group = "verb")]
+    post: bool,
+    /// HTTP PUT
+    #[clap(long, group = "verb")]
+    put: bool,
+    /// HTTP DELETE
+    #[clap(long, group = "verb")]
+    delete: bool,
+}
+
+fn main() {
+    let opt = Opt::parse();
+    println!("{:?}", opt);
+}
diff --git a/clap_derive/examples/keyvalue.rs b/clap_derive/examples/keyvalue.rs
new file mode 100644
index 00000000..5238a701
--- /dev/null
+++ b/clap_derive/examples/keyvalue.rs
@@ -0,0 +1,36 @@
+//! How to parse "key=value" pairs with structopt.
+
+use clap::Clap;
+use std::error::Error;
+
+/// Parse a single key-value pair
+fn parse_key_val<T, U>(s: &str) -> Result<(T, U), Box<dyn Error>>
+where
+    T: std::str::FromStr,
+    T::Err: Error + 'static,
+    U: std::str::FromStr,
+    U::Err: Error + 'static,
+{
+    let pos = s
+        .find('=')
+        .ok_or_else(|| format!("invalid KEY=value: no `=` found in `{}`", s))?;
+    Ok((s[..pos].parse()?, s[pos + 1..].parse()?))
+}
+
+#[derive(Clap, Debug)]
+struct Opt {
+    // number_of_values = 1 forces the user to repeat the -D option for each key-value pair:
+    // my_program -D a=1 -D b=2
+    // Without number_of_values = 1 you can do:
+    // my_program -D a=1 b=2
+    // but this makes adding an argument after the values impossible:
+    // my_program -D a=1 -D b=2 my_input_file
+    // becomes invalid.
+    #[clap(short = "D", parse(try_from_str = parse_key_val), number_of_values = 1)]
+    defines: Vec<(String, i32)>,
+}
+
+fn main() {
+    let opt = Opt::parse();
+    println!("{:?}", opt);
+}
diff --git a/clap_derive/examples/negative_flag.rs b/clap_derive/examples/negative_flag.rs
new file mode 100644
index 00000000..27a1f07f
--- /dev/null
+++ b/clap_derive/examples/negative_flag.rs
@@ -0,0 +1,15 @@
+//! How to add `no-thing` flag which is `true` by default and
+//! `false` if passed.
+
+use clap::Clap;
+
+#[derive(Debug, Clap)]
+struct Opt {
+    #[clap(long = "no-verbose", parse(from_flag = std::ops::Not::not))]
+    verbose: bool,
+}
+
+fn main() {
+    let cmd = Opt::parse();
+    println!("{:#?}", cmd);
+}
diff --git a/clap_derive/examples/no_version.rs b/clap_derive/examples/no_version.rs
new file mode 100644
index 00000000..0b530813
--- /dev/null
+++ b/clap_derive/examples/no_version.rs
@@ -0,0 +1,16 @@
+//! How to completely remove version.
+
+use clap::{AppSettings, Clap};
+
+#[derive(Clap, Debug)]
+#[clap(
+    name = "no_version",
+    no_version,
+    global_setting = AppSettings::DisableVersion
+)]
+struct Opt {}
+
+fn main() {
+    let opt = Opt::parse();
+    println!("{:?}", opt);
+}
diff --git a/clap_derive/examples/rename_all.rs b/clap_derive/examples/rename_all.rs
new file mode 100644
index 00000000..c3dc2367
--- /dev/null
+++ b/clap_derive/examples/rename_all.rs
@@ -0,0 +1,74 @@
+//! Example on how the `rename_all` parameter works.
+//!
+//! `rename_all` can be used to override the casing style used during argument
+//! generation. By default the `kebab-case` style will be used but there are a wide
+//! variety of other styles available.
+//!
+//! ## Supported styles overview:
+//!
+//! - **Camel Case**: Indicate word boundaries with uppercase letter, excluding
+//!                   the first word.
+//! - **Kebab Case**: Keep all letters lowercase and indicate word boundaries
+//!                   with hyphens.
+//! - **Pascal Case**: Indicate word boundaries with uppercase letter,
+//!                    including the first word.
+//! - **Screaming Snake Case**: Keep all letters uppercase and indicate word
+//!                             boundaries with underscores.
+//! - **Snake Case**: Keep all letters lowercase and indicate word boundaries
+//!                   with underscores.
+//! - **Verbatim**: Use the original attribute name defined in the code.
+
+use clap::Clap;
+
+#[derive(Clap, Debug)]
+#[clap(name = "rename_all", rename_all = "screaming_snake_case")]
+enum Opt {
+    // This subcommand will be named `FIRST_COMMAND`. As the command doesn't
+    // override the initial casing style, ...
+    /// A screaming loud first command. Only use if necessary.
+    FirstCommand {
+        // this flag will be available as `--FOO` and `-F`.
+        /// This flag will even scream louder.
+        #[clap(long, short)]
+        foo: bool,
+    },
+
+    // As we override the casing style for this variant the related subcommand
+    // will be named `SecondCommand`.
+    /// Not nearly as loud as the first command.
+    #[clap(rename_all = "pascal_case")]
+    SecondCommand {
+        // We can also override it again on a single field.
+        /// Nice quiet flag. No one is annoyed.
+        #[clap(rename_all = "snake_case", long)]
+        bar_option: bool,
+
+        // Renaming will not be propagated into subcommand flagged enums. If
+        // a non default casing style is required it must be defined on the
+        // enum itself.
+        #[clap(subcommand)]
+        cmds: Subcommands,
+
+        // or flattened structs.
+        #[clap(flatten)]
+        options: BonusOptions,
+    },
+}
+
+#[derive(Clap, Debug)]
+enum Subcommands {
+    // This one will be available as `first-subcommand`.
+    FirstSubcommand,
+}
+
+#[derive(Clap, Debug)]
+struct BonusOptions {
+    // And this one will be available as `baz-option`.
+    #[clap(long)]
+    baz_option: bool,
+}
+
+fn main() {
+    let opt = Opt::parse();
+    println!("{:?}", opt);
+}
diff --git a/clap_derive/examples/skip.rs b/clap_derive/examples/skip.rs
new file mode 100644
index 00000000..6c79cf05
--- /dev/null
+++ b/clap_derive/examples/skip.rs
@@ -0,0 +1,47 @@
+//! How to use `#[structopt(skip)]`
+
+use clap::Clap;
+
+#[derive(Clap, Debug, PartialEq)]
+pub struct Opt {
+    #[clap(long, short)]
+    number: u32,
+    #[clap(skip)]
+    k: Kind,
+    #[clap(skip)]
+    v: Vec<u32>,
+
+    #[clap(skip = Kind::A)]
+    k2: Kind,
+    #[clap(skip = vec![1, 2, 3])]
+    v2: Vec<u32>,
+    #[clap(skip = "cake")] // &str implements Into<String>
+    s: String,
+}
+
+#[derive(Debug, PartialEq)]
+enum Kind {
+    A,
+    B,
+}
+
+impl Default for Kind {
+    fn default() -> Self {
+        return Kind::B;
+    }
+}
+
+fn main() {
+    assert_eq!(
+        Opt::parse_from(&["test", "-n", "10"]),
+        Opt {
+            number: 10,
+            k: Kind::B,
+            v: vec![],
+
+            k2: Kind::A,
+            v2: vec![1, 2, 3],
+            s: String::from("cake")
+        }
+    );
+}
diff --git a/clap_derive/examples/subcommand_aliases.rs b/clap_derive/examples/subcommand_aliases.rs
new file mode 100644
index 00000000..1cb717c4
--- /dev/null
+++ b/clap_derive/examples/subcommand_aliases.rs
@@ -0,0 +1,20 @@
+//! How to assign some aliases to subcommands
+
+use clap::{AppSettings, Clap};
+
+#[derive(Clap, Debug)]
+// https://docs.rs/clap/2/clap/enum.AppSettings.html#variant.InferSubcommands
+#[clap(setting = AppSettings::InferSubcommands)]
+enum Opt {
+    // https://docs.rs/clap/2/clap/struct.App.html#method.alias
+    #[clap(alias = "foobar")]
+    Foo,
+    // https://docs.rs/clap/2/clap/struct.App.html#method.aliases
+    #[clap(aliases = &["baz", "fizz"])]
+    Bar,
+}
+
+fn main() {
+    let opt = Opt::parse();
+    println!("{:?}", opt);
+}
diff --git a/clap_derive/examples/true_or_false.rs b/clap_derive/examples/true_or_false.rs
new file mode 100644
index 00000000..85e29ba6
--- /dev/null
+++ b/clap_derive/examples/true_or_false.rs
@@ -0,0 +1,41 @@
+//! How to parse `--foo=true --bar=false` and turn them into bool.
+
+use clap::Clap;
+
+fn true_or_false(s: &str) -> Result<bool, &'static str> {
+    match s {
+        "true" => Ok(true),
+        "false" => Ok(false),
+        _ => Err("expected `true` or `false`"),
+    }
+}
+
+#[derive(Clap, Debug, PartialEq)]
+struct Opt {
+    // Default parser for `try_from_str` is FromStr::from_str.
+    // `impl FromStr for bool` parses `true` or `false` so this
+    // works as expected.
+    #[clap(long, parse(try_from_str))]
+    foo: bool,
+
+    // Of course, this could be done with an explicit parser function.
+    #[clap(long, parse(try_from_str = true_or_false))]
+    bar: bool,
+
+    // `bool` can be positional only with explicit `parse(...)` annotation
+    #[clap(long, parse(try_from_str))]
+    boom: bool,
+}
+
+fn main() {
+    assert_eq!(
+        Opt::parse_from(&["test", "--foo=true", "--bar=false", "true"]),
+        Opt {
+            foo: true,
+            bar: false,
+            boom: true
+        }
+    );
+    // no beauty, only truth and falseness
+    assert!(Opt::try_parse_from(&["test", "--foo=beauty"]).is_err());
+}
diff --git a/clap_derive/rustfmt.toml b/clap_derive/rustfmt.toml
new file mode 100644
index 00000000..0d83eda4
--- /dev/null
+++ b/clap_derive/rustfmt.toml
@@ -0,0 +1,2 @@
+format_strings = false
+fn_single_line = true
diff --git a/clap_derive/src/derives/arg_enum.rs b/clap_derive/src/derives/arg_enum.rs
new file mode 100644
index 00000000..faf94e08
--- /dev/null
+++ b/clap_derive/src/derives/arg_enum.rs
@@ -0,0 +1,94 @@
+// Copyright 2018 Guillaume Pinot (@TeXitoi) <texitoi@texitoi.eu>,
+// Kevin Knapp (@kbknapp) <kbknapp@gmail.com>, and
+// Andrew Hobden (@hoverbear) <andrew@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.
+use proc_macro2;
+// use quote;
+use syn;
+// use syn::punctuated;
+// use syn::token;
+
+pub fn derive_arg_enum(_ast: &syn::DeriveInput) -> proc_macro2::TokenStream {
+    unimplemented!()
+
+    // let from_str_block = impl_from_str(ast)?;
+    // let variants_block = impl_variants(ast)?;
+
+    // quote! {
+    //     #from_str_block
+    //     #variants_block
+    // }
+}
+
+/*
+fn impl_from_str(ast: &syn::DeriveInput) -> proc_macro2::TokenStream {
+    let ident = &ast.ident;
+    let is_case_sensitive = ast.attrs.iter().any(|v| v.name() == "case_sensitive");
+    let variants = variants(ast)?;
+
+    let strings = variants
+        .iter()
+        .map(|ref variant| String::from(variant.ident.as_ref()))
+        .collect::<Vec<_>>();
+
+    // All of these need to be iterators.
+    let ident_slice = [ident.clone()];
+    let idents = ident_slice.iter().cycle();
+
+    let for_error_message = strings.clone();
+
+    let condition_function_slice = [match is_case_sensitive {
+        true => quote! { str::eq },
+        false => quote! { ::std::ascii::AsciiExt::eq_ignore_ascii_case },
+    }];
+    let condition_function = condition_function_slice.iter().cycle();
+
+    Ok(quote! {
+        impl ::std::str::FromStr for #ident {
+            type Err = String;
+
+            fn from_str(input: &str) -> ::std::result::Result<Self, Self::Err> {
+                match input {
+                    #(val if #condition_function(val, #strings) => Ok(#idents::#variants),)*
+                    _ => Err({
+                        let v = #for_error_message;
+                        format!("valid values: {}",
+                            v.join(" ,"))
+                    }),
+                }
+            }
+        }
+    })
+}
+
+fn impl_variants(ast: &syn::DeriveInput) -> proc_macro2::TokenStream {
+    let ident = &ast.ident;
+    let variants = variants(ast)?
+        .iter()
+        .map(|ref variant| String::from(variant.ident.as_ref()))
+        .collect::<Vec<_>>();
+    let length = variants.len();
+
+    Ok(quote! {
+        impl #ident {
+            fn variants() -> [&'static str; #length] {
+                #variants
+            }
+        }
+    })
+}
+
+fn variants(ast: &syn::DeriveInput) -> &punctuated::Punctuated<syn::Variant, token::Comma> {
+    use syn::Data::*;
+
+    match ast.data {
+        Enum(ref data) => data.variants,
+        _ => panic!("Only enums are supported for deriving the ArgEnum trait"),
+    }
+}
+*/
diff --git a/clap_derive/src/derives/attrs.rs b/clap_derive/src/derives/attrs.rs
new file mode 100644
index 00000000..f62ead59
--- /dev/null
+++ b/clap_derive/src/derives/attrs.rs
@@ -0,0 +1,663 @@
+// Copyright 2018 Guillaume Pinot (@TeXitoi) <texitoi@texitoi.eu>,
+// Kevin Knapp (@kbknapp) <kbknapp@gmail.com>, and
+// Andrew Hobden (@hoverbear) <andrew@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 super::{parse::*, spanned::Sp, ty::Ty};
+
+use std::env;
+
+use heck::{CamelCase, KebabCase, MixedCase, ShoutySnakeCase, SnakeCase};
+use proc_macro2::{self, Span};
+use proc_macro_error::abort;
+use quote::{quote, quote_spanned, ToTokens};
+use syn::{self, ext::IdentExt, spanned::Spanned, LitStr};
+
+/// Default casing style for generated arguments.
+pub const DEFAULT_CASING: CasingStyle = CasingStyle::Kebab;
+
+#[derive(Clone)]
+pub enum Kind {
+    Arg(Sp<Ty>),
+    Subcommand(Sp<Ty>),
+    FlattenStruct,
+    Skip(Option<syn::Expr>),
+}
+
+#[derive(Clone)]
+pub struct Method {
+    name: syn::Ident,
+    args: proc_macro2::TokenStream,
+}
+
+#[derive(Clone)]
+pub struct Parser {
+    pub kind: Sp<ParserKind>,
+    pub func: proc_macro2::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(syn::Ident),
+    Assigned(syn::LitStr),
+}
+
+#[derive(Clone)]
+pub struct Attrs {
+    name: Name,
+    casing: Sp<CasingStyle>,
+    methods: Vec<Method>,
+    parser: Sp<Parser>,
+    author: Option<Method>,
+    about: Option<Method>,
+    version: Option<Method>,
+    no_version: Option<syn::Ident>,
+    has_custom_parser: bool,
+    kind: Sp<Kind>,
+}
+
+/// 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.
+pub struct GenOutput {
+    pub tokens: proc_macro2::TokenStream,
+    pub attrs: Attrs,
+}
+
+impl Method {
+    fn new(name: syn::Ident, args: proc_macro2::TokenStream) -> Self {
+        Method { name, args }
+    }
+
+    fn from_lit_or_env(ident: syn::Ident, lit: Option<syn::LitStr>, env_var: &str) -> Option<Self> {
+        let mut lit = match lit {
+            Some(lit) => lit,
+
+            None => match env::var(env_var) {
+                Ok(val) => syn::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 = syn::LitStr::new(&edited, lit.span());
+        }
+
+        Some(Method::new(ident, quote!(#lit)))
+    }
+}
+
+impl ToTokens for Method {
+    fn to_tokens(&self, ts: &mut proc_macro2::TokenStream) {
+        let Method { ref name, ref args } = self;
+
+        let tokens = if name == "short" {
+            quote!( .#name(#args.chars().nth(0).unwrap()) )
+        } else {
+            quote!( .#name(#args) )
+        };
+
+        tokens.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: syn::Ident, spec: ParserSpec) -> Sp<Self> {
+        use self::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: syn::LitStr) -> Sp<Self> {
+        use self::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 self::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,
+                };
+                syn::LitStr::new(&s, ident.span())
+            }
+        }
+    }
+}
+
+impl Attrs {
+    fn new(default_span: Span, name: Name, casing: Sp<CasingStyle>) -> Self {
+        Self {
+            name,
+            casing,
+            methods: vec![],
+            parser: Parser::default_spanned(default_span),
+            about: None,
+            author: None,
+            version: None,
+            no_version: 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>) {
+        match (&**name, &**arg) {
+            ("name", _) => {
+                self.name = Name::Assigned(arg.as_lit());
+            }
+            _ => self
+                .methods
+                .push(Method::new(name.as_ident(), quote!(#arg))),
+        }
+    }
+
+    fn push_attrs(&mut self, attrs: &[syn::Attribute]) {
+        use ClapAttr::*;
+
+        for attr in parse_clap_attributes(attrs) {
+            match attr {
+                Short(ident) | Long(ident) => {
+                    self.push_str_method(
+                        ident.into(),
+                        self.name.clone().translate(*self.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),
+
+                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);
+                }
+
+                Parse(ident, spec) => {
+                    self.has_custom_parser = true;
+                    self.parser = Parser::from_spec(ident, spec);
+                }
+            }
+        }
+    }
+
+    fn push_doc_comment(&mut self, attrs: &[syn::Attribute], name: &str) {
+        let doc_comments = attrs
+            .iter()
+            .filter_map(|attr| {
+                if attr.path.is_ident("doc") {
+                    attr.parse_meta().ok()
+                } else {
+                    None
+                }
+            })
+            .filter_map(|attr| {
+                use syn::Lit::*;
+                use syn::Meta::*;
+                if let NameValue(syn::MetaNameValue {
+                    path, lit: Str(s), ..
+                }) = attr
+                {
+                    if !path.is_ident("doc") {
+                        return None;
+                    }
+                    let value = s.value();
+
+                    let text = value
+                        .trim_start_matches("//!")
+                        .trim_start_matches("///")
+                        .trim_start_matches("/*!")
+                        .trim_start_matches("/**")
+                        .trim_end_matches("*/")
+                        .trim();
+                    if text.is_empty() {
+                        Some("\n\n".to_string())
+                    } else {
+                        Some(text.to_string())
+                    }
+                } else {
+                    None
+                }
+            })
+            .collect::<Vec<_>>();
+        if doc_comments.is_empty() {
+            return;
+        }
+        let merged_lines = doc_comments
+            .join(" ")
+            .split('\n')
+            .map(str::trim)
+            .map(str::to_string)
+            .collect::<Vec<_>>()
+            .join("\n");
+
+        let expected_doc_comment_split = if let Some(content) = doc_comments.get(1) {
+            (doc_comments.len() > 2) && (content == &"\n\n")
+        } else {
+            false
+        };
+
+        if expected_doc_comment_split {
+            let long_name = Sp::call_site(format!("long_{}", name));
+
+            self.methods
+                .push(Method::new(long_name.as_ident(), quote!(#merged_lines)));
+
+            // Remove trailing whitespace and period from short help, as rustdoc
+            // best practice is to use complete sentences, but command-line help
+            // typically omits the trailing period.
+            let short_arg = doc_comments
+                .first()
+                .map(|s| s.trim())
+                .map_or("", |s| s.trim_end_matches('.'));
+
+            self.methods.push(Method::new(
+                syn::Ident::new(name, Span::call_site()),
+                quote!(#short_arg),
+            ));
+        } else {
+            self.methods.push(Method::new(
+                syn::Ident::new(name, Span::call_site()),
+                quote!(#merged_lines),
+            ));
+        }
+    }
+
+    pub fn from_struct(
+        span: Span,
+        attrs: &[syn::Attribute],
+        name: Name,
+        argument_casing: Sp<CasingStyle>,
+    ) -> Self {
+        let mut res = Self::new(span, name, argument_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>) -> Self {
+        let name = field.ident.clone().unwrap();
+        let mut res = Self::new(field.span(), Name::Derived(name.clone()), struct_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/clap-rs/clap_derive/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) -> proc_macro2::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;
+
+        quote!( #author #version #(#methods)* #about )
+    }
+
+    /// generate methods on top of a field
+    pub fn field_methods(&self) -> proc_macro2::TokenStream {
+        let methods = &self.methods;
+        quote!( #(#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 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.methods
+            .iter()
+            .any(|m| m.name == "help" || m.name == "long_help")
+    }
+}
+
+/// 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/clap_derive/src/derives/clap.rs b/clap_derive/src/derives/clap.rs
new file mode 100644
index 00000000..9d0cd267
--- /dev/null
+++ b/clap_derive/src/derives/clap.rs
@@ -0,0 +1,427 @@
+// Copyright 2018 Guillaume Pinot (@TeXitoi) <texitoi@texitoi.eu>,
+// Kevin Knapp (@kbknapp) <kbknapp@gmail.com>, and
+// Andrew Hobden (@hoverbear) <andrew@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;
+use proc_macro_error::{abort, abort_call_site, set_dummy};
+use syn::{self, punctuated, spanned::Spanned, token};
+
+use super::{from_argmatches, into_app, sub_type, Attrs, Kind, Name, ParserKind, Ty};
+
+/// Generate a block of code to add arguments/subcommands corresponding to
+/// the `fields` to an app.
+fn gen_app_augmentation(
+    fields: &punctuated::Punctuated<syn::Field, token::Comma>,
+    app_var: &syn::Ident,
+    parent_attribute: &Attrs,
+) -> proc_macro2::TokenStream {
+    let mut subcmds = fields.iter().filter_map(|field| {
+        let attrs = Attrs::from_field(&field, parent_attribute.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(
+                        ::clap::AppSettings::SubcommandRequiredElseHelp
+                    );
+                }
+            };
+
+            let span = field.span();
+            let ts = quote! {
+                let #app_var = <#subcmd_type>::augment_app( #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());
+        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>::augment_app(#app_var);
+                    let #app_var = if <#ty>::is_subcommand() {
+                        #app_var.setting(::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!(),
+
+                    Ty::Option => quote_spanned! { ty.span()=>
+                        .takes_value(true)
+                        #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()=>
+                        .multiple_occurrences(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)
+                            .required(#required)
+                            #validator
+                        }
+                    }
+                };
+
+                let name = attrs.cased_name();
+                let methods = attrs.field_methods();
+
+                Some(quote_spanned! { field.span()=>
+                    let #app_var = #app_var.arg(
+                        ::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_augment_app_fn(
+    fields: &punctuated::Punctuated<syn::Field, token::Comma>,
+    parent_attribute: &Attrs,
+) -> proc_macro2::TokenStream {
+    let app_var = syn::Ident::new("app", proc_macro2::Span::call_site());
+    let augmentation = gen_app_augmentation(fields, &app_var, parent_attribute);
+    quote! {
+        pub fn augment_app<'b>(
+            #app_var: ::clap::App<'b>
+        ) -> ::clap::App<'b> {
+            #augmentation
+        }
+    }
+}
+
+fn gen_augment_app_for_enum(
+    variants: &punctuated::Punctuated<syn::Variant, token::Comma>,
+    parent_attribute: &Attrs,
+) -> proc_macro2::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(),
+        );
+        let app_var = syn::Ident::new("subcommand", proc_macro2::Span::call_site());
+        let arg_block = match variant.fields {
+            Named(ref fields) => gen_app_augmentation(&fields.named, &app_var, &attrs),
+            Unit => quote!( #app_var ),
+            Unnamed(syn::FieldsUnnamed { ref unnamed, .. }) if unnamed.len() == 1 => {
+                let ty = &unnamed[0];
+                quote_spanned! { ty.span() =>
+                    {
+                        let #app_var = <#ty>::augment_app(#app_var);
+                        if <#ty>::is_subcommand() {
+                            #app_var.setting(
+                                ::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 = ::clap::App::new(#name);
+                let #app_var = #arg_block;
+                #app_var#from_attrs
+            })
+        }
+    });
+
+    let app_methods = parent_attribute.top_level_methods();
+
+    quote! {
+        pub fn augment_app<'b>(
+            app: ::clap::App<'b>
+        ) -> ::clap::App<'b> {
+            app #app_methods #( #subcommands )*
+        }
+    }
+}
+
+fn gen_from_subcommand(
+    name: &syn::Ident,
+    variants: &punctuated::Punctuated<syn::Variant, token::Comma>,
+    parent_attribute: &Attrs,
+) -> proc_macro2::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(),
+        );
+        let sub_name = attrs.cased_name();
+        let variant_name = &variant.ident;
+        let constructor_block = match variant.fields {
+            Named(ref fields) => from_argmatches::gen_constructor(&fields.named, &attrs),
+            Unit => quote!(),
+            Unnamed(ref fields) if fields.unnamed.len() == 1 => {
+                let ty = &fields.unnamed[0];
+                quote!( ( <#ty as ::clap::FromArgMatches>::from_argmatches(matches) ) )
+            }
+            Unnamed(..) => abort_call_site!("{}: tuple enums are not supported", variant.ident),
+        };
+
+        quote! {
+            (#sub_name, Some(matches)) =>
+                Some(#name :: #variant_name #constructor_block)
+        }
+    });
+
+    quote! {
+        pub fn from_subcommand<'b>(
+            sub: (&'b str, Option<&'b ::clap::ArgMatches>)
+        ) -> Option<Self> {
+            match sub {
+                #( #match_arms ),*,
+                _ => None
+            }
+        }
+    }
+}
+
+fn clap_impl_for_struct(
+    name: &syn::Ident,
+    fields: &punctuated::Punctuated<syn::Field, token::Comma>,
+    attrs: &[syn::Attribute],
+) -> proc_macro2::TokenStream {
+    let into_app_impl = into_app::gen_into_app_impl_for_struct(name, attrs);
+    let into_app_impl_tokens = into_app_impl.tokens;
+    let augment_app_fn = gen_augment_app_fn(fields, &into_app_impl.attrs);
+    let from_argmatches_impl =
+        from_argmatches::gen_from_argmatches_impl_for_struct(name, fields, &into_app_impl.attrs);
+    let parse_fns = gen_parse_fns(name);
+
+    quote! {
+        #[allow(unused_variables)]
+        impl ::clap::Clap for #name { }
+
+        #into_app_impl_tokens
+
+        #from_argmatches_impl
+
+        #[allow(dead_code, unreachable_code)]
+        #[doc(hidden)]
+        impl #name {
+            #augment_app_fn
+
+            #parse_fns
+
+            pub fn is_subcommand() -> bool { false }
+        }
+    }
+}
+
+fn clap_impl_for_enum(
+    name: &syn::Ident,
+    variants: &punctuated::Punctuated<syn::Variant, token::Comma>,
+    attrs: &[syn::Attribute],
+) -> proc_macro2::TokenStream {
+    let into_app_impl = into_app::gen_into_app_impl_for_enum(name, attrs);
+    let into_app_impl_tokens = into_app_impl.tokens;
+    let augment_app_fn = gen_augment_app_for_enum(variants, &into_app_impl.attrs);
+    let from_argmatches_impl = from_argmatches::gen_from_argmatches_impl_for_enum(name);
+    let from_subcommand = gen_from_subcommand(name, variants, &into_app_impl.attrs);
+    let parse_fns = gen_parse_fns(name);
+
+    quote! {
+        #[allow(unused_variables)]
+        impl ::clap::Clap for #name { }
+
+        #into_app_impl_tokens
+
+        #from_argmatches_impl
+
+        #[allow(unused_variables, dead_code, unreachable_code)]
+        #[doc(hidden)]
+        impl #name {
+            #augment_app_fn
+
+            #from_subcommand
+
+            #parse_fns
+
+            pub fn is_subcommand() -> bool { true }
+        }
+    }
+}
+
+pub fn derive_clap(input: &syn::DeriveInput) -> proc_macro2::TokenStream {
+    use syn::Data::*;
+
+    let struct_name = &input.ident;
+
+    set_dummy(quote! {
+        impl ::clap::Clap for #struct_name {}
+
+        impl ::clap::IntoApp for #struct_name {
+            fn into_app<'b>() -> ::clap::App<'b> {
+                unimplemented!()
+            }
+        }
+
+        impl ::clap::FromArgMatches for #struct_name {
+            fn from_argmatches(m: &::clap::ArgMatches) -> Self {
+                unimplemented!()
+            }
+        }
+
+        impl #struct_name {
+            fn parse() -> Self {
+                unimplemented!();
+            }
+        }
+    });
+
+    match input.data {
+        Struct(syn::DataStruct {
+            fields: syn::Fields::Named(ref fields),
+            ..
+        }) => clap_impl_for_struct(struct_name, &fields.named, &input.attrs),
+        Enum(ref e) => clap_impl_for_enum(struct_name, &e.variants, &input.attrs),
+        _ => abort_call_site!("clap_derive only supports non-tuple structs and enums"),
+    }
+}
+
+fn gen_parse_fns(name: &syn::Ident) -> proc_macro2::TokenStream {
+    quote! {
+        #[allow(unreachable_pub)]
+        pub fn parse() -> #name {
+            use ::clap::{FromArgMatches, IntoApp};
+            #name::from_argmatches(&#name::into_app().get_matches())
+        }
+        #[allow(unreachable_pub)]
+        pub fn try_parse() -> ::std::result::Result<#name, ::clap::Error> {
+            use ::clap::{FromArgMatches, IntoApp};
+            Ok(#name::from_argmatches(&#name::into_app().try_get_matches()?))
+        }
+        #[allow(unreachable_pub)]
+        pub fn parse_from<I, T>(itr: I) -> #name
+        where
+            I: ::std::iter::IntoIterator<Item = T>,
+            T: Into<::std::ffi::OsString> + Clone {
+            use ::clap::{FromArgMatches, IntoApp};
+            #name::from_argmatches(&#name::into_app().get_matches_from(itr))
+        }
+        #[allow(unreachable_pub)]
+        pub fn try_parse_from<I, T>(itr: I) -> ::std::result::Result<#name, ::clap::Error>
+        where
+            I: ::std::iter::IntoIterator<Item = T>,
+            T: Into<::std::ffi::OsString> + Clone {
+            use ::clap::{FromArgMatches, IntoApp};
+            Ok(#name::from_argmatches(&#name::into_app().try_get_matches_from(itr)?))
+        }
+    }
+}
diff --git a/clap_derive/src/derives/from_argmatches.rs b/clap_derive/src/derives/from_argmatches.rs
new file mode 100644
index 00000000..963b6ac4
--- /dev/null
+++ b/clap_derive/src/derives/from_argmatches.rs
@@ -0,0 +1,237 @@
+// Copyright 2018 Guillaume Pinot (@TeXitoi) <texitoi@texitoi.eu>,
+// Kevin Knapp (@kbknapp) <kbknapp@gmail.com>, and
+// Andrew Hobden (@hoverbear) <andrew@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 std::env;
+
+use proc_macro2;
+use syn;
+use syn::punctuated;
+use syn::spanned::Spanned as _;
+use syn::token;
+
+use super::{spanned::Sp, sub_type, Attrs, Kind, Name, ParserKind, Ty, DEFAULT_CASING};
+
+pub fn derive_from_argmatches(input: &syn::DeriveInput) -> proc_macro2::TokenStream {
+    use syn::Data::*;
+
+    let struct_name = &input.ident;
+    let inner_impl = match input.data {
+        Struct(syn::DataStruct {
+            fields: syn::Fields::Named(ref fields),
+            ..
+        }) => {
+            let name = env::var("CARGO_PKG_NAME")
+                .ok()
+                .unwrap_or_else(String::default);
+
+            let attrs = Attrs::from_struct(
+                proc_macro2::Span::call_site(),
+                &input.attrs,
+                Name::Assigned(syn::LitStr::new(&name, proc_macro2::Span::call_site())),
+                Sp::call_site(DEFAULT_CASING),
+            );
+
+            gen_from_argmatches_impl_for_struct(struct_name, &fields.named, &attrs)
+        }
+        // Enum(ref e) => clap_for_enum_impl(struct_name, &e.variants, &input.attrs),
+        _ => panic!("clap_derive only supports non-tuple structs"), // and enums"),
+    };
+
+    quote!(#inner_impl)
+}
+
+pub fn gen_from_argmatches_impl_for_struct(
+    name: &syn::Ident,
+    fields: &punctuated::Punctuated<syn::Field, token::Comma>,
+    parent_attribute: &Attrs,
+) -> proc_macro2::TokenStream {
+    let from_argmatches_fn = gen_from_argmatches_fn_for_struct(name, fields, parent_attribute);
+
+    quote! {
+        impl ::clap::FromArgMatches for #name {
+            #from_argmatches_fn
+        }
+
+        impl From<::clap::ArgMatches> for #name {
+            fn from(m: ::clap::ArgMatches) -> Self {
+                use ::clap::FromArgMatches;
+                <Self as ::clap::FromArgMatches>::from_argmatches(&m)
+            }
+        }
+
+        // @TODO impl TryFrom once stable
+    }
+}
+
+pub fn gen_from_argmatches_fn_for_struct(
+    struct_name: &syn::Ident,
+    fields: &punctuated::Punctuated<syn::Field, token::Comma>,
+    parent_attribute: &Attrs,
+) -> proc_macro2::TokenStream {
+    let field_block = gen_constructor(fields, parent_attribute);
+
+    quote! {
+        fn from_argmatches(matches: &::clap::ArgMatches) -> Self {
+            #struct_name #field_block
+        }
+    }
+}
+
+pub fn gen_constructor(
+    fields: &punctuated::Punctuated<syn::Field, token::Comma>,
+    parent_attribute: &Attrs,
+) -> proc_macro2::TokenStream {
+    let fields = fields.iter().map(|field| {
+        let attrs = Attrs::from_field(field, parent_attribute.casing());
+        let field_name = field.ident.as_ref().unwrap();
+        let kind = attrs.kind();
+        match &*attrs.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>::from_subcommand(matches.subcommand())#unwrapper
+                }
+            }
+
+            Kind::FlattenStruct => quote_spanned! { kind.span()=>
+                #field_name: ::clap::FromArgMatches::from_argmatches(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 self::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(|v| v.map(#parse).collect())
+                                 .unwrap_or_else(Vec::new))
+                        } else {
+                            None
+                        }
+                    },
+
+                    Ty::Vec => quote_spanned! { ty.span()=>
+                        matches.#values_of(#name)
+                            .map(|v| v.map(#parse).collect())
+                            .unwrap_or_else(Vec::new)
+                    },
+
+                    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 ),*
+    }}
+}
+
+pub fn gen_from_argmatches_impl_for_enum(name: &syn::Ident) -> proc_macro2::TokenStream {
+    quote! {
+        impl ::clap::FromArgMatches for #name {
+            fn from_argmatches(matches: &::clap::ArgMatches) -> Self {
+                <#name>::from_subcommand(matches.subcommand())
+                    .unwrap()
+            }
+        }
+
+        impl From<::clap::ArgMatches> for #name {
+            fn from(m: ::clap::ArgMatches) -> Self {
+                use ::clap::FromArgMatches;
+                <Self as ::clap::FromArgMatches>::from_argmatches(&m)
+            }
+        }
+
+        // @TODO: impl TryFrom once stable
+    }
+}
diff --git a/clap_derive/src/derives/into_app.rs b/clap_derive/src/derives/into_app.rs
new file mode 100644
index 00000000..31e2b57e
--- /dev/null
+++ b/clap_derive/src/derives/into_app.rs
@@ -0,0 +1,132 @@
+// Copyright 2018 Guillaume Pinot (@TeXitoi) <texitoi@texitoi.eu>,
+// Kevin Knapp (@kbknapp) <kbknapp@gmail.com>, and
+// Andrew Hobden (@hoverbear) <andrew@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 std::env;
+
+use proc_macro2;
+use syn;
+
+use super::{spanned::Sp, Attrs, GenOutput, Name, DEFAULT_CASING};
+
+pub fn derive_into_app(input: &syn::DeriveInput) -> proc_macro2::TokenStream {
+    use syn::Data::*;
+
+    let struct_name = &input.ident;
+    let inner_impl = match input.data {
+        Struct(syn::DataStruct { .. }) => {
+            gen_into_app_impl_for_struct(struct_name, &input.attrs).tokens
+        }
+        // @TODO impl into_app for enums?
+        // Enum(ref e) => clap_for_enum_impl(struct_name, &e.variants, &input.attrs),
+        _ => panic!("clap_derive only supports non-tuple structs"), // and enums"),
+    };
+
+    quote!(#inner_impl)
+}
+
+pub fn gen_into_app_impl_for_struct(name: &syn::Ident, attrs: &[syn::Attribute]) -> GenOutput {
+    let into_app_fn = gen_into_app_fn_for_struct(attrs);
+    let into_app_fn_tokens = into_app_fn.tokens;
+
+    let tokens = quote! {
+        impl ::clap::IntoApp for #name {
+            #into_app_fn_tokens
+        }
+
+        impl<'b> Into<::clap::App<'b>> for #name {
+            fn into(self) -> ::clap::App<'b> {
+                use ::clap::IntoApp;
+                <#name as ::clap::IntoApp>::into_app()
+            }
+        }
+    };
+
+    GenOutput {
+        tokens,
+        attrs: into_app_fn.attrs,
+    }
+}
+
+pub fn gen_into_app_fn_for_struct(struct_attrs: &[syn::Attribute]) -> GenOutput {
+    let gen = gen_app_builder(struct_attrs);
+    let app_tokens = gen.tokens;
+
+    let tokens = quote! {
+        fn into_app<'b>() -> ::clap::App<'b> {
+            Self::augment_app(#app_tokens)
+        }
+    };
+
+    GenOutput {
+        tokens,
+        attrs: gen.attrs,
+    }
+}
+
+pub fn gen_app_builder(attrs: &[syn::Attribute]) -> GenOutput {
+    let name = env::var("CARGO_PKG_NAME").ok().unwrap_or_default();
+
+    let attrs = Attrs::from_struct(
+        proc_macro2::Span::call_site(),
+        attrs,
+        Name::Assigned(syn::LitStr::new(&name, proc_macro2::Span::call_site())),
+        Sp::call_site(DEFAULT_CASING),
+    );
+    let tokens = {
+        let name = attrs.cased_name();
+        quote!(::clap::App::new(#name))
+    };
+
+    GenOutput { tokens, attrs }
+}
+
+pub fn gen_into_app_impl_for_enum(name: &syn::Ident, attrs: &[syn::Attribute]) -> GenOutput {
+    let into_app_fn = gen_into_app_fn_for_enum(attrs);
+    let into_app_fn_tokens = into_app_fn.tokens;
+
+    let tokens = quote! {
+        impl ::clap::IntoApp for #name {
+            #into_app_fn_tokens
+        }
+
+        impl<'b> Into<::clap::App<'b>> for #name {
+            fn into(self) -> ::clap::App<'b> {
+                use ::clap::IntoApp;
+                <#name as ::clap::IntoApp>::into_app()
+            }
+        }
+    };
+
+    GenOutput {
+        tokens,
+        attrs: into_app_fn.attrs,
+    }
+}
+
+pub fn gen_into_app_fn_for_enum(enum_attrs: &[syn::Attribute]) -> GenOutput {
+    let gen = gen_app_builder(enum_attrs);
+    let app_tokens = gen.tokens;
+
+    let tokens = quote! {
+        fn into_app<'b>() -> ::clap::App<'b> {
+            let app = #app_tokens
+                .setting(::clap::AppSettings::SubcommandRequiredElseHelp);
+            Self::augment_app(app)
+        }
+    };
+
+    GenOutput {
+        tokens,
+        attrs: gen.attrs,
+    }
+}
diff --git a/clap_derive/src/derives/mod.rs b/clap_derive/src/derives/mod.rs
new file mode 100644
index 00000000..6bd4b4b8
--- /dev/null
+++ b/clap_derive/src/derives/mod.rs
@@ -0,0 +1,30 @@
+// Copyright 2018 Guillaume Pinot (@TeXitoi) <texitoi@texitoi.eu>,
+// Kevin Knapp (@kbknapp) <kbknapp@gmail.com>, and
+// Andrew Hobden (@hoverbear) <andrew@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.
+pub mod arg_enum;
+pub mod attrs;
+mod clap;
+mod from_argmatches;
+mod into_app;
+pub mod parse;
+pub mod spanned;
+pub mod ty;
+
+pub use self::arg_enum::derive_arg_enum;
+pub use self::attrs::{
+    Attrs, CasingStyle, GenOutput, Kind, Name, Parser, ParserKind, DEFAULT_CASING,
+};
+pub use self::clap::derive_clap;
+pub use self::from_argmatches::derive_from_argmatches;
+pub use self::into_app::derive_into_app;
+pub use self::ty::{sub_type, Ty};
diff --git a/clap_derive/src/derives/parse.rs b/clap_derive/src/derives/parse.rs
new file mode 100644
index 00000000..2a4722db
--- /dev/null
+++ b/clap_derive/src/derives/parse.rs
@@ -0,0 +1,268 @@
+use std::iter::FromIterator;
+
+use proc_macro2::TokenStream;
+use proc_macro_error::{abort, ResultExt};
+use syn::{
+    self, parenthesized,
+    parse::{Parse, ParseBuffer, ParseStream},
+    parse2,
+    punctuated::Punctuated,
+    spanned::Spanned,
+    Attribute, Expr, ExprLit, Ident, Lit, LitBool, LitStr, Token,
+};
+
+pub struct ClapAttributes {
+    pub paren_token: syn::token::Paren,
+    pub attrs: Punctuated<ClapAttr, Token![,]>,
+}
+
+impl Parse for ClapAttributes {
+    fn parse(input: ParseStream) -> syn::Result<Self> {
+        let content;
+        let paren_token = parenthesized!(content in input);
+        let attrs = content.parse_terminated(ClapAttr::parse)?;
+
+        Ok(ClapAttributes { paren_token, attrs })
+    }
+}
+
+pub enum ClapAttr {
+    // single-identifier attributes
+    Short(Ident),
+    Long(Ident),
+    Flatten(Ident),
+    Subcommand(Ident),
+    NoVersion(Ident),
+
+    // ident [= "string literal"]
+    About(Ident, Option<LitStr>),
+    Author(Ident, Option<LitStr>),
+
+    // ident = "string literal"
+    Version(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 ClapAttr {
+    fn parse(input: ParseStream) -> syn::Result<Self> {
+        use self::ClapAttr::*;
+
+        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(),
+                            "`#[clap({} = \"\")` is deprecated, \
+                             now it's default behavior",
+                            s
+                        );
+                    }
+                };
+
+                match &*name_str.to_string() {
+                    "rename_all" => Ok(RenameAll(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(),
+                            "`#[clap(raw(...))` attributes are removed, \
+                            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)),
+                "flatten" => Ok(Flatten(name)),
+                "subcommand" => Ok(Subcommand(name)),
+                "no_version" => Ok(NoVersion(name)),
+
+                "about" => (Ok(About(name, None))),
+                "author" => (Ok(Author(name, None))),
+
+                "skip" => Ok(Skip(name, None)),
+
+                "version" => abort!(
+                    name.span(),
+                    "#[clap(version)] is invalid attribute, \
+                     clap_derive 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,
+        })
+    }
+}
+
+fn raw_method_suggestion(ts: ParseBuffer) -> String {
+    let do_parse = move || -> Result<(Ident, TokenStream), syn::Error> {
+        let name = ts.parse()?;
+        let _eq: Token![=] = ts.parse()?;
+        let val: LitStr = ts.parse()?;
+        Ok((name, syn::parse_str(&val.value())?))
+    };
+    if let Ok((name, val)) = do_parse() {
+        let val = val.to_string().replace(" ", "").replace(",", ", ");
+        format!(
+            "if you need to call `clap::Arg/App::{}` method you \
+             can do it like this: #[clap({}({}))]",
+            name, name, val
+        )
+    } 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_clap_attributes(all_attrs: &[Attribute]) -> Vec<ClapAttr> {
+    all_attrs
+        .iter()
+        .filter(|attr| attr.path.is_ident("clap"))
+        .flat_map(|attr| {
+            let attrs: ClapAttributes = 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 `clap`";
+                        syn::Error::new(span, patch_msg)
+                    }
+                    _ => e,
+                })
+                .unwrap_or_abort();
+            attrs.attrs
+        })
+        .collect()
+}
diff --git a/clap_derive/src/derives/spanned.rs b/clap_derive/src/derives/spanned.rs
new file mode 100644
index 00000000..4eacfad7
--- /dev/null
+++ b/clap_derive/src/derives/spanned.rs
@@ -0,0 +1,101 @@
+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<T: PartialEq> PartialEq for Sp<T> {
+    fn eq(&self, other: &Sp<T>) -> bool {
+        self.val == other.val
+    }
+}
+
+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/clap_derive/src/derives/ty.rs b/clap_derive/src/derives/ty.rs
new file mode 100644
index 00000000..f9313f71
--- /dev/null
+++ b/clap_derive/src/derives/ty.rs
@@ -0,0 +1,108 @@
+//! Special types handling
+
+use super::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 self::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())
+}
diff --git a/clap_derive/src/lib.rs b/clap_derive/src/lib.rs
new file mode 100644
index 00000000..214cdeb6
--- /dev/null
+++ b/clap_derive/src/lib.rs
@@ -0,0 +1,61 @@
+// Copyright 2018 Guillaume Pinot (@TeXitoi) <texitoi@texitoi.eu>,
+// Kevin Knapp (@kbknapp) <kbknapp@gmail.com>, and
+// Andrew Hobden (@hoverbear) <andrew@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.
+
+//! This crate is custom derive for clap. It should not be used
+//! directly. See [clap documentation](https://docs.rs/clap)
+//! for the usage of `#[derive(Clap)]`.
+#![recursion_limit = "256"]
+
+extern crate proc_macro;
+extern crate syn;
+#[macro_use]
+extern crate quote;
+extern crate heck;
+extern crate proc_macro2;
+extern crate proc_macro_error;
+
+use proc_macro_error::proc_macro_error;
+
+mod derives;
+
+// /// It is required to have this seperate and specificly defined.
+// #[proc_macro_derive(ArgEnum, attributes(case_sensitive))]
+// pub fn arg_enum(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
+//     let input: syn::DeriveInput = syn::parse(input).unwrap();
+//     derives::derive_arg_enum(&input).into()
+// }
+
+/// Generates the `Clap` impl.
+#[proc_macro_derive(Clap, attributes(clap))]
+#[proc_macro_error]
+pub fn clap(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
+    let input: syn::DeriveInput = syn::parse(input).unwrap();
+    derives::derive_clap(&input).into()
+}
+
+/// Generates the `IntoApp` impl.
+#[proc_macro_derive(IntoApp, attributes(clap))]
+#[proc_macro_error]
+pub fn into_app(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
+    let input: syn::DeriveInput = syn::parse(input).unwrap();
+    derives::derive_into_app(&input).into()
+}
+
+/// Generates the `FromArgMatches` impl.
+#[proc_macro_derive(FromArgMatches)]
+#[proc_macro_error]
+pub fn from_argmatches(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
+    let input: syn::DeriveInput = syn::parse(input).unwrap();
+    derives::derive_from_argmatches(&input).into()
+}


Test patch:
diff --git a/clap_derive/tests/arg_enum_basic.rs b/clap_derive/tests/arg_enum_basic.rs
new file mode 100644
index 00000000..703fe097
--- /dev/null
+++ b/clap_derive/tests/arg_enum_basic.rs
@@ -0,0 +1,54 @@
+// // Copyright 2018 Guillaume Pinot (@TeXitoi) <texitoi@texitoi.eu>,
+// // Kevin Knapp (@kbknapp) <kbknapp@gmail.com>, and
+// // Andrew Hobden (@hoverbear) <andrew@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.
+// #[macro_use]
+// extern crate clap;
+// #[macro_use]
+// extern crate clap_derive;
+
+// use clap::{App, Arg};
+
+// #[derive(ArgEnum, Debug, PartialEq)]
+// enum ArgChoice {
+//     Foo,
+//     Bar,
+//     Baz,
+// }
+
+// #[test]
+// fn when_lowercase() {
+//     let matches = App::new(env!("CARGO_PKG_NAME"))
+//         .arg(
+//             Arg::with_name("arg")
+//                 .required(true)
+//                 .takes_value(true)
+//                 .possible_values(&ArgChoice::variants()),
+//         )
+//         .try_get_matches_from(vec!["", "foo"])
+//         .unwrap();
+//     let t = value_t!(matches.value_of("arg"), ArgChoice);
+//     assert!(t.is_ok());
+//     assert_eq!(t.unwrap(), ArgChoice::Foo);
+// }
+
+// #[test]
+// fn when_capitalized() {
+//     let matches = App::new(env!("CARGO_PKG_NAME"))
+//         .arg(
+//             Arg::with_name("arg")
+//                 .required(true)
+//                 .takes_value(true)
+//                 .possible_values(&ArgChoice::variants()),
+//         )
+//         .try_get_matches_from(vec!["", "Foo"])
+//         .unwrap();
+//     let t = value_t!(matches.value_of("arg"), ArgChoice);
+//     assert!(t.is_ok());
+//     assert_eq!(t.unwrap(), ArgChoice::Foo);
+// }
diff --git a/clap_derive/tests/arg_enum_case_sensitive.rs b/clap_derive/tests/arg_enum_case_sensitive.rs
new file mode 100644
index 00000000..2f82a0f9
--- /dev/null
+++ b/clap_derive/tests/arg_enum_case_sensitive.rs
@@ -0,0 +1,51 @@
+// // Copyright 2018 Guillaume Pinot (@TeXitoi) <texitoi@texitoi.eu>,
+// // Kevin Knapp (@kbknapp) <kbknapp@gmail.com>, and
+// // Andrew Hobden (@hoverbear) <andrew@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.
+// #[macro_use]
+// extern crate clap;
+
+// use clap::{App, Arg, ArgEnum};
+
+// #[derive(ArgEnum, Debug, PartialEq)]
+// #[case_sensitive]
+// enum ArgChoice {
+//     Foo,
+//     Bar,
+//     Baz,
+// }
+
+// #[test]
+// fn when_lowercase() {
+//     let matches = App::new(env!("CARGO_PKG_NAME"))
+//         .arg(
+//             Arg::with_name("arg")
+//                 .required(true)
+//                 .takes_value(true)
+//                 .possible_values(&ArgChoice::variants()),
+//         )
+//         .try_get_matches_from(vec!["", "foo"]); // We expect this to fail.
+//     assert!(matches.is_err());
+//     assert_eq!(matches.unwrap_err().kind, clap::ErrorKind::InvalidValue);
+// }
+
+// #[test]
+// fn when_capitalized() {
+//     let matches = App::new(env!("CARGO_PKG_NAME"))
+//         .arg(
+//             Arg::with_name("arg")
+//                 .required(true)
+//                 .takes_value(true)
+//                 .possible_values(&ArgChoice::variants()),
+//         )
+//         .try_get_matches_from(vec!["", "Foo"])
+//         .unwrap();
+//     let t = value_t!(matches.value_of("arg"), ArgChoice);
+//     assert!(t.is_ok());
+//     assert_eq!(t.unwrap(), ArgChoice::Foo);
+// }
diff --git a/clap_derive/tests/argument_naming.rs b/clap_derive/tests/argument_naming.rs
new file mode 100644
index 00000000..479eae29
--- /dev/null
+++ b/clap_derive/tests/argument_naming.rs
@@ -0,0 +1,290 @@
+use clap::Clap;
+
+#[test]
+fn test_single_word_enum_variant_is_default_renamed_into_kebab_case() {
+    #[derive(Clap, Debug, PartialEq)]
+    enum Opt {
+        Command { foo: u32 },
+    }
+
+    assert_eq!(
+        Opt::Command { foo: 0 },
+        Opt::parse_from(&["test", "command", "0"])
+    );
+}
+
+#[test]
+fn test_multi_word_enum_variant_is_renamed() {
+    #[derive(Clap, Debug, PartialEq)]
+    enum Opt {
+        FirstCommand { foo: u32 },
+    }
+
+    assert_eq!(
+        Opt::FirstCommand { foo: 0 },
+        Opt::parse_from(&["test", "first-command", "0"])
+    );
+}
+
+#[test]
+fn test_standalone_long_generates_kebab_case() {
+    #[derive(Clap, Debug, PartialEq)]
+    #[allow(non_snake_case)]
+    struct Opt {
+        #[clap(long)]
+        FOO_OPTION: bool,
+    }
+
+    assert_eq!(
+        Opt { FOO_OPTION: true },
+        Opt::parse_from(&["test", "--foo-option"])
+    );
+}
+
+#[test]
+fn test_custom_long_overwrites_default_name() {
+    #[derive(Clap, Debug, PartialEq)]
+    struct Opt {
+        #[clap(long = "foo")]
+        foo_option: bool,
+    }
+
+    assert_eq!(
+        Opt { foo_option: true },
+        Opt::parse_from(&["test", "--foo"])
+    );
+}
+
+#[test]
+fn test_standalone_long_uses_previous_defined_custom_name() {
+    #[derive(Clap, Debug, PartialEq)]
+    struct Opt {
+        #[clap(name = "foo", long)]
+        foo_option: bool,
+    }
+
+    assert_eq!(
+        Opt { foo_option: true },
+        Opt::parse_from(&["test", "--foo"])
+    );
+}
+
+#[test]
+fn test_standalone_long_ignores_afterwards_defined_custom_name() {
+    #[derive(Clap, Debug, PartialEq)]
+    struct Opt {
+        #[clap(long, name = "foo")]
+        foo_option: bool,
+    }
+
+    assert_eq!(
+        Opt { foo_option: true },
+        Opt::parse_from(&["test", "--foo-option"])
+    );
+}
+
+#[test]
+fn test_standalone_short_generates_kebab_case() {
+    #[derive(Clap, Debug, PartialEq)]
+    #[allow(non_snake_case)]
+    struct Opt {
+        #[clap(short)]
+        FOO_OPTION: bool,
+    }
+
+    assert_eq!(Opt { FOO_OPTION: true }, Opt::parse_from(&["test", "-f"]));
+}
+
+#[test]
+fn test_custom_short_overwrites_default_name() {
+    #[derive(Clap, Debug, PartialEq)]
+    struct Opt {
+        #[clap(short = "o")]
+        foo_option: bool,
+    }
+
+    assert_eq!(Opt { foo_option: true }, Opt::parse_from(&["test", "-o"]));
+}
+
+#[test]
+fn test_standalone_short_uses_previous_defined_custom_name() {
+    #[derive(Clap, Debug, PartialEq)]
+    struct Opt {
+        #[clap(name = "option", short)]
+        foo_option: bool,
+    }
+
+    assert_eq!(Opt { foo_option: true }, Opt::parse_from(&["test", "-o"]));
+}
+
+#[test]
+fn test_standalone_short_ignores_afterwards_defined_custom_name() {
+    #[derive(Clap, Debug, PartialEq)]
+    struct Opt {
+        #[clap(short, name = "option")]
+        foo_option: bool,
+    }
+
+    assert_eq!(Opt { foo_option: true }, Opt::parse_from(&["test", "-f"]));
+}
+
+#[test]
+fn test_standalone_long_uses_previous_defined_casing() {
+    #[derive(Clap, Debug, PartialEq)]
+    struct Opt {
+        #[clap(rename_all = "screaming_snake", long)]
+        foo_option: bool,
+    }
+
+    assert_eq!(
+        Opt { foo_option: true },
+        Opt::parse_from(&["test", "--FOO_OPTION"])
+    );
+}
+
+#[test]
+fn test_standalone_short_uses_previous_defined_casing() {
+    #[derive(Clap, Debug, PartialEq)]
+    struct Opt {
+        #[clap(rename_all = "screaming_snake", short)]
+        foo_option: bool,
+    }
+
+    assert_eq!(Opt { foo_option: true }, Opt::parse_from(&["test", "-F"]));
+}
+
+#[test]
+fn test_standalone_long_works_with_verbatim_casing() {
+    #[derive(Clap, Debug, PartialEq)]
+    #[allow(non_snake_case)]
+    struct Opt {
+        #[clap(rename_all = "verbatim", long)]
+        _fOO_oPtiON: bool,
+    }
+
+    assert_eq!(
+        Opt { _fOO_oPtiON: true },
+        Opt::parse_from(&["test", "--_fOO_oPtiON"])
+    );
+}
+
+#[test]
+fn test_standalone_short_works_with_verbatim_casing() {
+    #[derive(Clap, Debug, PartialEq)]
+    struct Opt {
+        #[clap(rename_all = "verbatim", short)]
+        _foo: bool,
+    }
+
+    assert_eq!(Opt { _foo: true }, Opt::parse_from(&["test", "-_"]));
+}
+
+#[test]
+fn test_rename_all_is_propagated_from_struct_to_fields() {
+    #[derive(Clap, Debug, PartialEq)]
+    #[clap(rename_all = "screaming_snake")]
+    struct Opt {
+        #[clap(long)]
+        foo: bool,
+    }
+
+    assert_eq!(Opt { foo: true }, Opt::parse_from(&["test", "--FOO"]));
+}
+
+#[test]
+fn test_rename_all_is_not_propagated_from_struct_into_flattened() {
+    #[derive(Clap, Debug, PartialEq)]
+    #[clap(rename_all = "screaming_snake")]
+    struct Opt {
+        #[clap(flatten)]
+        foo: Foo,
+    }
+
+    #[derive(Clap, Debug, PartialEq)]
+    struct Foo {
+        #[clap(long)]
+        foo: bool,
+    }
+
+    assert_eq!(
+        Opt {
+            foo: Foo { foo: true }
+        },
+        Opt::parse_from(&["test", "--foo"])
+    );
+}
+
+#[test]
+fn test_rename_all_is_not_propagated_from_struct_into_subcommand() {
+    #[derive(Clap, Debug, PartialEq)]
+    #[clap(rename_all = "screaming_snake")]
+    struct Opt {
+        #[clap(subcommand)]
+        foo: Foo,
+    }
+
+    #[derive(Clap, Debug, PartialEq)]
+    enum Foo {
+        Command {
+            #[clap(long)]
+            foo: bool,
+        },
+    }
+
+    assert_eq!(
+        Opt {
+            foo: Foo::Command { foo: true }
+        },
+        Opt::parse_from(&["test", "command", "--foo"])
+    );
+}
+
+#[test]
+fn test_rename_all_is_propagated_from_enum_to_variants_and_their_fields() {
+    #[derive(Clap, Debug, PartialEq)]
+    #[clap(rename_all = "screaming_snake")]
+    enum Opt {
+        FirstVariant,
+        SecondVariant {
+            #[clap(long)]
+            foo: bool,
+        },
+    }
+
+    assert_eq!(
+        Opt::FirstVariant,
+        Opt::parse_from(&["test", "FIRST_VARIANT"])
+    );
+
+    assert_eq!(
+        Opt::SecondVariant { foo: true },
+        Opt::parse_from(&["test", "SECOND_VARIANT", "--FOO"])
+    );
+}
+
+#[test]
+fn test_rename_all_is_propagation_can_be_overridden() {
+    #[derive(Clap, Debug, PartialEq)]
+    #[clap(rename_all = "screaming_snake")]
+    enum Opt {
+        #[clap(rename_all = "kebab_case")]
+        FirstVariant {
+            #[clap(long)]
+            foo_option: bool,
+        },
+        SecondVariant {
+            #[clap(rename_all = "kebab_case", long)]
+            foo_option: bool,
+        },
+    }
+
+    assert_eq!(
+        Opt::FirstVariant { foo_option: true },
+        Opt::parse_from(&["test", "first-variant", "--foo-option"])
+    );
+
+    assert_eq!(
+        Opt::SecondVariant { foo_option: true },
+        Opt::parse_from(&["test", "SECOND_VARIANT", "--foo-option"])
+    );
+}
diff --git a/clap_derive/tests/arguments.rs b/clap_derive/tests/arguments.rs
new file mode 100644
index 00000000..e9740a40
--- /dev/null
+++ b/clap_derive/tests/arguments.rs
@@ -0,0 +1,85 @@
+// Copyright 2018 Guillaume Pinot (@TeXitoi) <texitoi@texitoi.eu>,
+// Kevin Knapp (@kbknapp) <kbknapp@gmail.com>, and
+// Andrew Hobden (@hoverbear) <andrew@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 clap::Clap;
+
+#[test]
+fn required_argument() {
+    #[derive(Clap, PartialEq, Debug)]
+    struct Opt {
+        arg: i32,
+    }
+    assert_eq!(Opt { arg: 42 }, Opt::parse_from(&["test", "42"]));
+    assert!(Opt::try_parse_from(&["test"]).is_err());
+    assert!(Opt::try_parse_from(&["test", "42", "24"]).is_err());
+}
+
+#[test]
+fn optional_argument() {
+    #[derive(Clap, PartialEq, Debug)]
+    struct Opt {
+        arg: Option<i32>,
+    }
+    assert_eq!(Opt { arg: Some(42) }, Opt::parse_from(&["test", "42"]));
+    assert_eq!(Opt { arg: None }, Opt::parse_from(&["test"]));
+    assert!(Opt::try_parse_from(&["test", "42", "24"]).is_err());
+}
+
+#[test]
+fn argument_with_default() {
+    #[derive(Clap, PartialEq, Debug)]
+    struct Opt {
+        #[clap(default_value = "42")]
+        arg: i32,
+    }
+    assert_eq!(Opt { arg: 24 }, Opt::parse_from(&["test", "24"]));
+    assert_eq!(Opt { arg: 42 }, Opt::parse_from(&["test"]));
+    assert!(Opt::try_parse_from(&["test", "42", "24"]).is_err());
+}
+
+#[test]
+fn arguments() {
+    #[derive(Clap, PartialEq, Debug)]
+    struct Opt {
+        arg: Vec<i32>,
+    }
+    assert_eq!(Opt { arg: vec![24] }, Opt::parse_from(&["test", "24"]));
+    assert_eq!(Opt { arg: vec![] }, Opt::parse_from(&["test"]));
+    assert_eq!(
+        Opt { arg: vec![24, 42] },
+        Opt::parse_from(&["test", "24", "42"])
+    );
+}
+
+#[test]
+fn arguments_safe() {
+    #[derive(Clap, PartialEq, Debug)]
+    struct Opt {
+        arg: Vec<i32>,
+    }
+    assert_eq!(
+        Opt { arg: vec![24] },
+        Opt::try_parse_from(&["test", "24"]).unwrap()
+    );
+    assert_eq!(Opt { arg: vec![] }, Opt::try_parse_from(&["test"]).unwrap());
+    assert_eq!(
+        Opt { arg: vec![24, 42] },
+        Opt::try_parse_from(&["test", "24", "42"]).unwrap()
+    );
+
+    assert_eq!(
+        clap::ErrorKind::ValueValidation,
+        Opt::try_parse_from(&["test", "NOPE"]).err().unwrap().kind
+    );
+}
diff --git a/clap_derive/tests/author_version_about.rs b/clap_derive/tests/author_version_about.rs
new file mode 100644
index 00000000..1233bebf
--- /dev/null
+++ b/clap_derive/tests/author_version_about.rs
@@ -0,0 +1,52 @@
+// Copyright 2018 Guillaume Pinot (@TeXitoi) <texitoi@texitoi.eu>,
+// Kevin Knapp (@kbknapp) <kbknapp@gmail.com>, and
+// Andrew Hobden (@hoverbear) <andrew@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.
+
+mod utils;
+
+use clap::Clap;
+use utils::*;
+
+#[test]
+fn no_author_version_about() {
+    #[derive(Clap, PartialEq, Debug)]
+    #[clap(name = "foo", no_version)]
+    struct Opt {}
+
+    let output = get_long_help::<Opt>();
+    assert!(output.starts_with("foo \n\nUSAGE:"));
+}
+
+#[test]
+fn use_env() {
+    #[derive(Clap, PartialEq, Debug)]
+    #[clap(author, about)]
+    struct Opt {}
+
+    let output = get_long_help::<Opt>();
+    assert!(output.starts_with("clap_derive"));
+    assert!(output.contains("Guillaume Pinot <texitoi@texitoi.eu>, Kevin K. <kbknapp@gmail.com>"));
+    assert!(output.contains("Parse command line argument by defining a struct, derive crate"));
+}
+
+#[test]
+fn explicit_version_not_str() {
+    const VERSION: &str = "custom version";
+
+    #[derive(Clap)]
+    #[clap(version = VERSION)]
+    pub struct Opt {}
+
+    let output = get_long_help::<Opt>();
+    assert!(output.contains("custom version"));
+}
diff --git a/clap_derive/tests/basic.rs b/clap_derive/tests/basic.rs
new file mode 100644
index 00000000..a3d31fbd
--- /dev/null
+++ b/clap_derive/tests/basic.rs
@@ -0,0 +1,30 @@
+// Copyright 2018 Guillaume Pinot (@TeXitoi) <texitoi@texitoi.eu>,
+// Kevin Knapp (@kbknapp) <kbknapp@gmail.com>, and
+// Andrew Hobden (@hoverbear) <andrew@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 clap::Clap;
+
+#[test]
+fn basic() {
+    #[derive(Clap, PartialEq, Debug)]
+    struct Opt {
+        #[clap(short = "a", long = "arg")]
+        arg: Vec<i32>,
+    }
+    assert_eq!(Opt { arg: vec![24] }, Opt::parse_from(&["test", "-a24"]));
+    assert_eq!(Opt { arg: vec![] }, Opt::parse_from(&["test"]));
+    assert_eq!(
+        Opt { arg: vec![24, 42] },
+        Opt::parse_from(&["test", "-a24", "--arg", "42"])
+    );
+}
diff --git a/clap_derive/tests/custom-string-parsers.rs b/clap_derive/tests/custom-string-parsers.rs
new file mode 100644
index 00000000..3379fb24
--- /dev/null
+++ b/clap_derive/tests/custom-string-parsers.rs
@@ -0,0 +1,309 @@
+// Copyright 2018 Guillaume Pinot (@TeXitoi) <texitoi@texitoi.eu>,
+// Kevin Knapp (@kbknapp) <kbknapp@gmail.com>, and
+// Andrew Hobden (@hoverbear) <andrew@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 clap::Clap;
+
+use std::ffi::{CString, OsStr, OsString};
+use std::num::ParseIntError;
+use std::path::PathBuf;
+
+#[derive(Clap, PartialEq, Debug)]
+struct PathOpt {
+    #[clap(short, long, parse(from_os_str))]
+    path: PathBuf,
+
+    #[clap(short, default_value = "../", parse(from_os_str))]
+    default_path: PathBuf,
+
+    #[clap(short, parse(from_os_str))]
+    vector_path: Vec<PathBuf>,
+
+    #[clap(short, parse(from_os_str))]
+    option_path_1: Option<PathBuf>,
+
+    #[clap(short = "q", parse(from_os_str))]
+    option_path_2: Option<PathBuf>,
+}
+
+#[test]
+fn test_path_opt_simple() {
+    assert_eq!(
+        PathOpt {
+            path: PathBuf::from("/usr/bin"),
+            default_path: PathBuf::from("../"),
+            vector_path: vec![
+                PathBuf::from("/a/b/c"),
+                PathBuf::from("/d/e/f"),
+                PathBuf::from("/g/h/i"),
+            ],
+            option_path_1: None,
+            option_path_2: Some(PathBuf::from("j.zip")),
+        },
+        PathOpt::parse_from(&[
+            "test", "-p", "/usr/bin", "-v", "/a/b/c", "-v", "/d/e/f", "-v", "/g/h/i", "-q",
+            "j.zip",
+        ])
+    );
+}
+
+fn parse_hex(input: &str) -> Result<u64, ParseIntError> {
+    u64::from_str_radix(input, 16)
+}
+
+#[derive(Clap, PartialEq, Debug)]
+struct HexOpt {
+    #[clap(short, parse(try_from_str = parse_hex))]
+    number: u64,
+}
+
+#[test]
+fn test_parse_hex() {
+    assert_eq!(
+        HexOpt { number: 5 },
+        HexOpt::parse_from(&["test", "-n", "5"])
+    );
+    assert_eq!(
+        HexOpt { number: 0xabcdef },
+        HexOpt::parse_from(&["test", "-n", "abcdef"])
+    );
+
+    let err = HexOpt::try_parse_from(&["test", "-n", "gg"]).unwrap_err();
+    assert!(err.message.contains("invalid digit found in string"), err);
+}
+
+fn custom_parser_1(_: &str) -> &'static str {
+    "A"
+}
+fn custom_parser_2(_: &str) -> Result<&'static str, u32> {
+    Ok("B")
+}
+fn custom_parser_3(_: &OsStr) -> &'static str {
+    "C"
+}
+fn custom_parser_4(_: &OsStr) -> Result<&'static str, String> {
+    Ok("D")
+}
+
+#[derive(Clap, PartialEq, Debug)]
+struct NoOpOpt {
+    #[clap(short, parse(from_str = custom_parser_1))]
+    a: &'static str,
+    #[clap(short, parse(try_from_str = custom_parser_2))]
+    b: &'static str,
+    #[clap(short, parse(from_os_str = custom_parser_3))]
+    c: &'static str,
+    #[clap(short, parse(try_from_os_str = custom_parser_4))]
+    d: &'static str,
+}
+
+#[test]
+fn test_every_custom_parser() {
+    assert_eq!(
+        NoOpOpt {
+            a: "A",
+            b: "B",
+            c: "C",
+            d: "D"
+        },
+        NoOpOpt::parse_from(&["test", "-a=?", "-b=?", "-c=?", "-d=?"])
+    );
+}
+
+// Note: can't use `Vec<u8>` directly, as clap would instead look for
+// conversion function from `&str` to `u8`.
+type Bytes = Vec<u8>;
+
+#[derive(Clap, PartialEq, Debug)]
+struct DefaultedOpt {
+    #[clap(short, parse(from_str))]
+    bytes: Bytes,
+
+    #[clap(short, parse(try_from_str))]
+    integer: u64,
+
+    #[clap(short, parse(from_os_str))]
+    path: PathBuf,
+}
+
+#[test]
+fn test_parser_with_default_value() {
+    assert_eq!(
+        DefaultedOpt {
+            bytes: b"E\xc2\xb2=p\xc2\xb2c\xc2\xb2+m\xc2\xb2c\xe2\x81\xb4".to_vec(),
+            integer: 9000,
+            path: PathBuf::from("src/lib.rs"),
+        },
+        DefaultedOpt::parse_from(&[
+            "test",
+            "-b",
+            "E²=p²c²+m²c⁴",
+            "-i",
+            "9000",
+            "-p",
+            "src/lib.rs",
+        ])
+    );
+}
+
+#[derive(PartialEq, Debug)]
+struct Foo(u8);
+
+fn foo(value: u64) -> Foo {
+    Foo(value as u8)
+}
+
+#[derive(Clap, PartialEq, Debug)]
+struct Occurrences {
+    #[clap(short, long, parse(from_occurrences))]
+    signed: i32,
+
+    #[clap(short, parse(from_occurrences))]
+    little_signed: i8,
+
+    #[clap(short, parse(from_occurrences))]
+    unsigned: usize,
+
+    #[clap(short = "r", parse(from_occurrences))]
+    little_unsigned: u8,
+
+    #[clap(short, long, parse(from_occurrences = foo))]
+    custom: Foo,
+}
+
+#[test]
+fn test_parser_occurrences() {
+    assert_eq!(
+        Occurrences {
+            signed: 3,
+            little_signed: 1,
+            unsigned: 0,
+            little_unsigned: 4,
+            custom: Foo(5),
+        },
+        Occurrences::parse_from(&[
+            "test", "-s", "--signed", "--signed", "-l", "-rrrr", "-cccc", "--custom",
+        ])
+    );
+}
+
+#[test]
+fn test_custom_bool() {
+    fn parse_bool(s: &str) -> Result<bool, String> {
+        match s {
+            "true" => Ok(true),
+            "false" => Ok(false),
+            _ => Err(format!("invalid bool {}", s)),
+        }
+    }
+    #[derive(Clap, PartialEq, Debug)]
+    struct Opt {
+        #[clap(short, parse(try_from_str = parse_bool))]
+        debug: bool,
+        #[clap(
+            short,
+            default_value = "false",
+            parse(try_from_str = parse_bool)
+        )]
+        verbose: bool,
+        #[clap(short, parse(try_from_str = parse_bool))]
+        tribool: Option<bool>,
+        #[clap(short, parse(try_from_str = parse_bool))]
+        bitset: Vec<bool>,
+    }
+
+    assert!(Opt::try_parse_from(&["test"]).is_err());
+    assert!(Opt::try_parse_from(&["test", "-d"]).is_err());
+    assert!(Opt::try_parse_from(&["test", "-dfoo"]).is_err());
+    assert_eq!(
+        Opt {
+            debug: false,
+            verbose: false,
+            tribool: None,
+            bitset: vec![],
+        },
+        Opt::parse_from(&["test", "-dfalse"])
+    );
+    assert_eq!(
+        Opt {
+            debug: true,
+            verbose: false,
+            tribool: None,
+            bitset: vec![],
+        },
+        Opt::parse_from(&["test", "-dtrue"])
+    );
+    assert_eq!(
+        Opt {
+            debug: true,
+            verbose: false,
+            tribool: None,
+            bitset: vec![],
+        },
+        Opt::parse_from(&["test", "-dtrue", "-vfalse"])
+    );
+    assert_eq!(
+        Opt {
+            debug: true,
+            verbose: true,
+            tribool: None,
+            bitset: vec![],
+        },
+        Opt::parse_from(&["test", "-dtrue", "-vtrue"])
+    );
+    assert_eq!(
+        Opt {
+            debug: true,
+            verbose: false,
+            tribool: Some(false),
+            bitset: vec![],
+        },
+        Opt::parse_from(&["test", "-dtrue", "-tfalse"])
+    );
+    assert_eq!(
+        Opt {
+            debug: true,
+            verbose: false,
+            tribool: Some(true),
+            bitset: vec![],
+        },
+        Opt::parse_from(&["test", "-dtrue", "-ttrue"])
+    );
+    assert_eq!(
+        Opt {
+            debug: true,
+            verbose: false,
+            tribool: None,
+            bitset: vec![false, true, false, false],
+        },
+        Opt::parse_from(&["test", "-dtrue", "-bfalse", "-btrue", "-bfalse", "-bfalse"])
+    );
+}
+
+#[test]
+fn test_cstring() {
+    use clap::IntoApp;
+
+    #[derive(Clap)]
+    struct Opt {
+        #[clap(parse(try_from_str = CString::new))]
+        c_string: CString,
+    }
+
+    assert!(Opt::try_parse_from(&["test"]).is_err());
+    assert_eq!(
+        Opt::parse_from(&["test", "bla"]).c_string.to_bytes(),
+        b"bla"
+    );
+    assert!(Opt::try_parse_from(&["test", "bla\0bla"]).is_err());
+}
diff --git a/clap_derive/tests/deny-warnings.rs b/clap_derive/tests/deny-warnings.rs
new file mode 100644
index 00000000..68643752
--- /dev/null
+++ b/clap_derive/tests/deny-warnings.rs
@@ -0,0 +1,55 @@
+// Copyright 2018 Guillaume Pinot (@TeXitoi) <texitoi@texitoi.eu>,
+// Kevin Knapp (@kbknapp) <kbknapp@gmail.com>, and
+// Andrew Hobden (@hoverbear) <andrew@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.
+
+#![deny(warnings)]
+
+extern crate clap;
+
+use clap::Clap;
+
+fn try_str(s: &str) -> Result<String, std::convert::Infallible> {
+    Ok(s.into())
+}
+
+#[test]
+fn warning_never_struct() {
+    #[derive(Debug, PartialEq, Clap)]
+    struct Opt {
+        #[clap(parse(try_from_str = try_str))]
+        s: String,
+    }
+    assert_eq!(
+        Opt {
+            s: "foo".to_string()
+        },
+        Opt::parse_from(&["test", "foo"])
+    );
+}
+
+#[test]
+fn warning_never_enum() {
+    #[derive(Debug, PartialEq, Clap)]
+    enum Opt {
+        Foo {
+            #[clap(parse(try_from_str = try_str))]
+            s: String,
+        },
+    }
+    assert_eq!(
+        Opt::Foo {
+            s: "foo".to_string()
+        },
+        Opt::parse_from(&["test", "foo", "foo"])
+    );
+}
diff --git a/clap_derive/tests/doc-comments-help.rs b/clap_derive/tests/doc-comments-help.rs
new file mode 100644
index 00000000..81b7fb04
--- /dev/null
+++ b/clap_derive/tests/doc-comments-help.rs
@@ -0,0 +1,116 @@
+// Copyright 2018 Guillaume Pinot (@TeXitoi) <texitoi@texitoi.eu>,
+// Kevin Knapp (@kbknapp) <kbknapp@gmail.com>, and
+// Andrew Hobden (@hoverbear) <andrew@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.
+
+mod utils;
+
+use clap::Clap;
+use utils::*;
+
+#[test]
+fn doc_comments() {
+    /// Lorem ipsum
+    #[derive(Clap, PartialEq, Debug)]
+    struct LoremIpsum {
+        /// Fooify a bar
+        /// and a baz
+        #[clap(short, long)]
+        foo: bool,
+    }
+
+    let help = get_long_help::<LoremIpsum>();
+    assert!(help.contains("Lorem ipsum"));
+    assert!(help.contains("Fooify a bar and a baz"));
+}
+
+#[test]
+fn help_is_better_than_comments() {
+    /// Lorem ipsum
+    #[derive(Clap, PartialEq, Debug)]
+    #[clap(name = "lorem-ipsum", about = "Dolor sit amet")]
+    struct LoremIpsum {
+        /// Fooify a bar
+        #[clap(short, long, help = "DO NOT PASS A BAR UNDER ANY CIRCUMSTANCES")]
+        foo: bool,
+    }
+
+    let help = get_long_help::<LoremIpsum>();
+    assert!(help.contains("Dolor sit amet"));
+    assert!(!help.contains("Lorem ipsum"));
+    assert!(help.contains("DO NOT PASS A BAR"));
+}
+
+#[test]
+fn empty_line_in_doc_comment_is_double_linefeed() {
+    /// Foo.
+    ///
+    /// Bar
+    #[derive(Clap, PartialEq, Debug)]
+    #[clap(name = "lorem-ipsum", no_version)]
+    struct LoremIpsum {}
+
+    let help = get_long_help::<LoremIpsum>();
+    assert!(help.starts_with("lorem-ipsum \nFoo.\n\nBar\n\nUSAGE:"));
+}
+
+#[test]
+fn field_long_doc_comment_both_help_long_help() {
+    /// Lorem ipsumclap
+    #[derive(Clap, PartialEq, Debug)]
+    #[clap(name = "lorem-ipsum", about = "Dolor sit amet")]
+    struct LoremIpsum {
+        /// DO NOT PASS A BAR UNDER ANY CIRCUMSTANCES.
+        ///
+        /// Or something else
+        #[clap(long)]
+        foo: bool,
+    }
+
+    let short_help = get_help::<LoremIpsum>();
+    let long_help = get_long_help::<LoremIpsum>();
+
+    assert!(short_help.contains("CIRCUMSTANCES"));
+    assert!(!short_help.contains("CIRCUMSTANCES."));
+    assert!(!short_help.contains("Or something else"));
+    assert!(long_help.contains("DO NOT PASS A BAR UNDER ANY CIRCUMSTANCES"));
+    assert!(long_help.contains("Or something else"));
+}
+
+#[test]
+fn top_long_doc_comment_both_help_long_help() {
+    /// Lorem ipsumclap
+    #[derive(Clap, Debug)]
+    #[clap(name = "lorem-ipsum", about = "Dolor sit amet")]
+    struct LoremIpsum {
+        #[clap(subcommand)]
+        foo: SubCommand,
+    }
+
+    #[derive(Clap, Debug)]
+    pub enum SubCommand {
+        /// DO NOT PASS A BAR UNDER ANY CIRCUMSTANCES
+        ///
+        /// Or something else
+        Foo {
+            #[clap(help = "foo")]
+            bars: Vec<String>,
+        },
+    }
+
+    let short_help = get_help::<LoremIpsum>();
+    let long_help = get_subcommand_long_help::<LoremIpsum>("foo");
+
+    assert!(!short_help.contains("Or something else"));
+    assert!(long_help.contains("DO NOT PASS A BAR UNDER ANY CIRCUMSTANCES"));
+    assert!(long_help.contains("Or something else"));
+}
diff --git a/clap_derive/tests/explicit_name_no_renaming.rs b/clap_derive/tests/explicit_name_no_renaming.rs
new file mode 100644
index 00000000..56fa9fd3
--- /dev/null
+++ b/clap_derive/tests/explicit_name_no_renaming.rs
@@ -0,0 +1,32 @@
+mod utils;
+
+use clap::Clap;
+use utils::*;
+
+#[test]
+fn explicit_short_long_no_rename() {
+    #[derive(Clap, PartialEq, Debug)]
+    struct Opt {
+        #[clap(short = ".", long = ".foo")]
+        foo: Vec<String>,
+    }
+
+    assert_eq!(
+        Opt {
+            foo: vec!["short".into(), "long".into()]
+        },
+        Opt::parse_from(&["test", "-.", "short", "--.foo", "long"])
+    );
+}
+
+#[test]
+fn explicit_name_no_rename() {
+    #[derive(Clap, PartialEq, Debug)]
+    struct Opt {
+        #[clap(name = ".options")]
+        foo: Vec<String>,
+    }
+
+    let help = get_long_help::<Opt>();
+    assert!(help.contains("[.options]..."))
+}
diff --git a/clap_derive/tests/flags.rs b/clap_derive/tests/flags.rs
new file mode 100644
index 00000000..e973a234
--- /dev/null
+++ b/clap_derive/tests/flags.rs
@@ -0,0 +1,145 @@
+// Copyright 2018 Guillaume Pinot (@TeXitoi) <texitoi@texitoi.eu>,
+// Kevin Knapp (@kbknapp) <kbknapp@gmail.com>, and
+// Andrew Hobden (@hoverbear) <andrew@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 clap::Clap;
+
+#[test]
+fn unique_flag() {
+    #[derive(Clap, PartialEq, Debug)]
+    struct Opt {
+        #[clap(short, long)]
+        alice: bool,
+    }
+
+    assert_eq!(Opt { alice: false }, Opt::parse_from(&["test"]));
+    assert_eq!(Opt { alice: true }, Opt::parse_from(&["test", "-a"]));
+    assert_eq!(Opt { alice: true }, Opt::parse_from(&["test", "--alice"]));
+    assert!(Opt::try_parse_from(&["test", "-i"]).is_err());
+    assert!(Opt::try_parse_from(&["test", "-a", "foo"]).is_err());
+    assert!(Opt::try_parse_from(&["test", "-a", "-a"]).is_err());
+    assert!(Opt::try_parse_from(&["test", "-a", "--alice"]).is_err());
+}
+
+#[test]
+fn multiple_flag() {
+    #[derive(Clap, PartialEq, Debug)]
+    struct Opt {
+        #[clap(short, long, parse(from_occurrences))]
+        alice: u64,
+        #[clap(short, long, parse(from_occurrences))]
+        bob: u8,
+    }
+
+    assert_eq!(Opt { alice: 0, bob: 0 }, Opt::parse_from(&["test"]));
+    assert_eq!(Opt { alice: 1, bob: 0 }, Opt::parse_from(&["test", "-a"]));
+    assert_eq!(
+        Opt { alice: 2, bob: 0 },
+        Opt::parse_from(&["test", "-a", "-a"])
+    );
+    assert_eq!(
+        Opt { alice: 2, bob: 2 },
+        Opt::parse_from(&["test", "-a", "--alice", "-bb"])
+    );
+    assert_eq!(
+        Opt { alice: 3, bob: 1 },
+        Opt::parse_from(&["test", "-aaa", "--bob"])
+    );
+    assert!(Opt::try_parse_from(&["test", "-i"]).is_err());
+    assert!(Opt::try_parse_from(&["test", "-a", "foo"]).is_err());
+}
+
+fn parse_from_flag(b: bool) -> std::sync::atomic::AtomicBool {
+    std::sync::atomic::AtomicBool::new(b)
+}
+
+#[test]
+fn non_bool_flags() {
+    #[derive(Clap, Debug)]
+    struct Opt {
+        #[clap(short, long, parse(from_flag = parse_from_flag))]
+        alice: std::sync::atomic::AtomicBool,
+        #[clap(short, long, parse(from_flag))]
+        bob: std::sync::atomic::AtomicBool,
+    }
+
+    let falsey = Opt::parse_from(&["test"]);
+    assert!(!falsey.alice.load(std::sync::atomic::Ordering::Relaxed));
+    assert!(!falsey.bob.load(std::sync::atomic::Ordering::Relaxed));
+
+    let alice = Opt::parse_from(&["test", "-a"]);
+    assert!(alice.alice.load(std::sync::atomic::Ordering::Relaxed));
+    assert!(!alice.bob.load(std::sync::atomic::Ordering::Relaxed));
+
+    let bob = Opt::parse_from(&["test", "-b"]);
+    assert!(!bob.alice.load(std::sync::atomic::Ordering::Relaxed));
+    assert!(bob.bob.load(std::sync::atomic::Ordering::Relaxed));
+
+    let both = Opt::parse_from(&["test", "-b", "-a"]);
+    assert!(both.alice.load(std::sync::atomic::Ordering::Relaxed));
+    assert!(both.bob.load(std::sync::atomic::Ordering::Relaxed));
+}
+
+#[test]
+fn combined_flags() {
+    #[derive(Clap, PartialEq, Debug)]
+    struct Opt {
+        #[clap(short, long)]
+        alice: bool,
+        #[clap(short, long, parse(from_occurrences))]
+        bob: u64,
+    }
+
+    assert_eq!(
+        Opt {
+            alice: false,
+            bob: 0
+        },
+        Opt::parse_from(&["test"])
+    );
+    assert_eq!(
+        Opt {
+            alice: true,
+            bob: 0
+        },
+        Opt::parse_from(&["test", "-a"])
+    );
+    assert_eq!(
+        Opt {
+            alice: true,
+            bob: 0
+        },
+        Opt::parse_from(&["test", "-a"])
+    );
+    assert_eq!(
+        Opt {
+            alice: false,
+            bob: 1
+        },
+        Opt::parse_from(&["test", "-b"])
+    );
+    assert_eq!(
+        Opt {
+            alice: true,
+            bob: 1
+        },
+        Opt::parse_from(&["test", "--alice", "--bob"])
+    );
+    assert_eq!(
+        Opt {
+            alice: true,
+            bob: 4
+        },
+        Opt::parse_from(&["test", "-bb", "-a", "-bb"])
+    );
+}
diff --git a/clap_derive/tests/flatten.rs b/clap_derive/tests/flatten.rs
new file mode 100644
index 00000000..c35145df
--- /dev/null
+++ b/clap_derive/tests/flatten.rs
@@ -0,0 +1,99 @@
+// Copyright 2018 Guillaume Pinot (@TeXitoi) <texitoi@texitoi.eu>,
+// Kevin Knapp (@kbknapp) <kbknapp@gmail.com>, and
+// Andrew Hobden (@hoverbear) <andrew@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 clap::Clap;
+
+#[test]
+fn flatten() {
+    #[derive(Clap, PartialEq, Debug)]
+    struct Common {
+        arg: i32,
+    }
+
+    #[derive(Clap, PartialEq, Debug)]
+    struct Opt {
+        #[clap(flatten)]
+        common: Common,
+    }
+    assert_eq!(
+        Opt {
+            common: Common { arg: 42 }
+        },
+        Opt::parse_from(&["test", "42"])
+    );
+    assert!(Opt::try_parse_from(&["test"]).is_err());
+    assert!(Opt::try_parse_from(&["test", "42", "24"]).is_err());
+}
+
+#[test]
+#[should_panic]
+fn flatten_twice() {
+    #[derive(Clap, PartialEq, Debug)]
+    struct Common {
+        arg: i32,
+    }
+
+    #[derive(Clap, PartialEq, Debug)]
+    struct Opt {
+        #[clap(flatten)]
+        c1: Common,
+        // Defines "arg" twice, so this should not work.
+        #[clap(flatten)]
+        c2: Common,
+    }
+    Opt::parse_from(&["test", "42", "43"]);
+}
+
+#[test]
+fn flatten_in_subcommand() {
+    #[derive(Clap, PartialEq, Debug)]
+    struct Common {
+        arg: i32,
+    }
+
+    #[derive(Clap, PartialEq, Debug)]
+    struct Add {
+        #[clap(short)]
+        interactive: bool,
+        #[clap(flatten)]
+        common: Common,
+    }
+
+    #[derive(Clap, PartialEq, Debug)]
+    enum Opt {
+        Fetch {
+            #[clap(short)]
+            all: bool,
+            #[clap(flatten)]
+            common: Common,
+        },
+
+        Add(Add),
+    }
+
+    assert_eq!(
+        Opt::Fetch {
+            all: false,
+            common: Common { arg: 42 }
+        },
+        Opt::parse_from(&["test", "fetch", "42"])
+    );
+    assert_eq!(
+        Opt::Add(Add {
+            interactive: true,
+            common: Common { arg: 43 }
+        }),
+        Opt::parse_from(&["test", "add", "-i", "43"])
+    );
+}
diff --git a/clap_derive/tests/issues.rs b/clap_derive/tests/issues.rs
new file mode 100644
index 00000000..90aeaebb
--- /dev/null
+++ b/clap_derive/tests/issues.rs
@@ -0,0 +1,50 @@
+// https://github.com/TeXitoi/structopt/issues/151
+// https://github.com/TeXitoi/structopt/issues/289
+
+#[test]
+fn issue_151() {
+    use clap::{ArgGroup, Clap, IntoApp};
+
+    #[derive(Clap, Debug)]
+    #[clap(group = ArgGroup::with_name("verb").required(true).multiple(true))]
+    struct Opt {
+        #[clap(long, group = "verb")]
+        foo: bool,
+        #[clap(long, group = "verb")]
+        bar: bool,
+    }
+
+    #[derive(Debug, Clap)]
+    struct Cli {
+        #[clap(flatten)]
+        a: Opt,
+    }
+
+    assert!(Cli::try_parse_from(&["test"]).is_err());
+    assert!(Cli::try_parse_from(&["test", "--foo"]).is_ok());
+    assert!(Cli::try_parse_from(&["test", "--bar"]).is_ok());
+    assert!(Cli::try_parse_from(&["test", "--zebra"]).is_err());
+}
+
+#[test]
+fn issue_289() {
+    use clap::{AppSettings, Clap, IntoApp};
+
+    #[derive(Clap)]
+    #[clap(setting = AppSettings::InferSubcommands)]
+    enum Args {
+        SomeCommand(SubSubCommand),
+        AnotherCommand,
+    }
+
+    #[derive(Clap)]
+    #[clap(setting = AppSettings::InferSubcommands)]
+    enum SubSubCommand {
+        TestCommand,
+    }
+
+    assert!(Args::try_parse_from(&["test", "some-command", "test-command"]).is_ok());
+    assert!(Args::try_parse_from(&["test", "some", "test-command"]).is_ok());
+    assert!(Args::try_parse_from(&["test", "some-command", "test"]).is_ok());
+    assert!(Args::try_parse_from(&["test", "some", "test"]).is_ok());
+}
diff --git a/clap_derive/tests/macro-errors.rs b/clap_derive/tests/macro-errors.rs
new file mode 100644
index 00000000..ae4f5a28
--- /dev/null
+++ b/clap_derive/tests/macro-errors.rs
@@ -0,0 +1,13 @@
+// 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
+
+#[rustversion::attr(any(not(stable), before(1.39)), ignore)]
+#[test]
+fn ui() {
+    let t = trybuild::TestCases::new();
+    t.compile_fail("tests/ui/*.rs");
+}
diff --git a/clap_derive/tests/nested-subcommands.rs b/clap_derive/tests/nested-subcommands.rs
new file mode 100644
index 00000000..d5869a85
--- /dev/null
+++ b/clap_derive/tests/nested-subcommands.rs
@@ -0,0 +1,196 @@
+// Copyright 2018 Guillaume Pinot (@TeXitoi) <texitoi@texitoi.eu>,
+// Kevin Knapp (@kbknapp) <kbknapp@gmail.com>, and
+// Andrew Hobden (@hoverbear) <andrew@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 clap::Clap;
+
+#[derive(Clap, PartialEq, Debug)]
+struct Opt {
+    #[clap(short, long)]
+    force: bool,
+    #[clap(short, long, parse(from_occurrences))]
+    verbose: u64,
+    #[clap(subcommand)]
+    cmd: Sub,
+}
+
+#[derive(Clap, PartialEq, Debug)]
+enum Sub {
+    Fetch {},
+    Add {},
+}
+
+#[derive(Clap, PartialEq, Debug)]
+struct Opt2 {
+    #[clap(short, long)]
+    force: bool,
+    #[clap(short, long, parse(from_occurrences))]
+    verbose: u64,
+    #[clap(subcommand)]
+    cmd: Option<Sub>,
+}
+
+#[test]
+fn test_no_cmd() {
+    let result = Opt::try_parse_from(&["test"]);
+    assert!(result.is_err());
+
+    assert_eq!(
+        Opt2 {
+            force: false,
+            verbose: 0,
+            cmd: None
+        },
+        Opt2::parse_from(&["test"])
+    );
+}
+
+#[test]
+fn test_fetch() {
+    assert_eq!(
+        Opt {
+            force: false,
+            verbose: 3,
+            cmd: Sub::Fetch {}
+        },
+        Opt::parse_from(&["test", "-vvv", "fetch"])
+    );
+    assert_eq!(
+        Opt {
+            force: true,
+            verbose: 0,
+            cmd: Sub::Fetch {}
+        },
+        Opt::parse_from(&["test", "--force", "fetch"])
+    );
+}
+
+#[test]
+fn test_add() {
+    assert_eq!(
+        Opt {
+            force: false,
+            verbose: 0,
+            cmd: Sub::Add {}
+        },
+        Opt::parse_from(&["test", "add"])
+    );
+    assert_eq!(
+        Opt {
+            force: false,
+            verbose: 2,
+            cmd: Sub::Add {}
+        },
+        Opt::parse_from(&["test", "-vv", "add"])
+    );
+}
+
+#[test]
+fn test_badinput() {
+    let result = Opt::try_parse_from(&["test", "badcmd"]);
+    assert!(result.is_err());
+    let result = Opt::try_parse_from(&["test", "add", "--verbose"]);
+    assert!(result.is_err());
+    let result = Opt::try_parse_from(&["test", "--badopt", "add"]);
+    assert!(result.is_err());
+    let result = Opt::try_parse_from(&["test", "add", "--badopt"]);
+    assert!(result.is_err());
+}
+
+#[derive(Clap, PartialEq, Debug)]
+struct Opt3 {
+    #[clap(short, long)]
+    all: bool,
+    #[clap(subcommand)]
+    cmd: Sub2,
+}
+
+#[derive(Clap, PartialEq, Debug)]
+enum Sub2 {
+    Foo {
+        file: String,
+        #[clap(subcommand)]
+        cmd: Sub3,
+    },
+    Bar {},
+}
+
+#[derive(Clap, PartialEq, Debug)]
+enum Sub3 {
+    Baz {},
+    Quux {},
+}
+
+#[test]
+fn test_subsubcommand() {
+    assert_eq!(
+        Opt3 {
+            all: true,
+            cmd: Sub2::Foo {
+                file: "lib.rs".to_string(),
+                cmd: Sub3::Quux {}
+            }
+        },
+        Opt3::parse_from(&["test", "--all", "foo", "lib.rs", "quux"])
+    );
+}
+
+#[derive(Clap, PartialEq, Debug)]
+enum SubSubCmdWithOption {
+    Remote {
+        #[clap(subcommand)]
+        cmd: Option<Remote>,
+    },
+    Stash {
+        #[clap(subcommand)]
+        cmd: Stash,
+    },
+}
+#[derive(Clap, PartialEq, Debug)]
+enum Remote {
+    Add { name: String, url: String },
+    Remove { name: String },
+}
+
+#[derive(Clap, PartialEq, Debug)]
+enum Stash {
+    Save,
+    Pop,
+}
+
+#[test]
+fn sub_sub_cmd_with_option() {
+    fn make(args: &[&str]) -> Option<SubSubCmdWithOption> {
+        use clap::{FromArgMatches, IntoApp};
+
+        SubSubCmdWithOption::try_parse_from(args).ok()
+    }
+    assert_eq!(
+        Some(SubSubCmdWithOption::Remote { cmd: None }),
+        make(&["", "remote"])
+    );
+    assert_eq!(
+        Some(SubSubCmdWithOption::Remote {
+            cmd: Some(Remote::Add {
+                name: "origin".into(),
+                url: "http".into()
+            })
+        }),
+        make(&["", "remote", "add", "origin", "http"])
+    );
+    assert_eq!(
+        Some(SubSubCmdWithOption::Stash { cmd: Stash::Save }),
+        make(&["", "stash", "save"])
+    );
+    assert_eq!(None, make(&["", "stash"]));
+}
diff --git a/clap_derive/tests/non_literal_attributes.rs b/clap_derive/tests/non_literal_attributes.rs
new file mode 100644
index 00000000..341e3b70
--- /dev/null
+++ b/clap_derive/tests/non_literal_attributes.rs
@@ -0,0 +1,149 @@
+// Copyright 2018 Guillaume Pinot (@TeXitoi) <texitoi@texitoi.eu>,
+// Kevin Knapp (@kbknapp) <kbknapp@gmail.com>, and
+// Andrew Hobden (@hoverbear) <andrew@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 clap::{AppSettings, Clap};
+use std::num::ParseIntError;
+
+pub const DISPLAY_ORDER: usize = 2;
+
+// Check if the global settings compile
+#[derive(Clap, Debug, PartialEq, Eq)]
+#[clap(global_setting = AppSettings::ColoredHelp)]
+struct Opt {
+    #[clap(
+        long = "x",
+        display_order = DISPLAY_ORDER,
+        next_line_help = true,
+        default_value = "0",
+        require_equals = true
+    )]
+    x: i32,
+
+    #[clap(short = "l", long = "level", aliases = &["set-level", "lvl"])]
+    level: String,
+
+    #[clap(long("values"))]
+    values: Vec<i32>,
+
+    #[clap(name = "FILE", requires_if("FILE", "values"))]
+    files: Vec<String>,
+}
+
+#[test]
+fn test_slice() {
+    assert_eq!(
+        Opt {
+            x: 0,
+            level: "1".to_string(),
+            files: Vec::new(),
+            values: vec![],
+        },
+        Opt::parse_from(&["test", "-l", "1"])
+    );
+    assert_eq!(
+        Opt {
+            x: 0,
+            level: "1".to_string(),
+            files: Vec::new(),
+            values: vec![],
+        },
+        Opt::parse_from(&["test", "--level", "1"])
+    );
+    assert_eq!(
+        Opt {
+            x: 0,
+            level: "1".to_string(),
+            files: Vec::new(),
+            values: vec![],
+        },
+        Opt::parse_from(&["test", "--set-level", "1"])
+    );
+    assert_eq!(
+        Opt {
+            x: 0,
+            level: "1".to_string(),
+            files: Vec::new(),
+            values: vec![],
+        },
+        Opt::parse_from(&["test", "--lvl", "1"])
+    );
+}
+
+#[test]
+fn test_multi_args() {
+    assert_eq!(
+        Opt {
+            x: 0,
+            level: "1".to_string(),
+            files: vec!["file".to_string()],
+            values: vec![],
+        },
+        Opt::parse_from(&["test", "-l", "1", "file"])
+    );
+    assert_eq!(
+        Opt {
+            x: 0,
+            level: "1".to_string(),
+            files: vec!["FILE".to_string()],
+            values: vec![1],
+        },
+        Opt::parse_from(&["test", "-l", "1", "--values", "1", "--", "FILE"])
+    );
+}
+
+#[test]
+fn test_multi_args_fail() {
+    let result = Opt::try_parse_from(&["test", "-l", "1", "--", "FILE"]);
+    assert!(result.is_err());
+}
+
+#[test]
+fn test_bool() {
+    assert_eq!(
+        Opt {
+            x: 1,
+            level: "1".to_string(),
+            files: vec![],
+            values: vec![],
+        },
+        Opt::parse_from(&["test", "-l", "1", "--x=1"])
+    );
+    let result = Opt::try_parse_from(&["test", "-l", "1", "--x", "1"]);
+    assert!(result.is_err());
+}
+
+fn parse_hex(input: &str) -> Result<u64, ParseIntError> {
+    u64::from_str_radix(input, 16)
+}
+
+#[derive(Clap, PartialEq, Debug)]
+struct HexOpt {
+    #[clap(short = "n", parse(try_from_str = parse_hex))]
+    number: u64,
+}
+
+#[test]
+fn test_parse_hex_function_path() {
+    assert_eq!(
+        HexOpt { number: 5 },
+        HexOpt::parse_from(&["test", "-n", "5"])
+    );
+    assert_eq!(
+        HexOpt { number: 0xabcdef },
+        HexOpt::parse_from(&["test", "-n", "abcdef"])
+    );
+
+    let err = HexOpt::try_parse_from(&["test", "-n", "gg"]).unwrap_err();
+    assert!(err.message.contains("invalid digit found in string"), err);
+}
diff --git a/clap_derive/tests/options.rs b/clap_derive/tests/options.rs
new file mode 100644
index 00000000..26cc66ef
--- /dev/null
+++ b/clap_derive/tests/options.rs
@@ -0,0 +1,285 @@
+// Copyright 2018 Guillaume Pinot (@TeXitoi) <texitoi@texitoi.eu>,
+// Kevin Knapp (@kbknapp) <kbknapp@gmail.com>, and
+// Andrew Hobden (@hoverbear) <andrew@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 clap::Clap;
+
+#[test]
+fn required_option() {
+    #[derive(Clap, PartialEq, Debug)]
+    struct Opt {
+        #[clap(short, long)]
+        arg: i32,
+    }
+    assert_eq!(Opt { arg: 42 }, Opt::parse_from(&["test", "-a42"]));
+    assert_eq!(Opt { arg: 42 }, Opt::parse_from(&["test", "-a", "42"]));
+    assert_eq!(Opt { arg: 42 }, Opt::parse_from(&["test", "--arg", "42"]));
+    assert!(Opt::try_parse_from(&["test"]).is_err());
+    assert!(Opt::try_parse_from(&["test", "-a42", "-a24"]).is_err());
+}
+
+#[test]
+fn optional_option() {
+    #[derive(Clap, PartialEq, Debug)]
+    struct Opt {
+        #[clap(short)]
+        arg: Option<i32>,
+    }
+    assert_eq!(Opt { arg: Some(42) }, Opt::parse_from(&["test", "-a42"]));
+    assert_eq!(Opt { arg: None }, Opt::parse_from(&["test"]));
+    assert!(Opt::try_parse_from(&["test", "-a42", "-a24"]).is_err());
+}
+
+#[test]
+fn option_with_default() {
+    #[derive(Clap, PartialEq, Debug)]
+    struct Opt {
+        #[clap(short, default_value = "42")]
+        arg: i32,
+    }
+    assert_eq!(Opt { arg: 24 }, Opt::parse_from(&["test", "-a24"]));
+    assert_eq!(Opt { arg: 42 }, Opt::parse_from(&["test"]));
+    assert!(Opt::try_parse_from(&["test", "-a42", "-a24"]).is_err());
+}
+
+#[test]
+fn option_with_raw_default() {
+    #[derive(Clap, PartialEq, Debug)]
+    struct Opt {
+        #[clap(short, default_value = "42")]
+        arg: i32,
+    }
+    assert_eq!(Opt { arg: 24 }, Opt::parse_from(&["test", "-a24"]));
+    assert_eq!(Opt { arg: 42 }, Opt::parse_from(&["test"]));
+    assert!(Opt::try_parse_from(&["test", "-a42", "-a24"]).is_err());
+}
+
+#[test]
+fn options() {
+    #[derive(Clap, PartialEq, Debug)]
+    struct Opt {
+        #[clap(short, long)]
+        arg: Vec<i32>,
+    }
+    assert_eq!(Opt { arg: vec![24] }, Opt::parse_from(&["test", "-a24"]));
+    assert_eq!(Opt { arg: vec![] }, Opt::parse_from(&["test"]));
+    assert_eq!(
+        Opt { arg: vec![24, 42] },
+        Opt::parse_from(&["test", "-a24", "--arg", "42"])
+    );
+}
+
+#[test]
+fn default_value() {
+    #[derive(Clap, PartialEq, Debug)]
+    struct Opt {
+        #[clap(short, default_value = "test")]
+        arg: String,
+    }
+    assert_eq!(Opt { arg: "test".into() }, Opt::parse_from(&["test"]));
+    assert_eq!(
+        Opt { arg: "foo".into() },
+        Opt::parse_from(&["test", "-afoo"])
+    );
+}
+
+#[test]
+fn option_from_str() {
+    #[derive(Debug, PartialEq)]
+    struct A;
+
+    impl<'a> From<&'a str> for A {
+        fn from(_: &str) -> A {
+            A
+        }
+    }
+
+    #[derive(Debug, Clap, PartialEq)]
+    struct Opt {
+        #[clap(parse(from_str))]
+        a: Option<A>,
+    }
+
+    assert_eq!(Opt { a: None }, Opt::parse_from(&["test"]));
+    assert_eq!(Opt { a: Some(A) }, Opt::parse_from(&["test", "foo"]));
+}
+
+#[test]
+fn optional_argument_for_optional_option() {
+    use clap::IntoApp;
+
+    #[derive(Clap, PartialEq, Debug)]
+    struct Opt {
+        #[clap(short)]
+        #[allow(clippy::option_option)]
+        arg: Option<Option<i32>>,
+    }
+    assert_eq!(
+        Opt {
+            arg: Some(Some(42))
+        },
+        Opt::parse_from(&["test", "-a42"])
+    );
+    assert_eq!(Opt { arg: Some(None) }, Opt::parse_from(&["test", "-a"]));
+    assert_eq!(Opt { arg: None }, Opt::parse_from(&["test"]));
+    assert!(Opt::try_parse_from(&["test", "-a42", "-a24"]).is_err());
+}
+
+#[test]
+fn two_option_options() {
+    #[derive(Clap, PartialEq, Debug)]
+    struct Opt {
+        #[clap(short)]
+        arg: Option<Option<i32>>,
+
+        #[clap(long)]
+        field: Option<Option<String>>,
+    }
+    assert_eq!(
+        Opt {
+            arg: Some(Some(42)),
+            field: Some(Some("f".into()))
+        },
+        Opt::parse_from(&["test", "-a42", "--field", "f"])
+    );
+    assert_eq!(
+        Opt {
+            arg: Some(Some(42)),
+            field: Some(None)
+        },
+        Opt::parse_from(&["test", "-a42", "--field"])
+    );
+    assert_eq!(
+        Opt {
+            arg: Some(None),
+            field: Some(None)
+        },
+        Opt::parse_from(&["test", "-a", "--field"])
+    );
+    assert_eq!(
+        Opt {
+            arg: Some(None),
+            field: Some(Some("f".into()))
+        },
+        Opt::parse_from(&["test", "-a", "--field", "f"])
+    );
+    assert_eq!(
+        Opt {
+            arg: None,
+            field: Some(None)
+        },
+        Opt::parse_from(&["test", "--field"])
+    );
+    assert_eq!(
+        Opt {
+            arg: None,
+            field: None
+        },
+        Opt::parse_from(&["test"])
+    );
+}
+
+#[test]
+fn optional_vec() {
+    #[derive(Clap, PartialEq, Debug)]
+    struct Opt {
+        #[clap(short)]
+        arg: Option<Vec<i32>>,
+    }
+    assert_eq!(
+        Opt { arg: Some(vec![1]) },
+        Opt::parse_from(&["test", "-a", "1"])
+    );
+
+    assert_eq!(
+        Opt {
+            arg: Some(vec![1, 2])
+        },
+        Opt::parse_from(&["test", "-a1", "-a2"])
+    );
+
+    assert_eq!(
+        Opt {
+            arg: Some(vec![1, 2])
+        },
+        Opt::parse_from(&["test", "-a1", "-a2", "-a"])
+    );
+
+    assert_eq!(
+        Opt {
+            arg: Some(vec![1, 2])
+        },
+        Opt::parse_from(&["test", "-a1", "-a", "-a2"])
+    );
+
+    assert_eq!(
+        Opt {
+            arg: Some(vec![1, 2])
+        },
+        Opt::parse_from(&["test", "-a", "1", "2"])
+    );
+
+    assert_eq!(
+        Opt {
+            arg: Some(vec![1, 2, 3])
+        },
+        Opt::parse_from(&["test", "-a", "1", "2", "-a", "3"])
+    );
+
+    assert_eq!(Opt { arg: Some(vec![]) }, Opt::parse_from(&["test", "-a"]));
+
+    assert_eq!(
+        Opt { arg: Some(vec![]) },
+        Opt::parse_from(&["test", "-a", "-a"])
+    );
+
+    assert_eq!(Opt { arg: None }, Opt::parse_from(&["test"]));
+}
+
+#[test]
+fn two_optional_vecs() {
+    #[derive(Clap, PartialEq, Debug)]
+    struct Opt {
+        #[clap(short)]
+        arg: Option<Vec<i32>>,
+
+        #[clap(short)]
+        b: Option<Vec<i32>>,
+    }
+
+    assert_eq!(
+        Opt {
+            arg: Some(vec![1]),
+            b: Some(vec![])
+        },
+        Opt::parse_from(&["test", "-a", "1", "-b"])
+    );
+
+    assert_eq!(
+        Opt {
+            arg: Some(vec![1]),
+            b: Some(vec![])
+        },
+        Opt::parse_from(&["test", "-a", "-b", "-a1"])
+    );
+
+    assert_eq!(
+        Opt {
+            arg: Some(vec![1, 2]),
+            b: Some(vec![1, 2])
+        },
+        Opt::parse_from(&["test", "-a1", "-a2", "-b1", "-b2"])
+    );
+
+    assert_eq!(Opt { arg: None, b: None }, Opt::parse_from(&["test"]));
+}
diff --git a/clap_derive/tests/privacy.rs b/clap_derive/tests/privacy.rs
new file mode 100644
index 00000000..d6692960
--- /dev/null
+++ b/clap_derive/tests/privacy.rs
@@ -0,0 +1,36 @@
+// Copyright 2018 Guillaume Pinot (@TeXitoi) <texitoi@texitoi.eu>,
+// Kevin Knapp (@kbknapp) <kbknapp@gmail.com>, and
+// Andrew Hobden (@hoverbear) <andrew@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.
+
+mod options {
+    use clap::Clap;
+
+    #[derive(Debug, Clap)]
+    pub struct Options {
+        #[clap(subcommand)]
+        pub subcommand: super::subcommands::SubCommand,
+    }
+}
+
+mod subcommands {
+    use clap::Clap;
+
+    #[derive(Debug, Clap)]
+    pub enum SubCommand {
+        /// foo
+        Foo {
+            /// foo
+            bars: Vec<String>,
+        },
+    }
+}
diff --git a/clap_derive/tests/raw_bool_literal.rs b/clap_derive/tests/raw_bool_literal.rs
new file mode 100644
index 00000000..2daa35c7
--- /dev/null
+++ b/clap_derive/tests/raw_bool_literal.rs
@@ -0,0 +1,29 @@
+// 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 clap::Clap;
+
+#[test]
+fn raw_bool_literal() {
+    #[derive(Clap, Debug, PartialEq)]
+    #[clap(no_version, name = "raw_bool")]
+    struct Opt {
+        #[clap(raw(false))]
+        a: String,
+        #[clap(raw(true))]
+        b: String,
+    }
+
+    assert_eq!(
+        Opt {
+            a: "one".into(),
+            b: "--help".into()
+        },
+        Opt::parse_from(&["test", "one", "--", "--help"])
+    );
+}
diff --git a/clap_derive/tests/raw_idents.rs b/clap_derive/tests/raw_idents.rs
new file mode 100644
index 00000000..6e8d0008
--- /dev/null
+++ b/clap_derive/tests/raw_idents.rs
@@ -0,0 +1,17 @@
+use clap::Clap;
+
+#[test]
+fn raw_idents() {
+    #[derive(Clap, Debug, PartialEq)]
+    struct Opt {
+        #[clap(short, long)]
+        r#type: Vec<String>,
+    }
+
+    assert_eq!(
+        Opt {
+            r#type: vec!["long".into(), "short".into()]
+        },
+        Opt::parse_from(&["test", "--type", "long", "-t", "short"])
+    );
+}
diff --git a/clap_derive/tests/skip.rs b/clap_derive/tests/skip.rs
new file mode 100644
index 00000000..33b795aa
--- /dev/null
+++ b/clap_derive/tests/skip.rs
@@ -0,0 +1,148 @@
+// 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 clap::Clap;
+
+#[test]
+fn skip_1() {
+    #[derive(Clap, Debug, PartialEq)]
+    struct Opt {
+        #[clap(short)]
+        x: u32,
+        #[clap(skip)]
+        s: u32,
+    }
+
+    assert!(Opt::try_parse_from(&["test", "-x", "10", "20"]).is_err());
+    assert_eq!(
+        Opt::parse_from(&["test", "-x", "10"]),
+        Opt {
+            x: 10,
+            s: 0, // default
+        }
+    );
+}
+
+#[test]
+fn skip_2() {
+    #[derive(Clap, Debug, PartialEq)]
+    struct Opt {
+        #[clap(short)]
+        x: u32,
+        #[clap(skip)]
+        ss: String,
+        #[clap(skip)]
+        sn: u8,
+        y: u32,
+        #[clap(skip)]
+        sz: u16,
+        t: u32,
+    }
+
+    assert_eq!(
+        Opt::parse_from(&["test", "-x", "10", "20", "30"]),
+        Opt {
+            x: 10,
+            ss: String::from(""),
+            sn: 0,
+            y: 20,
+            sz: 0,
+            t: 30,
+        }
+    );
+}
+
+#[test]
+fn skip_enum() {
+    #[derive(Debug, PartialEq)]
+    #[allow(unused)]
+    enum Kind {
+        A,
+        B,
+    }
+
+    impl Default for Kind {
+        fn default() -> Self {
+            return Kind::B;
+        }
+    }
+
+    #[derive(Clap, Debug, PartialEq)]
+    pub struct Opt {
+        #[clap(long, short)]
+        number: u32,
+        #[clap(skip)]
+        k: Kind,
+        #[clap(skip)]
+        v: Vec<u32>,
+    }
+
+    assert_eq!(
+        Opt::parse_from(&["test", "-n", "10"]),
+        Opt {
+            number: 10,
+            k: Kind::B,
+            v: vec![],
+        }
+    );
+}
+
+#[test]
+fn skip_help_doc_comments() {
+    #[derive(Clap, Debug, PartialEq)]
+    pub struct Opt {
+        #[clap(skip, help = "internal_stuff")]
+        a: u32,
+
+        #[clap(skip, long_help = "internal_stuff\ndo not touch")]
+        b: u32,
+
+        /// Not meant to be used by clap.
+        ///
+        /// I want a default here.
+        #[clap(skip)]
+        c: u32,
+
+        #[clap(short, parse(try_from_str))]
+        n: u32,
+    }
+
+    assert_eq!(
+        Opt::parse_from(&["test", "-n", "10"]),
+        Opt {
+            n: 10,
+            a: 0,
+            b: 0,
+            c: 0,
+        }
+    );
+}
+
+#[test]
+fn skip_val() {
+    #[derive(Clap, Debug, PartialEq)]
+    pub struct Opt {
+        #[clap(long, short)]
+        number: u32,
+
+        #[clap(skip = "key")]
+        k: String,
+
+        #[clap(skip = vec![1, 2, 3])]
+        v: Vec<u32>,
+    }
+
+    assert_eq!(
+        Opt::parse_from(&["test", "-n", "10"]),
+        Opt {
+            number: 10,
+            k: "key".into(),
+            v: vec![1, 2, 3]
+        }
+    );
+}
diff --git a/clap_derive/tests/special_types.rs b/clap_derive/tests/special_types.rs
new file mode 100644
index 00000000..dad20742
--- /dev/null
+++ b/clap_derive/tests/special_types.rs
@@ -0,0 +1,73 @@
+//! Checks that types like `::std::option::Option` are not special
+
+use clap::Clap;
+
+#[rustversion::all(since(1.37), stable)]
+#[test]
+fn special_types_bool() {
+    mod inner {
+        #[allow(non_camel_case_types)]
+        #[derive(PartialEq, Debug)]
+        pub struct bool(pub String);
+
+        impl std::str::FromStr for self::bool {
+            type Err = String;
+
+            fn from_str(s: &str) -> Result<Self, Self::Err> {
+                Ok(self::bool(s.into()))
+            }
+        }
+    };
+
+    #[derive(Clap, PartialEq, Debug)]
+    struct Opt {
+        arg: inner::bool,
+    }
+
+    assert_eq!(
+        Opt {
+            arg: inner::bool("success".into())
+        },
+        Opt::parse_from(&["test", "success"])
+    );
+}
+
+#[test]
+fn special_types_option() {
+    fn parser(s: &str) -> Option<String> {
+        Some(s.to_string())
+    }
+
+    #[derive(Clap, PartialEq, Debug)]
+    struct Opt {
+        #[clap(parse(from_str = parser))]
+        arg: ::std::option::Option<String>,
+    }
+
+    assert_eq!(
+        Opt {
+            arg: Some("success".into())
+        },
+        Opt::parse_from(&["test", "success"])
+    );
+}
+
+#[test]
+fn special_types_vec() {
+    fn parser(s: &str) -> Vec<String> {
+        vec![s.to_string()]
+    }
+
+    #[derive(Clap, PartialEq, Debug)]
+    struct Opt {
+        #[clap(parse(from_str = parser))]
+        arg: ::std::vec::Vec<String>,
+    }
+
+    assert_eq!(
+        Opt {
+            arg: vec!["success".into()]
+        },
+        Opt::parse_from(&["test", "success"])
+    );
+}
diff --git a/clap_derive/tests/subcommands.rs b/clap_derive/tests/subcommands.rs
new file mode 100644
index 00000000..f32a9409
--- /dev/null
+++ b/clap_derive/tests/subcommands.rs
@@ -0,0 +1,209 @@
+// Copyright 2018 Guillaume Pinot (@TeXitoi) <texitoi@texitoi.eu>,
+// Kevin Knapp (@kbknapp) <kbknapp@gmail.com>, and
+// Andrew Hobden (@hoverbear) <andrew@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.
+
+mod utils;
+
+use clap::Clap;
+use utils::*;
+
+#[derive(Clap, PartialEq, Debug)]
+enum Opt {
+    /// Fetch stuff from GitHub
+    Fetch {
+        #[clap(long)]
+        all: bool,
+        #[clap(short, long)]
+        /// Overwrite local branches.
+        force: bool,
+        repo: String,
+    },
+
+    Add {
+        #[clap(short, long)]
+        interactive: bool,
+        #[clap(short, long)]
+        verbose: bool,
+    },
+}
+
+#[test]
+fn test_fetch() {
+    assert_eq!(
+        Opt::Fetch {
+            all: true,
+            force: false,
+            repo: "origin".to_string()
+        },
+        Opt::parse_from(&["test", "fetch", "--all", "origin"])
+    );
+    assert_eq!(
+        Opt::Fetch {
+            all: false,
+            force: true,
+            repo: "origin".to_string()
+        },
+        Opt::parse_from(&["test", "fetch", "-f", "origin"])
+    );
+}
+
+#[test]
+fn test_add() {
+    assert_eq!(
+        Opt::Add {
+            interactive: false,
+            verbose: false
+        },
+        Opt::parse_from(&["test", "add"])
+    );
+    assert_eq!(
+        Opt::Add {
+            interactive: true,
+            verbose: true
+        },
+        Opt::parse_from(&["test", "add", "-i", "-v"])
+    );
+}
+
+#[test]
+fn test_no_parse() {
+    let result = Opt::try_parse_from(&["test", "badcmd", "-i", "-v"]);
+    assert!(result.is_err());
+
+    let result = Opt::try_parse_from(&["test", "add", "--badoption"]);
+    assert!(result.is_err());
+
+    let result = Opt::try_parse_from(&["test"]);
+    assert!(result.is_err());
+}
+
+#[derive(Clap, PartialEq, Debug)]
+enum Opt2 {
+    DoSomething { arg: String },
+}
+
+#[test]
+/// This test is specifically to make sure that hyphenated subcommands get
+/// processed correctly.
+fn test_hyphenated_subcommands() {
+    assert_eq!(
+        Opt2::DoSomething {
+            arg: "blah".to_string()
+        },
+        Opt2::parse_from(&["test", "do-something", "blah"])
+    );
+}
+
+#[derive(Clap, PartialEq, Debug)]
+enum Opt3 {
+    Add,
+    Init,
+    Fetch,
+}
+
+#[test]
+fn test_null_commands() {
+    assert_eq!(Opt3::Add, Opt3::parse_from(&["test", "add"]));
+    assert_eq!(Opt3::Init, Opt3::parse_from(&["test", "init"]));
+    assert_eq!(Opt3::Fetch, Opt3::parse_from(&["test", "fetch"]));
+}
+
+#[derive(Clap, PartialEq, Debug)]
+#[clap(about = "Not shown")]
+struct Add {
+    file: String,
+}
+/// Not shown
+#[derive(Clap, PartialEq, Debug)]
+struct Fetch {
+    remote: String,
+}
+#[derive(Clap, PartialEq, Debug)]
+enum Opt4 {
+    // Not shown
+    /// Add a file
+    Add(Add),
+    Init,
+    /// download history from remote
+    Fetch(Fetch),
+}
+
+#[test]
+fn test_tuple_commands() {
+    use clap::IntoApp;
+
+    assert_eq!(
+        Opt4::Add(Add {
+            file: "f".to_string()
+        }),
+        Opt4::parse_from(&["test", "add", "f"])
+    );
+    assert_eq!(Opt4::Init, Opt4::parse_from(&["test", "init"]));
+    assert_eq!(
+        Opt4::Fetch(Fetch {
+            remote: "origin".to_string()
+        }),
+        Opt4::parse_from(&["test", "fetch", "origin"])
+    );
+
+    let output = get_long_help::<Opt4>();
+
+    assert!(output.contains("download history from remote"));
+    assert!(output.contains("Add a file"));
+    assert!(!output.contains("Not shown"));
+}
+
+#[test]
+fn enum_in_enum_subsubcommand() {
+    #[derive(Clap, Debug, PartialEq)]
+    pub enum Opt {
+        Daemon(DaemonCommand),
+    }
+
+    #[derive(Clap, Debug, PartialEq)]
+    pub enum DaemonCommand {
+        Start,
+        Stop,
+    }
+
+    let result = Opt::try_parse_from(&["test"]);
+    assert!(result.is_err());
+
+    let result = Opt::try_parse_from(&["test", "daemon"]);
+    assert!(result.is_err());
+
+    let result = Opt::parse_from(&["test", "daemon", "start"]);
+    assert_eq!(Opt::Daemon(DaemonCommand::Start), result);
+}
+
+#[test]
+fn flatten_enum() {
+    #[derive(Clap, Debug, PartialEq)]
+    struct Opt {
+        #[clap(flatten)]
+        sub_cmd: SubCmd,
+    }
+    #[derive(Clap, Debug, PartialEq)]
+    enum SubCmd {
+        Foo,
+        Bar,
+    }
+
+    assert!(Opt::try_parse_from(&["test"]).is_err());
+    assert_eq!(
+        Opt::parse_from(&["test", "foo"]),
+        Opt {
+            sub_cmd: SubCmd::Foo
+        }
+    );
+}
diff --git a/clap_derive/tests/ui/bool_default_value.rs b/clap_derive/tests/ui/bool_default_value.rs
new file mode 100644
index 00000000..502e93af
--- /dev/null
+++ b/clap_derive/tests/ui/bool_default_value.rs
@@ -0,0 +1,21 @@
+// 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 clap::Clap;
+
+#[derive(Clap, Debug)]
+#[clap(name = "basic")]
+struct Opt {
+    #[clap(short, default_value = true)]
+    b: bool,
+}
+
+fn main() {
+    let opt = Opt::parse();
+    println!("{:?}", opt);
+}
diff --git a/clap_derive/tests/ui/bool_default_value.stderr b/clap_derive/tests/ui/bool_default_value.stderr
new file mode 100644
index 00000000..33521d76
--- /dev/null
+++ b/clap_derive/tests/ui/bool_default_value.stderr
@@ -0,0 +1,11 @@
+error: default_value is meaningless for bool
+  --> $DIR/bool_default_value.rs:14:19
+   |
+14 |     #[clap(short, default_value = true)]
+   |                   ^^^^^^^^^^^^^
+
+error[E0277]: the trait bound `Opt: std::convert::From<clap::parse::matches::arg_matches::ArgMatches>` is not satisfied
+  --> $DIR/bool_default_value.rs:11:10
+   |
+11 | #[derive(Clap, Debug)]
+   |          ^^^^ the trait `std::convert::From<clap::parse::matches::arg_matches::ArgMatches>` is not implemented for `Opt`
diff --git a/clap_derive/tests/ui/bool_required.rs b/clap_derive/tests/ui/bool_required.rs
new file mode 100644
index 00000000..6cfc5867
--- /dev/null
+++ b/clap_derive/tests/ui/bool_required.rs
@@ -0,0 +1,21 @@
+// 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 clap::Clap;
+
+#[derive(Clap, Debug)]
+#[clap(name = "basic")]
+struct Opt {
+    #[clap(short, required = true)]
+    b: bool,
+}
+
+fn main() {
+    let opt = Opt::parse();
+    println!("{:?}", opt);
+}
diff --git a/clap_derive/tests/ui/bool_required.stderr b/clap_derive/tests/ui/bool_required.stderr
new file mode 100644
index 00000000..b95bcb30
--- /dev/null
+++ b/clap_derive/tests/ui/bool_required.stderr
@@ -0,0 +1,11 @@
+error: required is meaningless for bool
+  --> $DIR/bool_required.rs:14:19
+   |
+14 |     #[clap(short, required = true)]
+   |                   ^^^^^^^^
+
+error[E0277]: the trait bound `Opt: std::convert::From<clap::parse::matches::arg_matches::ArgMatches>` is not satisfied
+  --> $DIR/bool_required.rs:11:10
+   |
+11 | #[derive(Clap, Debug)]
+   |          ^^^^ the trait `std::convert::From<clap::parse::matches::arg_matches::ArgMatches>` is not implemented for `Opt`
diff --git a/clap_derive/tests/ui/clap_derive_empty_attr.rs b/clap_derive/tests/ui/clap_derive_empty_attr.rs
new file mode 100644
index 00000000..8acad7b2
--- /dev/null
+++ b/clap_derive/tests/ui/clap_derive_empty_attr.rs
@@ -0,0 +1,22 @@
+// 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 clap::Clap;
+
+#[derive(Clap, Debug)]
+#[clap(name = "basic")]
+struct Opt {
+    #[clap]
+    debug: bool,
+}
+
+fn main() {
+    let opt = Opt::parse();
+    println!("{:?}", opt);
+}
+
diff --git a/clap_derive/tests/ui/clap_derive_empty_attr.stderr b/clap_derive/tests/ui/clap_derive_empty_attr.stderr
new file mode 100644
index 00000000..b2dea36a
--- /dev/null
+++ b/clap_derive/tests/ui/clap_derive_empty_attr.stderr
@@ -0,0 +1,11 @@
+error: expected parentheses after `clap`
+  --> $DIR/clap_derive_empty_attr.rs:14:7
+   |
+14 |     #[clap]
+   |       ^^^^
+
+error[E0277]: the trait bound `Opt: std::convert::From<clap::parse::matches::arg_matches::ArgMatches>` is not satisfied
+  --> $DIR/clap_derive_empty_attr.rs:11:10
+   |
+11 | #[derive(Clap, Debug)]
+   |          ^^^^ the trait `std::convert::From<clap::parse::matches::arg_matches::ArgMatches>` is not implemented for `Opt`
diff --git a/clap_derive/tests/ui/clap_derive_name_value_attr.rs b/clap_derive/tests/ui/clap_derive_name_value_attr.rs
new file mode 100644
index 00000000..b497dbf5
--- /dev/null
+++ b/clap_derive/tests/ui/clap_derive_name_value_attr.rs
@@ -0,0 +1,22 @@
+// 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 clap::Clap;
+
+#[derive(Clap, Debug)]
+#[clap(name = "basic")]
+struct Opt {
+    #[clap = "short"]
+    debug: bool,
+}
+
+fn main() {
+    let opt = Opt::parse();
+    println!("{:?}", opt);
+}
+
diff --git a/clap_derive/tests/ui/clap_derive_name_value_attr.stderr b/clap_derive/tests/ui/clap_derive_name_value_attr.stderr
new file mode 100644
index 00000000..017c434c
--- /dev/null
+++ b/clap_derive/tests/ui/clap_derive_name_value_attr.stderr
@@ -0,0 +1,11 @@
+error: expected parentheses
+  --> $DIR/clap_derive_name_value_attr.rs:14:12
+   |
+14 |     #[clap = "short"]
+   |            ^
+
+error[E0277]: the trait bound `Opt: std::convert::From<clap::parse::matches::arg_matches::ArgMatches>` is not satisfied
+  --> $DIR/clap_derive_name_value_attr.rs:11:10
+   |
+11 | #[derive(Clap, Debug)]
+   |          ^^^^ the trait `std::convert::From<clap::parse::matches::arg_matches::ArgMatches>` is not implemented for `Opt`
diff --git a/clap_derive/tests/ui/flatten_and_doc.rs b/clap_derive/tests/ui/flatten_and_doc.rs
new file mode 100644
index 00000000..dea35c23
--- /dev/null
+++ b/clap_derive/tests/ui/flatten_and_doc.rs
@@ -0,0 +1,30 @@
+// 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 clap::Clap;
+
+#[derive(Clap, Debug)]
+struct DaemonOpts {
+    #[clap(short)]
+    user: String,
+    #[clap(short)]
+    group: String,
+}
+
+#[derive(Clap, Debug)]
+#[clap(name = "basic")]
+struct Opt {
+    /// Opts.
+    #[clap(flatten)]
+    opts: DaemonOpts,
+}
+
+fn main() {
+    let opt = Opt::parse();
+    println!("{:?}", opt);
+}
diff --git a/clap_derive/tests/ui/flatten_and_doc.stderr b/clap_derive/tests/ui/flatten_and_doc.stderr
new file mode 100644
index 00000000..f9b3d8e5
--- /dev/null
+++ b/clap_derive/tests/ui/flatten_and_doc.stderr
@@ -0,0 +1,11 @@
+error: methods and doc comments are not allowed for flattened entry
+  --> $DIR/flatten_and_doc.rs:23:12
+   |
+23 |     #[clap(flatten)]
+   |            ^^^^^^^
+
+error[E0277]: the trait bound `Opt: std::convert::From<clap::parse::matches::arg_matches::ArgMatches>` is not satisfied
+  --> $DIR/flatten_and_doc.rs:19:10
+   |
+19 | #[derive(Clap, Debug)]
+   |          ^^^^ the trait `std::convert::From<clap::parse::matches::arg_matches::ArgMatches>` is not implemented for `Opt`
diff --git a/clap_derive/tests/ui/flatten_and_methods.rs b/clap_derive/tests/ui/flatten_and_methods.rs
new file mode 100644
index 00000000..ce74b09c
--- /dev/null
+++ b/clap_derive/tests/ui/flatten_and_methods.rs
@@ -0,0 +1,29 @@
+// 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 clap::Clap;
+
+#[derive(Clap, Debug)]
+struct DaemonOpts {
+    #[clap(short)]
+    user: String,
+    #[clap(short)]
+    group: String,
+}
+
+#[derive(Clap, Debug)]
+#[clap(name = "basic")]
+struct Opt {
+    #[clap(short, flatten)]
+    opts: DaemonOpts,
+}
+
+fn main() {
+    let opt = Opt::parse();
+    println!("{:?}", opt);
+}
diff --git a/clap_derive/tests/ui/flatten_and_methods.stderr b/clap_derive/tests/ui/flatten_and_methods.stderr
new file mode 100644
index 00000000..20c84815
--- /dev/null
+++ b/clap_derive/tests/ui/flatten_and_methods.stderr
@@ -0,0 +1,11 @@
+error: methods and doc comments are not allowed for flattened entry
+  --> $DIR/flatten_and_methods.rs:22:19
+   |
+22 |     #[clap(short, flatten)]
+   |                   ^^^^^^^
+
+error[E0277]: the trait bound `Opt: std::convert::From<clap::parse::matches::arg_matches::ArgMatches>` is not satisfied
+  --> $DIR/flatten_and_methods.rs:19:10
+   |
+19 | #[derive(Clap, Debug)]
+   |          ^^^^ the trait `std::convert::From<clap::parse::matches::arg_matches::ArgMatches>` is not implemented for `Opt`
diff --git a/clap_derive/tests/ui/flatten_and_parse.rs b/clap_derive/tests/ui/flatten_and_parse.rs
new file mode 100644
index 00000000..9c2c0ec5
--- /dev/null
+++ b/clap_derive/tests/ui/flatten_and_parse.rs
@@ -0,0 +1,29 @@
+// 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 clap::Clap;
+
+#[derive(Clap, Debug)]
+struct DaemonOpts {
+    #[clap(short)]
+    user: String,
+    #[clap(short)]
+    group: String,
+}
+
+#[derive(Clap, Debug)]
+#[clap(name = "basic")]
+struct Opt {
+    #[clap(flatten, parse(from_occurrences))]
+    opts: DaemonOpts,
+}
+
+fn main() {
+    let opt = Opt::parse();
+    println!("{:?}", opt);
+}
diff --git a/clap_derive/tests/ui/flatten_and_parse.stderr b/clap_derive/tests/ui/flatten_and_parse.stderr
new file mode 100644
index 00000000..76b7ec7c
--- /dev/null
+++ b/clap_derive/tests/ui/flatten_and_parse.stderr
@@ -0,0 +1,11 @@
+error: parse attribute is not allowed for flattened entry
+  --> $DIR/flatten_and_parse.rs:22:21
+   |
+22 |     #[clap(flatten, parse(from_occurrences))]
+   |                     ^^^^^
+
+error[E0277]: the trait bound `Opt: std::convert::From<clap::parse::matches::arg_matches::ArgMatches>` is not satisfied
+  --> $DIR/flatten_and_parse.rs:19:10
+   |
+19 | #[derive(Clap, Debug)]
+   |          ^^^^ the trait `std::convert::From<clap::parse::matches::arg_matches::ArgMatches>` is not implemented for `Opt`
diff --git a/clap_derive/tests/ui/non_existent_attr.rs b/clap_derive/tests/ui/non_existent_attr.rs
new file mode 100644
index 00000000..94b5b971
--- /dev/null
+++ b/clap_derive/tests/ui/non_existent_attr.rs
@@ -0,0 +1,21 @@
+// 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 clap::Clap;
+
+#[derive(Clap, Debug)]
+#[clap(name = "basic")]
+struct Opt {
+    #[clap(short, non_existing_attribute = 1)]
+    debug: bool,
+}
+
+fn main() {
+    let opt = Opt::parse();
+    println!("{:?}", opt);
+}
diff --git a/clap_derive/tests/ui/non_existent_attr.stderr b/clap_derive/tests/ui/non_existent_attr.stderr
new file mode 100644
index 00000000..3ad7af65
--- /dev/null
+++ b/clap_derive/tests/ui/non_existent_attr.stderr
@@ -0,0 +1,5 @@
+error[E0599]: no method named `non_existing_attribute` found for type `clap::build::arg::Arg<'_>` in the current scope
+  --> $DIR/non_existent_attr.rs:14:19
+   |
+14 |     #[clap(short, non_existing_attribute = 1)]
+   |                   ^^^^^^^^^^^^^^^^^^^^^^ method not found in `clap::build::arg::Arg<'_>`
diff --git a/clap_derive/tests/ui/opt_opt_nonpositional.rs b/clap_derive/tests/ui/opt_opt_nonpositional.rs
new file mode 100644
index 00000000..53333371
--- /dev/null
+++ b/clap_derive/tests/ui/opt_opt_nonpositional.rs
@@ -0,0 +1,20 @@
+// 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 clap::Clap;
+
+#[derive(Clap, Debug)]
+#[clap(name = "basic")]
+struct Opt {
+    n: Option<Option<u32>>,
+}
+
+fn main() {
+    let opt = Opt::parse();
+    println!("{:?}", opt);
+}
diff --git a/clap_derive/tests/ui/opt_opt_nonpositional.stderr b/clap_derive/tests/ui/opt_opt_nonpositional.stderr
new file mode 100644
index 00000000..a0800498
--- /dev/null
+++ b/clap_derive/tests/ui/opt_opt_nonpositional.stderr
@@ -0,0 +1,11 @@
+error: Option<Option<T>> type is meaningless for positional argument
+  --> $DIR/opt_opt_nonpositional.rs:14:8
+   |
+14 |     n: Option<Option<u32>>,
+   |        ^^^^^^
+
+error[E0277]: the trait bound `Opt: std::convert::From<clap::parse::matches::arg_matches::ArgMatches>` is not satisfied
+  --> $DIR/opt_opt_nonpositional.rs:11:10
+   |
+11 | #[derive(Clap, Debug)]
+   |          ^^^^ the trait `std::convert::From<clap::parse::matches::arg_matches::ArgMatches>` is not implemented for `Opt`
diff --git a/clap_derive/tests/ui/opt_vec_nonpositional.rs b/clap_derive/tests/ui/opt_vec_nonpositional.rs
new file mode 100644
index 00000000..672867e7
--- /dev/null
+++ b/clap_derive/tests/ui/opt_vec_nonpositional.rs
@@ -0,0 +1,20 @@
+// 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 clap::Clap;
+
+#[derive(Clap, Debug)]
+#[clap(name = "basic")]
+struct Opt {
+    n: Option<Vec<u32>>,
+}
+
+fn main() {
+    let opt = Opt::parse();
+    println!("{:?}", opt);
+}
diff --git a/clap_derive/tests/ui/opt_vec_nonpositional.stderr b/clap_derive/tests/ui/opt_vec_nonpositional.stderr
new file mode 100644
index 00000000..055196b7
--- /dev/null
+++ b/clap_derive/tests/ui/opt_vec_nonpositional.stderr
@@ -0,0 +1,11 @@
+error: Option<Vec<T>> type is meaningless for positional argument
+  --> $DIR/opt_vec_nonpositional.rs:14:8
+   |
+14 |     n: Option<Vec<u32>>,
+   |        ^^^^^^
+
+error[E0277]: the trait bound `Opt: std::convert::From<clap::parse::matches::arg_matches::ArgMatches>` is not satisfied
+  --> $DIR/opt_vec_nonpositional.rs:11:10
+   |
+11 | #[derive(Clap, Debug)]
+   |          ^^^^ the trait `std::convert::From<clap::parse::matches::arg_matches::ArgMatches>` is not implemented for `Opt`
diff --git a/clap_derive/tests/ui/option_default_value.rs b/clap_derive/tests/ui/option_default_value.rs
new file mode 100644
index 00000000..256c4f25
--- /dev/null
+++ b/clap_derive/tests/ui/option_default_value.rs
@@ -0,0 +1,21 @@
+// 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 clap::Clap;
+
+#[derive(Clap, Debug)]
+#[clap(name = "basic")]
+struct Opt {
+    #[clap(short, default_value = 1)]
+    n: Option<u32>,
+}
+
+fn main() {
+    let opt = Opt::parse();
+    println!("{:?}", opt);
+}
diff --git a/clap_derive/tests/ui/option_default_value.stderr b/clap_derive/tests/ui/option_default_value.stderr
new file mode 100644
index 00000000..e06fa477
--- /dev/null
+++ b/clap_derive/tests/ui/option_default_value.stderr
@@ -0,0 +1,11 @@
+error: default_value is meaningless for Option
+  --> $DIR/option_default_value.rs:14:19
+   |
+14 |     #[clap(short, default_value = 1)]
+   |                   ^^^^^^^^^^^^^
+
+error[E0277]: the trait bound `Opt: std::convert::From<clap::parse::matches::arg_matches::ArgMatches>` is not satisfied
+  --> $DIR/option_default_value.rs:11:10
+   |
+11 | #[derive(Clap, Debug)]
+   |          ^^^^ the trait `std::convert::From<clap::parse::matches::arg_matches::ArgMatches>` is not implemented for `Opt`
diff --git a/clap_derive/tests/ui/option_required.rs b/clap_derive/tests/ui/option_required.rs
new file mode 100644
index 00000000..8aa345f5
--- /dev/null
+++ b/clap_derive/tests/ui/option_required.rs
@@ -0,0 +1,21 @@
+// 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 clap::Clap;
+
+#[derive(Clap, Debug)]
+#[clap(name = "basic")]
+struct Opt {
+    #[clap(short, required = true)]
+    n: Option<u32>,
+}
+
+fn main() {
+    let opt = Opt::parse();
+    println!("{:?}", opt);
+}
diff --git a/clap_derive/tests/ui/option_required.stderr b/clap_derive/tests/ui/option_required.stderr
new file mode 100644
index 00000000..66e470c3
--- /dev/null
+++ b/clap_derive/tests/ui/option_required.stderr
@@ -0,0 +1,11 @@
+error: required is meaningless for Option
+  --> $DIR/option_required.rs:14:19
+   |
+14 |     #[clap(short, required = true)]
+   |                   ^^^^^^^^
+
+error[E0277]: the trait bound `Opt: std::convert::From<clap::parse::matches::arg_matches::ArgMatches>` is not satisfied
+  --> $DIR/option_required.rs:11:10
+   |
+11 | #[derive(Clap, Debug)]
+   |          ^^^^ the trait `std::convert::From<clap::parse::matches::arg_matches::ArgMatches>` is not implemented for `Opt`
diff --git a/clap_derive/tests/ui/parse_empty_try_from_os.rs b/clap_derive/tests/ui/parse_empty_try_from_os.rs
new file mode 100644
index 00000000..ee1d99c4
--- /dev/null
+++ b/clap_derive/tests/ui/parse_empty_try_from_os.rs
@@ -0,0 +1,21 @@
+// 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 clap::Clap;
+
+#[derive(Clap, Debug)]
+#[clap(name = "basic")]
+struct Opt {
+    #[clap(parse(try_from_os_str))]
+    s: String,
+}
+
+fn main() {
+    let opt = Opt::parse();
+    println!("{:?}", opt);
+}
diff --git a/clap_derive/tests/ui/parse_empty_try_from_os.stderr b/clap_derive/tests/ui/parse_empty_try_from_os.stderr
new file mode 100644
index 00000000..b102ea63
--- /dev/null
+++ b/clap_derive/tests/ui/parse_empty_try_from_os.stderr
@@ -0,0 +1,11 @@
+error: you must set parser for `try_from_os_str` explicitly
+  --> $DIR/parse_empty_try_from_os.rs:14:18
+   |
+14 |     #[clap(parse(try_from_os_str))]
+   |                  ^^^^^^^^^^^^^^^
+
+error[E0277]: the trait bound `Opt: std::convert::From<clap::parse::matches::arg_matches::ArgMatches>` is not satisfied
+  --> $DIR/parse_empty_try_from_os.rs:11:10
+   |
+11 | #[derive(Clap, Debug)]
+   |          ^^^^ the trait `std::convert::From<clap::parse::matches::arg_matches::ArgMatches>` is not implemented for `Opt`
diff --git a/clap_derive/tests/ui/parse_function_is_not_path.rs b/clap_derive/tests/ui/parse_function_is_not_path.rs
new file mode 100644
index 00000000..01077540
--- /dev/null
+++ b/clap_derive/tests/ui/parse_function_is_not_path.rs
@@ -0,0 +1,21 @@
+// 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 clap::Clap;
+
+#[derive(Clap, Debug)]
+#[clap(name = "basic")]
+struct Opt {
+    #[clap(parse(from_str = "2"))]
+    s: String,
+}
+
+fn main() {
+    let opt = Opt::parse();
+    println!("{:?}", opt);
+}
diff --git a/clap_derive/tests/ui/parse_function_is_not_path.stderr b/clap_derive/tests/ui/parse_function_is_not_path.stderr
new file mode 100644
index 00000000..ae59a092
--- /dev/null
+++ b/clap_derive/tests/ui/parse_function_is_not_path.stderr
@@ -0,0 +1,11 @@
+error: `parse` argument must be a function path
+  --> $DIR/parse_function_is_not_path.rs:14:29
+   |
+14 |     #[clap(parse(from_str = "2"))]
+   |                             ^^^
+
+error[E0277]: the trait bound `Opt: std::convert::From<clap::parse::matches::arg_matches::ArgMatches>` is not satisfied
+  --> $DIR/parse_function_is_not_path.rs:11:10
+   |
+11 | #[derive(Clap, Debug)]
+   |          ^^^^ the trait `std::convert::From<clap::parse::matches::arg_matches::ArgMatches>` is not implemented for `Opt`
diff --git a/clap_derive/tests/ui/parse_literal_spec.rs b/clap_derive/tests/ui/parse_literal_spec.rs
new file mode 100644
index 00000000..26f018af
--- /dev/null
+++ b/clap_derive/tests/ui/parse_literal_spec.rs
@@ -0,0 +1,21 @@
+// 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 clap::Clap;
+
+#[derive(Clap, Debug)]
+#[clap(name = "basic")]
+struct Opt {
+    #[clap(parse("from_str"))]
+    s: String,
+}
+
+fn main() {
+    let opt = Opt::parse();
+    println!("{:?}", opt);
+}
diff --git a/clap_derive/tests/ui/parse_literal_spec.stderr b/clap_derive/tests/ui/parse_literal_spec.stderr
new file mode 100644
index 00000000..fb2e7203
--- /dev/null
+++ b/clap_derive/tests/ui/parse_literal_spec.stderr
@@ -0,0 +1,11 @@
+error: parser specification must start with identifier
+  --> $DIR/parse_literal_spec.rs:14:18
+   |
+14 |     #[clap(parse("from_str"))]
+   |                  ^^^^^^^^^^
+
+error[E0277]: the trait bound `Opt: std::convert::From<clap::parse::matches::arg_matches::ArgMatches>` is not satisfied
+  --> $DIR/parse_literal_spec.rs:11:10
+   |
+11 | #[derive(Clap, Debug)]
+   |          ^^^^ the trait `std::convert::From<clap::parse::matches::arg_matches::ArgMatches>` is not implemented for `Opt`
diff --git a/clap_derive/tests/ui/parse_not_zero_args.rs b/clap_derive/tests/ui/parse_not_zero_args.rs
new file mode 100644
index 00000000..883cc262
--- /dev/null
+++ b/clap_derive/tests/ui/parse_not_zero_args.rs
@@ -0,0 +1,21 @@
+// 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 clap::Clap;
+
+#[derive(Clap, Debug)]
+#[clap(name = "basic")]
+struct Opt {
+    #[clap(parse(from_str, from_str))]
+    s: String,
+}
+
+fn main() {
+    let opt = Opt::parse();
+    println!("{:?}", opt);
+}
diff --git a/clap_derive/tests/ui/parse_not_zero_args.stderr b/clap_derive/tests/ui/parse_not_zero_args.stderr
new file mode 100644
index 00000000..a8bf2caf
--- /dev/null
+++ b/clap_derive/tests/ui/parse_not_zero_args.stderr
@@ -0,0 +1,11 @@
+error: parse must have exactly one argument
+  --> $DIR/parse_not_zero_args.rs:14:12
+   |
+14 |     #[clap(parse(from_str, from_str))]
+   |            ^^^^^
+
+error[E0277]: the trait bound `Opt: std::convert::From<clap::parse::matches::arg_matches::ArgMatches>` is not satisfied
+  --> $DIR/parse_not_zero_args.rs:11:10
+   |
+11 | #[derive(Clap, Debug)]
+   |          ^^^^ the trait `std::convert::From<clap::parse::matches::arg_matches::ArgMatches>` is not implemented for `Opt`
diff --git a/clap_derive/tests/ui/positional_bool.rs b/clap_derive/tests/ui/positional_bool.rs
new file mode 100644
index 00000000..61f91af6
--- /dev/null
+++ b/clap_derive/tests/ui/positional_bool.rs
@@ -0,0 +1,10 @@
+use clap::Clap;
+
+#[derive(Clap, Debug)]
+struct Opt {
+    verbose: bool,
+}
+
+fn main() {
+    Opt::parse();
+}
diff --git a/clap_derive/tests/ui/positional_bool.stderr b/clap_derive/tests/ui/positional_bool.stderr
new file mode 100644
index 00000000..7341ec89
--- /dev/null
+++ b/clap_derive/tests/ui/positional_bool.stderr
@@ -0,0 +1,16 @@
+error: `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/clap-rs/clap_derive/tree/master/examples/true_or_false.rs
+
+ --> $DIR/positional_bool.rs:5:14
+  |
+5 |     verbose: bool,
+  |              ^^^^
+
+error[E0277]: the trait bound `Opt: std::convert::From<clap::parse::matches::arg_matches::ArgMatches>` is not satisfied
+ --> $DIR/positional_bool.rs:3:10
+  |
+3 | #[derive(Clap, Debug)]
+  |          ^^^^ the trait `std::convert::From<clap::parse::matches::arg_matches::ArgMatches>` is not implemented for `Opt`
diff --git a/clap_derive/tests/ui/raw.rs b/clap_derive/tests/ui/raw.rs
new file mode 100644
index 00000000..b49fd6e8
--- /dev/null
+++ b/clap_derive/tests/ui/raw.rs
@@ -0,0 +1,20 @@
+// 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 clap::Clap;
+
+#[derive(Clap, Debug)]
+struct Opt {
+    #[clap(raw(case_insensitive = "true"))]
+    s: String,
+}
+
+fn main() {
+    let opt = Opt::parse();
+    println!("{:?}", opt);
+}
diff --git a/clap_derive/tests/ui/raw.stderr b/clap_derive/tests/ui/raw.stderr
new file mode 100644
index 00000000..36102cf0
--- /dev/null
+++ b/clap_derive/tests/ui/raw.stderr
@@ -0,0 +1,15 @@
+error: `#[clap(raw(...))` attributes are removed, 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: if you need to call `clap::Arg/App::case_insensitive` method you can do it like this: #[clap(case_insensitive(true))]
+
+  --> $DIR/raw.rs:13:12
+   |
+13 |     #[clap(raw(case_insensitive = "true"))]
+   |            ^^^
+
+error[E0277]: the trait bound `Opt: std::convert::From<clap::parse::matches::arg_matches::ArgMatches>` is not satisfied
+  --> $DIR/raw.rs:11:10
+   |
+11 | #[derive(Clap, Debug)]
+   |          ^^^^ the trait `std::convert::From<clap::parse::matches::arg_matches::ArgMatches>` is not implemented for `Opt`
diff --git a/clap_derive/tests/ui/rename_all_wrong_casing.rs b/clap_derive/tests/ui/rename_all_wrong_casing.rs
new file mode 100644
index 00000000..75cb4a07
--- /dev/null
+++ b/clap_derive/tests/ui/rename_all_wrong_casing.rs
@@ -0,0 +1,21 @@
+// 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 clap::Clap;
+
+#[derive(Clap, Debug)]
+#[clap(name = "basic", rename_all = "fail")]
+struct Opt {
+    #[clap(short)]
+    s: String,
+}
+
+fn main() {
+    let opt = Opt::parse();
+    println!("{:?}", opt);
+}
diff --git a/clap_derive/tests/ui/rename_all_wrong_casing.stderr b/clap_derive/tests/ui/rename_all_wrong_casing.stderr
new file mode 100644
index 00000000..84d4eae9
--- /dev/null
+++ b/clap_derive/tests/ui/rename_all_wrong_casing.stderr
@@ -0,0 +1,11 @@
+error: unsupported casing: `fail`
+  --> $DIR/rename_all_wrong_casing.rs:12:37
+   |
+12 | #[clap(name = "basic", rename_all = "fail")]
+   |                                     ^^^^^^
+
+error[E0277]: the trait bound `Opt: std::convert::From<clap::parse::matches::arg_matches::ArgMatches>` is not satisfied
+  --> $DIR/rename_all_wrong_casing.rs:11:10
+   |
+11 | #[derive(Clap, Debug)]
+   |          ^^^^ the trait `std::convert::From<clap::parse::matches::arg_matches::ArgMatches>` is not implemented for `Opt`
diff --git a/clap_derive/tests/ui/skip_flatten.rs b/clap_derive/tests/ui/skip_flatten.rs
new file mode 100644
index 00000000..ffc94796
--- /dev/null
+++ b/clap_derive/tests/ui/skip_flatten.rs
@@ -0,0 +1,42 @@
+// 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 clap::Clap;
+
+#[derive(Clap, Debug)]
+#[clap(name = "make-cookie")]
+struct MakeCookie {
+    #[clap(short)]
+    s: String,
+
+    #[clap(skip, flatten)]
+    cmd: Command,
+}
+
+#[derive(Clap, Debug)]
+enum Command {
+    #[clap(name = "pound")]
+    /// Pound acorns into flour for cookie dough.
+    Pound { acorns: u32 },
+
+    Sparkle {
+        #[clap(short)]
+        color: String,
+    },
+}
+
+impl Default for Command {
+    fn default() -> Self {
+        Command::Pound { acorns: 0 }
+    }
+}
+
+fn main() {
+    let opt = MakeCookie::parse();
+    println!("{:?}", opt);
+}
diff --git a/clap_derive/tests/ui/skip_flatten.stderr b/clap_derive/tests/ui/skip_flatten.stderr
new file mode 100644
index 00000000..ac131454
--- /dev/null
+++ b/clap_derive/tests/ui/skip_flatten.stderr
@@ -0,0 +1,11 @@
+error: subcommand, flatten and skip cannot be used together
+  --> $DIR/skip_flatten.rs:17:18
+   |
+17 |     #[clap(skip, flatten)]
+   |                  ^^^^^^^
+
+error[E0277]: the trait bound `MakeCookie: std::convert::From<clap::parse::matches::arg_matches::ArgMatches>` is not satisfied
+  --> $DIR/skip_flatten.rs:11:10
+   |
+11 | #[derive(Clap, Debug)]
+   |          ^^^^ the trait `std::convert::From<clap::parse::matches::arg_matches::ArgMatches>` is not implemented for `MakeCookie`
diff --git a/clap_derive/tests/ui/skip_subcommand.rs b/clap_derive/tests/ui/skip_subcommand.rs
new file mode 100644
index 00000000..f6a98550
--- /dev/null
+++ b/clap_derive/tests/ui/skip_subcommand.rs
@@ -0,0 +1,42 @@
+// 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 clap::Clap;
+
+#[derive(Clap, Debug)]
+#[clap(name = "make-cookie")]
+struct MakeCookie {
+    #[clap(short)]
+    s: String,
+
+    #[clap(subcommand, skip)]
+    cmd: Command,
+}
+
+#[derive(Clap, Debug)]
+enum Command {
+    #[clap(name = "pound")]
+    /// Pound acorns into flour for cookie dough.
+    Pound { acorns: u32 },
+
+    Sparkle {
+        #[clap(short)]
+        color: String,
+    },
+}
+
+impl Default for Command {
+    fn default() -> Self {
+        Command::Pound { acorns: 0 }
+    }
+}
+
+fn main() {
+    let opt = MakeCookie::parse();
+    println!("{:?}", opt);
+}
diff --git a/clap_derive/tests/ui/skip_subcommand.stderr b/clap_derive/tests/ui/skip_subcommand.stderr
new file mode 100644
index 00000000..164605c1
--- /dev/null
+++ b/clap_derive/tests/ui/skip_subcommand.stderr
@@ -0,0 +1,11 @@
+error: subcommand, flatten and skip cannot be used together
+  --> $DIR/skip_subcommand.rs:17:24
+   |
+17 |     #[clap(subcommand, skip)]
+   |                        ^^^^
+
+error[E0277]: the trait bound `MakeCookie: std::convert::From<clap::parse::matches::arg_matches::ArgMatches>` is not satisfied
+  --> $DIR/skip_subcommand.rs:11:10
+   |
+11 | #[derive(Clap, Debug)]
+   |          ^^^^ the trait `std::convert::From<clap::parse::matches::arg_matches::ArgMatches>` is not implemented for `MakeCookie`
diff --git a/clap_derive/tests/ui/skip_with_other_options.rs b/clap_derive/tests/ui/skip_with_other_options.rs
new file mode 100644
index 00000000..31cae475
--- /dev/null
+++ b/clap_derive/tests/ui/skip_with_other_options.rs
@@ -0,0 +1,15 @@
+use clap::Clap;
+
+#[derive(Clap, Debug)]
+#[clap(name = "test")]
+pub struct Opt {
+    #[clap(long)]
+    a: u32,
+    #[clap(skip, long)]
+    b: u32,
+}
+
+fn main() {
+    let opt = Opt::parse();
+    println!("{:?}", opt);
+}
diff --git a/clap_derive/tests/ui/skip_with_other_options.stderr b/clap_derive/tests/ui/skip_with_other_options.stderr
new file mode 100644
index 00000000..7aa4667d
--- /dev/null
+++ b/clap_derive/tests/ui/skip_with_other_options.stderr
@@ -0,0 +1,11 @@
+error: methods are not allowed for skipped fields
+ --> $DIR/skip_with_other_options.rs:8:12
+  |
+8 |     #[clap(skip, long)]
+  |            ^^^^
+
+error[E0277]: the trait bound `Opt: std::convert::From<clap::parse::matches::arg_matches::ArgMatches>` is not satisfied
+ --> $DIR/skip_with_other_options.rs:3:10
+  |
+3 | #[derive(Clap, Debug)]
+  |          ^^^^ the trait `std::convert::From<clap::parse::matches::arg_matches::ArgMatches>` is not implemented for `Opt`
diff --git a/clap_derive/tests/ui/skip_without_default.rs b/clap_derive/tests/ui/skip_without_default.rs
new file mode 100644
index 00000000..ee801faf
--- /dev/null
+++ b/clap_derive/tests/ui/skip_without_default.rs
@@ -0,0 +1,29 @@
+// 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 clap::Clap;
+
+#[derive(Debug)]
+enum Kind {
+    A,
+    B,
+}
+
+#[derive(Clap, Debug)]
+#[clap(name = "test")]
+pub struct Opt {
+    #[clap(short)]
+    number: u32,
+    #[clap(skip)]
+    k: Kind,
+}
+
+fn main() {
+    let opt = Opt::parse();
+    println!("{:?}", opt);
+}
diff --git a/clap_derive/tests/ui/skip_without_default.stderr b/clap_derive/tests/ui/skip_without_default.stderr
new file mode 100644
index 00000000..85545e56
--- /dev/null
+++ b/clap_derive/tests/ui/skip_without_default.stderr
@@ -0,0 +1,9 @@
+error[E0277]: the trait bound `Kind: std::default::Default` is not satisfied
+  --> $DIR/skip_without_default.rs:22:12
+   |
+22 |     #[clap(skip)]
+   |            ^^^^ the trait `std::default::Default` is not implemented for `Kind`
+   |
+   = note: required by `std::default::Default::default`
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/clap_derive/tests/ui/struct_flatten.rs b/clap_derive/tests/ui/struct_flatten.rs
new file mode 100644
index 00000000..36d6bb21
--- /dev/null
+++ b/clap_derive/tests/ui/struct_flatten.rs
@@ -0,0 +1,21 @@
+// 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 clap::Clap;
+
+#[derive(Clap, Debug)]
+#[clap(name = "basic", flatten)]
+struct Opt {
+    #[clap(short)]
+    s: String,
+}
+
+fn main() {
+    let opt = Opt::parse();
+    println!("{:?}", opt);
+}
diff --git a/clap_derive/tests/ui/struct_flatten.stderr b/clap_derive/tests/ui/struct_flatten.stderr
new file mode 100644
index 00000000..bdcfd873
--- /dev/null
+++ b/clap_derive/tests/ui/struct_flatten.stderr
@@ -0,0 +1,11 @@
+error: flatten is only allowed on fields
+  --> $DIR/struct_flatten.rs:12:24
+   |
+12 | #[clap(name = "basic", flatten)]
+   |                        ^^^^^^^
+
+error[E0277]: the trait bound `Opt: std::convert::From<clap::parse::matches::arg_matches::ArgMatches>` is not satisfied
+  --> $DIR/struct_flatten.rs:11:10
+   |
+11 | #[derive(Clap, Debug)]
+   |          ^^^^ the trait `std::convert::From<clap::parse::matches::arg_matches::ArgMatches>` is not implemented for `Opt`
diff --git a/clap_derive/tests/ui/struct_parse.rs b/clap_derive/tests/ui/struct_parse.rs
new file mode 100644
index 00000000..52954fb5
--- /dev/null
+++ b/clap_derive/tests/ui/struct_parse.rs
@@ -0,0 +1,21 @@
+// 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 clap::Clap;
+
+#[derive(Clap, Debug)]
+#[clap(name = "basic", parse(from_str))]
+struct Opt {
+    #[clap(short)]
+    s: String,
+}
+
+fn main() {
+    let opt = Opt::parse();
+    println!("{:?}", opt);
+}
diff --git a/clap_derive/tests/ui/struct_parse.stderr b/clap_derive/tests/ui/struct_parse.stderr
new file mode 100644
index 00000000..9dc07f59
--- /dev/null
+++ b/clap_derive/tests/ui/struct_parse.stderr
@@ -0,0 +1,11 @@
+error: `parse` attribute is only allowed on fields
+  --> $DIR/struct_parse.rs:12:24
+   |
+12 | #[clap(name = "basic", parse(from_str))]
+   |                        ^^^^^
+
+error[E0277]: the trait bound `Opt: std::convert::From<clap::parse::matches::arg_matches::ArgMatches>` is not satisfied
+  --> $DIR/struct_parse.rs:11:10
+   |
+11 | #[derive(Clap, Debug)]
+   |          ^^^^ the trait `std::convert::From<clap::parse::matches::arg_matches::ArgMatches>` is not implemented for `Opt`
diff --git a/clap_derive/tests/ui/struct_subcommand.rs b/clap_derive/tests/ui/struct_subcommand.rs
new file mode 100644
index 00000000..f4f499fd
--- /dev/null
+++ b/clap_derive/tests/ui/struct_subcommand.rs
@@ -0,0 +1,21 @@
+// 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 clap::Clap;
+
+#[derive(Clap, Debug)]
+#[clap(name = "basic", subcommand)]
+struct Opt {
+    #[clap(short)]
+    s: String,
+}
+
+fn main() {
+    let opt = Opt::parse();
+    println!("{:?}", opt);
+}
diff --git a/clap_derive/tests/ui/struct_subcommand.stderr b/clap_derive/tests/ui/struct_subcommand.stderr
new file mode 100644
index 00000000..b1dd3eed
--- /dev/null
+++ b/clap_derive/tests/ui/struct_subcommand.stderr
@@ -0,0 +1,11 @@
+error: subcommand is only allowed on fields
+  --> $DIR/struct_subcommand.rs:12:24
+   |
+12 | #[clap(name = "basic", subcommand)]
+   |                        ^^^^^^^^^^
+
+error[E0277]: the trait bound `Opt: std::convert::From<clap::parse::matches::arg_matches::ArgMatches>` is not satisfied
+  --> $DIR/struct_subcommand.rs:11:10
+   |
+11 | #[derive(Clap, Debug)]
+   |          ^^^^ the trait `std::convert::From<clap::parse::matches::arg_matches::ArgMatches>` is not implemented for `Opt`
diff --git a/clap_derive/tests/ui/subcommand_and_flatten.rs b/clap_derive/tests/ui/subcommand_and_flatten.rs
new file mode 100644
index 00000000..d8bac093
--- /dev/null
+++ b/clap_derive/tests/ui/subcommand_and_flatten.rs
@@ -0,0 +1,34 @@
+// 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 clap::Clap;
+
+#[derive(Clap, Debug)]
+struct MakeCookie {
+    #[clap(short)]
+    s: String,
+
+    #[clap(subcommand, flatten)]
+    cmd: Command,
+}
+
+#[derive(Clap, Debug)]
+enum Command {
+    /// Pound acorns into flour for cookie dough.
+    Pound { acorns: u32 },
+
+    Sparkle {
+        #[clap(short)]
+        color: String,
+    },
+}
+
+fn main() {
+    let opt = MakeCookie::parse();
+    println!("{:?}", opt);
+}
diff --git a/clap_derive/tests/ui/subcommand_and_flatten.stderr b/clap_derive/tests/ui/subcommand_and_flatten.stderr
new file mode 100644
index 00000000..91c005fe
--- /dev/null
+++ b/clap_derive/tests/ui/subcommand_and_flatten.stderr
@@ -0,0 +1,11 @@
+error: subcommand, flatten and skip cannot be used together
+  --> $DIR/subcommand_and_flatten.rs:16:24
+   |
+16 |     #[clap(subcommand, flatten)]
+   |                        ^^^^^^^
+
+error[E0277]: the trait bound `MakeCookie: std::convert::From<clap::parse::matches::arg_matches::ArgMatches>` is not satisfied
+  --> $DIR/subcommand_and_flatten.rs:11:10
+   |
+11 | #[derive(Clap, Debug)]
+   |          ^^^^ the trait `std::convert::From<clap::parse::matches::arg_matches::ArgMatches>` is not implemented for `MakeCookie`
diff --git a/clap_derive/tests/ui/subcommand_and_methods.rs b/clap_derive/tests/ui/subcommand_and_methods.rs
new file mode 100644
index 00000000..61dfa3de
--- /dev/null
+++ b/clap_derive/tests/ui/subcommand_and_methods.rs
@@ -0,0 +1,34 @@
+// 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 clap::Clap;
+
+#[derive(Clap, Debug)]
+struct MakeCookie {
+    #[clap(short)]
+    s: String,
+
+    #[clap(subcommand, long)]
+    cmd: Command,
+}
+
+#[derive(Clap, Debug)]
+enum Command {
+    /// Pound acorns into flour for cookie dough.
+    Pound { acorns: u32 },
+
+    Sparkle {
+        #[clap(short)]
+        color: String,
+    },
+}
+
+fn main() {
+    let opt = MakeCookie::parse();
+    println!("{:?}", opt);
+}
diff --git a/clap_derive/tests/ui/subcommand_and_methods.stderr b/clap_derive/tests/ui/subcommand_and_methods.stderr
new file mode 100644
index 00000000..e565a28e
--- /dev/null
+++ b/clap_derive/tests/ui/subcommand_and_methods.stderr
@@ -0,0 +1,11 @@
+error: methods in attributes are not allowed for subcommand
+  --> $DIR/subcommand_and_methods.rs:16:12
+   |
+16 |     #[clap(subcommand, long)]
+   |            ^^^^^^^^^^
+
+error[E0277]: the trait bound `MakeCookie: std::convert::From<clap::parse::matches::arg_matches::ArgMatches>` is not satisfied
+  --> $DIR/subcommand_and_methods.rs:11:10
+   |
+11 | #[derive(Clap, Debug)]
+   |          ^^^^ the trait `std::convert::From<clap::parse::matches::arg_matches::ArgMatches>` is not implemented for `MakeCookie`
diff --git a/clap_derive/tests/ui/subcommand_and_parse.rs b/clap_derive/tests/ui/subcommand_and_parse.rs
new file mode 100644
index 00000000..0e65b515
--- /dev/null
+++ b/clap_derive/tests/ui/subcommand_and_parse.rs
@@ -0,0 +1,34 @@
+// 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 clap::Clap;
+
+#[derive(Clap, Debug)]
+struct MakeCookie {
+    #[clap(short)]
+    s: String,
+
+    #[clap(subcommand, parse(from_occurrences))]
+    cmd: Command,
+}
+
+#[derive(Clap, Debug)]
+enum Command {
+    /// Pound acorns into flour for cookie dough.
+    Pound { acorns: u32 },
+
+    Sparkle {
+        #[clap(short)]
+        color: String,
+    },
+}
+
+fn main() {
+    let opt = MakeCookie::parse();
+    println!("{:?}", opt);
+}
diff --git a/clap_derive/tests/ui/subcommand_and_parse.stderr b/clap_derive/tests/ui/subcommand_and_parse.stderr
new file mode 100644
index 00000000..1de015d2
--- /dev/null
+++ b/clap_derive/tests/ui/subcommand_and_parse.stderr
@@ -0,0 +1,11 @@
+error: parse attribute is not allowed for subcommand
+  --> $DIR/subcommand_and_parse.rs:16:24
+   |
+16 |     #[clap(subcommand, parse(from_occurrences))]
+   |                        ^^^^^
+
+error[E0277]: the trait bound `MakeCookie: std::convert::From<clap::parse::matches::arg_matches::ArgMatches>` is not satisfied
+  --> $DIR/subcommand_and_parse.rs:11:10
+   |
+11 | #[derive(Clap, Debug)]
+   |          ^^^^ the trait `std::convert::From<clap::parse::matches::arg_matches::ArgMatches>` is not implemented for `MakeCookie`
diff --git a/clap_derive/tests/ui/subcommand_opt_opt.rs b/clap_derive/tests/ui/subcommand_opt_opt.rs
new file mode 100644
index 00000000..1d3cb078
--- /dev/null
+++ b/clap_derive/tests/ui/subcommand_opt_opt.rs
@@ -0,0 +1,34 @@
+// 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 clap::Clap;
+
+#[derive(Clap, Debug)]
+struct MakeCookie {
+    #[clap(short)]
+    s: String,
+
+    #[clap(subcommand)]
+    cmd: Option<Option<Command>>,
+}
+
+#[derive(Clap, Debug)]
+enum Command {
+    /// Pound acorns into flour for cookie dough.
+    Pound { acorns: u32 },
+
+    Sparkle {
+        #[clap(short)]
+        color: String,
+    },
+}
+
+fn main() {
+    let opt = MakeCookie::parse();
+    println!("{:?}", opt);
+}
diff --git a/clap_derive/tests/ui/subcommand_opt_opt.stderr b/clap_derive/tests/ui/subcommand_opt_opt.stderr
new file mode 100644
index 00000000..9c7a7123
--- /dev/null
+++ b/clap_derive/tests/ui/subcommand_opt_opt.stderr
@@ -0,0 +1,11 @@
+error: Option<Option<T>> type is not allowed for subcommand
+  --> $DIR/subcommand_opt_opt.rs:17:10
+   |
+17 |     cmd: Option<Option<Command>>,
+   |          ^^^^^^
+
+error[E0277]: the trait bound `MakeCookie: std::convert::From<clap::parse::matches::arg_matches::ArgMatches>` is not satisfied
+  --> $DIR/subcommand_opt_opt.rs:11:10
+   |
+11 | #[derive(Clap, Debug)]
+   |          ^^^^ the trait `std::convert::From<clap::parse::matches::arg_matches::ArgMatches>` is not implemented for `MakeCookie`
diff --git a/clap_derive/tests/ui/subcommand_opt_vec.rs b/clap_derive/tests/ui/subcommand_opt_vec.rs
new file mode 100644
index 00000000..2a0cc9c9
--- /dev/null
+++ b/clap_derive/tests/ui/subcommand_opt_vec.rs
@@ -0,0 +1,34 @@
+// 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 clap::Clap;
+
+#[derive(Clap, Debug)]
+struct MakeCookie {
+    #[clap(short)]
+    s: String,
+
+    #[clap(subcommand)]
+    cmd: Option<Vec<Command>>,
+}
+
+#[derive(Clap, Debug)]
+enum Command {
+    /// Pound acorns into flour for cookie dough.
+    Pound { acorns: u32 },
+
+    Sparkle {
+        #[clap(short)]
+        color: String,
+    },
+}
+
+fn main() {
+    let opt = MakeCookie::parse();
+    println!("{:?}", opt);
+}
diff --git a/clap_derive/tests/ui/subcommand_opt_vec.stderr b/clap_derive/tests/ui/subcommand_opt_vec.stderr
new file mode 100644
index 00000000..8a77dbb9
--- /dev/null
+++ b/clap_derive/tests/ui/subcommand_opt_vec.stderr
@@ -0,0 +1,11 @@
+error: Option<Vec<T>> type is not allowed for subcommand
+  --> $DIR/subcommand_opt_vec.rs:17:10
+   |
+17 |     cmd: Option<Vec<Command>>,
+   |          ^^^^^^
+
+error[E0277]: the trait bound `MakeCookie: std::convert::From<clap::parse::matches::arg_matches::ArgMatches>` is not satisfied
+  --> $DIR/subcommand_opt_vec.rs:11:10
+   |
+11 | #[derive(Clap, Debug)]
+   |          ^^^^ the trait `std::convert::From<clap::parse::matches::arg_matches::ArgMatches>` is not implemented for `MakeCookie`
diff --git a/clap_derive/tests/ui/tuple_struct.rs b/clap_derive/tests/ui/tuple_struct.rs
new file mode 100644
index 00000000..23f08623
--- /dev/null
+++ b/clap_derive/tests/ui/tuple_struct.rs
@@ -0,0 +1,18 @@
+// 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 clap::Clap;
+
+#[derive(Clap, Debug)]
+#[clap(name = "basic")]
+struct Opt(u32);
+
+fn main() {
+    let opt = Opt::parse();
+    println!("{:?}", opt);
+}
diff --git a/clap_derive/tests/ui/tuple_struct.stderr b/clap_derive/tests/ui/tuple_struct.stderr
new file mode 100644
index 00000000..51ab78ca
--- /dev/null
+++ b/clap_derive/tests/ui/tuple_struct.stderr
@@ -0,0 +1,11 @@
+error: clap_derive only supports non-tuple structs and enums
+  --> $DIR/tuple_struct.rs:11:10
+   |
+11 | #[derive(Clap, Debug)]
+   |          ^^^^
+
+error[E0277]: the trait bound `Opt: std::convert::From<clap::parse::matches::arg_matches::ArgMatches>` is not satisfied
+  --> $DIR/tuple_struct.rs:11:10
+   |
+11 | #[derive(Clap, Debug)]
+   |          ^^^^ the trait `std::convert::From<clap::parse::matches::arg_matches::ArgMatches>` is not implemented for `Opt`
diff --git a/clap_derive/tests/utils.rs b/clap_derive/tests/utils.rs
new file mode 100644
index 00000000..e21e9260
--- /dev/null
+++ b/clap_derive/tests/utils.rs
@@ -0,0 +1,48 @@
+#![allow(unused)]
+extern crate clap;
+
+use clap::IntoApp;
+
+pub fn get_help<T: IntoApp>() -> String {
+    let mut output = Vec::new();
+    <T as IntoApp>::into_app()
+        .write_help(&mut output)
+        .unwrap();
+    let output = String::from_utf8(output).unwrap();
+
+    eprintln!("\n%%% HELP %%%:=====\n{}\n=====\n", output);
+    eprintln!("\n%%% HELP (DEBUG) %%%:=====\n{:?}\n=====\n", output);
+
+    output
+}
+
+pub fn get_long_help<T: IntoApp>() -> String {
+    let mut output = Vec::new();
+    <T as IntoApp>::into_app()
+        .write_long_help(&mut output)
+        .unwrap();
+    let output = String::from_utf8(output).unwrap();
+
+    eprintln!("\n%%% LONG_HELP %%%:=====\n{}\n=====\n", output);
+    eprintln!("\n%%% LONG_HELP (DEBUG) %%%:=====\n{:?}\n=====\n", output);
+
+    output
+}
+
+pub fn get_subcommand_long_help<T: IntoApp>(subcmd: &str) -> String {
+    let output = <T as IntoApp>::into_app()
+        .try_get_matches_from(vec!["test", subcmd, "--help"])
+        .expect_err("")
+        .message;
+
+    eprintln!(
+        "\n%%% SUBCOMMAND `{}` HELP %%%:=====\n{}\n=====\n",
+        subcmd, output
+    );
+    eprintln!(
+        "\n%%% SUBCOMMAND `{}` HELP (DEBUG) %%%:=====\n{:?}\n=====\n",
+        subcmd, output
+    );
+
+    output
+}