From 0ba987fca93558e47f83c23208b6855e12b71e23 Mon Sep 17 00:00:00 2001 From: Ed Page Date: Mon, 17 Jul 2023 16:57:22 -0500 Subject: [PATCH 1/4] refactor(test): Make it easier to compare features with manifest --- tests/examples.rs | 15 +++++++++------ tests/ui.rs | 15 +++++++++------ 2 files changed, 18 insertions(+), 12 deletions(-) diff --git a/tests/examples.rs b/tests/examples.rs index 74473d549d5..49b7af8f451 100644 --- a/tests/examples.rs +++ b/tests/examples.rs @@ -7,24 +7,27 @@ fn example_tests() { let t = trycmd::TestCases::new(); let features = [ + // Default #[cfg(feature = "std")] "std", + #[cfg(feature = "color")] + "color", + #[cfg(feature = "suggestions")] + "suggestions", + // Optional #[cfg(feature = "derive")] "derive", #[cfg(feature = "cargo")] "cargo", - #[cfg(feature = "color")] - "color", + #[cfg(feature = "wrap_help")] + "wrap_help", #[cfg(feature = "env")] "env", - #[cfg(feature = "suggestions")] - "suggestions", #[cfg(feature = "unicode")] "unicode", #[cfg(feature = "string")] "string", - #[cfg(feature = "wrap_help")] - "wrap_help", + // In-work #[cfg(feature = "unstable-replace")] "unstable-replace", ] diff --git a/tests/ui.rs b/tests/ui.rs index 2bbd80860d1..4bcfd0df1c2 100644 --- a/tests/ui.rs +++ b/tests/ui.rs @@ -7,24 +7,27 @@ fn ui_tests() { let t = trycmd::TestCases::new(); let features = [ + // Default #[cfg(feature = "std")] "std", + #[cfg(feature = "color")] + "color", + #[cfg(feature = "suggestions")] + "suggestions", + // Optional #[cfg(feature = "derive")] "derive", #[cfg(feature = "cargo")] "cargo", - #[cfg(feature = "color")] - "color", + #[cfg(feature = "wrap_help")] + "wrap_help", #[cfg(feature = "env")] "env", - #[cfg(feature = "suggestions")] - "suggestions", #[cfg(feature = "unicode")] "unicode", #[cfg(feature = "string")] "string", - #[cfg(feature = "wrap_help")] - "wrap_help", + // In-work ] .join(" "); t.register_bins(trycmd::cargo::compile_examples(["--features", &features]).unwrap()); From 97f4c72af123832e126e1b2917919ff76c9a7418 Mon Sep 17 00:00:00 2001 From: Ed Page Date: Mon, 17 Jul 2023 17:01:31 -0500 Subject: [PATCH 2/4] test(examples): Verify all features --- tests/examples.rs | 12 ++++++++++-- tests/ui.rs | 10 ++++++++++ 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/tests/examples.rs b/tests/examples.rs index 49b7af8f451..4dbbaab2e68 100644 --- a/tests/examples.rs +++ b/tests/examples.rs @@ -12,6 +12,12 @@ fn example_tests() { "std", #[cfg(feature = "color")] "color", + #[cfg(feature = "help")] + "help", + #[cfg(feature = "usage")] + "usage", + #[cfg(feature = "error-context")] + "error-context", #[cfg(feature = "suggestions")] "suggestions", // Optional @@ -28,8 +34,10 @@ fn example_tests() { #[cfg(feature = "string")] "string", // In-work - #[cfg(feature = "unstable-replace")] - "unstable-replace", + //#[cfg(feature = "unstable-v5")] // Currently has failures + //"unstable-v5", + #[cfg(feature = "unstable-styles")] + "unstable-styles", ] .join(" "); t.register_bins(trycmd::cargo::compile_examples(["--features", &features]).unwrap()); diff --git a/tests/ui.rs b/tests/ui.rs index 4bcfd0df1c2..b1328ff9513 100644 --- a/tests/ui.rs +++ b/tests/ui.rs @@ -12,6 +12,12 @@ fn ui_tests() { "std", #[cfg(feature = "color")] "color", + #[cfg(feature = "help")] + "help", + #[cfg(feature = "usage")] + "usage", + #[cfg(feature = "error-context")] + "error-context", #[cfg(feature = "suggestions")] "suggestions", // Optional @@ -28,6 +34,10 @@ fn ui_tests() { #[cfg(feature = "string")] "string", // In-work + //#[cfg(feature = "unstable-v5")] // Currently has failures + //"unstable-v5", + #[cfg(feature = "unstable-styles")] + "unstable-styles", ] .join(" "); t.register_bins(trycmd::cargo::compile_examples(["--features", &features]).unwrap()); From e31768bb5599fe1a87fcf76d84743292598f94a9 Mon Sep 17 00:00:00 2001 From: Ed Page Date: Mon, 17 Jul 2023 17:10:13 -0500 Subject: [PATCH 3/4] fix(builder): Re-export anstyle for easy access --- clap_builder/src/builder/mod.rs | 9 +- clap_builder/src/builder/styled_str.rs | 161 ------------------------ clap_builder/src/builder/styling.rs | 166 +++++++++++++++++++++++++ 3 files changed, 173 insertions(+), 163 deletions(-) create mode 100644 clap_builder/src/builder/styling.rs diff --git a/clap_builder/src/builder/mod.rs b/clap_builder/src/builder/mod.rs index 495c8458762..ad70911a972 100644 --- a/clap_builder/src/builder/mod.rs +++ b/clap_builder/src/builder/mod.rs @@ -23,6 +23,11 @@ mod debug_asserts; #[cfg(test)] mod tests; +#[cfg(feature = "unstable-styles")] +pub mod styling; +#[cfg(not(feature = "unstable-styles"))] +pub(crate) mod styling; + pub use self::str::Str; pub use action::ArgAction; pub use arg::Arg; @@ -36,7 +41,7 @@ pub use resettable::IntoResettable; pub use resettable::Resettable; pub use styled_str::StyledStr; #[cfg(feature = "unstable-styles")] -pub use styled_str::Styles; +pub use styling::Styles; pub use value_hint::ValueHint; pub use value_parser::_AutoValueParser; pub use value_parser::via_prelude; @@ -63,4 +68,4 @@ pub(crate) use action::CountType; pub(crate) use arg_settings::{ArgFlags, ArgSettings}; pub(crate) use command::AppTag; #[cfg(not(feature = "unstable-styles"))] -pub(crate) use styled_str::Styles; +pub(crate) use styling::Styles; diff --git a/clap_builder/src/builder/styled_str.rs b/clap_builder/src/builder/styled_str.rs index e4acc63ffba..d856a301516 100644 --- a/clap_builder/src/builder/styled_str.rs +++ b/clap_builder/src/builder/styled_str.rs @@ -197,164 +197,3 @@ impl std::fmt::Display for StyledStr { Ok(()) } } - -/// Terminal styling definitions -#[derive(Clone, Debug)] -#[allow(missing_copy_implementations)] // Large enough type that I want an explicit `clone()` for now -pub struct Styles { - header: anstyle::Style, - error: anstyle::Style, - usage: anstyle::Style, - literal: anstyle::Style, - placeholder: anstyle::Style, - valid: anstyle::Style, - invalid: anstyle::Style, -} - -impl Styles { - /// No terminal styling - pub const fn plain() -> Self { - Self { - header: anstyle::Style::new(), - error: anstyle::Style::new(), - usage: anstyle::Style::new(), - literal: anstyle::Style::new(), - placeholder: anstyle::Style::new(), - valid: anstyle::Style::new(), - invalid: anstyle::Style::new(), - } - } - - /// Default terminal styling - pub const fn styled() -> Self { - #[cfg(feature = "color")] - { - Self { - header: anstyle::Style::new().bold().underline(), - error: anstyle::Style::new() - .fg_color(Some(anstyle::Color::Ansi(anstyle::AnsiColor::Red))) - .bold(), - usage: anstyle::Style::new().bold().underline(), - literal: anstyle::Style::new().bold(), - placeholder: anstyle::Style::new(), - valid: anstyle::Style::new() - .fg_color(Some(anstyle::Color::Ansi(anstyle::AnsiColor::Green))), - invalid: anstyle::Style::new() - .fg_color(Some(anstyle::Color::Ansi(anstyle::AnsiColor::Yellow))), - } - } - #[cfg(not(feature = "color"))] - { - Self::plain() - } - } - - /// General Heading style, e.g. [`help_heading`][crate::Arg::help_heading] - #[inline] - pub const fn header(mut self, style: anstyle::Style) -> Self { - self.header = style; - self - } - - /// Error heading - #[inline] - pub const fn error(mut self, style: anstyle::Style) -> Self { - self.error = style; - self - } - - /// Usage heading - #[inline] - pub const fn usage(mut self, style: anstyle::Style) -> Self { - self.usage = style; - self - } - - /// Literal command-line syntax, e.g. `--help` - #[inline] - pub const fn literal(mut self, style: anstyle::Style) -> Self { - self.literal = style; - self - } - - /// Descriptions within command-line syntax, e.g. [`value_name`][crate::Arg::value_name] - #[inline] - pub const fn placeholder(mut self, style: anstyle::Style) -> Self { - self.placeholder = style; - self - } - - /// Highlight suggested usage - #[inline] - pub const fn valid(mut self, style: anstyle::Style) -> Self { - self.valid = style; - self - } - - /// Highlight invalid usage - #[inline] - pub const fn invalid(mut self, style: anstyle::Style) -> Self { - self.invalid = style; - self - } -} - -/// Reflection -impl Styles { - /// General Heading style, e.g. [`help_heading`][crate::Arg::help_heading] - #[inline(always)] - pub const fn get_header(&self) -> &anstyle::Style { - &self.header - } - - /// Error heading - #[inline(always)] - pub const fn get_error(&self) -> &anstyle::Style { - &self.error - } - - /// Usage heading - #[inline(always)] - pub const fn get_usage(&self) -> &anstyle::Style { - &self.usage - } - - /// Literal command-line syntax, e.g. `--help` - #[inline(always)] - pub const fn get_literal(&self) -> &anstyle::Style { - &self.literal - } - - /// Descriptions within command-line syntax, e.g. [`value_name`][crate::Arg::value_name] - #[inline(always)] - pub const fn get_placeholder(&self) -> &anstyle::Style { - &self.placeholder - } - - /// Highlight suggested usage - #[inline(always)] - pub const fn get_valid(&self) -> &anstyle::Style { - &self.valid - } - - /// Highlight invalid usage - #[inline(always)] - pub const fn get_invalid(&self) -> &anstyle::Style { - &self.invalid - } -} - -impl super::AppTag for Styles {} - -impl Default for Styles { - fn default() -> Self { - Self::styled() - } -} - -impl Default for &'_ Styles { - fn default() -> Self { - const STYLES: Styles = Styles::styled(); - &STYLES - } -} diff --git a/clap_builder/src/builder/styling.rs b/clap_builder/src/builder/styling.rs new file mode 100644 index 00000000000..7189d179a6e --- /dev/null +++ b/clap_builder/src/builder/styling.rs @@ -0,0 +1,166 @@ +//! Terminal [`Styles`] for help and error output + +pub use anstyle::*; + +/// Terminal styling definitions +/// +/// See also [`Command::styles`][crate::Command::styles]. +#[derive(Clone, Debug)] +#[allow(missing_copy_implementations)] // Large enough type that I want an explicit `clone()` for now +pub struct Styles { + header: anstyle::Style, + error: anstyle::Style, + usage: anstyle::Style, + literal: anstyle::Style, + placeholder: anstyle::Style, + valid: anstyle::Style, + invalid: anstyle::Style, +} + +impl Styles { + /// No terminal styling + pub const fn plain() -> Self { + Self { + header: anstyle::Style::new(), + error: anstyle::Style::new(), + usage: anstyle::Style::new(), + literal: anstyle::Style::new(), + placeholder: anstyle::Style::new(), + valid: anstyle::Style::new(), + invalid: anstyle::Style::new(), + } + } + + /// Default terminal styling + pub const fn styled() -> Self { + #[cfg(feature = "color")] + { + Self { + header: anstyle::Style::new().bold().underline(), + error: anstyle::Style::new() + .fg_color(Some(anstyle::Color::Ansi(anstyle::AnsiColor::Red))) + .bold(), + usage: anstyle::Style::new().bold().underline(), + literal: anstyle::Style::new().bold(), + placeholder: anstyle::Style::new(), + valid: anstyle::Style::new() + .fg_color(Some(anstyle::Color::Ansi(anstyle::AnsiColor::Green))), + invalid: anstyle::Style::new() + .fg_color(Some(anstyle::Color::Ansi(anstyle::AnsiColor::Yellow))), + } + } + #[cfg(not(feature = "color"))] + { + Self::plain() + } + } + + /// General Heading style, e.g. [`help_heading`][crate::Arg::help_heading] + #[inline] + pub const fn header(mut self, style: anstyle::Style) -> Self { + self.header = style; + self + } + + /// Error heading + #[inline] + pub const fn error(mut self, style: anstyle::Style) -> Self { + self.error = style; + self + } + + /// Usage heading + #[inline] + pub const fn usage(mut self, style: anstyle::Style) -> Self { + self.usage = style; + self + } + + /// Literal command-line syntax, e.g. `--help` + #[inline] + pub const fn literal(mut self, style: anstyle::Style) -> Self { + self.literal = style; + self + } + + /// Descriptions within command-line syntax, e.g. [`value_name`][crate::Arg::value_name] + #[inline] + pub const fn placeholder(mut self, style: anstyle::Style) -> Self { + self.placeholder = style; + self + } + + /// Highlight suggested usage + #[inline] + pub const fn valid(mut self, style: anstyle::Style) -> Self { + self.valid = style; + self + } + + /// Highlight invalid usage + #[inline] + pub const fn invalid(mut self, style: anstyle::Style) -> Self { + self.invalid = style; + self + } +} + +/// Reflection +impl Styles { + /// General Heading style, e.g. [`help_heading`][crate::Arg::help_heading] + #[inline(always)] + pub const fn get_header(&self) -> &anstyle::Style { + &self.header + } + + /// Error heading + #[inline(always)] + pub const fn get_error(&self) -> &anstyle::Style { + &self.error + } + + /// Usage heading + #[inline(always)] + pub const fn get_usage(&self) -> &anstyle::Style { + &self.usage + } + + /// Literal command-line syntax, e.g. `--help` + #[inline(always)] + pub const fn get_literal(&self) -> &anstyle::Style { + &self.literal + } + + /// Descriptions within command-line syntax, e.g. [`value_name`][crate::Arg::value_name] + #[inline(always)] + pub const fn get_placeholder(&self) -> &anstyle::Style { + &self.placeholder + } + + /// Highlight suggested usage + #[inline(always)] + pub const fn get_valid(&self) -> &anstyle::Style { + &self.valid + } + + /// Highlight invalid usage + #[inline(always)] + pub const fn get_invalid(&self) -> &anstyle::Style { + &self.invalid + } +} + +impl super::AppTag for Styles {} + +impl Default for Styles { + fn default() -> Self { + Self::styled() + } +} + +impl Default for &'_ Styles { + fn default() -> Self { + const STYLES: Styles = Styles::styled(); + &STYLES + } +} From 82f17a40c0b12589b6cd689330d50e83f4db3682 Mon Sep 17 00:00:00 2001 From: Ed Page Date: Mon, 17 Jul 2023 17:10:33 -0500 Subject: [PATCH 4/4] docs(builder): Provide styling examples --- clap_builder/src/builder/command.rs | 9 +++++++-- clap_builder/src/builder/styling.rs | 15 +++++++++++++++ src/bin/stdio-fixture.rs | 13 ++++++++++++- 3 files changed, 34 insertions(+), 3 deletions(-) diff --git a/clap_builder/src/builder/command.rs b/clap_builder/src/builder/command.rs index c5a3dd6b8c1..b2efdbc7ebb 100644 --- a/clap_builder/src/builder/command.rs +++ b/clap_builder/src/builder/command.rs @@ -1111,9 +1111,14 @@ impl Command { /// /// ```no_run /// # use clap_builder as clap; - /// # use clap::{Command, ColorChoice, builder::Styles}; + /// # use clap::{Command, ColorChoice, builder::styling}; + /// let styles = styling::Styles::styled() + /// .header(styling::AnsiColor::Green.on_default() | styling::Effects::BOLD) + /// .usage(styling::AnsiColor::Green.on_default() | styling::Effects::BOLD) + /// .literal(styling::AnsiColor::Blue.on_default() | styling::Effects::BOLD) + /// .placeholder(styling::AnsiColor::Cyan.on_default()); /// Command::new("myprog") - /// .styles(Styles::styled().usage(Default::default())) + /// .styles(styles) /// .get_matches(); /// ``` #[cfg(feature = "color")] diff --git a/clap_builder/src/builder/styling.rs b/clap_builder/src/builder/styling.rs index 7189d179a6e..f7f2ee1e35f 100644 --- a/clap_builder/src/builder/styling.rs +++ b/clap_builder/src/builder/styling.rs @@ -5,6 +5,21 @@ pub use anstyle::*; /// Terminal styling definitions /// /// See also [`Command::styles`][crate::Command::styles]. +/// +/// # Example +/// +/// clap v3 styling +/// ```rust +/// # #[cfg(feature = "unstable-styles")] { +/// # use clap_builder as clap; +/// # use clap::builder::styling::*; +/// let styles = Styles::styled() +/// .header(AnsiColor::Yellow.on_default()) +/// .usage(AnsiColor::Green.on_default()) +/// .literal(AnsiColor::Green.on_default()) +/// .placeholder(AnsiColor::Green.on_default()); +/// # } +/// ``` #[derive(Clone, Debug)] #[allow(missing_copy_implementations)] // Large enough type that I want an explicit `clone()` for now pub struct Styles { diff --git a/src/bin/stdio-fixture.rs b/src/bin/stdio-fixture.rs index 3a60d1338d5..792e040567a 100644 --- a/src/bin/stdio-fixture.rs +++ b/src/bin/stdio-fixture.rs @@ -1,5 +1,6 @@ fn main() { - let cmd = clap::Command::new("stdio-fixture") + #[allow(unused_mut)] + let mut cmd = clap::Command::new("stdio-fixture") .version("1.0") .long_version("1.0 - a2132c") .arg_required_else_help(true) @@ -11,5 +12,15 @@ fn main() { .action(clap::ArgAction::SetTrue) .long_help("more log"), ); + #[cfg(feature = "unstable-styles")] + { + use clap::builder::styling; + let styles = styling::Styles::styled() + .header(styling::AnsiColor::Green.on_default() | styling::Effects::BOLD) + .usage(styling::AnsiColor::Green.on_default() | styling::Effects::BOLD) + .literal(styling::AnsiColor::Blue.on_default() | styling::Effects::BOLD) + .placeholder(styling::AnsiColor::Cyan.on_default()); + cmd = cmd.styles(styles); + } cmd.get_matches(); }