Repository: kbknapp/clap-rs
Pull request #923 (2017-04-05 05:10:13)

Issues 869,900,919,922


<!-- Reviewable:start -->
This change is [<img src="https://reviewable.io/review_button.svg" height="34" align="absmiddle" alt="Reviewable"/>](https://reviewable.io/reviews/kbknapp/clap-rs/923)
<!-- Reviewable:end -->



Patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index c8c6beab..19ee5e55 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,34 @@
+<a name="v2.23.0"></a>
+## v2.23.0 (2017-04-05)
+
+
+#### API Additions
+
+* `App::long_about`
+* `App::long_version`
+* `App::print_long_help`
+* `App::write_long_help`
+* `App::print_long_version`
+* `App::write_long_version`
+* `Arg::long_help`
+
+#### Features
+
+*   allows distinguishing between short and long version messages (-V/short or --version/long) ([59272b06](https://github.com/kbknapp/clap-rs/commit/59272b06cc213289dc604dbc694cb95d383a5d68))
+*   allows distinguishing between short and long help with subcommands in the same manner as args ([6b371891](https://github.com/kbknapp/clap-rs/commit/6b371891a1702173a849d1e95f9fecb168bf6fc4))
+*   allows specifying a short help vs a long help (i.e. varying levels of detail depending on if -h or --help was used) ([ef1b24c3](https://github.com/kbknapp/clap-rs/commit/ef1b24c3a0dff2f58c5e2e90880fbc2b69df20ee))
+* **clap_app!:**  adds support for arg names with hyphens similar to longs with hyphens ([f7a88779](https://github.com/kbknapp/clap-rs/commit/f7a8877978c8f90e6543d4f0d9600c086cf92cd7), closes [#869](https://github.com/kbknapp/clap-rs/issues/869))
+
+#### Bug Fixes
+
+*   fixes a bug that wasn't allowing help and version to be properly overridden ([8b2ceb83](https://github.com/kbknapp/clap-rs/commit/8b2ceb8368bcb70689fadf1c7f4b9549184926c1), closes [#922](https://github.com/kbknapp/clap-rs/issues/922))
+
+#### Documentation
+
+* **clap_app!:**  documents the `--("some-arg")` method for using args with hyphens inside them ([bc08ef3e](https://github.com/kbknapp/clap-rs/commit/bc08ef3e185393073d969d301989b6319c616c1f), closes [#919](https://github.com/kbknapp/clap-rs/issues/919))
+
+
+
 <a name="v2.22.2"></a>
 ### v2.22.2 (2017-03-30)
 
diff --git a/Cargo.toml b/Cargo.toml
index b41c32ac..306fd5c9 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -1,7 +1,7 @@
 [package]
 
 name = "clap"
-version = "2.22.2"
+version = "2.23.0"
 authors = ["Kevin K. <kbknapp@gmail.com>"]
 exclude = ["examples/*", "clap-test/*", "tests/*", "benches/*", "*.png", "clap-perf/*", "*.dot"]
 repository = "https://github.com/kbknapp/clap-rs.git"
diff --git a/README.md b/README.md
index 876e9eb7..36b8677e 100644
--- a/README.md
+++ b/README.md
@@ -45,12 +45,24 @@ Created by [gh-md-toc](https://github.com/ekalinin/github-markdown-toc)
 
 ## What's New
 
-Here's the highlights for v2.22.2
+Here's the highlights for v2.23.0
+
+* allows specifying a short help vs a long help (i.e. varying levels of detail depending on if -h or --help was used) 
+* **clap_app!:**  adds support for arg names with hyphens similar to longs with hyphens 
+* fixes a bug that wasn't allowing help and version to be properly overridden 
+  * This may break code that was relying on this bug! If you add a flag with a long of `help` manually *and* rely on the help message to be printed automatically your code could break. Please see the commit link in the full CHANGELOG.md
+* `App::long_about`
+* `App::long_version`
+* `App::print_long_help`
+* `App::write_long_help`
+* `App::print_long_version`
+* `App::write_long_version`
+* `Arg::long_help`
+* **clap_app!:**  documents the `--("some-arg")` method for using args with hyphens inside them 
+
+Here's the highlights for v2.21.0 to v2.22.2
 
 * fixes the usage string regression when using help templates 
-
-Here's the highlights for v2.21.0 to v2.22.1
-
 * fixes a big regression with custom usage strings 
 * adds the ability to change the name of the App instance after creation
 * adds ability to hide the default value of an argument from the help string
diff --git a/src/app/help.rs b/src/app/help.rs
index 1b400ef4..c79142fe 100644
--- a/src/app/help.rs
+++ b/src/app/help.rs
@@ -89,6 +89,7 @@ pub struct Help<'a> {
     cizer: Colorizer,
     longest: usize,
     force_next_line: bool,
+    use_long: bool,
 }
 
 // Public Functions
@@ -100,7 +101,8 @@ impl<'a> Help<'a> {
                color: bool,
                cizer: Colorizer,
                term_w: Option<usize>,
-               max_w: Option<usize>)
+               max_w: Option<usize>,
+               use_long: bool)
                -> Self {
         debugln!("Help::new;");
         Help {
@@ -121,21 +123,22 @@ impl<'a> Help<'a> {
             cizer: cizer,
             longest: 0,
             force_next_line: false,
+            use_long: use_long,
         }
     }
 
     /// Reads help settings from an App
     /// and write its help to the wrapped stream.
-    pub fn write_app_help(w: &'a mut Write, app: &App) -> ClapResult<()> {
+    pub fn write_app_help(w: &'a mut Write, app: &App, use_long: bool) -> ClapResult<()> {
         debugln!("Help::write_app_help;");
-        Self::write_parser_help(w, &app.p)
+        Self::write_parser_help(w, &app.p, use_long)
     }
 
     /// Reads help settings from a Parser
     /// and write its help to the wrapped stream.
-    pub fn write_parser_help(w: &'a mut Write, parser: &Parser) -> ClapResult<()> {
+    pub fn write_parser_help(w: &'a mut Write, parser: &Parser, use_long: bool) -> ClapResult<()> {
         debugln!("Help::write_parser_help;");
-        Self::_write_parser_help(w, parser, false)
+        Self::_write_parser_help(w, parser, false, use_long)
     }
 
     /// Reads help settings from a Parser
@@ -143,11 +146,11 @@ impl<'a> Help<'a> {
     /// formatting when required.
     pub fn write_parser_help_to_stderr(w: &'a mut Write, parser: &Parser) -> ClapResult<()> {
         debugln!("Help::write_parser_help;");
-        Self::_write_parser_help(w, parser, true)
+        Self::_write_parser_help(w, parser, true, false)
     }
 
     #[doc(hidden)]
-    pub fn _write_parser_help(w: &'a mut Write, parser: &Parser, stderr: bool) -> ClapResult<()> {
+    pub fn _write_parser_help(w: &'a mut Write, parser: &Parser, stderr: bool, use_long: bool) -> ClapResult<()> {
         debugln!("Help::write_parser_help;");
         let nlh = parser.is_set(AppSettings::NextLineHelp);
         let hide_v = parser.is_set(AppSettings::HidePossibleValuesInHelp);
@@ -162,8 +165,9 @@ impl<'a> Help<'a> {
                   color,
                   cizer,
                   parser.meta.term_w,
-                  parser.meta.max_w)
-            .write_help(parser)
+                  parser.meta.max_w,
+                  use_long)
+                .write_help(parser)
     }
 
     /// Writes the parser help to the wrapped stream.
@@ -191,8 +195,9 @@ impl<'a> Help<'a> {
         self.longest = 2;
         let mut arg_v = Vec::with_capacity(10);
         for arg in args.filter(|arg| {
-            !(arg.is_set(ArgSettings::Hidden)) || arg.is_set(ArgSettings::NextLineHelp)
-        }) {
+                                   !(arg.is_set(ArgSettings::Hidden)) ||
+                                   arg.is_set(ArgSettings::NextLineHelp)
+                               }) {
             if arg.longest_filter() {
                 self.longest = cmp::max(self.longest, arg.to_string().len());
             }
@@ -432,8 +437,12 @@ impl<'a> Help<'a> {
     fn help<'b, 'c>(&mut self, arg: &ArgWithDisplay<'b, 'c>, spec_vals: &str) -> io::Result<()> {
         debugln!("Help::help;");
         let mut help = String::new();
-        let h = arg.help().unwrap_or("");
-        let nlh = self.next_line_help || arg.is_set(ArgSettings::NextLineHelp);
+        let h = if self.use_long {
+            arg.long_help().unwrap_or(arg.help().unwrap_or(""))
+        } else {
+            arg.help().unwrap_or(arg.long_help().unwrap_or(""))
+        };
+        let nlh = self.next_line_help || arg.is_set(ArgSettings::NextLineHelp) || self.use_long;
         debugln!("Help::help: Next Line...{:?}", nlh);
 
         let spcs = if nlh || self.force_next_line {
@@ -513,7 +522,8 @@ impl<'a> Help<'a> {
             debugln!("Help::spec_vals: Found aliases...{:?}", aliases);
             spec_vals.push(format!(" [aliases: {}]",
                                    if self.color {
-                                       aliases.iter()
+                                       aliases
+                                           .iter()
                                            .map(|v| format!("{}", self.cizer.good(v)))
                                            .collect::<Vec<_>>()
                                            .join(", ")
@@ -525,14 +535,14 @@ impl<'a> Help<'a> {
             if let Some(pv) = a.possible_vals() {
                 debugln!("Help::spec_vals: Found possible vals...{:?}", pv);
                 spec_vals.push(if self.color {
-                    format!(" [values: {}]",
-                            pv.iter()
-                                .map(|v| format!("{}", self.cizer.good(v)))
-                                .collect::<Vec<_>>()
-                                .join(", "))
-                } else {
-                    format!(" [values: {}]", pv.join(", "))
-                });
+                                   format!(" [values: {}]",
+                                           pv.iter()
+                                               .map(|v| format!("{}", self.cizer.good(v)))
+                                               .collect::<Vec<_>>()
+                                               .join(", "))
+                               } else {
+                                   format!(" [values: {}]", pv.join(", "))
+                               });
             }
         }
         spec_vals.join(" ")
@@ -548,7 +558,10 @@ impl<'a> Help<'a> {
     pub fn write_all_args(&mut self, parser: &Parser) -> ClapResult<()> {
         debugln!("Help::write_all_args;");
         let flags = parser.has_flags();
-        let pos = parser.positionals().filter(|arg| !arg.is_set(ArgSettings::Hidden)).count() > 0;
+        let pos = parser
+            .positionals()
+            .filter(|arg| !arg.is_set(ArgSettings::Hidden))
+            .count() > 0;
         let opts = parser.has_opts();
         let subcmds = parser.has_subcommands();
 
@@ -557,7 +570,8 @@ impl<'a> Help<'a> {
         let mut first = true;
 
         if unified_help && (flags || opts) {
-            let opts_flags = parser.flags()
+            let opts_flags = parser
+                .flags()
                 .map(as_arg_trait)
                 .chain(parser.opts().map(as_arg_trait));
             try!(color!(self, "OPTIONS:\n", warning));
@@ -566,8 +580,7 @@ impl<'a> Help<'a> {
         } else {
             if flags {
                 try!(color!(self, "FLAGS:\n", warning));
-                try!(self.write_args(parser.flags()
-                    .map(as_arg_trait)));
+                try!(self.write_args(parser.flags().map(as_arg_trait)));
                 first = false;
             }
             if opts {
@@ -606,8 +619,13 @@ impl<'a> Help<'a> {
         // The shortest an arg can legally be is 2 (i.e. '-x')
         self.longest = 2;
         let mut ord_m = VecMap::new();
-        for sc in parser.subcommands.iter().filter(|s| !s.p.is_set(AppSettings::Hidden)) {
-            let btm = ord_m.entry(sc.p.meta.disp_ord).or_insert(BTreeMap::new());
+        for sc in parser
+                .subcommands
+                .iter()
+                .filter(|s| !s.p.is_set(AppSettings::Hidden)) {
+            let btm = ord_m
+                .entry(sc.p.meta.disp_ord)
+                .or_insert(BTreeMap::new());
             self.longest = cmp::max(self.longest, sc.p.meta.name.len());
             btm.insert(sc.p.meta.name.clone(), sc.clone());
         }
@@ -861,9 +879,9 @@ impl<'a> Help<'a> {
 
             debugln!("Help::write_template_help:iter: tag_buf={};", unsafe {
                 String::from_utf8_unchecked(tag_buf.get_ref()[0..tag_length]
-                    .iter()
-                    .map(|&i| i)
-                    .collect::<Vec<_>>())
+                                                .iter()
+                                                .map(|&i| i)
+                                                .collect::<Vec<_>>())
             });
             match &tag_buf.get_ref()[0..tag_length] {
                 b"?" => {
@@ -894,22 +912,20 @@ impl<'a> Help<'a> {
                     try!(self.write_all_args(&parser));
                 }
                 b"unified" => {
-                    let opts_flags = parser.flags()
+                    let opts_flags = parser
+                        .flags()
                         .map(as_arg_trait)
                         .chain(parser.opts().map(as_arg_trait));
                     try!(self.write_args(opts_flags));
                 }
                 b"flags" => {
-                    try!(self.write_args(parser.flags()
-                        .map(as_arg_trait)));
+                    try!(self.write_args(parser.flags().map(as_arg_trait)));
                 }
                 b"options" => {
-                    try!(self.write_args(parser.opts()
-                        .map(as_arg_trait)));
+                    try!(self.write_args(parser.opts().map(as_arg_trait)));
                 }
                 b"positionals" => {
-                    try!(self.write_args(parser.positionals()
-                        .map(as_arg_trait)));
+                    try!(self.write_args(parser.positionals().map(as_arg_trait)));
                 }
                 b"subcommands" => {
                     try!(self.write_subcommands(&parser));
diff --git a/src/app/meta.rs b/src/app/meta.rs
index 33b2f355..6fbf412c 100644
--- a/src/app/meta.rs
+++ b/src/app/meta.rs
@@ -1,11 +1,14 @@
 #[doc(hidden)]
 #[allow(missing_debug_implementations)]
+#[derive(Default, Clone)]
 pub struct AppMeta<'b> {
     pub name: String,
     pub bin_name: Option<String>,
     pub author: Option<&'b str>,
     pub version: Option<&'b str>,
+    pub long_version: Option<&'b str>,
     pub about: Option<&'b str>,
+    pub long_about: Option<&'b str>,
     pub more_help: Option<&'b str>,
     pub pre_help: Option<&'b str>,
     pub aliases: Option<Vec<(&'b str, bool)>>, // (name, visible)
@@ -18,51 +21,7 @@ pub struct AppMeta<'b> {
     pub template: Option<&'b str>,
 }
 
-impl<'b> Default for AppMeta<'b> {
-    fn default() -> Self {
-        AppMeta {
-            name: String::new(),
-            author: None,
-            about: None,
-            more_help: None,
-            pre_help: None,
-            version: None,
-            usage_str: None,
-            usage: None,
-            bin_name: None,
-            help_str: None,
-            disp_ord: 999,
-            template: None,
-            aliases: None,
-            term_w: None,
-            max_w: None,
-        }
-    }
-}
-
 impl<'b> AppMeta<'b> {
     pub fn new() -> Self { Default::default() }
-    pub fn with_name(s: String) -> Self { AppMeta { name: s, ..Default::default() } }
-}
-
-impl<'b> Clone for AppMeta<'b> {
-    fn clone(&self) -> Self {
-        AppMeta {
-            name: self.name.clone(),
-            author: self.author,
-            about: self.about,
-            more_help: self.more_help,
-            pre_help: self.pre_help,
-            version: self.version,
-            usage_str: self.usage_str,
-            usage: self.usage.clone(),
-            bin_name: self.bin_name.clone(),
-            help_str: self.help_str,
-            disp_ord: self.disp_ord,
-            template: self.template,
-            aliases: self.aliases.clone(),
-            term_w: self.term_w,
-            max_w: self.max_w,
-        }
-    }
-}
+    pub fn with_name(s: String) -> Self { AppMeta { name: s, disp_ord: 999, ..Default::default() } }
+}
\ No newline at end of file
diff --git a/src/app/mod.rs b/src/app/mod.rs
index 428bcdbd..0c9f9aee 100644
--- a/src/app/mod.rs
+++ b/src/app/mod.rs
@@ -200,7 +200,13 @@ impl<'a, 'b> App<'a, 'b> {
     }
 
     /// Sets a string describing what the program does. This will be displayed when displaying help
-    /// information.
+    /// information with `-h`.
+    ///
+    /// **NOTE:** If only `about` is provided, and not [`App::long_about`] but the user requests
+    /// `--help` clap will still display the contents of `about` appropriately
+    ///
+    /// **NOTE:** Only [`App::about`] is used in completion script generation in order to be
+    /// concise
     ///
     /// # Examples
     ///
@@ -210,11 +216,38 @@ impl<'a, 'b> App<'a, 'b> {
     ///     .about("Does really amazing things to great people")
     /// # ;
     /// ```
+    /// [`App::long_about`]: ./struct.App.html#method.long_about
     pub fn about<S: Into<&'b str>>(mut self, about: S) -> Self {
         self.p.meta.about = Some(about.into());
         self
     }
 
+    /// Sets a string describing what the program does. This will be displayed when displaying help
+    /// information.
+    ///
+    /// **NOTE:** If only `long_about` is provided, and not [`App::about`] but the user requests
+    /// `-h` clap will still display the contents of `long_about` appropriately
+    ///
+    /// **NOTE:** Only [`App::about`] is used in completion script generation in order to be
+    /// concise
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// # use clap::{App, Arg};
+    /// App::new("myprog")
+    ///     .long_about(
+    /// "Does really amazing things to great people. Now let's talk a little
+    ///  more in depth about how this subcommand really works. It may take about
+    ///  a few lines of text, but that's ok!")
+    /// # ;
+    /// ```
+    /// [`App::about`]: ./struct.App.html#method.about
+    pub fn long_about<S: Into<&'b str>>(mut self, about: S) -> Self {
+        self.p.meta.long_about = Some(about.into());
+        self
+    }
+
     /// Sets the program's name. This will be displayed when displaying help information.
     ///
     /// **Pro-top:** This function is particularly useful when configuring a program via
@@ -277,7 +310,10 @@ impl<'a, 'b> App<'a, 'b> {
     }
 
     /// Sets a string of the version number to be displayed when displaying version or help
-    /// information.
+    /// information with `-V`. 
+    ///
+    /// **NOTE:** If only `version` is provided, and not [`App::long_version`] but the user
+    /// requests `--version` clap will still display the contents of `version` appropriately
     ///
     /// **Pro-tip:** Use `clap`s convenience macro [`crate_version!`] to automatically set your
     /// application's version to the same thing as your crate at compile time. See the [`examples/`]
@@ -293,11 +329,43 @@ impl<'a, 'b> App<'a, 'b> {
     /// ```
     /// [`crate_version!`]: ./macro.crate_version!.html
     /// [`examples/`]: https://github.com/kbknapp/clap-rs/tree/master/examples
+    /// [`App::long_version`]: ./struct.App.html#method.long_version
     pub fn version<S: Into<&'b str>>(mut self, ver: S) -> Self {
         self.p.meta.version = Some(ver.into());
         self
     }
 
+    /// Sets a string of the version number to be displayed when displaying version or help
+    /// information with `--version`.
+    ///
+    /// **NOTE:** If only `long_version` is provided, and not [`App::version`] but the user
+    /// requests `-V` clap will still display the contents of `long_version` appropriately
+    ///
+    /// **Pro-tip:** Use `clap`s convenience macro [`crate_version!`] to automatically set your
+    /// application's version to the same thing as your crate at compile time. See the [`examples/`]
+    /// directory for more information
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// # use clap::{App, Arg};
+    /// App::new("myprog")
+    ///     .long_version(
+    /// "v0.1.24
+    ///  commit: abcdef89726d
+    ///  revision: 123
+    ///  release: 2
+    ///  binary: myprog")
+    /// # ;
+    /// ```
+    /// [`crate_version!`]: ./macro.crate_version!.html
+    /// [`examples/`]: https://github.com/kbknapp/clap-rs/tree/master/examples
+    /// [`App::version`]: ./struct.App.html#method.version
+    pub fn long_version<S: Into<&'b str>>(mut self, ver: S) -> Self {
+        self.p.meta.long_version = Some(ver.into());
+        self
+    }
+
     /// Sets a custom usage string to override the auto-generated usage string.
     ///
     /// This will be displayed to the user when errors are found in argument parsing, or when you
@@ -1062,7 +1130,11 @@ impl<'a, 'b> App<'a, 'b> {
         self
     }
 
-    /// Prints the full help message to [`io::stdout()`] using a [`BufWriter`]
+    /// Prints the full help message to [`io::stdout()`] using a [`BufWriter`] using the same
+    /// method as if someone ran `-h` to request the help message
+    ///
+    /// **NOTE:** clap has the ability to distinguish between "short" and "long" help messages
+    /// depending on if the user ran [`-h` (short)] or [`--help` (long)]
     ///
     /// # Examples
     ///
@@ -1073,6 +1145,8 @@ impl<'a, 'b> App<'a, 'b> {
     /// ```
     /// [`io::stdout()`]: https://doc.rust-lang.org/std/io/fn.stdout.html
     /// [`BufWriter`]: https://doc.rust-lang.org/std/io/struct.BufWriter.html
+    /// [`-h` (short)]: ./struct.Arg.html#method.help
+    /// [`--help` (long)]: ./struct.Arg.html#method.long_help
     pub fn print_help(&mut self) -> ClapResult<()> {
         // If there are global arguments, or settings we need to propgate them down to subcommands
         // before parsing incase we run into a subcommand
@@ -1086,7 +1160,45 @@ impl<'a, 'b> App<'a, 'b> {
         self.write_help(&mut buf_w)
     }
 
-    /// Writes the full help message to the user to a [`io::Write`] object
+    /// Prints the full help message to [`io::stdout()`] using a [`BufWriter`] using the same
+    /// method as if someone ran `-h` to request the help message
+    ///
+    /// **NOTE:** clap has the ability to distinguish between "short" and "long" help messages
+    /// depending on if the user ran [`-h` (short)] or [`--help` (long)]
+    ///
+    /// # Examples
+    ///
+    /// ```rust
+    /// # use clap::App;
+    /// let mut app = App::new("myprog");
+    /// app.print_long_help();
+    /// ```
+    /// [`io::stdout()`]: https://doc.rust-lang.org/std/io/fn.stdout.html
+    /// [`BufWriter`]: https://doc.rust-lang.org/std/io/struct.BufWriter.html
+    /// [`-h` (short)]: ./struct.Arg.html#method.help
+    /// [`--help` (long)]: ./struct.Arg.html#method.long_help
+    pub fn print_long_help(&mut self) -> ClapResult<()> {
+        // If there are global arguments, or settings we need to propgate them down to subcommands
+        // before parsing incase we run into a subcommand
+        self.p.propogate_globals();
+        self.p.propogate_settings();
+        self.p.derive_display_order();
+
+        self.p.create_help_and_version();
+        let out = io::stdout();
+        let mut buf_w = BufWriter::new(out.lock());
+        self.write_long_help(&mut buf_w)
+    }
+
+    /// Writes the full help message to the user to a [`io::Write`] object in the same method as if
+    /// the user ran `-h`
+    ///
+    /// **NOTE:** clap has the ability to distinguish between "short" and "long" help messages
+    /// depending on if the user ran [`-h` (short)] or [`--help` (long)]
+    ///
+    /// **NOTE:** There is a known bug where this method does not write propogated global arguments
+    /// or autogenerated arguments (i.e. the default help/version args). Prefer
+    /// [`App::write_long_help`] instead if possibe!
     ///
     /// # Examples
     ///
@@ -1098,6 +1210,8 @@ impl<'a, 'b> App<'a, 'b> {
     /// app.write_help(&mut out).expect("failed to write to stdout");
     /// ```
     /// [`io::Write`]: https://doc.rust-lang.org/std/io/trait.Write.html
+    /// [`-h` (short)]: ./struct.Arg.html#method.help
+    /// [`--help` (long)]: ./struct.Arg.html#method.long_help
     pub fn write_help<W: Write>(&self, w: &mut W) -> ClapResult<()> {
         // PENDING ISSUE: 808
         //      https://github.com/kbknapp/clap-rs/issues/808
@@ -1108,10 +1222,40 @@ impl<'a, 'b> App<'a, 'b> {
         // self.p.derive_display_order();
         // self.p.create_help_and_version();
 
-        Help::write_app_help(w, self)
+        Help::write_app_help(w, self, false)
     }
 
-    /// Writes the version message to the user to a [`io::Write`] object
+    /// Writes the full help message to the user to a [`io::Write`] object in the same method as if
+    /// the user ran `--help`
+    ///
+    /// **NOTE:** clap has the ability to distinguish between "short" and "long" help messages
+    /// depending on if the user ran [`-h` (short)] or [`--help` (long)]
+    ///
+    /// # Examples
+    ///
+    /// ```rust
+    /// # use clap::App;
+    /// use std::io;
+    /// let mut app = App::new("myprog");
+    /// let mut out = io::stdout();
+    /// app.write_long_help(&mut out).expect("failed to write to stdout");
+    /// ```
+    /// [`io::Write`]: https://doc.rust-lang.org/std/io/trait.Write.html
+    /// [`-h` (short)]: ./struct.Arg.html#method.help
+    /// [`--help` (long)]: ./struct.Arg.html#method.long_help
+    pub fn write_long_help<W: Write>(&mut self, w: &mut W) -> ClapResult<()> {
+        self.p.propogate_globals();
+        self.p.propogate_settings();
+        self.p.derive_display_order();
+        self.p.create_help_and_version();
+
+        Help::write_app_help(w, self, true)
+    }
+
+    /// Writes the version message to the user to a [`io::Write`] object as if the user ran `-V`.
+    ///
+    /// **NOTE:** clap has the ability to distinguish between "short" and "long" version messages
+    /// depending on if the user ran [`-V` (short)] or [`--version` (long)]
     ///
     /// # Examples
     ///
@@ -1123,10 +1267,32 @@ impl<'a, 'b> App<'a, 'b> {
     /// app.write_version(&mut out).expect("failed to write to stdout");
     /// ```
     /// [`io::Write`]: https://doc.rust-lang.org/std/io/trait.Write.html
+    /// [`-V` (short)]: ./struct.App.html#method.version
+    /// [`--version` (long)]: ./struct.App.html#method.long_version
     pub fn write_version<W: Write>(&self, w: &mut W) -> ClapResult<()> {
-        self.p.write_version(w).map_err(From::from)
+        self.p.write_version(w, false).map_err(From::from)
     }
 
+    /// Writes the version message to the user to a [`io::Write`] object
+    ///
+    /// **NOTE:** clap has the ability to distinguish between "short" and "long" version messages
+    /// depending on if the user ran [`-V` (short)] or [`--version` (long)]
+    ///
+    /// # Examples
+    ///
+    /// ```rust
+    /// # use clap::App;
+    /// use std::io;
+    /// let mut app = App::new("myprog");
+    /// let mut out = io::stdout();
+    /// app.write_long_version(&mut out).expect("failed to write to stdout");
+    /// ```
+    /// [`io::Write`]: https://doc.rust-lang.org/std/io/trait.Write.html
+    /// [`-V` (short)]: ./struct.App.html#method.version
+    /// [`--version` (long)]: ./struct.App.html#method.long_version
+    pub fn write_long_version<W: Write>(&self, w: &mut W) -> ClapResult<()> {
+        self.p.write_version(w, true).map_err(From::from)
+    }
 
     /// Generate a completions file for a specified shell at compile time.
     ///
@@ -1183,7 +1349,7 @@ impl<'a, 'b> App<'a, 'b> {
     /// build = "build.rs"
     ///
     /// [build-dependencies]
-    /// clap = "2.9"
+    /// clap = "2.23"
     /// ```
     ///
     /// Next, we place a `build.rs` in our project root.
@@ -1622,6 +1788,7 @@ impl<'n, 'e> AnyArg<'n, 'e> for App<'n, 'e> {
     fn val_delim(&self) -> Option<char> { None }
     fn takes_value(&self) -> bool { true }
     fn help(&self) -> Option<&'e str> { self.p.meta.about }
+    fn long_help(&self) -> Option<&'e str> { self.p.meta.long_about }
     fn default_val(&self) -> Option<&'e OsStr> { None }
     fn default_vals_ifs(&self) -> Option<vec_map::Values<(&'n str, Option<&'e OsStr>, &'e OsStr)>> {
         None
diff --git a/src/app/parser.rs b/src/app/parser.rs
index d0cdae9e..4c6b8664 100644
--- a/src/app/parser.rs
+++ b/src/app/parser.rs
@@ -63,7 +63,10 @@ impl<'a, 'b> Parser<'a, 'b>
     where 'a: 'b
 {
     pub fn with_name(n: String) -> Self {
-        Parser { meta: AppMeta::with_name(n), ..Default::default() }
+        Parser {
+            meta: AppMeta::with_name(n),
+            ..Default::default()
+        }
     }
 
     pub fn help_short(&mut self, s: &str) {
@@ -98,11 +101,7 @@ impl<'a, 'b> Parser<'a, 'b>
         use std::error::Error;
 
         let out_dir = PathBuf::from(od);
-        let name = &*self.meta
-                         .bin_name
-                         .as_ref()
-                         .unwrap()
-                         .clone();
+        let name = &*self.meta.bin_name.as_ref().unwrap().clone();
         let file_name = match for_shell {
             Shell::Bash => format!("{}.bash-completion", name),
             Shell::Fish => format!("{}.fish", name),
@@ -146,7 +145,9 @@ impl<'a, 'b> Parser<'a, 'b>
                           global and required",
                 a.b.name);
         if a.b.is_set(ArgSettings::Last) {
-            assert!(!self.positionals.values().any(|p| p.b.is_set(ArgSettings::Last)),
+            assert!(!self.positionals
+                         .values()
+                         .any(|p| p.b.is_set(ArgSettings::Last)),
                     "Only one positional argument may have last(true) set. Found two.");
             assert!(a.s.long.is_none(),
                     "Flags or Options may not have last(true) set. {} has both a long and last(true) set.",
@@ -190,7 +191,10 @@ impl<'a, 'b> Parser<'a, 'b>
         if a.is_set(ArgSettings::Required) {
             // If the arg is required, add all it's requirements to master required list
             if let Some(ref areqs) = a.b.requires {
-                for name in areqs.iter().filter(|&&(val, _)| val.is_none()).map(|&(_, name)| name) {
+                for name in areqs
+                        .iter()
+                        .filter(|&&(val, _)| val.is_none())
+                        .map(|&(_, name)| name) {
                     self.required.push(name);
                 }
             }
@@ -206,6 +210,13 @@ impl<'a, 'b> Parser<'a, 'b>
             self.set(AS::DontCollapseArgsInUsage);
             self.set(AS::ContainsLast);
         }
+        if let Some(l) = a.s.long {
+            if l == "version" {
+                self.unset(AS::NeedsLongVersion);
+            } else if l == "help" {
+                self.unset(AS::NeedsLongHelp);
+            }
+        }
     }
 
     // actually adds the arguments
@@ -225,7 +236,8 @@ impl<'a, 'b> Parser<'a, 'b>
             } else {
                 a.index.unwrap() as usize
             };
-            self.positionals.insert(i, PosBuilder::from_arg(a, i as u64));
+            self.positionals
+                .insert(i, PosBuilder::from_arg(a, i as u64));
         } else if a.is_set(ArgSettings::TakesValue) {
             let mut ob = OptBuilder::from(a);
             ob.s.unified_ord = self.flags.len() + self.opts.len();
@@ -319,11 +331,7 @@ impl<'a, 'b> Parser<'a, 'b>
                 if vsc {
                     sc.p.set(AS::DisableVersion);
                 }
-                if gv &&
-                   sc.p
-                       .meta
-                       .version
-                       .is_none() && self.meta.version.is_some() {
+                if gv && sc.p.meta.version.is_none() && self.meta.version.is_some() {
                     sc.p.set(AS::GlobalVersion);
                     sc.p.meta.version = Some(self.meta.version.unwrap());
                 }
@@ -397,7 +405,9 @@ impl<'a, 'b> Parser<'a, 'b>
         if self.flags.is_empty() {
             return false;
         }
-        self.flags.iter().any(|f| !f.is_set(ArgSettings::Hidden))
+        self.flags
+            .iter()
+            .any(|f| !f.is_set(ArgSettings::Hidden))
     }
 
     #[inline]
@@ -405,7 +415,9 @@ impl<'a, 'b> Parser<'a, 'b>
         if self.positionals.is_empty() {
             return false;
         }
-        self.positionals.values().any(|p| !p.is_set(ArgSettings::Hidden))
+        self.positionals
+            .values()
+            .any(|p| !p.is_set(ArgSettings::Hidden))
     }
 
     #[inline]
@@ -433,10 +445,7 @@ impl<'a, 'b> Parser<'a, 'b>
         // Firt we verify that the index highest supplied index, is equal to the number of
         // positional arguments to verify there are no gaps (i.e. supplying an index of 1 and 3
         // but no 2)
-        if let Some((idx, p)) = self.positionals
-               .iter()
-               .rev()
-               .next() {
+        if let Some((idx, p)) = self.positionals.iter().rev().next() {
             assert!(!(idx != self.positionals.len()),
                     "Found positional argument \"{}\" who's index is {} but there \
                           are only {} positional arguments defined",
@@ -446,10 +455,12 @@ impl<'a, 'b> Parser<'a, 'b>
         }
 
         // Next we verify that only the highest index has a .multiple(true) (if any)
-        if self.positionals.values().any(|a| {
-                                             a.b.is_set(ArgSettings::Multiple) &&
-                                             (a.index as usize != self.positionals.len())
-                                         }) {
+        if self.positionals
+               .values()
+               .any(|a| {
+                        a.b.is_set(ArgSettings::Multiple) &&
+                        (a.index as usize != self.positionals.len())
+                    }) {
             let mut it = self.positionals.values().rev();
             let last = it.next().unwrap();
             let second_to_last = it.next().unwrap();
@@ -535,10 +546,11 @@ impl<'a, 'b> Parser<'a, 'b>
                 }
             }
         }
-        if self.positionals.values().any(|p| {
-                                             p.b.is_set(ArgSettings::Last) &&
-                                             p.b.is_set(ArgSettings::Required)
-                                         }) && self.has_subcommands() &&
+        if self.positionals
+               .values()
+               .any(|p| {
+                        p.b.is_set(ArgSettings::Last) && p.b.is_set(ArgSettings::Required)
+                    }) && self.has_subcommands() &&
            !self.is_set(AS::SubcommandsNegateReqs) {
             panic!("Having a required positional argument with .last(true) set *and* child \
             subcommands without setting SubcommandsNegateReqs isn't compatible.");
@@ -587,10 +599,7 @@ impl<'a, 'b> Parser<'a, 'b>
                 .iter()
                 .filter(|s| {
                     starts(&s.p.meta.name[..], &*arg_os) ||
-                    (s.p
-                         .meta
-                         .aliases
-                         .is_some() &&
+                    (s.p.meta.aliases.is_some() &&
                      s.p
                          .meta
                          .aliases
@@ -673,7 +682,7 @@ impl<'a, 'b> Parser<'a, 'b>
         if sc.meta.bin_name != self.meta.bin_name {
             sc.meta.bin_name = Some(format!("{} {}", bin_name, sc.meta.name));
         }
-        sc._help()
+        sc._help(false)
     }
 
     // allow wrong self convention due to self.valid_neg_num = true and it's a private method
@@ -743,11 +752,16 @@ impl<'a, 'b> Parser<'a, 'b>
         debugln!("Parser::get_matches_with;");
         // Verify all positional assertions pass
         debug_assert!(self.verify_positionals());
-        if self.positionals.values().any(|a| {
-                                             a.b.is_set(ArgSettings::Multiple) &&
-                                             (a.index as usize != self.positionals.len())
-                                         }) &&
-           self.positionals.values().last().map_or(false, |p| !p.is_set(ArgSettings::Last)) {
+        if self.positionals
+               .values()
+               .any(|a| {
+                        a.b.is_set(ArgSettings::Multiple) &&
+                        (a.index as usize != self.positionals.len())
+                    }) &&
+           self.positionals
+               .values()
+               .last()
+               .map_or(false, |p| !p.is_set(ArgSettings::Last)) {
             self.settings.set(AS::LowIndexMultiplePositional);
         }
         let has_args = self.has_args();
@@ -836,7 +850,8 @@ impl<'a, 'b> Parser<'a, 'b>
                    !self.is_set(AS::InferSubcommands) {
                     if let Some(cdate) = suggestions::did_you_mean(&*arg_os.to_string_lossy(),
                                                                    sc_names!(self)) {
-                        return Err(Error::invalid_subcommand(arg_os.to_string_lossy()
+                        return Err(Error::invalid_subcommand(arg_os
+                                                                 .to_string_lossy()
                                                                  .into_owned(),
                                                              cdate,
                                                              self.meta
@@ -955,7 +970,8 @@ impl<'a, 'b> Parser<'a, 'b>
                                                                                      None),
                                                          self.color()));
                 } else {
-                    return Err(Error::unrecognized_subcommand(arg_os.to_string_lossy()
+                    return Err(Error::unrecognized_subcommand(arg_os
+                                                                  .to_string_lossy()
                                                                   .into_owned(),
                                                               self.meta
                                                                   .bin_name
@@ -977,10 +993,7 @@ impl<'a, 'b> Parser<'a, 'b>
             };
             try!(self.parse_subcommand(&*sc_name, matcher, it));
         } else if self.is_set(AS::SubcommandRequired) {
-            let bn = self.meta
-                .bin_name
-                .as_ref()
-                .unwrap_or(&self.meta.name);
+            let bn = self.meta.bin_name.as_ref().unwrap_or(&self.meta.name);
             return Err(Error::missing_subcommand(bn,
                                                  &usage::create_error_usage(self, matcher, None),
                                                  self.color()));
@@ -1011,10 +1024,7 @@ impl<'a, 'b> Parser<'a, 'b>
         debugln!("Parser::build_bin_names;");
         for sc in &mut self.subcommands {
             debug!("Parser::build_bin_names:iter: bin_name set...");
-            if sc.p
-                   .meta
-                   .bin_name
-                   .is_none() {
+            if sc.p.meta.bin_name.is_none() {
                 sdebugln!("No");
                 let bin_name = format!("{}{}{}",
                                        self.meta
@@ -1052,10 +1062,7 @@ impl<'a, 'b> Parser<'a, 'b>
         debugln!("Parser::parse_subcommand;");
         let mut mid_string = String::new();
         if !self.is_set(AS::SubcommandsNegateReqs) {
-            let mut hs: Vec<&str> = self.required
-                .iter()
-                .map(|n| &**n)
-                .collect();
+            let mut hs: Vec<&str> = self.required.iter().map(|n| &**n).collect();
             for k in matcher.arg_names() {
                 hs.push(k);
             }
@@ -1066,41 +1073,35 @@ impl<'a, 'b> Parser<'a, 'b>
             }
         }
         mid_string.push_str(" ");
-        if let Some(ref mut sc) = self.subcommands.iter_mut().find(|s| &s.p.meta.name == &sc_name) {
+        if let Some(ref mut sc) = self.subcommands
+               .iter_mut()
+               .find(|s| &s.p.meta.name == &sc_name) {
             let mut sc_matcher = ArgMatcher::new();
             // bin_name should be parent's bin_name + [<reqs>] + the sc's name separated by
             // a space
             sc.p.meta.usage = Some(format!("{}{}{}",
-                                           self.meta
-                                               .bin_name
-                                               .as_ref()
-                                               .unwrap_or(&String::new()),
+                                           self.meta.bin_name.as_ref().unwrap_or(&String::new()),
                                            if self.meta.bin_name.is_some() {
                                                &*mid_string
                                            } else {
                                                ""
                                            },
                                            &*sc.p.meta.name));
-            sc.p.meta.bin_name = Some(format!("{}{}{}",
-                                              self.meta
-                                                  .bin_name
-                                                  .as_ref()
-                                                  .unwrap_or(&String::new()),
-                                              if self.meta.bin_name.is_some() {
-                                                  " "
-                                              } else {
-                                                  ""
-                                              },
-                                              &*sc.p.meta.name));
+            sc.p.meta.bin_name =
+                Some(format!("{}{}{}",
+                             self.meta.bin_name.as_ref().unwrap_or(&String::new()),
+                             if self.meta.bin_name.is_some() {
+                                 " "
+                             } else {
+                                 ""
+                             },
+                             &*sc.p.meta.name));
             debugln!("Parser::parse_subcommand: About to parse sc={}",
                      sc.p.meta.name);
             debugln!("Parser::parse_subcommand: sc settings={:#?}", sc.p.settings);
             try!(sc.p.get_matches_with(&mut sc_matcher, it));
             matcher.subcommand(SubCommand {
-                                   name: sc.p
-                                       .meta
-                                       .name
-                                       .clone(),
+                                   name: sc.p.meta.name.clone(),
                                    matches: sc_matcher.into(),
                                });
         }
@@ -1211,7 +1212,8 @@ impl<'a, 'b> Parser<'a, 'b>
             let arg = FlagBuilder {
                 b: Base {
                     name: "vclap_version",
-                    help: self.version_message.or(Some("Prints version information")),
+                    help: self.version_message
+                        .or(Some("Prints version information")),
                     ..Default::default()
                 },
                 s: Switched {
@@ -1239,11 +1241,11 @@ impl<'a, 'b> Parser<'a, 'b>
                arg.to_str().unwrap());
         if arg == "help" && self.is_set(AS::NeedsLongHelp) {
             sdebugln!("Help");
-            try!(self._help());
+            try!(self._help(true));
         }
         if arg == "version" && self.is_set(AS::NeedsLongVersion) {
             sdebugln!("Version");
-            try!(self._version());
+            try!(self._version(true));
         }
         sdebugln!("Neither");
 
@@ -1257,22 +1259,37 @@ impl<'a, 'b> Parser<'a, 'b>
         if let Some(h) = self.help_short {
             if arg == h && self.is_set(AS::NeedsLongHelp) {
                 sdebugln!("Help");
-                try!(self._help());
+                try!(self._help(false));
             }
         }
         if let Some(v) = self.version_short {
             if arg == v && self.is_set(AS::NeedsLongVersion) {
                 sdebugln!("Version");
-                try!(self._version());
+                try!(self._version(false));
             }
         }
         sdebugln!("Neither");
         Ok(())
     }
 
-    fn _help(&self) -> ClapResult<()> {
+    fn use_long_help(&self) -> bool {
+        let ul = self.flags.iter().any(|f| f.b.long_help.is_some()) ||
+                 self.opts.iter().any(|o| o.b.long_help.is_some()) ||
+                 self.positionals
+                     .values()
+                     .any(|p| p.b.long_help.is_some()) ||
+                 self.subcommands
+                     .iter()
+                     .any(|s| s.p.meta.long_about.is_some());
+        debugln!("Parser::use_long_help: ret={:?}", ul);
+        ul
+    }
+
+    fn _help(&self, mut use_long: bool) -> ClapResult<()> {
+        debugln!("Parser::_help: use_long={:?}", use_long);
+        use_long = use_long && self.use_long_help();
         let mut buf = vec![];
-        try!(Help::write_parser_help(&mut buf, self));
+        try!(Help::write_parser_help(&mut buf, self, use_long));
         Err(Error {
                 message: unsafe { String::from_utf8_unchecked(buf) },
                 kind: ErrorKind::HelpDisplayed,
@@ -1280,10 +1297,11 @@ impl<'a, 'b> Parser<'a, 'b>
             })
     }
 
-    fn _version(&self) -> ClapResult<()> {
+    fn _version(&self, use_long: bool) -> ClapResult<()> {
+        debugln!("Parser::_version: ");
         let out = io::stdout();
         let mut buf_w = BufWriter::new(out.lock());
-        try!(self.print_version(&mut buf_w));
+        try!(self.print_version(&mut buf_w, use_long));
         Err(Error {
                 message: String::new(),
                 kind: ErrorKind::VersionDisplayed,
@@ -1344,7 +1362,8 @@ impl<'a, 'b> Parser<'a, 'b>
         }
 
         debugln!("Parser::parse_long_arg: Didn't match anything");
-        self.did_you_mean_error(arg.to_str().expect(INVALID_UTF8), matcher).map(|_| None)
+        self.did_you_mean_error(arg.to_str().expect(INVALID_UTF8), matcher)
+            .map(|_| None)
     }
 
     #[cfg_attr(feature = "lints", allow(len_zero))]
@@ -1470,7 +1489,8 @@ impl<'a, 'b> Parser<'a, 'b>
 
         matcher.inc_occurrence_of(opt.b.name);
         // Increment or create the group "args"
-        self.groups_for_arg(opt.b.name).and_then(|vec| Some(matcher.inc_occurrences_of(&*vec)));
+        self.groups_for_arg(opt.b.name)
+            .and_then(|vec| Some(matcher.inc_occurrences_of(&*vec)));
 
         if val.is_none() ||
            !has_eq &&
@@ -1556,7 +1576,8 @@ impl<'a, 'b> Parser<'a, 'b>
 
         matcher.inc_occurrence_of(flag.b.name);
         // Increment or create the group "args"
-        self.groups_for_arg(flag.b.name).and_then(|vec| Some(matcher.inc_occurrences_of(&*vec)));
+        self.groups_for_arg(flag.b.name)
+            .and_then(|vec| Some(matcher.inc_occurrences_of(&*vec)));
 
         Ok(())
     }
@@ -1589,30 +1610,30 @@ impl<'a, 'b> Parser<'a, 'b>
     }
 
     // Prints the version to the user and exits if quit=true
-    fn print_version<W: Write>(&self, w: &mut W) -> ClapResult<()> {
-        try!(self.write_version(w));
+    fn print_version<W: Write>(&self, w: &mut W, use_long: bool) -> ClapResult<()> {
+        try!(self.write_version(w, use_long));
         w.flush().map_err(Error::from)
     }
 
-    pub fn write_version<W: Write>(&self, w: &mut W) -> io::Result<()> {
+    pub fn write_version<W: Write>(&self, w: &mut W, use_long: bool) -> io::Result<()> {
+        let ver = if use_long {
+            self.meta
+                .long_version
+                .unwrap_or(self.meta.version.unwrap_or("".into()))
+        } else {
+            self.meta
+                .version
+                .unwrap_or(self.meta.long_version.unwrap_or("".into()))
+        };
         if let Some(bn) = self.meta.bin_name.as_ref() {
             if bn.contains(' ') {
                 // Incase we're dealing with subcommands i.e. git mv is translated to git-mv
-                write!(w,
-                       "{} {}",
-                       bn.replace(" ", "-"),
-                       self.meta.version.unwrap_or("".into()))
+                write!(w, "{} {}", bn.replace(" ", "-"), ver)
             } else {
-                write!(w,
-                       "{} {}",
-                       &self.meta.name[..],
-                       self.meta.version.unwrap_or("".into()))
+                write!(w, "{} {}", &self.meta.name[..], ver)
             }
         } else {
-            write!(w,
-                   "{} {}",
-                   &self.meta.name[..],
-                   self.meta.version.unwrap_or("".into()))
+            write!(w, "{} {}", &self.meta.name[..], ver)
         }
     }
 
@@ -1623,7 +1644,11 @@ impl<'a, 'b> Parser<'a, 'b>
     }
 
     pub fn write_help<W: Write>(&self, w: &mut W) -> ClapResult<()> {
-        Help::write_parser_help(w, self)
+        Help::write_parser_help(w, self, false)
+    }
+
+    pub fn write_long_help<W: Write>(&self, w: &mut W) -> ClapResult<()> {
+        Help::write_parser_help(w, self, true)
     }
 
     pub fn write_help_err<W: Write>(&self, w: &mut W) -> ClapResult<()> {
@@ -1730,20 +1755,10 @@ impl<'a, 'b> Parser<'a, 'b>
     pub fn find_subcommand(&'b self, sc: &str) -> Option<&'b App<'a, 'b>> {
         debugln!("Parser::find_subcommand: sc={}", sc);
         debugln!("Parser::find_subcommand: Currently in Parser...{}",
-                 self.meta
-                     .bin_name
-                     .as_ref()
-                     .unwrap());
+                 self.meta.bin_name.as_ref().unwrap());
         for s in self.subcommands.iter() {
-            if s.p
-                   .meta
-                   .bin_name
-                   .as_ref()
-                   .unwrap_or(&String::new()) == sc ||
-               (s.p
-                    .meta
-                    .aliases
-                    .is_some() &&
+            if s.p.meta.bin_name.as_ref().unwrap_or(&String::new()) == sc ||
+               (s.p.meta.aliases.is_some() &&
                 s.p
                     .meta
                     .aliases
@@ -1751,12 +1766,8 @@ impl<'a, 'b> Parser<'a, 'b>
                     .unwrap()
                     .iter()
                     .any(|&(s, _)| {
-                s ==
-                sc.split(' ')
-                    .rev()
-                    .next()
-                    .expect(INTERNAL_ERROR_MSG)
-            })) {
+                             s == sc.split(' ').rev().next().expect(INTERNAL_ERROR_MSG)
+                         })) {
                 return Some(s);
             }
             if let Some(app) = s.p.find_subcommand(sc) {
diff --git a/src/args/any_arg.rs b/src/args/any_arg.rs
index 55245dba..5f8615fc 100644
--- a/src/args/any_arg.rs
+++ b/src/args/any_arg.rs
@@ -32,6 +32,7 @@ pub trait AnyArg<'n, 'e>: std_fmt::Display {
     fn takes_value(&self) -> bool;
     fn val_names(&self) -> Option<&VecMap<&'e str>>;
     fn help(&self) -> Option<&'e str>;
+    fn long_help(&self) -> Option<&'e str>;
     fn default_val(&self) -> Option<&'e OsStr>;
     fn default_vals_ifs(&self) -> Option<vec_map::Values<(&'n str, Option<&'e OsStr>, &'e OsStr)>>;
     fn longest_filter(&self) -> bool;
diff --git a/src/args/arg.rs b/src/args/arg.rs
index 9f57a883..860477c6 100644
--- a/src/args/arg.rs
+++ b/src/args/arg.rs
@@ -103,6 +103,7 @@ impl<'a, 'b> Arg<'a, 'b> {
                 "long" => yaml_to_str!(a, v, long),
                 "aliases" => yaml_vec_or_str!(v, a, alias),
                 "help" => yaml_to_str!(a, v, help),
+                "long_help" => yaml_to_str!(a, v, long_help),
                 "required" => yaml_to_bool!(a, v, required),
                 "required_if" => yaml_tuple2!(a, v, required_if),
                 "required_ifs" => yaml_tuple2!(a, v, required_if),
@@ -489,8 +490,14 @@ impl<'a, 'b> Arg<'a, 'b> {
         self
     }
 
-    /// Sets the help text of the argument that will be displayed to the user when they print the
-    /// usage/help information.
+    /// Sets the short help text of the argument that will be displayed to the user when they print
+    /// the help information with `-h`. Typically, this is a short (one line) description of the
+    /// arg.
+    ///
+    /// **NOTE:** If only `Arg::help` is provided, and not [`Arg::long_help`] but the user requests
+    /// `--help` clap will still display the contents of `help` appropriately
+    ///
+    /// **NOTE:** Only `Arg::help` is used in completion script generation in order to be concise
     ///
     /// # Examples
     ///
@@ -532,11 +539,83 @@ impl<'a, 'b> Arg<'a, 'b> {
     /// -h, --help       Prints help information
     /// -V, --version    Prints version information
     /// ```
+    /// [`Arg::long_help`]: ./struct.Arg.html#method.long_help
     pub fn help(mut self, h: &'b str) -> Self {
         self.b.help = Some(h);
         self
     }
 
+    /// Sets the long help text of the argument that will be displayed to the user when they print
+    /// the help information with `--help`. Typically this a more detailed (multi-line) message
+    /// that describes the arg.
+    ///
+    /// **NOTE:** If only `long_help` is provided, and not [`Arg::help`] but the user requests `-h`
+    /// clap will still display the contents of `long_help` appropriately
+    ///
+    /// **NOTE:** Only [`Arg::help`] is used in completion script generation in order to be concise
+    ///
+    /// # Examples
+    ///
+    /// Any valid UTF-8 is allowed in the help text. The one exception is when one wishes to
+    /// include a newline in the help text and have the following text be properly aligned with all
+    /// the other help text.
+    ///
+    /// ```rust
+    /// # use clap::{App, Arg};
+    /// Arg::with_name("config")
+    ///     .long_help(
+    /// "The config file used by the myprog must be in JSON format
+    /// with only valid keys and may not contain other nonsense
+    /// that cannot be read by this program. Obviously I'm going on
+    /// and on, so I'll stop now.")
+    /// # ;
+    /// ```
+    ///
+    /// Setting `help` displays a short message to the side of the argument when the user passes
+    /// `-h` or `--help` (by default).
+    ///
+    /// ```rust
+    /// # use clap::{App, Arg};
+    /// let m = App::new("prog")
+    ///     .arg(Arg::with_name("cfg")
+    ///         .long("config")
+    ///         .long_help(
+    /// "The config file used by the myprog must be in JSON format
+    /// with only valid keys and may not contain other nonsense
+    /// that cannot be read by this program. Obviously I'm going on
+    /// and on, so I'll stop now."))
+    ///     .get_matches_from(vec![
+    ///         "prog", "--help"
+    ///     ]);
+    /// ```
+    ///
+    /// The above example displays
+    ///
+    /// ```notrust
+    /// helptest
+    ///
+    /// USAGE:
+    ///    helptest [FLAGS]
+    ///
+    /// FLAGS:
+    ///    --config
+    ///         The config file used by the myprog must be in JSON format
+    ///         with only valid keys and may not contain other nonsense
+    ///         that cannot be read by this program. Obviously I'm going on
+    ///         and on, so I'll stop now.
+    ///
+    /// -h, --help       
+    ///         Prints help information
+    ///
+    /// -V, --version    
+    ///         Prints version information
+    /// ```
+    /// [`Arg::help`]: ./struct.Arg.html#method.help
+    pub fn long_help(mut self, h: &'b str) -> Self {
+        self.b.long_help = Some(h);
+        self
+    }
+
     /// Specifies that this arg is the last, or final, positional argument (i.e. has the highest
     /// index) and is *only* able to be accessed via the `--` syntax (i.e. `$ prog args --
     /// last_arg`). Even, if no other arguments are left to parse, if the user omits the `--` syntax
diff --git a/src/args/arg_builder/base.rs b/src/args/arg_builder/base.rs
index 8b566e38..5990bc08 100644
--- a/src/args/arg_builder/base.rs
+++ b/src/args/arg_builder/base.rs
@@ -7,6 +7,7 @@ pub struct Base<'a, 'b>
 {
     pub name: &'a str,
     pub help: Option<&'b str>,
+    pub long_help: Option<&'b str>,
     pub blacklist: Option<Vec<&'a str>>,
     pub settings: ArgFlags,
     pub r_unless: Option<Vec<&'a str>>,
diff --git a/src/args/arg_builder/flag.rs b/src/args/arg_builder/flag.rs
index d1c16690..e3e9dd01 100644
--- a/src/args/arg_builder/flag.rs
+++ b/src/args/arg_builder/flag.rs
@@ -79,6 +79,7 @@ impl<'n, 'e> AnyArg<'n, 'e> for FlagBuilder<'n, 'e> {
     fn long(&self) -> Option<&'e str> { self.s.long }
     fn val_delim(&self) -> Option<char> { None }
     fn help(&self) -> Option<&'e str> { self.b.help }
+    fn long_help(&self) -> Option<&'e str> { self.b.long_help }
     fn val_terminator(&self) -> Option<&'e str> { None }
     fn default_val(&self) -> Option<&'e OsStr> { None }
     fn default_vals_ifs(&self) -> Option<vec_map::Values<(&'n str, Option<&'e OsStr>, &'e OsStr)>> {
diff --git a/src/args/arg_builder/option.rs b/src/args/arg_builder/option.rs
index 342ccbdc..64dd9c46 100644
--- a/src/args/arg_builder/option.rs
+++ b/src/args/arg_builder/option.rs
@@ -129,6 +129,7 @@ impl<'n, 'e> AnyArg<'n, 'e> for OptBuilder<'n, 'e> {
     fn val_delim(&self) -> Option<char> { self.v.val_delim }
     fn takes_value(&self) -> bool { true }
     fn help(&self) -> Option<&'e str> { self.b.help }
+    fn long_help(&self) -> Option<&'e str> { self.b.long_help }
     fn default_val(&self) -> Option<&'e OsStr> { self.v.default_val }
     fn default_vals_ifs(&self) -> Option<vec_map::Values<(&'n str, Option<&'e OsStr>, &'e OsStr)>> {
         self.v.default_vals_ifs.as_ref().map(|vm| vm.values())
diff --git a/src/args/arg_builder/positional.rs b/src/args/arg_builder/positional.rs
index ddbd8964..c77976b1 100644
--- a/src/args/arg_builder/positional.rs
+++ b/src/args/arg_builder/positional.rs
@@ -126,6 +126,7 @@ impl<'n, 'e> AnyArg<'n, 'e> for PosBuilder<'n, 'e> {
     fn val_delim(&self) -> Option<char> { self.v.val_delim }
     fn takes_value(&self) -> bool { true }
     fn help(&self) -> Option<&'e str> { self.b.help }
+    fn long_help(&self) -> Option<&'e str> { self.b.long_help }
     fn default_vals_ifs(&self) -> Option<vec_map::Values<(&'n str, Option<&'e OsStr>, &'e OsStr)>> {
         self.v.default_vals_ifs.as_ref().map(|vm| vm.values())
     }
diff --git a/src/macros.rs b/src/macros.rs
index 6fc7763a..650042fb 100644
--- a/src/macros.rs
+++ b/src/macros.rs
@@ -562,6 +562,8 @@ macro_rules! app_from_crate {
 ///
 /// * A single hyphen followed by a character (such as `-c`) sets the [`Arg::short`]
 /// * A double hyphen followed by a character or word (such as `--config`) sets [`Arg::long`]
+///   * If one wishes to use a [`Arg::long`] with a hyphen inside (i.e. `--config-file`), you
+///     must use `--("config-file")` due to limitations of the Rust macro system.
 /// * Three dots (`...`) sets [`Arg::multiple(true)`]
 /// * Angled brackets after either a short or long will set [`Arg::value_name`] and
 /// `Arg::required(true)` such as `--config <FILE>` = `Arg::value_name("FILE")` and
@@ -595,6 +597,13 @@ macro_rules! app_from_crate {
 #[macro_export]
 macro_rules! clap_app {
     (@app ($builder:expr)) => { $builder };
+    (@app ($builder:expr) (@arg ($name:expr): $($tail:tt)*) $($tt:tt)*) => {
+        clap_app!{ @app
+            ($builder.arg(
+                clap_app!{ @arg ($crate::Arg::with_name($name)) (-) $($tail)* }))
+            $($tt)*
+        }
+    };
     (@app ($builder:expr) (@arg $name:ident: $($tail:tt)*) $($tt:tt)*) => {
         clap_app!{ @app
             ($builder.arg(


Test patch:
diff --git a/tests/help.rs b/tests/help.rs
index 3f273931..89ed7ec6 100644
--- a/tests/help.rs
+++ b/tests/help.rs
@@ -831,3 +831,16 @@ fn hidden_default_val() {
              .default_value("default-argument"));
     assert!(test::compare_output(app2, "default --help", HIDE_DEFAULT_VAL, false));
 }
+
+#[test]
+fn override_help() {
+    let m = App::new("test")
+        .author("Kevin K.")
+        .about("tests stuff")
+        .version("1.3")
+        .arg(Arg::from_usage("-H, --help 'some help'"))
+        .get_matches_from_safe(vec!["test", "--help"]);
+
+    assert!(m.is_ok());
+    assert!(m.unwrap().is_present("help"));
+}
\ No newline at end of file
diff --git a/tests/macros.rs b/tests/macros.rs
index cc25e1bf..035983bb 100644
--- a/tests/macros.rs
+++ b/tests/macros.rs
@@ -110,3 +110,40 @@ fn quoted_arg_long_name() {
         .expect("Expected to successfully match the given args.");
     assert!(matches.is_present("option2"));
 }
+
+#[test]
+fn quoted_arg_name() {
+    let app = clap_app!(claptests =>
+        (version: "0.1")
+        (about: "tests clap library")
+        (author: "Kevin K. <kbknapp@gmail.com>")
+        (@arg opt: -o --option +takes_value ... "tests options")
+        (@arg ("positional-arg"): index(1) "tests positionals")
+        (@arg flag: -f --flag ... +global "tests flags")
+        (@arg flag2: -F conflicts_with[flag] requires[option2]
+            "tests flags with exclusions")
+        (@arg option2: --("long-option-2") conflicts_with[option] requires[positional2]
+            "tests long options with exclusions")
+        (@arg positional2: index(2) "tests positionals with exclusions")
+        (@arg option3: -O --Option +takes_value possible_value[fast slow]
+            "tests options with specific value sets")
+        (@arg ("positional-3"): index(3) ... possible_value[vi emacs]
+            "tests positionals with specific values")
+        (@arg multvals: --multvals +takes_value value_name[one two]
+            "Tests mutliple values, not mult occs")
+        (@arg multvalsmo: --multvalsmo ... +takes_value value_name[one two]
+            "Tests mutliple values, not mult occs")
+        (@arg minvals: --minvals2 min_values(1) ... +takes_value "Tests 2 min vals")
+        (@arg maxvals: --maxvals3 ... +takes_value max_values(3) "Tests 3 max vals")
+        (@subcommand subcmd =>
+            (about: "tests subcommands")
+            (version: "0.1")
+            (author: "Kevin K. <kbknapp@gmail.com>")
+            (@arg scoption: -o --option ... +takes_value "tests options")
+            (@arg scpositional: index(1) "tests positionals"))
+    );
+
+    let matches = app.get_matches_from_safe(vec!["bin_name", "value1", "value2", "--long-option-2"])
+        .expect("Expected to successfully match the given args.");
+    assert!(matches.is_present("option2"));
+}
diff --git a/tests/version.rs b/tests/version.rs
index f6e9ff8b..de0f8179 100644
--- a/tests/version.rs
+++ b/tests/version.rs
@@ -3,7 +3,7 @@ extern crate regex;
 
 use std::str;
 
-use clap::{App, ErrorKind};
+use clap::{App, Arg, ErrorKind};
 
 include!("../clap-test.rs");
 
@@ -43,3 +43,16 @@ fn complex_version_output() {
         a.write_version(&mut ver).unwrap();
         assert_eq!(str::from_utf8(&ver).unwrap(), VERSION);
 }
+
+#[test]
+fn override_ver() {
+    let m = App::new("test")
+        .author("Kevin K.")
+        .about("tests stuff")
+        .version("1.3")
+        .arg(Arg::from_usage("-v, --version 'some version'"))
+        .get_matches_from_safe(vec!["test", "--version"]);
+
+    assert!(m.is_ok());
+    assert!(m.unwrap().is_present("version"));
+}
\ No newline at end of file