Repository: clap-rs/clap
Pull request #2165 (2020-10-10 15:50:30)

Help & Version settings
<!--
If your PR closes some issues, please write `Closes #XXXX`
where `XXXX` is the number of the issue you want to fix.
Each issue goes on its own line.
-->

I am wondering which is better, `DisableVersionFlagForSubcommands` or `DisableVersionForSubcommands`. Because if we ever have version subcommand, then we would want to disable even that for subcommands, so, thinking about the `Flag` in that name.



Patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index aa05b5cb..017ab289 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -8,6 +8,13 @@ TODO: `cargo`, `std` features
 #### Minimum Required Rust
 * As of this release, `clap` requires `rustc 1.42.0` or greater.
 
+#### BREAKING CHANGES
+
+* **Renamed Settings**
+  * `AppSettings::DisableHelpFlags` => `AppSettings::DisableHelpFlag`
+  * `AppSettings::DisableVersion` => `AppSettings::DisableVersionFlag`
+  * `AppSettings::VersionlessSubcommands` => `AppSettings::DisableVersionForSubcommands`
+
 #### Features
 
 * **Added Methods**
@@ -52,8 +59,8 @@ TODO: `cargo`, `std` features
   * `App::print_help` & `App::print_long_help` now return `std::io::Result`
   * `App::write_help` & `App::write_long_help` now return `std::io::Result`
   * `Error::info` now is of type `Vec<String>` instead of `Option<Vec<String>>`
-  * `short` in `#[clap()]` now accepts `char` instead of `&str`
   * `ArgMatches::subcommand` now returns `Option<(&str, &ArgMatches)>`
+  * `short` in `#[clap()]` now accepts `char` instead of `&str`
 
 #### Features
 
@@ -71,12 +78,11 @@ TODO: `cargo`, `std` features
     * `Arg::visible_short_alias`
     * `Arg::visible_short_aliases`
     * `Arg::value_hint`
+    * `Arg::validator_regex` (gated behind `regex` feature)
   * **App**
     * `App::subcommand_placeholder`
     * `App::before_long_help`
     * `App::after_long_help`
-* **Added Settings**
-  * `AppSettings::DisableHelpFlags`
 * TODO: List App::get_* methods
 
 #### Enhancements
@@ -107,7 +113,7 @@ TODO: `cargo`, `std` features
     * `App::help_message` in favor of `App::mut_arg`
     * `App::help_short` in favor of `App::mut_arg`
     * `App::arg_from_usage` in favor of `App::arg`
-    * `App::args_from_usage` in favor of TODO: `App::args(usage.split('\n'))`
+    * `App::args_from_usage` in favor of `App::args(usage.lines().map(|l| l.trim()).filter(|l| !l.is_empty()))`
     * `App::gen_completions` in favor of TODO:
     * `App::gen_completions_to` in favor of TODO:
     * `App::settings` in favor of `App::setting(Setting1 | Setting2)`
@@ -115,18 +121,18 @@ TODO: `cargo`, `std` features
     * `App::global_settings` in favor of `App::global_setting(Setting1 | Setting2)`
   * **Arg**
     * `Arg::empty_values` in favor of TODO:
-  * `ArgMatches::usage` in favor of `App::generate_usage`
-  * **Settings**
-    * `AppSettings::PropagateGlobalValuesDown`
-    * `ArgSettings::Global` in favor of `Arg::global` method
-    * `ArgSettings::Multiple` in favor of `ArgSettings::MultipleValues` and `ArgSettings::MultipleOccurrences`
+  * **ArgMatches**
+    * `ArgMatches::usage` in favor of `App::generate_usage`
   * **Macros**
     * `arg_enum!` in favor of `ArgEnum` derive macro.
     * `value_t!` in favor of `ArgMatches::value_of_t`
     * `value_t_or_exit!` in favor of `ArgMatches::value_of_t_or_exit`
     * `values_t!` in favor of `ArgMatches::values_of_t`
     * `values_t_or_exit!` in favor of `ArgMatches::values_of_t_or_exit`
-  * Support for `{n}` in help text
+* **Removed Settings**
+  * `AppSettings::PropagateGlobalValuesDown`
+  * `ArgSettings::Global` in favor of `Arg::global` method
+  * `ArgSettings::Multiple` in favor of `ArgSettings::MultipleValues` and `ArgSettings::MultipleOccurrences`
 * **Renamed Methods**
   * **App**
     * `App::from_yaml` => `App::from`
@@ -155,6 +161,7 @@ TODO: `cargo`, `std` features
     `Fn(String) -> Result<(), String>`
   * `Arg::validator_os` now takes first argument as `Fn(&OsStr) -> Result<O, OsString>` instead of
     `Fn(&OsStr) -> Result<(), OsString>`
+* Removed support for `{n}` in help text
 * In usage parser, for options `[name]... --option [val]` results in `ArgSettings::MultipleOccurrences`
   but `--option [val]...` results in `ArgSettings::MultipleValues` *and* `ArgSettings::MultipleOccurrences`.
   Before both resulted in the same thing
@@ -178,7 +185,7 @@ TODO: `cargo`, `std` features
     * `Arg::multiple_values`
     * `Arg::multiple_occurrences`
     * `Arg::help_heading`
-* **Added Variants**
+* **Added Settings**
   * `AppSettings::HelpRequired`
   * `AppSettings::NoAutoHelp`
   * `AppSettings::NoAutoVersion`
diff --git a/benches/06_rustup.rs b/benches/06_rustup.rs
index 4a9d69ce..907ad702 100644
--- a/benches/06_rustup.rs
+++ b/benches/06_rustup.rs
@@ -26,7 +26,7 @@ fn build_cli() -> App<'static> {
         .version("0.9.0") // Simulating
         .about("The Rust toolchain installer")
         .after_help(RUSTUP_HELP)
-        .setting(AppSettings::VersionlessSubcommands)
+        .setting(AppSettings::DisableVersionForSubcommands)
         .setting(AppSettings::DeriveDisplayOrder)
         // .setting(AppSettings::SubcommandRequiredElseHelp)
         .arg(
@@ -107,7 +107,7 @@ fn build_cli() -> App<'static> {
         .subcommand(
             App::new("target")
                 .about("Modify a toolchain's supported targets")
-                .setting(AppSettings::VersionlessSubcommands)
+                .setting(AppSettings::DisableVersionForSubcommands)
                 .setting(AppSettings::DeriveDisplayOrder)
                 // .setting(AppSettings::SubcommandRequiredElseHelp)
                 .subcommand(
@@ -163,7 +163,7 @@ fn build_cli() -> App<'static> {
         .subcommand(
             App::new("component")
                 .about("Modify a toolchain's installed components")
-                .setting(AppSettings::VersionlessSubcommands)
+                .setting(AppSettings::DisableVersionForSubcommands)
                 .setting(AppSettings::DeriveDisplayOrder)
                 // .setting(AppSettings::SubcommandRequiredElseHelp)
                 .subcommand(
@@ -210,7 +210,7 @@ fn build_cli() -> App<'static> {
             App::new("override")
                 .about("Modify directory toolchain overrides")
                 .after_help(OVERRIDE_HELP)
-                .setting(AppSettings::VersionlessSubcommands)
+                .setting(AppSettings::DisableVersionForSubcommands)
                 .setting(AppSettings::DeriveDisplayOrder)
                 // .setting(AppSettings::SubcommandRequiredElseHelp)
                 .subcommand(App::new("list").about("List directory toolchain overrides"))
@@ -302,7 +302,7 @@ fn build_cli() -> App<'static> {
         .subcommand(
             App::new("self")
                 .about("Modify the rustup installation")
-                .setting(AppSettings::VersionlessSubcommands)
+                .setting(AppSettings::DisableVersionForSubcommands)
                 .setting(AppSettings::DeriveDisplayOrder)
                 .subcommand(App::new("update").about("Download and install updates to rustup"))
                 .subcommand(
@@ -316,7 +316,7 @@ fn build_cli() -> App<'static> {
             App::new("telemetry")
                 .about("rustup telemetry commands")
                 .setting(AppSettings::Hidden)
-                .setting(AppSettings::VersionlessSubcommands)
+                .setting(AppSettings::DisableVersionForSubcommands)
                 .setting(AppSettings::DeriveDisplayOrder)
                 .subcommand(App::new("enable").about("Enable rustup telemetry"))
                 .subcommand(App::new("disable").about("Disable rustup telemetry"))
diff --git a/clap.schema.json b/clap.schema.json
index 4fa922bd..09e83195 100644
--- a/clap.schema.json
+++ b/clap.schema.json
@@ -69,14 +69,10 @@
           "type": "boolean"
         },
         "conflicts_with": {
-          "anyOf": [
-            {
-              "type": "string"
-            },
-            {
-              "$ref": "#/structures/arrayStrUnique"
-            }
-          ]
+          "type": "string"
+        },
+        "conflicts_with_all": {
+          "$ref": "#/structures/arrayStrUnique"
         },
         "default_value": {
           "type": "string"
diff --git a/clap_derive/examples/value_hints_derive.rs b/clap_derive/examples/value_hints_derive.rs
index 38194115..859411a1 100644
--- a/clap_derive/examples/value_hints_derive.rs
+++ b/clap_derive/examples/value_hints_derive.rs
@@ -34,7 +34,7 @@ enum GeneratorChoice {
     name = "value_hints_derive",
     // AppSettings::TrailingVarArg is required to use ValueHint::CommandWithArguments
     setting = AppSettings::TrailingVarArg,
-    setting = AppSettings::DisableVersion
+    setting = AppSettings::DisableVersionFlag
 )]
 struct Opt {
     /// If provided, outputs the completion file for given shell
diff --git a/clap_generate/examples/value_hints.rs b/clap_generate/examples/value_hints.rs
index 884a2ffb..91162f10 100644
--- a/clap_generate/examples/value_hints.rs
+++ b/clap_generate/examples/value_hints.rs
@@ -19,7 +19,7 @@ use std::io;
 
 fn build_cli() -> App<'static> {
     App::new("value_hints")
-        .setting(AppSettings::DisableVersion)
+        .setting(AppSettings::DisableVersionFlag)
         // AppSettings::TrailingVarArg is required to use ValueHint::CommandWithArguments
         .setting(AppSettings::TrailingVarArg)
         .arg(Arg::new("generator").long("generate").possible_values(&[
diff --git a/clap_generate/src/generators/mod.rs b/clap_generate/src/generators/mod.rs
index 102aeb68..7c1701b1 100644
--- a/clap_generate/src/generators/mod.rs
+++ b/clap_generate/src/generators/mod.rs
@@ -144,7 +144,7 @@ pub trait Generator {
             shorts_and_visible_aliases.push('h');
         }
 
-        if !p.is_set(AppSettings::DisableVersion)
+        if !p.is_set(AppSettings::DisableVersionFlag)
             && !shorts_and_visible_aliases.iter().any(|&x| x == 'V')
         {
             shorts_and_visible_aliases.push('V');
@@ -173,7 +173,7 @@ pub trait Generator {
             longs.push(String::from("help"));
         }
 
-        if !p.is_set(AppSettings::DisableVersion) && !longs.iter().any(|x| *x == "version") {
+        if !p.is_set(AppSettings::DisableVersionFlag) && !longs.iter().any(|x| *x == "version") {
             longs.push(String::from("version"));
         }
 
@@ -196,7 +196,7 @@ pub trait Generator {
             );
         }
 
-        if !p.is_set(AppSettings::DisableVersion)
+        if !p.is_set(AppSettings::DisableVersionFlag)
             && !flags.iter().any(|x| x.get_name() == "version")
         {
             flags.push(
diff --git a/src/build/app/mod.rs b/src/build/app/mod.rs
index c501152f..d92795cc 100644
--- a/src/build/app/mod.rs
+++ b/src/build/app/mod.rs
@@ -2293,11 +2293,13 @@ impl<'help> App<'help> {
                 // We have to create a new scope in order to tell rustc the borrow of `sc` is
                 // done and to recursively call this method
                 {
-                    let vsc = $_self.settings.is_set(AppSettings::VersionlessSubcommands);
+                    let vsc = $_self
+                        .settings
+                        .is_set(AppSettings::DisableVersionForSubcommands);
                     let gv = $_self.settings.is_set(AppSettings::GlobalVersion);
 
                     if vsc {
-                        $sc.set(AppSettings::DisableVersion);
+                        $sc.set(AppSettings::DisableVersionFlag);
                     }
                     if gv && $sc.version.is_none() && $_self.version.is_some() {
                         $sc.set(AppSettings::GlobalVersion);
@@ -2351,50 +2353,58 @@ impl<'help> App<'help> {
     pub(crate) fn _create_help_and_version(&mut self) {
         debug!("App::_create_help_and_version");
 
-        if !(self
-            .args
-            .args
-            .iter()
-            .any(|x| x.long == Some("help") || x.id == Id::help_hash())
-            || self.is_set(AppSettings::DisableHelpFlags)
+        if !(self.is_set(AppSettings::DisableHelpFlag)
+            || self
+                .args
+                .args
+                .iter()
+                .any(|x| x.long == Some("help") || x.id == Id::help_hash())
             || self
                 .subcommands
                 .iter()
-                .any(|sc| sc.short_flag == Some('h') || sc.long_flag == Some("help")))
+                .any(|sc| sc.long_flag == Some("help")))
         {
             debug!("App::_create_help_and_version: Building --help");
             let mut help = Arg::new("help")
                 .long("help")
                 .about(self.help_about.unwrap_or("Prints help information"));
-            if !self.args.args.iter().any(|x| x.short == Some('h')) {
+
+            if !(self.args.args.iter().any(|x| x.short == Some('h'))
+                || self.subcommands.iter().any(|sc| sc.short_flag == Some('h')))
+            {
                 help = help.short('h');
             }
 
             self.args.push(help);
         }
-        if !(self
-            .args
-            .args
-            .iter()
-            .any(|x| x.long == Some("version") || x.id == Id::version_hash())
-            || self.is_set(AppSettings::DisableVersion)
+
+        if !(self.is_set(AppSettings::DisableVersionFlag)
+            || self
+                .args
+                .args
+                .iter()
+                .any(|x| x.long == Some("version") || x.id == Id::version_hash())
             || self
                 .subcommands
                 .iter()
-                .any(|sc| sc.short_flag == Some('V') || sc.long_flag == Some("version")))
+                .any(|sc| sc.long_flag == Some("version")))
         {
             debug!("App::_create_help_and_version: Building --version");
             let mut version = Arg::new("version")
                 .long("version")
                 .about(self.version_about.unwrap_or("Prints version information"));
-            if !self.args.args.iter().any(|x| x.short == Some('V')) {
+
+            if !(self.args.args.iter().any(|x| x.short == Some('V'))
+                || self.subcommands.iter().any(|sc| sc.short_flag == Some('V')))
+            {
                 version = version.short('V');
             }
 
             self.args.push(version);
         }
-        if self.has_subcommands()
-            && !self.is_set(AppSettings::DisableHelpSubcommand)
+
+        if !self.is_set(AppSettings::DisableHelpSubcommand)
+            && self.has_subcommands()
             && !self.subcommands.iter().any(|s| s.id == Id::help_hash())
         {
             debug!("App::_create_help_and_version: Building help");
diff --git a/src/build/app/settings.rs b/src/build/app/settings.rs
index ee6da75f..4770a214 100644
--- a/src/build/app/settings.rs
+++ b/src/build/app/settings.rs
@@ -10,13 +10,13 @@ bitflags! {
         const SC_REQUIRED                    = 1 << 1;
         const A_REQUIRED_ELSE_HELP           = 1 << 2;
         const GLOBAL_VERSION                 = 1 << 3;
-        const VERSIONLESS_SC                 = 1 << 4;
+        const DISABLE_VERSION_FOR_SC         = 1 << 4;
         const UNIFIED_HELP                   = 1 << 5;
         const WAIT_ON_ERROR                  = 1 << 6;
         const SC_REQUIRED_ELSE_HELP          = 1 << 7;
         const NO_AUTO_HELP                   = 1 << 8;
         const NO_AUTO_VERSION                = 1 << 9;
-        const DISABLE_VERSION                = 1 << 10;
+        const DISABLE_VERSION_FLAG           = 1 << 10;
         const HIDDEN                         = 1 << 11;
         const TRAILING_VARARG                = 1 << 12;
         const NO_BIN_NAME                    = 1 << 13;
@@ -48,7 +48,7 @@ bitflags! {
         const ARGS_OVERRIDE_SELF             = 1 << 39;
         const HELP_REQUIRED                  = 1 << 40;
         const SUBCOMMAND_PRECEDENCE_OVER_ARG = 1 << 41;
-        const DISABLE_HELP_FLAGS             = 1 << 42;
+        const DISABLE_HELP_FLAG              = 1 << 42;
     }
 }
 
@@ -101,10 +101,10 @@ impl_settings! { AppSettings, AppFlags,
         => Flags::DERIVE_DISP_ORDER,
     DisableHelpSubcommand("disablehelpsubcommand")
         => Flags::DISABLE_HELP_SC,
-    DisableHelpFlags("disablehelpflags")
-        => Flags::DISABLE_HELP_FLAGS,
-    DisableVersion("disableversion")
-        => Flags::DISABLE_VERSION,
+    DisableHelpFlag("disablehelpflag")
+        => Flags::DISABLE_HELP_FLAG,
+    DisableVersionFlag("disableversionflag")
+        => Flags::DISABLE_VERSION_FLAG,
     GlobalVersion("globalversion")
         => Flags::GLOBAL_VERSION,
     HidePossibleValuesInHelp("hidepossiblevaluesinhelp")
@@ -135,8 +135,8 @@ impl_settings! { AppSettings, AppFlags,
         => Flags::UNIFIED_HELP,
     NextLineHelp("nextlinehelp")
         => Flags::NEXT_LINE_HELP,
-    VersionlessSubcommands("versionlesssubcommands")
-        => Flags::VERSIONLESS_SC,
+    DisableVersionForSubcommands("disableversionforsubcommands")
+        => Flags::DISABLE_VERSION_FOR_SC,
     WaitOnError("waitonerror")
         => Flags::WAIT_ON_ERROR,
     TrailingValues("trailingvalues")
@@ -613,7 +613,7 @@ pub enum AppSettings {
     /// ```rust
     /// # use clap::{App, AppSettings, ErrorKind};
     /// let res = App::new("myprog")
-    ///     .setting(AppSettings::DisableHelpFlags)
+    ///     .setting(AppSettings::DisableHelpFlag)
     ///     .try_get_matches_from(vec![
     ///         "myprog", "-h"
     ///     ]);
@@ -624,7 +624,7 @@ pub enum AppSettings {
     /// ```rust
     /// # use clap::{App, AppSettings, ErrorKind};
     /// let res = App::new("myprog")
-    ///     .setting(AppSettings::DisableHelpFlags)
+    ///     .setting(AppSettings::DisableHelpFlag)
     ///     .subcommand(App::new("test"))
     ///     .try_get_matches_from(vec![
     ///         "myprog", "test", "-h"
@@ -634,7 +634,7 @@ pub enum AppSettings {
     /// ```
     /// [`SubCommand`]: ./struct.SubCommand.html
     /// [`App`]: ./struct.App.html
-    DisableHelpFlags,
+    DisableHelpFlag,
 
     /// Disables the `help` subcommand
     ///
@@ -657,7 +657,7 @@ pub enum AppSettings {
     /// [``]: ./struct..html
     DisableHelpSubcommand,
 
-    /// Disables `-V` and `--version` [`App`] without affecting any of the [``]s
+    /// Disables `-V` and `--version` for this [`App`] without affecting any of the [``]s
     /// (Defaults to `false`; application *does* have a version flag)
     ///
     /// # Examples
@@ -666,7 +666,7 @@ pub enum AppSettings {
     /// # use clap::{App, AppSettings, ErrorKind};
     /// let res = App::new("myprog")
     ///     .version("v1.1")
-    ///     .setting(AppSettings::DisableVersion)
+    ///     .setting(AppSettings::DisableVersionFlag)
     ///     .try_get_matches_from(vec![
     ///         "myprog", "-V"
     ///     ]);
@@ -678,7 +678,7 @@ pub enum AppSettings {
     /// # use clap::{App, AppSettings, ErrorKind};
     /// let res = App::new("myprog")
     ///     .version("v1.1")
-    ///     .setting(AppSettings::DisableVersion)
+    ///     .setting(AppSettings::DisableVersionFlag)
     ///     .subcommand(App::new("test"))
     ///     .try_get_matches_from(vec![
     ///         "myprog", "test", "-V"
@@ -688,7 +688,28 @@ pub enum AppSettings {
     /// ```
     /// [``]: ./struct..html
     /// [`App`]: ./struct.App.html
-    DisableVersion,
+    DisableVersionFlag,
+
+    /// Disables `-V` and `--version` for all [`subcommand`]s of this [`App`]
+    /// (Defaults to `false`; subcommands *do* have version flags.)
+    ///
+    /// # Examples
+    ///
+    /// ```rust
+    /// # use clap::{App, AppSettings, ErrorKind};
+    /// let res = App::new("myprog")
+    ///     .version("v1.1")
+    ///     .setting(AppSettings::DisableVersionForSubcommands)
+    ///     .subcommand(App::new("test"))
+    ///     .try_get_matches_from(vec![
+    ///         "myprog", "test", "-V"
+    ///     ]);
+    /// assert!(res.is_err());
+    /// assert_eq!(res.unwrap_err().kind, ErrorKind::UnknownArgument);
+    /// ```
+    /// [`App`]: ./struct.App.html
+    /// [``]: ./struct..html
+    DisableVersionForSubcommands,
 
     /// Displays the arguments and [``]s in the help message in the order that they were
     /// declared in, and not alphabetically which is the default.
@@ -707,9 +728,6 @@ pub enum AppSettings {
     /// Specifies to use the version of the current command for all child [``]s.
     /// (Defaults to `false`; subcommands have independent version strings from their parents.)
     ///
-    /// **NOTE:** The version for the current command **and** this setting must be set **prior** to
-    /// adding any child subcommands
-    ///
     /// # Examples
     ///
     /// ```no_run
@@ -999,28 +1017,6 @@ pub enum AppSettings {
     /// ```
     UnifiedHelpMessage,
 
-    /// Disables `-V` and `--version` for all [``]s
-    /// (Defaults to `false`; subcommands *do* have version flags.)
-    ///
-    /// **NOTE:** This setting must be set **prior** to adding any subcommands.
-    ///
-    /// # Examples
-    ///
-    /// ```rust
-    /// # use clap::{App, AppSettings, ErrorKind};
-    /// let res = App::new("myprog")
-    ///     .version("v1.1")
-    ///     .setting(AppSettings::VersionlessSubcommands)
-    ///     .subcommand(App::new("test"))
-    ///     .try_get_matches_from(vec![
-    ///         "myprog", "test", "-V"
-    ///     ]);
-    /// assert!(res.is_err());
-    /// assert_eq!(res.unwrap_err().kind, ErrorKind::UnknownArgument);
-    /// ```
-    /// [``]: ./struct..html
-    VersionlessSubcommands,
-
     /// Will display a message "Press \[ENTER\]/\[RETURN\] to continue..." and wait for user before
     /// exiting
     ///
@@ -1076,8 +1072,8 @@ mod test {
     #[test]
     fn app_settings_fromstr() {
         assert_eq!(
-            "disablehelpflags".parse::<AppSettings>().unwrap(),
-            AppSettings::DisableHelpFlags
+            "disablehelpflag".parse::<AppSettings>().unwrap(),
+            AppSettings::DisableHelpFlag
         );
         assert_eq!(
             "argsnegatesubcommands".parse::<AppSettings>().unwrap(),
@@ -1130,8 +1126,8 @@ mod test {
             AppSettings::DisableHelpSubcommand
         );
         assert_eq!(
-            "disableversion".parse::<AppSettings>().unwrap(),
-            AppSettings::DisableVersion
+            "disableversionflag".parse::<AppSettings>().unwrap(),
+            AppSettings::DisableVersionFlag
         );
         assert_eq!(
             "dontcollapseargsinusage".parse::<AppSettings>().unwrap(),
@@ -1198,8 +1194,10 @@ mod test {
             AppSettings::UnifiedHelpMessage
         );
         assert_eq!(
-            "versionlesssubcommands".parse::<AppSettings>().unwrap(),
-            AppSettings::VersionlessSubcommands
+            "disableversionforsubcommands"
+                .parse::<AppSettings>()
+                .unwrap(),
+            AppSettings::DisableVersionForSubcommands
         );
         assert_eq!(
             "waitonerror".parse::<AppSettings>().unwrap(),
diff --git a/src/build/arg/mod.rs b/src/build/arg/mod.rs
index 3b8b8680..2de73c04 100644
--- a/src/build/arg/mod.rs
+++ b/src/build/arg/mod.rs
@@ -885,7 +885,7 @@ impl<'help> Arg<'help> {
         self
     }
 
-    /// The same as [`Arg::conflicts_with`] but allows specifying multiple two-way conflicts per
+    /// The same as [`Arg::conflicts_with`] but allows specifying multiple two-way conlicts per
     /// argument.
     ///
     /// **NOTE:** Conflicting rules take precedence over being required by default. Conflict rules
@@ -895,9 +895,6 @@ impl<'help> Arg<'help> {
     /// (i.e. if A conflicts with B, defining A.conflicts_with(B) is sufficient. You do not need
     /// need to also do B.conflicts_with(A))
     ///
-    /// **NOTE:** This option does not exist when using a YAML configuration file. Using [`Arg::conflicts_with`]
-    /// followed by an array of strings will achieve the equivalent effect.
-    ///
     /// **NOTE:** [`Arg::exclusive(true)`] allows specifying an argument which conflicts with every other argument.
     ///
     /// # Examples
diff --git a/src/output/help.rs b/src/output/help.rs
index 6bd5be51..fc065e5c 100644
--- a/src/output/help.rs
+++ b/src/output/help.rs
@@ -48,6 +48,8 @@ pub(crate) struct Help<'help, 'app, 'parser, 'writer> {
     next_line_help: bool,
     hide_pv: bool,
     term_w: usize,
+    longest: usize,
+    force_next_line: bool,
     use_long: bool,
 }
 
@@ -69,7 +71,7 @@ impl<'help, 'app, 'parser, 'writer> Help<'help, 'app, 'parser, 'writer> {
 
     /// Create a new `Help` instance.
     pub(crate) fn new(
-        writer: HelpWriter<'writer>,
+        w: HelpWriter<'writer>,
         parser: &'parser Parser<'help, 'app>,
         use_long: bool,
     ) -> Self {
@@ -85,15 +87,17 @@ impl<'help, 'app, 'parser, 'writer> Help<'help, 'app, 'parser, 'writer> {
                 },
             ),
         };
-        let next_line_help = parser.is_set(AppSettings::NextLineHelp);
+        let nlh = parser.is_set(AppSettings::NextLineHelp);
         let hide_pv = parser.is_set(AppSettings::HidePossibleValuesInHelp);
 
         Help {
-            writer,
+            writer: w,
             parser,
-            next_line_help,
+            next_line_help: nlh,
             hide_pv,
             term_w,
+            longest: 0,
+            force_next_line: false,
             use_long,
         }
     }
@@ -137,6 +141,15 @@ macro_rules! write_method {
     };
 }
 
+macro_rules! write_nspaces {
+    ($_self:ident, $num:expr) => {{
+        debug!("Help::write_nspaces!: num={}", $num);
+        for _ in 0..$num {
+            $_self.none(" ")?;
+        }
+    }};
+}
+
 // Methods to write Arg help.
 impl<'help, 'app, 'parser, 'writer> Help<'help, 'app, 'parser, 'writer> {
     fn good<T: Into<String> + AsRef<[u8]>>(&mut self, msg: T) -> io::Result<()> {
@@ -151,32 +164,28 @@ impl<'help, 'app, 'parser, 'writer> Help<'help, 'app, 'parser, 'writer> {
         write_method!(self, msg, none)
     }
 
-    fn spaces(&mut self, n: usize) -> io::Result<()> {
-        self.none(" ".repeat(n))
-    }
-
     /// Writes help for each argument in the order they were declared to the wrapped stream.
     fn write_args_unsorted(&mut self, args: &[&Arg<'help>]) -> io::Result<()> {
         debug!("Help::write_args_unsorted");
         // The shortest an arg can legally be is 2 (i.e. '-x')
-        let mut longest = 2;
+        self.longest = 2;
         let mut arg_v = Vec::with_capacity(10);
-
-        for arg in args
-            .iter()
-            .filter(|arg| should_show_arg(self.use_long, *arg))
-        {
+        let use_long = self.use_long;
+        for arg in args.iter().filter(|arg| should_show_arg(use_long, *arg)) {
             if arg.longest_filter() {
-                longest = longest.max(str_width(arg.to_string().as_str()));
+                self.longest = cmp::max(self.longest, str_width(arg.to_string().as_str()));
             }
             arg_v.push(arg)
         }
-
-        let next_line_help = self.will_args_wrap(args, longest);
-
-        let argc = arg_v.len();
+        let mut first = true;
+        let arg_c = arg_v.len();
         for (i, arg) in arg_v.iter().enumerate() {
-            self.write_arg(arg, i + 1 == argc, next_line_help, longest)?;
+            if first {
+                first = false;
+            } else {
+                self.none("\n")?;
+            }
+            self.write_arg(arg, i < arg_c)?;
         }
         Ok(())
     }
@@ -185,20 +194,20 @@ impl<'help, 'app, 'parser, 'writer> Help<'help, 'app, 'parser, 'writer> {
     fn write_args(&mut self, args: &[&Arg<'help>]) -> io::Result<()> {
         debug!("Help::write_args");
         // The shortest an arg can legally be is 2 (i.e. '-x')
-        let mut longest = 2;
+        self.longest = 2;
         let mut ord_m = VecMap::new();
-
+        let use_long = self.use_long;
         // Determine the longest
         for arg in args.iter().filter(|arg| {
             // If it's NextLineHelp we don't care to compute how long it is because it may be
             // NextLineHelp on purpose simply *because* it's so long and would throw off all other
             // args alignment
-            should_show_arg(self.use_long, *arg)
+            should_show_arg(use_long, *arg)
         }) {
             if arg.longest_filter() {
-                debug!("Help::write_args: Current Longest...{}", longest);
-                longest = longest.max(str_width(arg.to_string().as_str()));
-                debug!("Help::write_args: New Longest...{}", longest);
+                debug!("Help::write_args: Current Longest...{}", self.longest);
+                self.longest = cmp::max(self.longest, str_width(arg.to_string().as_str()));
+                debug!("Help::write_args: New Longest...{}", self.longest);
             }
             let btm = ord_m.entry(arg.disp_ord).or_insert(BTreeMap::new());
 
@@ -223,39 +232,27 @@ impl<'help, 'app, 'parser, 'writer> Help<'help, 'app, 'parser, 'writer> {
             };
             btm.insert(key, arg);
         }
-
-        let next_line_help = self.will_args_wrap(args, longest);
-
-        let num_ord_m = ord_m.len();
-        for (i, btm) in ord_m.values().enumerate() {
-            let last_btm = i + 1 == num_ord_m;
-            let num_args = btm.len();
-            for (i, arg) in btm.values().enumerate() {
-                let last_arg = last_btm && i + 1 == num_args;
-                self.write_arg(arg, last_arg, next_line_help, longest)?;
+        let mut first = true;
+        for btm in ord_m.values() {
+            for arg in btm.values() {
+                if first {
+                    first = false;
+                } else {
+                    self.none("\n")?;
+                }
+                self.write_arg(arg, false)?;
             }
         }
         Ok(())
     }
 
     /// Writes help for an argument to the wrapped stream.
-    fn write_arg(
-        &mut self,
-        arg: &Arg<'help>,
-        last_arg: bool,
-        next_line_help: bool,
-        longest: usize,
-    ) -> io::Result<()> {
-        let spec_vals = &self.spec_vals(arg);
-
-        self.write_arg_inner(arg, spec_vals, next_line_help, longest)?;
-
-        if !last_arg {
-            self.none("\n")?;
-            if next_line_help {
-                self.none("\n")?;
-            }
-        }
+    fn write_arg(&mut self, arg: &Arg<'help>, prevent_nlh: bool) -> io::Result<()> {
+        debug!("Help::write_arg");
+        self.short(arg)?;
+        self.long(arg)?;
+        let spec_vals = self.val(arg)?;
+        self.help(arg, &*spec_vals, prevent_nlh)?;
         Ok(())
     }
 
@@ -304,7 +301,7 @@ impl<'help, 'app, 'parser, 'writer> Help<'help, 'app, 'parser, 'writer> {
     }
 
     /// Writes argument's possible values to the wrapped stream.
-    fn val(&mut self, arg: &Arg<'help>, next_line_help: bool, longest: usize) -> io::Result<()> {
+    fn val(&mut self, arg: &Arg) -> Result<String, io::Error> {
         debug!("Help::val: arg={}", arg.name);
         let mult =
             arg.is_set(ArgSettings::MultipleValues) || arg.is_set(ArgSettings::MultipleOccurrences);
@@ -347,17 +344,36 @@ impl<'help, 'app, 'parser, 'writer> Help<'help, 'app, 'parser, 'writer> {
             }
         }
 
+        let spec_vals = self.spec_vals(arg);
+        let h = arg.about.unwrap_or("");
+        let h_w = str_width(h) + str_width(&*spec_vals);
+        let nlh = self.next_line_help || arg.is_set(ArgSettings::NextLineHelp);
+        let taken = self.longest + 12;
+        self.force_next_line = !nlh
+            && self.term_w >= taken
+            && (taken as f32 / self.term_w as f32) > 0.40
+            && h_w > (self.term_w - taken);
+
         debug!("Help::val: Has switch...");
         if self.use_long {
             // long help prints messages on the next line so it don't need to align text
             debug!("Help::val: printing long help so skip alignment");
         } else if arg.has_switch() {
             debug!("Yes");
-            debug!("Help::val: nlh...{:?}", next_line_help);
-            if !next_line_help {
+            debug!("Help::val: force_next_line...{:?}", self.force_next_line);
+            debug!("Help::val: nlh...{:?}", nlh);
+            debug!("Help::val: taken...{}", taken);
+            debug!(
+                "val: help_width > (width - taken)...{} > ({} - {})",
+                h_w, self.term_w, taken
+            );
+            debug!("Help::val: longest...{}", self.longest);
+            debug!("Help::val: next_line...");
+            if !(nlh || self.force_next_line) {
+                debug!("No");
                 let self_len = str_width(arg.to_string().as_str());
                 // subtract ourself
-                let mut spcs = longest - self_len;
+                let mut spcs = self.longest - self_len;
                 // Since we're writing spaces from the tab point we first need to know if we
                 // had a long and short, or just short
                 if arg.long.is_some() {
@@ -368,86 +384,87 @@ impl<'help, 'app, 'parser, 'writer> Help<'help, 'app, 'parser, 'writer> {
                     spcs += 8;
                 }
 
-                self.spaces(spcs)?;
+                write_nspaces!(self, spcs);
+            } else {
+                debug!("Yes");
             }
-        } else if !next_line_help {
+        } else if !(nlh || self.force_next_line) {
             debug!("No, and not next_line");
-            self.spaces(longest + 4 - str_width(&arg.to_string()))?;
+            write_nspaces!(
+                self,
+                self.longest + 4 - (str_width(arg.to_string().as_str()))
+            );
         } else {
             debug!("No");
         }
-        Ok(())
+        Ok(spec_vals)
     }
 
-    fn write_before_help(&mut self) -> io::Result<()> {
-        debug!("Help::write_before_help");
-        let before_help = if self.use_long {
-            self.parser
-                .app
-                .before_long_help
-                .or(self.parser.app.before_help)
-        } else {
-            self.parser.app.before_help
-        };
-        if let Some(output) = before_help {
-            self.none(text_wrapper(output, self.term_w))?;
-            self.none("\n\n")?;
-        }
-        Ok(())
-    }
-
-    fn write_after_help(&mut self) -> io::Result<()> {
-        debug!("Help::write_after_help");
-        let after_help = if self.use_long {
-            self.parser
-                .app
-                .after_long_help
-                .or(self.parser.app.after_help)
+    fn write_before_after_help(&mut self, h: &str) -> io::Result<()> {
+        debug!("Help::write_before_after_help");
+        let mut help = String::from(h);
+        // determine if our help fits or needs to wrap
+        debug!(
+            "Help::write_before_after_help: Term width...{}",
+            self.term_w
+        );
+        let too_long = str_width(h) >= self.term_w;
+
+        debug!("Help::write_before_after_help: Too long...");
+        if too_long {
+            debug!("Yes");
+            debug!("Help::write_before_after_help: help: {}", help);
+            debug!(
+                "Help::write_before_after_help: help width: {}",
+                str_width(&*help)
+            );
+            // Determine how many newlines we need to insert
+            debug!(
+                "Help::write_before_after_help: Usable space: {}",
+                self.term_w
+            );
+            help = wrap_help(&help, self.term_w);
         } else {
-            self.parser.app.after_help
-        };
-        if let Some(output) = after_help {
-            self.none("\n\n")?;
-            self.none(text_wrapper(output, self.term_w))?;
+            debug!("No");
         }
+        self.none(&help)?;
         Ok(())
     }
 
     /// Writes argument's help to the wrapped stream.
-    fn help(
-        &mut self,
-        has_switch: bool,
-        about: &str,
-        spec_vals: &str,
-        next_line_help: bool,
-        longest: usize,
-    ) -> io::Result<()> {
+    fn help(&mut self, arg: &Arg, spec_vals: &str, prevent_nlh: bool) -> io::Result<()> {
         debug!("Help::help");
-        let mut help = String::from(about) + spec_vals;
-        debug!("Help::help: Next Line...{:?}", next_line_help);
+        let h = if self.use_long {
+            arg.long_about.unwrap_or_else(|| arg.about.unwrap_or(""))
+        } else {
+            arg.about.unwrap_or_else(|| arg.long_about.unwrap_or(""))
+        };
+        let mut help = String::from(h) + spec_vals;
+        let nlh = self.next_line_help || arg.is_set(ArgSettings::NextLineHelp) || self.use_long;
+        debug!("Help::help: Next Line...{:?}", nlh);
 
-        let spaces = if next_line_help {
+        let spcs = if nlh || self.force_next_line {
             12 // "tab" * 3
         } else {
-            longest + 12
+            self.longest + 12
         };
 
-        let too_long = spaces + str_width(about) + str_width(spec_vals) >= self.term_w;
+        let too_long = spcs + str_width(h) + str_width(&*spec_vals) >= self.term_w;
 
         // Is help on next line, if so then indent
-        if next_line_help {
+        if nlh || self.force_next_line {
             self.none(&format!("\n{}{}{}", TAB, TAB, TAB))?;
         }
 
         debug!("Help::help: Too long...");
-        if too_long && spaces <= self.term_w {
+        if too_long && spcs <= self.term_w {
             debug!("Yes");
             debug!("Help::help: help...{}", help);
-            debug!("Help::help: help width...{}", str_width(&help));
+            debug!("Help::help: help width...{}", str_width(&*help));
             // Determine how many newlines we need to insert
-            let avail_chars = self.term_w - spaces;
+            let avail_chars = self.term_w - spcs;
             debug!("Help::help: Usable space...{}", avail_chars);
-            help = text_wrapper(&help, avail_chars);
+            help = wrap_help(&help, avail_chars);
         } else {
             debug!("No");
         }
@@ -456,63 +473,19 @@ impl<'help, 'app, 'parser, 'writer> Help<'help, 'app, 'parser, 'writer> {
         }
         for part in help.lines().skip(1) {
             self.none("\n")?;
-            if next_line_help {
+            if nlh || self.force_next_line {
                 self.none(&format!("{}{}{}", TAB, TAB, TAB))?;
-            } else if has_switch {
-                self.spaces(longest + 12)?;
+            } else if arg.has_switch() {
+                write_nspaces!(self, self.longest + 12);
             } else {
-                self.spaces(longest + 8)?;
+                write_nspaces!(self, self.longest + 8);
             }
             self.none(part)?;
         }
-        Ok(())
-    }
-
-    /// Writes help for an argument to the wrapped stream.
-    fn write_arg_inner(
-        &mut self,
-        arg: &Arg<'help>,
-        spec_vals: &str,
-        next_line_help: bool,
-        longest: usize,
-    ) -> io::Result<()> {
-        self.short(arg)?;
-        self.long(arg)?;
-        self.val(arg, next_line_help, longest)?;
-
-        let about = if self.use_long {
-            arg.long_about.unwrap_or_else(|| arg.about.unwrap_or(""))
-        } else {
-            arg.about.unwrap_or_else(|| arg.long_about.unwrap_or(""))
-        };
-
-        self.help(arg.has_switch(), about, spec_vals, next_line_help, longest)?;
-        Ok(())
-    }
-
-    /// Will use next line help on writing args.
-    fn will_args_wrap(&self, args: &[&Arg<'help>], longest: usize) -> bool {
-        args.iter()
-            .filter(|arg| should_show_arg(self.use_long, *arg))
-            .any(|arg| {
-                let spec_vals = &self.spec_vals(arg);
-                self.arg_next_line_help(arg, spec_vals, longest)
-            })
-    }
-
-    fn arg_next_line_help(&self, arg: &Arg<'help>, spec_vals: &str, longest: usize) -> bool {
-        if self.next_line_help || arg.is_set(ArgSettings::NextLineHelp) || self.use_long {
-            // setting_next_line
-            true
-        } else {
-            // force_next_line
-            let h = arg.about.unwrap_or("");
-            let h_w = str_width(h) + str_width(spec_vals);
-            let taken = longest + 12;
-            self.term_w >= taken
-                && (taken as f32 / self.term_w as f32) > 0.40
-                && h_w > (self.term_w - taken)
+        if !prevent_nlh && (nlh || self.force_next_line) {
+            self.none("\n")?;
         }
+        Ok(())
     }
 
     fn spec_vals(&self, a: &Arg) -> String {
@@ -626,54 +599,35 @@ impl<'help, 'app, 'parser, 'writer> Help<'help, 'app, 'parser, 'writer> {
         };
         prefix.to_string() + &spec_vals.join(" ")
     }
-
-    fn write_about(&mut self, new_line: bool) -> io::Result<()> {
-        let about = if self.use_long {
-            self.parser.app.long_about.or(self.parser.app.about)
-        } else {
-            self.parser.app.about
-        };
-        if let Some(output) = about {
-            self.none(text_wrapper(output, self.term_w))?;
-            if new_line {
-                self.none("\n")?;
-            }
-        }
-        Ok(())
-    }
-
-    fn write_author(&mut self, new_line: bool) -> io::Result<()> {
-        if let Some(author) = self.parser.app.author {
-            self.none(text_wrapper(author, self.term_w))?;
-            if new_line {
-                self.none("\n")?;
-            }
-        }
-        Ok(())
-    }
 }
 
 /// Methods to write a single subcommand
 impl<'help, 'app, 'parser, 'writer> Help<'help, 'app, 'parser, 'writer> {
-    fn write_subcommand(
-        &mut self,
-        sc_str: &str,
-        app: &App<'help>,
-        next_line_help: bool,
-        longest: usize,
-    ) -> io::Result<()> {
+    fn write_subcommand(&mut self, sc_str: &str, app: &App<'help>) -> io::Result<()> {
         debug!("Help::write_subcommand");
+        self.none(TAB)?;
+        self.good(sc_str)?;
+        let spec_vals = self.sc_val(sc_str, app)?;
+        self.sc_help(app, &*spec_vals)?;
+        Ok(())
+    }
 
-        let spec_vals = &self.sc_spec_vals(app);
-
-        let about = if self.use_long {
-            app.long_about.unwrap_or_else(|| app.about.unwrap_or(""))
-        } else {
-            app.about.unwrap_or_else(|| app.long_about.unwrap_or(""))
-        };
-
-        self.subcmd(sc_str, next_line_help, longest)?;
-        self.help(false, about, spec_vals, next_line_help, longest)
+    fn sc_val(&mut self, sc_str: &str, app: &App) -> Result<String, io::Error> {
+        debug!("Help::sc_val: app={}", app.name);
+        let spec_vals = self.sc_spec_vals(app);
+        let h = app.about.unwrap_or("");
+        let h_w = str_width(h) + str_width(&*spec_vals);
+        let nlh = self.next_line_help;
+        let taken = self.longest + 12;
+        self.force_next_line = !nlh
+            && self.term_w >= taken
+            && (taken as f32 / self.term_w as f32) > 0.40
+            && h_w > (self.term_w - taken);
+
+        if !(nlh || self.force_next_line) {
+            write_nspaces!(self, self.longest + 4 - (str_width(sc_str)));
+        }
+        Ok(spec_vals)
     }
 
     fn sc_spec_vals(&self, a: &App) -> String {
@@ -704,28 +658,56 @@ impl<'help, 'app, 'parser, 'writer> Help<'help, 'app, 'parser, 'writer> {
         spec_vals.join(" ")
     }
 
-    fn subcommand_next_line_help(&self, app: &App<'help>, spec_vals: &str, longest: usize) -> bool {
-        if self.next_line_help | self.use_long {
-            // setting_next_line
-            true
+    fn sc_help(&mut self, app: &App<'help>, spec_vals: &str) -> io::Result<()> {
+        debug!("Help::sc_help");
+        let h = if self.use_long {
+            app.long_about.unwrap_or_else(|| app.about.unwrap_or(""))
         } else {
-            // force_next_line
-            let h = app.about.unwrap_or("");
-            let h_w = str_width(h) + str_width(spec_vals);
-            let taken = longest + 12;
-            self.term_w >= taken
-                && (taken as f32 / self.term_w as f32) > 0.40
-                && h_w > (self.term_w - taken)
+            app.about.unwrap_or_else(|| app.long_about.unwrap_or(""))
+        };
+        let mut help = String::from(h) + spec_vals;
+        let nlh = self.next_line_help || self.use_long;
+        debug!("Help::sc_help: Next Line...{:?}", nlh);
+
+        let spcs = if nlh || self.force_next_line {
+            12 // "tab" * 3
+        } else {
+            self.longest + 12
+        };
+
+        let too_long = spcs + str_width(h) + str_width(&*spec_vals) >= self.term_w;
+
+        // Is help on next line, if so then indent
+        if nlh || self.force_next_line {
+            self.none(&format!("\n{}{}{}", TAB, TAB, TAB))?;
         }
-    }
 
-    /// Writes subcommand to the wrapped stream.
-    fn subcmd(&mut self, sc_str: &str, next_line_help: bool, longest: usize) -> io::Result<()> {
-        self.none(TAB)?;
-        self.good(sc_str)?;
-        if !next_line_help {
-            let width = str_width(sc_str);
-            self.spaces(width.max(longest + 4) - width)?;
+        debug!("Help::sc_help: Too long...");
+        if too_long && spcs <= self.term_w {
+            debug!("Yes");
+            debug!("Help::sc_help: help...{}", help);
+            debug!("Help::sc_help: help width...{}", str_width(&*help));
+            // Determine how many newlines we need to insert
+            let avail_chars = self.term_w - spcs;
+            debug!("Help::sc_help: Usable space...{}", avail_chars);
+            help = wrap_help(&help, avail_chars);
+        } else {
+            debug!("No");
+        }
+        if let Some(part) = help.lines().next() {
+            self.none(part)?;
+        }
+        for part in help.lines().skip(1) {
+            self.none("\n")?;
+            if nlh || self.force_next_line {
+                self.none(&format!("{}{}{}", TAB, TAB, TAB))?;
+            } else {
+                write_nspaces!(self, self.longest + 8);
+            }
+            self.none(part)?;
+        }
+        if !help.contains('\n') && (nlh || self.force_next_line) {
+            self.none("\n")?;
         }
         Ok(())
     }
@@ -762,7 +744,6 @@ impl<'help, 'app, 'parser, 'writer> Help<'help, 'app, 'parser, 'writer> {
             .collect::<IndexSet<_>>();
 
         let mut first = if pos {
-            // Write positional args if any
             self.warning("ARGS:\n")?;
             self.write_args_unsorted(&self.parser.app.get_positionals().collect::<Vec<_>>())?;
             false
@@ -844,48 +825,27 @@ impl<'help, 'app, 'parser, 'writer> Help<'help, 'app, 'parser, 'writer> {
         Ok(())
     }
 
-    /// Will use next line help on writing subcommands.
-    fn will_subcommands_wrap(&self, subcommands: &[App<'help>], longest: usize) -> bool {
-        subcommands
-            .iter()
-            .filter(|&subcommand| should_show_subcommand(subcommand))
-            .any(|subcommand| {
-                let spec_vals = &self.sc_spec_vals(subcommand);
-                self.subcommand_next_line_help(subcommand, spec_vals, longest)
-            })
-    }
-
     /// Writes help for subcommands of a Parser Object to the wrapped stream.
     fn write_subcommands(&mut self, app: &App<'help>) -> io::Result<()> {
         debug!("Help::write_subcommands");
         // The shortest an arg can legally be is 2 (i.e. '-x')
-        let mut longest = 2;
+        self.longest = 2;
         let mut ord_m = VecMap::new();
-        for subcommand in app
+        for sc in app
             .subcommands
             .iter()
-            .filter(|subcommand| should_show_subcommand(subcommand))
+            .filter(|s| !s.is_set(AppSettings::Hidden))
         {
-            let btm = ord_m.entry(subcommand.disp_ord).or_insert(BTreeMap::new());
+            let btm = ord_m.entry(sc.disp_ord).or_insert(BTreeMap::new());
             let mut sc_str = String::new();
-            sc_str.push_str(
-                &subcommand
-                    .short_flag
-                    .map_or(String::new(), |c| format!("-{}, ", c)),
-            );
-            sc_str.push_str(
-                &subcommand
-                    .long_flag
-                    .map_or(String::new(), |c| format!("--{}, ", c)),
-            );
-            sc_str.push_str(&subcommand.name);
-            longest = longest.max(str_width(&sc_str));
-            btm.insert(sc_str, subcommand.clone());
+            sc_str.push_str(&sc.short_flag.map_or(String::new(), |c| format!("-{}, ", c)));
+            sc_str.push_str(&sc.long_flag.map_or(String::new(), |c| format!("--{}, ", c)));
+            sc_str.push_str(&sc.name);
+            self.longest = cmp::max(self.longest, str_width(&sc_str));
+            btm.insert(sc_str, sc.clone());
         }
 
-        debug!("Help::write_subcommands longest = {}", longest);
-
-        let next_line_help = self.will_subcommands_wrap(&app.subcommands, longest);
+        debug!("Help::write_subcommands longest = {}", self.longest);
 
         let mut first = true;
         for btm in ord_m.values() {
@@ -895,7 +855,7 @@ impl<'help, 'app, 'parser, 'writer> Help<'help, 'app, 'parser, 'writer> {
                 } else {
                     self.none("\n")?;
                 }
-                self.write_subcommand(sc_str, sc, next_line_help, longest)?;
+                self.write_subcommand(sc_str, sc)?;
             }
         }
         Ok(())
@@ -904,18 +864,22 @@ impl<'help, 'app, 'parser, 'writer> Help<'help, 'app, 'parser, 'writer> {
     /// Writes binary name of a Parser Object to the wrapped stream.
     fn write_bin_name(&mut self) -> io::Result<()> {
         debug!("Help::write_bin_name");
-
-        let bin_name = if let Some(bn) = self.parser.app.bin_name.as_ref() {
+        let term_w = self.term_w;
+        macro_rules! write_name {
+            () => {{
+                self.good(&*wrap_help(&self.parser.app.name, term_w))?;
+            }};
+        }
+        if let Some(bn) = self.parser.app.bin_name.as_ref() {
             if bn.contains(' ') {
                 // In case we're dealing with subcommands i.e. git mv is translated to git-mv
-                bn.replace(" ", "-")
+                self.good(&bn.replace(" ", "-"))?
             } else {
-                text_wrapper(&self.parser.app.name, self.term_w)
+                write_name!();
             }
         } else {
-            text_wrapper(&self.parser.app.name, self.term_w)
-        };
-        self.good(&bin_name)?;
+            write_name!();
+        }
         Ok(())
     }
 }
@@ -977,16 +941,36 @@ impl<'help, 'app, 'parser, 'writer> Help<'help, 'app, 'parser, 'writer> {
                         }
                     }
                     "author" => {
-                        self.write_author(false)?;
+                        if let Some(s) = self.parser.app.author {
+                            self.none(&wrap_help(s, self.term_w))?;
+                        }
                     }
                     "author-with-newline" => {
-                        self.write_author(true)?;
+                        if let Some(s) = self.parser.app.author {
+                            self.none(&wrap_help(s, self.term_w))?;
+                            self.none("\n")?;
+                        }
                     }
                     "about" => {
-                        self.write_about(false)?;
+                        let about = if self.use_long {
+                            self.parser.app.long_about.or(self.parser.app.about)
+                        } else {
+                            self.parser.app.about
+                        };
+                        if let Some(output) = about {
+                            self.none(wrap_help(output, self.term_w))?;
+                        }
                     }
                     "about-with-newline" => {
-                        self.write_about(true)?;
+                        let about = if self.use_long {
+                            self.parser.app.long_about.or(self.parser.app.about)
+                        } else {
+                            self.parser.app.about
+                        };
+                        if let Some(output) = about {
+                            self.none(wrap_help(output, self.term_w))?;
+                            self.none("\n")?;
+                        }
                     }
                     "usage-heading" => {
                         self.warning("USAGE:")?;
@@ -1021,10 +1005,32 @@ impl<'help, 'app, 'parser, 'writer> Help<'help, 'app, 'parser, 'writer> {
                         self.write_subcommands(self.parser.app)?;
                     }
                     "after-help" => {
-                        self.write_after_help()?;
+                        let after_help = if self.use_long {
+                            self.parser
+                                .app
+                                .after_long_help
+                                .or(self.parser.app.after_help)
+                        } else {
+                            self.parser.app.after_help
+                        };
+                        if let Some(output) = after_help {
+                            self.none("\n\n")?;
+                            self.write_before_after_help(output)?;
+                        }
                     }
                     "before-help" => {
-                        self.write_before_help()?;
+                        let before_help = if self.use_long {
+                            self.parser
+                                .app
+                                .before_long_help
+                                .or(self.parser.app.before_help)
+                        } else {
+                            self.parser.app.before_help
+                        };
+                        if let Some(output) = before_help {
+                            self.write_before_after_help(output)?;
+                            self.none("\n\n")?;
+                        }
                     }
                 }
             }
@@ -1044,12 +1050,8 @@ fn should_show_arg(use_long: bool, arg: &Arg) -> bool {
         || arg.is_set(ArgSettings::NextLineHelp)
 }
 
-fn should_show_subcommand(subcommand: &App) -> bool {
-    !subcommand.is_set(AppSettings::Hidden)
-}
-
-fn text_wrapper(help: &str, width: usize) -> String {
-    let wrapper = textwrap::Wrapper::new(width).break_words(false);
+fn wrap_help(help: &str, avail_chars: usize) -> String {
+    let wrapper = textwrap::Wrapper::new(avail_chars).break_words(false);
     help.lines()
         .map(|line| wrapper.fill(line))
         .collect::<Vec<String>>()
@@ -1058,11 +1060,11 @@ fn text_wrapper(help: &str, width: usize) -> String {
 
 #[cfg(test)]
 mod test {
-    use super::text_wrapper;
+    use super::wrap_help;
 
     #[test]
     fn wrap_help_last_word() {
         let help = String::from("foo bar baz");
-        assert_eq!(text_wrapper(&help, 5), "foo\nbar\nbaz");
+        assert_eq!(wrap_help(&help, 5), "foo\nbar\nbaz");
     }
 }
diff --git a/src/parse/parser.rs b/src/parse/parser.rs
index 1408c0a3..b8955e9b 100644
--- a/src/parse/parser.rs
+++ b/src/parse/parser.rs
@@ -1118,18 +1118,25 @@ impl<'help, 'app> Parser<'help, 'app> {
             arg
         );
 
-        // Needs to use app.settings.is_set instead of just is_set() because is_set() checks
-        // both global and local settings, we only want to check local
-        if arg == "help" && !self.app.settings.is_set(AS::NoAutoHelp) {
-            debug!("Help");
-            return Err(self.help_err(true));
+        if let Some(help) = self.app.find(&Id::help_hash()) {
+            if let Some(h) = help.long {
+                if arg == h && !self.is_set(AS::NoAutoHelp) {
+                    debug!("Help");
+                    return Err(self.help_err(true));
+                }
+            }
         }
-        if arg == "version" && !self.app.settings.is_set(AS::NoAutoVersion) {
-            debug!("Version");
-            return Err(self.version_err(true));
+
+        if let Some(version) = self.app.find(&Id::version_hash()) {
+            if let Some(v) = version.long {
+                if arg == v && !self.is_set(AS::NoAutoVersion) {
+                    debug!("Version");
+                    return Err(self.version_err(true));
+                }
+            }
         }
-        debug!("Neither");
 
+        debug!("Neither");
         Ok(())
     }
 
@@ -1139,24 +1146,25 @@ impl<'help, 'app> Parser<'help, 'app> {
             "Parser::check_for_help_and_version_char: Checking if -{} is help or version...",
             arg
         );
-        // Needs to use app.settings.is_set instead of just is_set() because is_set() checks
-        // both global and local settings, we only want to check local
+
         if let Some(help) = self.app.find(&Id::help_hash()) {
             if let Some(h) = help.short {
-                if arg == h && !self.app.settings.is_set(AS::NoAutoHelp) {
+                if arg == h && !self.is_set(AS::NoAutoHelp) {
                     debug!("Help");
                     return Err(self.help_err(false));
                 }
             }
         }
+
         if let Some(version) = self.app.find(&Id::version_hash()) {
             if let Some(v) = version.short {
-                if arg == v && !self.app.settings.is_set(AS::NoAutoVersion) {
+                if arg == v && !self.is_set(AS::NoAutoVersion) {
                     debug!("Version");
                     return Err(self.version_err(false));
                 }
             }
         }
+
         debug!("Neither");
         Ok(())
     }


Test patch:
diff --git a/clap_generate/tests/value_hints.rs b/clap_generate/tests/value_hints.rs
index 83d55f30..f050646e 100644
--- a/clap_generate/tests/value_hints.rs
+++ b/clap_generate/tests/value_hints.rs
@@ -6,7 +6,7 @@ mod completions;
 
 pub fn build_app_with_value_hints() -> App<'static> {
     App::new("my_app")
-        .setting(AppSettings::DisableVersion)
+        .setting(AppSettings::DisableVersionFlag)
         .setting(AppSettings::TrailingVarArg)
         .arg(
             Arg::new("choice")
diff --git a/src/build/app/tests.rs b/src/build/app/tests.rs
index 2f9aaa25..388570c5 100644
--- a/src/build/app/tests.rs
+++ b/src/build/app/tests.rs
@@ -55,9 +55,9 @@ fn app_send_sync() {
 #[test]
 fn issue_2090() {
     let mut app = App::new("app")
-        .global_setting(AppSettings::DisableVersion)
+        .global_setting(AppSettings::DisableVersionFlag)
         .subcommand(App::new("sub"));
     app._build();
 
-    assert!(app.subcommands[0].is_set(AppSettings::DisableVersion));
+    assert!(app.subcommands[0].is_set(AppSettings::DisableVersionFlag));
 }
diff --git a/tests/help.rs b/tests/help.rs
index 31187189..ba43493b 100644
--- a/tests/help.rs
+++ b/tests/help.rs
@@ -117,6 +117,7 @@ FLAGS:
     -V, --version
             Prints version information
 
+
 some longer text that comes after the help";
 
 static HIDDEN_ARGS: &str = "prog 1.0
@@ -886,114 +887,6 @@ fn no_wrap_default_help() {
     ));
 }
 
-#[test]
-#[cfg(feature = "wrap_help")]
-fn wrapped_help() {
-    static WRAPPED_HELP: &str = "test 
-
-USAGE:
-    rust_test.exe [FLAGS]
-
-FLAGS:
-    -a, --all
-            Also do versioning for private crates (will not be
-            published)
-
-        --exact
-            Specify inter dependency version numbers exactly with
-            `=`
-
-    -h, --help
-            Prints help information
-
-        --no-git-commit
-            Do not commit version changes
-
-        --no-git-push
-            Do not push generated commit and tags to git remote
-
-    -V, --version
-            Prints version information";
-    let app = App::new("test")
-        .term_width(67)
-        .arg(
-            Arg::new("all")
-                .short('a')
-                .long("all")
-                .about("Also do versioning for private crates (will not be published)"),
-        )
-        .arg(
-            Arg::new("exact")
-                .long("exact")
-                .about("Specify inter dependency version numbers exactly with `=`"),
-        )
-        .arg(
-            Arg::new("no_git_commit")
-                .long("no-git-commit")
-                .about("Do not commit version changes"),
-        )
-        .arg(
-            Arg::new("no_git_push")
-                .long("no-git-push")
-                .about("Do not push generated commit and tags to git remote"),
-        );
-    assert!(utils::compare_output(
-        app,
-        "test --help",
-        WRAPPED_HELP,
-        false
-    ));
-}
-
-#[test]
-#[cfg(feature = "wrap_help")]
-fn unwrapped_help() {
-    static UNWRAPPED_HELP: &str = "test 
-
-USAGE:
-    rust_test.exe [FLAGS]
-
-FLAGS:
-    -a, --all              Also do versioning for private crates
-                           (will not be published)
-        --exact            Specify inter dependency version numbers
-                           exactly with `=`
-    -h, --help             Prints help information
-        --no-git-commit    Do not commit version changes
-        --no-git-push      Do not push generated commit and tags to
-                           git remote
-    -V, --version          Prints version information";
-    let app = App::new("test")
-        .term_width(68)
-        .arg(
-            Arg::new("all")
-                .short('a')
-                .long("all")
-                .about("Also do versioning for private crates (will not be published)"),
-        )
-        .arg(
-            Arg::new("exact")
-                .long("exact")
-                .about("Specify inter dependency version numbers exactly with `=`"),
-        )
-        .arg(
-            Arg::new("no_git_commit")
-                .long("no-git-commit")
-                .about("Do not commit version changes"),
-        )
-        .arg(
-            Arg::new("no_git_push")
-                .long("no-git-push")
-                .about("Do not push generated commit and tags to git remote"),
-        );
-    assert!(utils::compare_output(
-        app,
-        "test --help",
-        UNWRAPPED_HELP,
-        false
-    ));
-}
-
 #[test]
 fn complex_subcommand_help_output() {
     let a = utils::complex_app();
@@ -1555,8 +1448,6 @@ fn escaped_whitespace_values() {
 
 fn issue_1112_setup() -> App<'static> {
     App::new("test")
-        .author("Kevin K.")
-        .about("tests stuff")
         .version("1.3")
         .global_setting(AppSettings::NoAutoHelp)
         .arg(Arg::from("-h, --help 'some help'"))
@@ -2026,8 +1917,8 @@ This is after help.
 fn after_help_no_args() {
     let mut app = App::new("myapp")
         .version("1.0")
-        .setting(AppSettings::DisableHelpFlags)
-        .setting(AppSettings::DisableVersion)
+        .setting(AppSettings::DisableHelpFlag)
+        .setting(AppSettings::DisableVersionFlag)
         .after_help("This is after help.");
 
     let help = {
diff --git a/tests/macros.rs b/tests/macros.rs
index 013b5097..b20eabe3 100644
--- a/tests/macros.rs
+++ b/tests/macros.rs
@@ -29,7 +29,7 @@ fn basic() {
         (about: "tests clap library")
         (author: "Kevin K. <kbknapp@gmail.com>")
         (@global_setting ColorNever)
-        (@setting VersionlessSubcommands)
+        (@setting DisableVersionForSubcommands)
         (@arg opt: -o --option +takes_value ... "tests options")
         (@arg positional: index(1) "tests positionals")
         (@arg flag: -f --flag ... +global "tests flags")