Add support for other underline types and the ability to color them (#679)

This commit is contained in:
ahoyiski 2022-06-30 16:33:49 -03:00 committed by GitHub
parent 73a8ecc95f
commit ad0d100304
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 98 additions and 20 deletions

View File

@ -8,6 +8,10 @@ const ATTRIBUTES: [(style::Attribute, style::Attribute); 6] = [
(style::Attribute::Bold, style::Attribute::NormalIntensity),
(style::Attribute::Italic, style::Attribute::NoItalic),
(style::Attribute::Underlined, style::Attribute::NoUnderline),
(style::Attribute::DoubleUnderlined, style::Attribute::NoUnderline),
(style::Attribute::Undercurled, style::Attribute::NoUnderline),
(style::Attribute::Underdotted, style::Attribute::NoUnderline),
(style::Attribute::Underdashed, style::Attribute::NoUnderline),
(style::Attribute::Reverse, style::Attribute::NoReverse),
(
style::Attribute::CrossedOut,

View File

@ -217,6 +217,25 @@ impl Command for SetBackgroundColor {
}
}
/// A command that sets the the underline color.
///
/// See [`Color`](enum.Color.html) for more info.
///
/// [`SetColors`](struct.SetColors.html) can also be used to set both the foreground and background
/// color with one command.
///
/// # Notes
///
/// Commands must be executed/queued for execution otherwise they do nothing.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct SetUnderlineColor(pub Color);
impl Command for SetUnderlineColor {
fn write_ansi(&self, f: &mut impl fmt::Write) -> fmt::Result {
write!(f, csi!("{}m"), Colored::UnderlineColor(self.0))
}
}
/// A command that optionally sets the foreground and/or background color.
///
/// For example:
@ -340,6 +359,11 @@ impl<D: Display> Command for PrintStyledContent<D> {
reset_foreground = true;
}
if let Some(ul) = style.underline_color {
execute_fmt(f, SetUnderlineColor(ul)).map_err(|_| fmt::Error)?;
reset_foreground = true;
}
if !style.attributes.is_empty() {
execute_fmt(f, SetAttributes(style.attributes)).map_err(|_| fmt::Error)?;
reset = true;

View File

@ -11,6 +11,8 @@ pub struct ContentStyle {
pub foreground_color: Option<Color>,
/// The background color.
pub background_color: Option<Color>,
/// The underline color.
pub underline_color: Option<Color>,
/// List of attributes.
pub attributes: Attributes,
}

View File

@ -17,7 +17,7 @@ macro_rules! stylize_method {
}
}
};
($method_name_fg:ident, $method_name_bg:ident Color::$color:ident) => {
($method_name_fg:ident, $method_name_bg:ident, $method_name_ul:ident Color::$color:ident) => {
calculated_docs! {
#[doc = concat!(
"Sets the foreground color to [`",
@ -40,6 +40,17 @@ macro_rules! stylize_method {
fn $method_name_bg(self) -> Self::Styled {
self.on(Color::$color)
}
#[doc = concat!(
"Sets the underline color to [`",
stringify!($color),
"`](Color::",
stringify!($color),
")."
)]
fn $method_name_ul(self) -> Self::Styled {
self.underline(Color::$color)
}
}
};
}
@ -77,6 +88,13 @@ pub trait Stylize: Sized {
styled
}
/// Sets the underline color.
fn underline(self, color: Color) -> Self::Styled {
let mut styled = self.stylize();
styled.as_mut().underline_color = Some(color);
styled
}
/// Styles the content with the attribute.
fn attribute(self, attr: Attribute) -> Self::Styled {
let mut styled = self.stylize();
@ -96,22 +114,22 @@ pub trait Stylize: Sized {
stylize_method!(hidden Attribute::Hidden);
stylize_method!(crossed_out Attribute::CrossedOut);
stylize_method!(black, on_black Color::Black);
stylize_method!(dark_grey, on_dark_grey Color::DarkGrey);
stylize_method!(red, on_red Color::Red);
stylize_method!(dark_red, on_dark_red Color::DarkRed);
stylize_method!(green, on_green Color::Green);
stylize_method!(dark_green, on_dark_green Color::DarkGreen);
stylize_method!(yellow, on_yellow Color::Yellow);
stylize_method!(dark_yellow, on_dark_yellow Color::DarkYellow);
stylize_method!(blue, on_blue Color::Blue);
stylize_method!(dark_blue, on_dark_blue Color::DarkBlue);
stylize_method!(magenta, on_magenta Color::Magenta);
stylize_method!(dark_magenta, on_dark_magenta Color::DarkMagenta);
stylize_method!(cyan, on_cyan Color::Cyan);
stylize_method!(dark_cyan, on_dark_cyan Color::DarkCyan);
stylize_method!(white, on_white Color::White);
stylize_method!(grey, on_grey Color::Grey);
stylize_method!(black, on_black, underline_black Color::Black);
stylize_method!(dark_grey, on_dark_grey, underline_dark_grey Color::DarkGrey);
stylize_method!(red, on_red, underline_red Color::Red);
stylize_method!(dark_red, on_dark_red, underline_dark_red Color::DarkRed);
stylize_method!(green, on_green, underline_green Color::Green);
stylize_method!(dark_green, on_dark_green, underline_dark_green Color::DarkGreen);
stylize_method!(yellow, on_yellow, underline_yellow Color::Yellow);
stylize_method!(dark_yellow, on_dark_yellow, underline_dark_yellow Color::DarkYellow);
stylize_method!(blue, on_blue, underline_blue Color::Blue);
stylize_method!(dark_blue, on_dark_blue, underline_dark_blue Color::DarkBlue);
stylize_method!(magenta, on_magenta, underline_magenta Color::Magenta);
stylize_method!(dark_magenta, on_dark_magenta, underline_dark_magenta Color::DarkMagenta);
stylize_method!(cyan, on_cyan, underline_cyan Color::Cyan);
stylize_method!(dark_cyan, on_dark_cyan, underline_dark_cyan Color::DarkCyan);
stylize_method!(white, on_white, underline_white Color::White);
stylize_method!(grey, on_grey, underline_grey Color::Grey);
}
macro_rules! impl_stylize_for_display {

View File

@ -100,6 +100,17 @@ Attribute! {
Italic = 3,
/// Underlines the text.
Underlined = 4,
// Other types of underlining
/// Double underlines the text.
DoubleUnderlined = 2,
/// Undercurls the text.
Undercurled = 3,
/// Underdots the text.
Underdotted = 4,
/// Underdashes the text.
Underdashed = 5,
/// Makes the text blinking (< 150 per minute).
SlowBlink = 5,
/// Makes the text blinking (>= 150 per minute).
@ -163,7 +174,10 @@ impl Attribute {
/// Returns the SGR attribute value.
///
/// See <https://en.wikipedia.org/wiki/ANSI_escape_code#SGR_parameters>
pub fn sgr(self) -> i16 {
SGR[self as usize]
pub fn sgr(self) -> String {
if (self as usize) > 4 && (self as usize) < 9 {
return "4:".to_string() + SGR[self as usize].to_string().as_str()
}
SGR[self as usize].to_string()
}
}

View File

@ -16,6 +16,8 @@ pub enum Colored {
ForegroundColor(Color),
/// A background color.
BackgroundColor(Color),
/// An underline color.
UnderlineColor(Color),
}
impl Colored {
@ -39,16 +41,18 @@ impl Colored {
///
/// See also: [`Color::parse_ansi`].
pub fn parse_ansi(ansi: &str) -> Option<Self> {
use Colored::{BackgroundColor, ForegroundColor};
use Colored::{BackgroundColor, ForegroundColor, UnderlineColor};
let values = &mut ansi.split(';');
let output = match parse_next_u8(values)? {
38 => return Color::parse_ansi_iter(values).map(ForegroundColor),
48 => return Color::parse_ansi_iter(values).map(BackgroundColor),
58 => return Color::parse_ansi_iter(values).map(UnderlineColor),
39 => ForegroundColor(Color::Reset),
49 => BackgroundColor(Color::Reset),
59 => UnderlineColor(Color::Reset),
_ => return None,
};
@ -82,6 +86,14 @@ impl fmt::Display for Colored {
color = new_color;
}
}
Colored::UnderlineColor(new_color) => {
if new_color == Color::Reset {
return f.write_str("59");
} else {
f.write_str("58;")?;
color = new_color;
}
}
}
match color {

View File

@ -63,6 +63,10 @@ impl From<Colored> for Colors {
foreground: None,
background: Some(color),
},
Colored::UnderlineColor(color) => Colors {
foreground: None,
background: Some(color),
}
}
}
}