feat(help): Break out help feature flag

This removes auto-generated help, saving about 50 KiB.
This commit is contained in:
Ed Page 2022-09-19 11:54:06 -05:00
parent 6ea5d46300
commit 7a5dad89ff
21 changed files with 100 additions and 38 deletions

View file

@ -57,6 +57,7 @@ pre-release-replacements = [
default = [
"std",
"color",
"help",
"error-context",
"suggestions",
]
@ -66,6 +67,7 @@ unstable-doc = ["derive", "cargo", "wrap_help", "env", "unicode", "string", "uns
# Used in default
std = [] # support for no_std in a backwards-compatible way
color = ["dep:atty", "dep:termcolor"]
help = []
error-context = []
suggestions = ["dep:strsim", "error-context"]
@ -153,6 +155,7 @@ path = "examples/multicall-hostname.rs"
[[example]]
name = "repl"
path = "examples/repl.rs"
required-features = ["help"]
[[example]]
name = "01_quick"

View file

@ -11,7 +11,7 @@ publish = false
release = false
[dev-dependencies]
clap = { path = "../", version = "4.0.0-alpha.0", default-features = false, features = ["std"] }
clap = { path = "../", version = "4.0.0-alpha.0", default-features = false, features = ["std", "help"] }
criterion = "0.3.2"
lazy_static = "1"

View file

@ -52,7 +52,7 @@ unicode-xid = { version = "0.2.2", optional = true }
snapbox = { version = "0.3", features = ["diff"] }
# Cutting out `filesystem` feature
trycmd = { version = "0.13", default-features = false, features = ["color-auto", "diff", "examples"] }
clap = { path = "../", version = "4.0.0-alpha.0", default-features = false, features = ["std", "derive"] }
clap = { path = "../", version = "4.0.0-alpha.0", default-features = false, features = ["std", "derive", "help"] }
[[example]]
name = "dynamic"

View file

@ -44,3 +44,4 @@ clap_complete = { path = "../clap_complete", version = "4.0.0-alpha.0" }
[dev-dependencies]
snapbox = { version = "0.3", features = ["diff"] }
clap = { path = "../", version = "4.0.0-alpha.0", default-features = false, features = ["std", "help"] }

View file

@ -45,7 +45,7 @@ clap = { path = "../", version = "4.0.0-alpha.0", default-features = false, feat
[dev-dependencies]
snapbox = { version = "0.3", features = ["diff"] }
clap = { path = "../", version = "4.0.0-alpha.0", default-features = false, features = ["std"] }
clap = { path = "../", version = "4.0.0-alpha.0", default-features = false, features = ["std", "help"] }
[features]
default = []

View file

@ -6,6 +6,7 @@
//!
//! * **std**: _Not Currently Used._ Placeholder for supporting `no_std` environments in a backwards compatible manner.
//! * **color**: Turns on colored error messages.
//! * **help**: Auto-generate help output
//! * **error-context**: Include contextual information for errors (which arg failed, etc)
//! * **suggestions**: Turns on the `Did you mean '--myoption'?` feature for when users make typos.
//!

View file

@ -2,7 +2,8 @@
///
/// # Examples
///
/// ```rust
#[cfg_attr(not(feature = "help"), doc = " ```ignore")]
#[cfg_attr(feature = "help", doc = " ```")]
/// # use clap::Command;
/// # use clap::Arg;
/// let cmd = Command::new("mycmd")
@ -211,7 +212,8 @@ pub enum ArgAction {
///
/// # Examples
///
/// ```rust
#[cfg_attr(not(feature = "help"), doc = " ```ignore")]
#[cfg_attr(feature = "help", doc = " ```")]
/// # use clap::Command;
/// # use clap::Arg;
/// let cmd = Command::new("mycmd")

View file

@ -1107,7 +1107,8 @@ impl Arg {
/// # ;
/// ```
///
/// ```rust
#[cfg_attr(not(feature = "help"), doc = " ```ignore")]
#[cfg_attr(feature = "help", doc = " ```")]
/// # use clap::{Command, Arg};
/// let m = Command::new("prog")
/// .arg(Arg::new("config")
@ -1168,7 +1169,8 @@ impl Arg {
/// .value_names(["fast", "slow"]);
/// ```
///
/// ```rust
#[cfg_attr(not(feature = "help"), doc = " ```ignore")]
#[cfg_attr(feature = "help", doc = " ```")]
/// # use clap::{Command, Arg};
/// let m = Command::new("prog")
/// .arg(Arg::new("io")
@ -1991,7 +1993,8 @@ impl Arg {
/// Setting `help` displays a short message to the side of the argument when the user passes
/// `-h` or `--help` (by default).
///
/// ```rust
#[cfg_attr(not(feature = "help"), doc = " ```ignore")]
#[cfg_attr(feature = "help", doc = " ```")]
/// # use clap::{Command, Arg};
/// let m = Command::new("prog")
/// .arg(Arg::new("cfg")
@ -2040,7 +2043,8 @@ impl Arg {
/// Setting `help` displays a short message to the side of the argument when the user passes
/// `-h` or `--help` (by default).
///
/// ```rust
#[cfg_attr(not(feature = "help"), doc = " ```ignore")]
#[cfg_attr(feature = "help", doc = " ```")]
/// # use clap::{Command, Arg};
/// let m = Command::new("prog")
/// .arg(Arg::new("cfg")
@ -2096,7 +2100,8 @@ impl Arg {
///
/// # Examples
///
/// ```rust
#[cfg_attr(not(feature = "help"), doc = " ```ignore")]
#[cfg_attr(feature = "help", doc = " ```")]
/// # use clap::{Command, Arg, ArgAction};
/// let m = Command::new("prog")
/// .arg(Arg::new("a") // Typically args are grouped alphabetically by name.
@ -2162,7 +2167,8 @@ impl Arg {
///
/// # Examples
///
/// ```rust
#[cfg_attr(not(feature = "help"), doc = " ```ignore")]
#[cfg_attr(feature = "help", doc = " ```")]
/// # use clap::{Command, Arg, ArgAction};
/// let m = Command::new("prog")
/// .arg(Arg::new("opt")
@ -2212,7 +2218,8 @@ impl Arg {
///
/// Setting `Hidden` will hide the argument when displaying help text
///
/// ```rust
#[cfg_attr(not(feature = "help"), doc = " ```ignore")]
#[cfg_attr(feature = "help", doc = " ```")]
/// # use clap::{Command, Arg};
/// let m = Command::new("prog")
/// .arg(Arg::new("cfg")
@ -2385,7 +2392,8 @@ impl Arg {
///
/// Setting `hide_short_help(true)` will hide the argument when displaying short help text
///
/// ```rust
#[cfg_attr(not(feature = "help"), doc = " ```ignore")]
#[cfg_attr(feature = "help", doc = " ```")]
/// # use clap::{Command, Arg};
/// let m = Command::new("prog")
/// .arg(Arg::new("cfg")
@ -2411,7 +2419,8 @@ impl Arg {
///
/// However, when --help is called
///
/// ```rust
#[cfg_attr(not(feature = "help"), doc = " ```ignore")]
#[cfg_attr(feature = "help", doc = " ```")]
/// # use clap::{Command, Arg};
/// let m = Command::new("prog")
/// .arg(Arg::new("cfg")
@ -2456,7 +2465,8 @@ impl Arg {
///
/// Setting `hide_long_help(true)` will hide the argument when displaying long help text
///
/// ```rust
#[cfg_attr(not(feature = "help"), doc = " ```ignore")]
#[cfg_attr(feature = "help", doc = " ```")]
/// # use clap::{Command, Arg};
/// let m = Command::new("prog")
/// .arg(Arg::new("cfg")
@ -2482,7 +2492,8 @@ impl Arg {
///
/// However, when -h is called
///
/// ```rust
#[cfg_attr(not(feature = "help"), doc = " ```ignore")]
#[cfg_attr(feature = "help", doc = " ```")]
/// # use clap::{Command, Arg};
/// let m = Command::new("prog")
/// .arg(Arg::new("cfg")
@ -4196,6 +4207,7 @@ impl Arg {
self.is_multiple_values_set() || matches!(*self.get_action(), ArgAction::Append)
}
#[cfg(feature = "help")]
pub(crate) fn get_display_order(&self) -> usize {
self.disp_ord.unwrap_or(999)
}

View file

@ -90,6 +90,7 @@ pub struct Command {
disp_ord: Option<usize>,
term_w: Option<usize>,
max_w: Option<usize>,
#[cfg(feature = "help")]
template: Option<StyledStr>,
settings: AppFlags,
g_settings: AppFlags,
@ -1727,6 +1728,7 @@ impl Command {
/// [`Command::before_help`]: Command::before_help()
/// [`Command::before_long_help`]: Command::before_long_help()
#[must_use]
#[cfg(feature = "help")]
pub fn help_template(mut self, s: impl IntoResettable<StyledStr>) -> Self {
self.template = s.into_resettable().into_option();
self
@ -2536,7 +2538,8 @@ impl Command {
///
/// # Examples
///
/// ```rust
#[cfg_attr(not(feature = "help"), doc = " ```ignore")]
#[cfg_attr(feature = "help", doc = " ```")]
/// # use clap::{Command, };
/// let m = Command::new("cust-ord")
/// .subcommand(Command::new("alpha") // typically subcommands are grouped
@ -3661,14 +3664,17 @@ impl Command {
self.help_str.as_ref()
}
#[cfg(feature = "help")]
pub(crate) fn get_help_template(&self) -> Option<&StyledStr> {
self.template.as_ref()
}
#[cfg(feature = "help")]
pub(crate) fn get_term_width(&self) -> Option<usize> {
self.term_w
}
#[cfg(feature = "help")]
pub(crate) fn get_max_term_width(&self) -> Option<usize> {
self.max_w
}
@ -3753,6 +3759,11 @@ impl Command {
self.settings.insert(AppSettings::DisableHelpFlag.into());
self.settings.insert(AppSettings::DisableVersionFlag.into());
}
if !cfg!(feature = "help") && self.get_override_help().is_none() {
self.settings.insert(AppSettings::DisableHelpFlag.into());
self.settings
.insert(AppSettings::DisableHelpSubcommand.into());
}
if self.is_set(AppSettings::ArgsNegateSubcommands) {
self.settings
.insert(AppSettings::SubcommandsNegateReqs.into());
@ -4461,6 +4472,7 @@ impl Command {
.map(|sc| sc.get_name())
}
#[cfg(feature = "help")]
pub(crate) fn get_display_order(&self) -> usize {
self.disp_ord.unwrap_or(999)
}
@ -4553,6 +4565,7 @@ impl Default for Command {
disp_ord: Default::default(),
term_w: Default::default(),
max_w: Default::default(),
#[cfg(feature = "help")]
template: Default::default(),
settings: Default::default(),
g_settings: Default::default(),

View file

@ -337,6 +337,7 @@ pub(crate) fn assert_app(cmd: &Command) {
_verify_positionals(cmd);
#[cfg(feature = "help")]
if let Some(help_template) = cmd.get_help_template() {
assert!(
!help_template.to_string().contains("{flags}"),

View file

@ -1,5 +1,3 @@
use std::{borrow::Cow, iter};
use crate::builder::IntoResettable;
use crate::builder::Str;
use crate::builder::StyledStr;
@ -157,6 +155,7 @@ impl PossibleValue {
/// Get the help specified for this argument, if any and the argument
/// value is not hidden
#[inline]
#[cfg(feature = "help")]
pub(crate) fn get_visible_help(&self) -> Option<&StyledStr> {
if !self.hide {
self.get_help()
@ -178,7 +177,8 @@ impl PossibleValue {
/// Get the name if argument value is not hidden, `None` otherwise,
/// but wrapped in quotes if it contains whitespace
pub(crate) fn get_visible_quoted_name(&self) -> Option<Cow<'_, str>> {
#[cfg(feature = "help")]
pub(crate) fn get_visible_quoted_name(&self) -> Option<std::borrow::Cow<'_, str>> {
if !self.hide {
Some(if self.name.contains(char::is_whitespace) {
format!("{:?}", self.name).into()
@ -194,7 +194,7 @@ impl PossibleValue {
///
/// Namely the name and all aliases.
pub fn get_name_and_aliases(&self) -> impl Iterator<Item = &str> + '_ {
iter::once(self.get_name()).chain(self.aliases.iter().map(|s| s.as_str()))
std::iter::once(self.get_name()).chain(self.aliases.iter().map(|s| s.as_str()))
}
/// Tests if the value is valid for this argument value

View file

@ -1,6 +1,3 @@
use crate::output::display_width;
use crate::output::textwrap;
/// Terminal-styling container
#[derive(Clone, Default, Debug, PartialEq, Eq)]
pub struct StyledStr {
@ -86,6 +83,7 @@ impl StyledStr {
self.pieces = self.pieces.trim_end().to_owned();
}
#[cfg(feature = "help")]
pub(crate) fn indent(&mut self, initial: &str, trailing: &str) {
if let Some((_, first)) = self.iter_mut().next() {
first.insert_str(0, initial);
@ -97,8 +95,9 @@ impl StyledStr {
}
}
#[cfg(feature = "help")]
pub(crate) fn wrap(&mut self, hard_width: usize) {
let mut wrapper = textwrap::wrap_algorithms::LineWrapper::new(hard_width);
let mut wrapper = crate::output::textwrap::wrap_algorithms::LineWrapper::new(hard_width);
for (_, content) in self.iter_mut() {
let mut total = Vec::new();
for (i, line) in content.split_inclusive('\n').enumerate() {
@ -106,8 +105,8 @@ impl StyledStr {
// start of a section does not imply newline
wrapper.reset();
}
let line =
textwrap::word_separators::find_words_ascii_space(line).collect::<Vec<_>>();
let line = crate::output::textwrap::word_separators::find_words_ascii_space(line)
.collect::<Vec<_>>();
total.extend(wrapper.wrap(line));
}
let total = total.join("");
@ -130,14 +129,16 @@ impl StyledStr {
}
#[inline(never)]
#[cfg(feature = "help")]
pub(crate) fn display_width(&self) -> usize {
let mut width = 0;
for (_, c) in self.iter() {
width += display_width(c);
width += crate::output::display_width(c);
}
width
}
#[cfg(feature = "help")]
pub(crate) fn is_empty(&self) -> bool {
self.pieces.is_empty()
}

View file

@ -250,7 +250,8 @@ pub enum ErrorKind {
///
/// # Examples
///
/// ```rust
#[cfg_attr(not(feature = "help"), doc = " ```ignore")]
#[cfg_attr(feature = "help", doc = " ```")]
/// # use clap::{Command, Arg, error::ErrorKind};
/// let result = Command::new("prog")
/// .try_get_matches_from(vec!["prog", "--help"]);

View file

@ -1,6 +1,6 @@
#![cfg_attr(not(feature = "help"), allow(unused_variables))]
// Internal
use super::AutoHelp;
use super::HelpTemplate;
use crate::builder::Command;
use crate::builder::StyledStr;
use crate::output::Usage;
@ -11,16 +11,29 @@ pub(crate) fn write_help(writer: &mut StyledStr, cmd: &Command, usage: &Usage<'_
if let Some(h) = cmd.get_override_help() {
writer.extend(h.iter());
} else if let Some(tmpl) = cmd.get_help_template() {
for (style, content) in tmpl.iter() {
if style == None {
HelpTemplate::new(writer, cmd, usage, use_long).write_templated_help(content);
} else {
#[cfg(feature = "help")]
{
use super::AutoHelp;
use super::HelpTemplate;
if let Some(tmpl) = cmd.get_help_template() {
for (style, content) in tmpl.iter() {
if style == None {
HelpTemplate::new(writer, cmd, usage, use_long)
.write_templated_help(content);
} else {
writer.stylize(style, content);
}
}
} else {
writer.stylize(style, content);
AutoHelp::new(writer, cmd, usage, use_long).write_help();
}
}
} else {
AutoHelp::new(writer, cmd, usage, use_long).write_help();
#[cfg(not(feature = "help"))]
{
debug!("write_help: no help, `Command::override_help` and `help` is missing");
}
}
// Remove any extra lines caused by book keeping

View file

@ -1,16 +1,23 @@
mod help;
#[cfg(feature = "help")]
mod help_template;
mod usage;
pub(crate) mod fmt;
#[cfg(feature = "help")]
pub(crate) mod textwrap;
pub(crate) use self::help::write_help;
#[cfg(feature = "help")]
pub(crate) use self::help_template::AutoHelp;
#[cfg(feature = "help")]
pub(crate) use self::help_template::HelpTemplate;
#[cfg(feature = "help")]
pub(crate) use self::textwrap::core::display_width;
#[cfg(feature = "help")]
pub(crate) use self::textwrap::wrap;
pub(crate) use self::usage::Usage;
pub(crate) const TAB: &str = " ";
#[cfg(feature = "help")]
pub(crate) const TAB_WIDTH: usize = TAB.len();

View file

@ -1,3 +1,5 @@
#![cfg(feature = "help")]
use clap::{arg, builder::PossibleValue, error::ErrorKind, Arg, ArgAction, ArgGroup, Command};
use super::utils;

View file

@ -1,5 +1,6 @@
#![allow(clippy::bool_assert_comparison)]
#![allow(clippy::redundant_clone)]
#![cfg(feature = "help")]
mod action;
mod app_settings;

View file

@ -1,3 +1,4 @@
#![cfg(feature = "help")]
#![cfg(feature = "derive")]
mod app_name;

View file

@ -1,6 +1,7 @@
#![cfg(not(tarpaulin))]
#[test]
#[cfg(feature = "help")]
#[cfg(feature = "error-context")]
fn example_tests() {
let t = trycmd::TestCases::new();

View file

@ -277,6 +277,7 @@ mod arg {
}
#[test]
#[cfg(feature = "help")]
fn optional_value() {
let mut cmd = clap::Command::new("test").arg(clap::arg!(port: -p [NUM]));

View file

@ -1,6 +1,7 @@
#![cfg(not(tarpaulin))]
#[test]
#[cfg(feature = "help")]
#[cfg(feature = "error-context")]
fn ui_tests() {
let t = trycmd::TestCases::new();