feat: Expose ANSI styling to the user

This gives users the control over where clap outputs while still getting
colors.  For users who want to support old windows versions, check out
`fwdansi` crate.
This commit is contained in:
Ed Page 2022-09-22 09:51:41 -05:00
parent a2272a2c50
commit 037b07577c
2 changed files with 29 additions and 2 deletions

View file

@ -272,10 +272,11 @@ Behavior Changes
- Can now pass runtime generated data to `Command`, `Arg`, `ArgGroup`, `PossibleValue`, etc without managing lifetimes with the `string` feature flag (#2150, #4223)
- New default `error-context`, `help` and `usage` feature flags that can be turned off for smaller binaries (#4236)
- *(error)* `Error::apply` for changing the formatter for dropping binary size (#4111)
- *(error)* `Command::render`
- *(error)* `Command::render` which can render to plain text or ANSI escape codes
- *(help)* Show `PossibleValue::help` in long help (`--help`) (#3312)
- *(help)* New `{tab}` variable for `Command::help_template` (#4161)
- *(help)* `Command::render_help` and `Command::render_long_help`
- *(help)* `Command::render_help` and `Command::render_long_help` which can render to plain text or ANSI escape codes
- *(help)* `Command::render_usage` now returns a `StyledStr` which can render to plain text or ANSI escape codes
### Fixes

View file

@ -22,6 +22,12 @@ impl StyledStr {
}
}
/// Display using [ANSI Escape Code](https://en.wikipedia.org/wiki/ANSI_escape_code) styling
#[cfg(feature = "color")]
pub fn ansi(&self) -> impl std::fmt::Display + '_ {
AnsiDisplay { styled: self }
}
pub(crate) fn header(&mut self, msg: impl Into<String>) {
self.stylize_(Some(Style::Header), msg.into());
}
@ -289,6 +295,26 @@ impl std::fmt::Display for StyledStr {
}
}
#[cfg(feature = "color")]
struct AnsiDisplay<'s> {
styled: &'s StyledStr,
}
#[cfg(feature = "color")]
impl std::fmt::Display for AnsiDisplay<'_> {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
let mut buffer = termcolor::Buffer::ansi();
self.styled
.write_colored(&mut buffer)
.map_err(|_| std::fmt::Error)?;
let buffer = buffer.into_inner();
let buffer = String::from_utf8(buffer).map_err(|_| std::fmt::Error)?;
std::fmt::Display::fmt(&buffer, f)?;
Ok(())
}
}
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub(crate) enum Style {
Header,