Add support for other underline types and the ability to color them (#679)
This commit is contained in:
parent
73a8ecc95f
commit
ad0d100304
@ -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,
|
||||
|
24
src/style.rs
24
src/style.rs
@ -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;
|
||||
|
@ -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,
|
||||
}
|
||||
|
@ -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 {
|
||||
|
@ -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()
|
||||
}
|
||||
}
|
||||
|
@ -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 {
|
||||
|
@ -63,6 +63,10 @@ impl From<Colored> for Colors {
|
||||
foreground: None,
|
||||
background: Some(color),
|
||||
},
|
||||
Colored::UnderlineColor(color) => Colors {
|
||||
foreground: None,
|
||||
background: Some(color),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user