Repository: clap-rs/clap (rust)

Issue:
Specifying a default value but no help text results in the default value being pushed one space to the right inside the help screen
## Output

```text
next-semver 0.0.0
Detect the next semantic release version based on your commit history

USAGE:
    next-semver.exe [FLAGS] [OPTIONS]

FLAGS:
    -h, --help       Prints help information

OPTIONS:
    -f, --from <from>    The branch, commit or tag from where to start the detection process
    -t, --to <to>         [default: HEAD]
```

Take a look at the `-t,--to` option. It's one space too much aligned to the right :)

### Code

```rust
use clap::Clap;

#[derive(Clap, Debug)]
struct Args {
    /// The branch, commit or tag from where to start the detection process.
    ///
    /// If not specified, the tool will automatically use the latest published
    /// semantic version compatible tag (`vX.X.X`).
    #[clap(long, short)]
    from: Option<String>,
    #[clap(long, short, default_value = "HEAD")]
    to: String,
}

fn main() {
	let _args = Args::parse();
}
```

### Steps to reproduce the issue

1. `cargo run -- -h`

### Version

* **Rust**: rustc 1.41.0 (5e1a79984 2020-01-27)
* **Clap**: 3.0.0-beta.1

### Expected Behavior Summary

The default value should be aligned with the help text, i.e. one space to the left.

__Edit:__ I know, it's nothing major but I haven't found an issue on here so I thought it's still worth mentioning :) 

Pull request:
fix: detect if space should be added before spec_vals
Here I check for situation when there's no `about` available about the argument, but there're some `spec_vals` to be printed. If that's the case, We don't need the separator (" ") between about section and those values, so it should be omitted.

Closes #2040 

Patch:
diff --git a/examples/03_args.rs b/examples/03_args.rs
index 86cfa997..dca9d2d6 100644
--- a/examples/03_args.rs
+++ b/examples/03_args.rs
@@ -41,6 +41,7 @@ fn main() {
                 .long("config"),
             Arg::new("input")
                 .about("the input file to use")
+                .index(1)
                 .required(true),
         ])
         // *Note* the following two examples are convenience methods, if you wish
diff --git a/examples/05_flag_args.rs b/examples/05_flag_args.rs
index 28e771d3..6183a0df 100644
--- a/examples/05_flag_args.rs
+++ b/examples/05_flag_args.rs
@@ -29,8 +29,9 @@ fn main() {
                                            // also has a conflicts_with_all(Vec<&str>)
                                            // and an exclusive(true)
         )
-        .arg("-c, --config=[FILE] 'sets a custom config file'")
-        .arg("<output> 'sets an output file'")
+        // NOTE: In order to compile this example, comment out requires() and
+        // conflicts_with() because we have not defined an "output" or "config"
+        // argument.
         .get_matches();
 
     // We can find out whether or not awesome was used
diff --git a/examples/06_positional_args.rs b/examples/06_positional_args.rs
index 31d2d66f..2a2d6a64 100644
--- a/examples/06_positional_args.rs
+++ b/examples/06_positional_args.rs
@@ -33,7 +33,8 @@ fn main() {
         // requires "config"
         // Note, we also do not need to specify requires("input")
         // because requires lists are automatically two-way
-        .arg(Arg::new("output").about("the output file to use").index(3))
+        // NOTE: In order to compile this example, comment out conflicts_with()
+        // because we have not defined an "output" argument.
         .get_matches();
 
     // We can find out whether or not "input" or "config" were used
diff --git a/examples/07_option_args.rs b/examples/07_option_args.rs
index 1c5eb438..2933b71b 100644
--- a/examples/07_option_args.rs
+++ b/examples/07_option_args.rs
@@ -33,8 +33,9 @@ fn main() {
                                            // also has a conflicts_with_all(Vec<&str>)
                                            // and an exclusive(true)
         )
-        .arg("-c, --config=[FILE] 'the config file to use'")
-        .arg("<output> 'the output file to use'")
+        // NOTE: In order to compile this example, comment out conflicts_with()
+        // and requires() because we have not defined an "output" or "config"
+        // argument.
         .get_matches();
 
     // We can find out whether or not "input" was used
diff --git a/examples/14_groups.rs b/examples/14_groups.rs
index 7341193d..4fbc727d 100644
--- a/examples/14_groups.rs
+++ b/examples/14_groups.rs
@@ -34,7 +34,7 @@ fn main() {
         .group(
             ArgGroup::new("vers")
                 .required(true)
-                .args(&["set-ver", "major", "minor", "patch"]),
+                .args(&["ver", "major", "minor", "patch"]),
         )
         // Arguments can also be added to a group individually, these two arguments
         // are part of the "input" group which is not required
diff --git a/src/output/help.rs b/src/output/help.rs
index ad114a26..ed11da1a 100644
--- a/src/output/help.rs
+++ b/src/output/help.rs
@@ -504,7 +504,7 @@ impl<'help, 'app, 'parser, 'writer> Help<'help, 'app, 'parser, 'writer> {
             } else {
                 String::new()
             };
-            let env_info = format!(" [env: {}{}]", env.0.to_string_lossy(), env_val);
+            let env_info = format!("[env: {}{}]", env.0.to_string_lossy(), env_val);
             spec_vals.push(env_info);
         }
         if !a.is_set(ArgSettings::HideDefaultValue) && !a.default_vals.is_empty() {
@@ -520,7 +520,7 @@ impl<'help, 'app, 'parser, 'writer> Help<'help, 'app, 'parser, 'writer> {
                 .collect::<Vec<_>>()
                 .join(" ");
 
-            spec_vals.push(format!(" [default: {}]", pvs));
+            spec_vals.push(format!("[default: {}]", pvs));
         }
         if !a.aliases.is_empty() {
             debug!("Help::spec_vals: Found aliases...{:?}", a.aliases);
@@ -534,7 +534,7 @@ impl<'help, 'app, 'parser, 'writer> Help<'help, 'app, 'parser, 'writer> {
                 .join(", ");
 
             if !als.is_empty() {
-                spec_vals.push(format!(" [aliases: {}]", als));
+                spec_vals.push(format!("[aliases: {}]", als));
             }
         }
 
@@ -566,12 +566,14 @@ impl<'help, 'app, 'parser, 'writer> Help<'help, 'app, 'parser, 'writer> {
                 a.possible_vals
             );
 
-            spec_vals.push(format!(
-                " [possible values: {}]",
-                a.possible_vals.join(", ")
-            ));
+            spec_vals.push(format!("[possible values: {}]", a.possible_vals.join(", ")));
         }
-        spec_vals.join(" ")
+        let prefix = if !spec_vals.is_empty() && !a.get_about().unwrap_or("").is_empty() {
+            " "
+        } else {
+            ""
+        };
+        prefix.to_string() + &spec_vals.join(" ")
     }
 }
 


Test patch:
diff --git a/tests/arg_aliases.rs b/tests/arg_aliases.rs
index 46e179ba..41643e14 100644
--- a/tests/arg_aliases.rs
+++ b/tests/arg_aliases.rs
@@ -9,12 +9,12 @@ USAGE:
     ct test [FLAGS] [OPTIONS]
 
 FLAGS:
-    -f, --flag        [aliases: v_flg, flag2, flg3]
+    -f, --flag       [aliases: v_flg, flag2, flg3]
     -h, --help       Prints help information
     -V, --version    Prints version information
 
 OPTIONS:
-    -o, --opt <opt>     [aliases: visible]";
+    -o, --opt <opt>    [aliases: visible]";
 
 static SC_INVISIBLE_ALIAS_HELP: &str = "ct-test 1.2
 Some help
diff --git a/tests/arg_aliases_short.rs b/tests/arg_aliases_short.rs
index 865dc8bc..102b0f87 100644
--- a/tests/arg_aliases_short.rs
+++ b/tests/arg_aliases_short.rs
@@ -9,7 +9,7 @@ USAGE:
     ct test [FLAGS] [OPTIONS]
 
 FLAGS:
-    -f, --flag        [aliases: flag1] [short aliases: a, b, 🦆]
+    -f, --flag       [aliases: flag1] [short aliases: a, b, 🦆]
     -h, --help       Prints help information
     -V, --version    Prints version information
 
diff --git a/tests/examples.rs b/tests/examples.rs
deleted file mode 100644
index 2c080256..00000000
--- a/tests/examples.rs
+++ /dev/null
@@ -1,53 +0,0 @@
-#![cfg(not(tarpaulin))]
-
-use std::ffi::OsStr;
-use std::fs;
-use std::process::{Command, Output};
-
-fn run_example<S: AsRef<str>>(name: S, args: &[&str]) -> Output {
-    let mut all_args = vec![
-        "run",
-        "--example",
-        name.as_ref(),
-        "--features",
-        "yaml unstable",
-        "--",
-    ];
-    all_args.extend_from_slice(args);
-
-    Command::new(env!("CARGO"))
-        .args(all_args)
-        .output()
-        .expect("failed to run example")
-}
-
-#[test]
-fn examples_are_functional() {
-    let example_paths = fs::read_dir("examples")
-        .expect("couldn't read examples directory")
-        .map(|result| result.expect("couldn't get directory entry").path())
-        .filter(|path| path.is_file() && path.extension().and_then(OsStr::to_str) == Some("rs"));
-
-    let mut example_count = 0;
-    for path in example_paths {
-        example_count += 1;
-
-        let example_name = path
-            .file_stem()
-            .and_then(OsStr::to_str)
-            .expect("unable to determine example name");
-
-        let help_output = run_example(example_name, &["--help"]);
-        assert!(
-            help_output.status.success(),
-            "{} --help exited with nonzero",
-            example_name,
-        );
-        assert!(
-            !help_output.stdout.is_empty(),
-            "{} --help had no output",
-            example_name,
-        );
-    }
-    assert!(example_count > 0);
-}