From 5dc0d6ef7e37a565b06d794b50fcc763079f9ed7 Mon Sep 17 00:00:00 2001 From: Dan Davison Date: Mon, 22 Nov 2021 20:15:06 -0500 Subject: New option to map raw styles encountered in input Unify handling of styles parsed from raw line and computed diff styles. This enables syntax highlighting to be used in color-moved sections. Fixes #72 --- src/style.rs | 104 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 104 insertions(+) (limited to 'src/style.rs') diff --git a/src/style.rs b/src/style.rs index b745cf33..047b9cc9 100644 --- a/src/style.rs +++ b/src/style.rs @@ -1,5 +1,6 @@ use std::borrow::Cow; use std::fmt; +use std::hash::{Hash, Hasher}; use lazy_static::lazy_static; @@ -210,6 +211,89 @@ pub fn ansi_term_style_equality(a: ansi_term::Style, b: ansi_term::Style) -> boo } } +// TODO: The equality methods were implemented first, and the equality_key +// methods later. The former should be re-implemented in terms of the latter. +// But why did the former not address equality of ansi_term::Color::RGB values? +pub struct AnsiTermStyleEqualityKey { + attrs_key: (bool, bool, bool, bool, bool, bool, bool, bool), + foreground_key: Option<(u8, u8, u8, u8)>, + background_key: Option<(u8, u8, u8, u8)>, +} + +impl PartialEq for AnsiTermStyleEqualityKey { + fn eq(&self, other: &Self) -> bool { + let option_eq = |opt_a, opt_b| match (opt_a, opt_b) { + (Some(a), Some(b)) => a == b, + (None, None) => true, + _ => false, + }; + + if self.attrs_key != other.attrs_key { + false + } else { + option_eq(self.foreground_key, other.foreground_key) + && option_eq(self.background_key, other.background_key) + } + } +} + +impl Eq for AnsiTermStyleEqualityKey {} + +impl Hash for AnsiTermStyleEqualityKey { + fn hash(&self, state: &mut H) { + self.attrs_key.hash(state); + self.foreground_key.hash(state); + self.background_key.hash(state); + } +} + +pub fn ansi_term_style_equality_key(style: ansi_term::Style) -> AnsiTermStyleEqualityKey { + let attrs_key = ( + style.is_bold, + style.is_dimmed, + style.is_italic, + style.is_underline, + style.is_blink, + style.is_reverse, + style.is_hidden, + style.is_strikethrough, + ); + AnsiTermStyleEqualityKey { + attrs_key, + foreground_key: style.foreground.map(ansi_term_color_equality_key), + background_key: style.background.map(ansi_term_color_equality_key), + } +} + +impl fmt::Debug for AnsiTermStyleEqualityKey { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let is_set = |c: char, set: bool| -> String { + if set { + c.to_uppercase().to_string() + } else { + c.to_lowercase().to_string() + } + }; + + let (bold, dimmed, italic, underline, blink, reverse, hidden, strikethrough) = + self.attrs_key; + write!( + f, + "ansi_term::Style {{ {:?} {:?} {}{}{}{}{}{}{}{} }}", + self.foreground_key, + self.background_key, + is_set('b', bold), + is_set('d', dimmed), + is_set('i', italic), + is_set('u', underline), + is_set('l', blink), + is_set('r', reverse), + is_set('h', hidden), + is_set('s', strikethrough), + ) + } +} + fn ansi_term_color_equality(a: Option, b: Option) -> bool { match (a, b) { (None, None) => true, @@ -239,6 +323,26 @@ fn ansi_term_16_color_equality(a: ansi_term::Color, b: ansi_term::Color) -> bool ) } +fn ansi_term_color_equality_key(color: ansi_term::Color) -> (u8, u8, u8, u8) { + // Same (r, g, b, a) encoding as in utils::bat::terminal::to_ansi_color. + // When a = 0xFF, then a 256-color number is stored in the red channel, and + // the green and blue channels are meaningless. But a=0 signifies an RGB + // color. + let default = 0xFF; + match color { + ansi_term::Color::Fixed(0) | ansi_term::Color::Black => (0, default, default, default), + ansi_term::Color::Fixed(1) | ansi_term::Color::Red => (1, default, default, default), + ansi_term::Color::Fixed(2) | ansi_term::Color::Green => (2, default, default, default), + ansi_term::Color::Fixed(3) | ansi_term::Color::Yellow => (3, default, default, default), + ansi_term::Color::Fixed(4) | ansi_term::Color::Blue => (4, default, default, default), + ansi_term::Color::Fixed(5) | ansi_term::Color::Purple => (5, default, default, default), + ansi_term::Color::Fixed(6) | ansi_term::Color::Cyan => (6, default, default, default), + ansi_term::Color::Fixed(7) | ansi_term::Color::White => (7, default, default, default), + ansi_term::Color::Fixed(n) => (n, default, default, default), + ansi_term::Color::RGB(r, g, b) => (r, g, b, 0), + } +} + lazy_static! { pub static ref GIT_DEFAULT_MINUS_STYLE: Style = Style { ansi_term_style: ansi_term::Color::Red.normal(), -- cgit v1.2.3