use bitflags::bitflags; use crate::color; use crate::config::delta_unreachable; use crate::fatal; use crate::git_config::GitConfig; use crate::style::{DecorationStyle, Style}; impl Style { /// Construct Style from style and decoration-style strings supplied on command line, together /// with defaults. A style string is a space-separated string containing 0, 1, or 2 colors /// (foreground and then background) and an arbitrary number of style attributes. See `delta /// --help` for more precise spec. pub fn from_str( style_string: &str, default: Option, decoration_style_string: Option<&str>, true_color: bool, git_config: Option<&GitConfig>, ) -> Self { let (ansi_term_style, is_omitted, is_raw, is_syntax_highlighted) = parse_ansi_term_style(style_string, default, true_color, git_config); let decoration_style = DecorationStyle::from_str( decoration_style_string.unwrap_or(""), true_color, git_config, ); Self { ansi_term_style, is_emph: false, is_omitted, is_raw, is_syntax_highlighted, decoration_style, } } pub fn from_git_str(git_style_string: &str) -> Self { Self::from_str(git_style_string, None, None, true, None) } /// Construct Style but interpreting 'ul', 'box', etc as applying to the decoration style. pub fn from_str_with_handling_of_special_decoration_attributes( style_string: &str, default: Option, decoration_style_string: Option<&str>, true_color: bool, git_config: Option<&GitConfig>, ) -> Self { let (special_attributes_from_style_string, style_string) = extract_special_decoration_attributes_from_non_decoration_style_string(style_string); let mut style = Style::from_str( &style_string, default, decoration_style_string, true_color, git_config, ); // TODO: box in this context resulted in box-with-underline for commit and file style.decoration_style = DecorationStyle::apply_special_decoration_attributes( &mut style, special_attributes_from_style_string, ); style } } bitflags! { struct DecorationAttributes: u8 { const EMPTY = 0b00000000; const BOX = 0b00000001; const OVERLINE = 0b00000010; const UNDERLINE = 0b00000100; } } impl DecorationStyle { pub fn from_str(style_string: &str, true_color: bool, git_config: Option<&GitConfig>) -> Self { let (special_attributes, style_string) = extract_special_decoration_attributes(style_string); let (style, is_omitted, is_raw, is_syntax_highlighted) = parse_ansi_term_style(&style_string, None, true_color, git_config); if is_raw { fatal("'raw' may not be used in a decoration style."); }; if is_syntax_highlighted { fatal("'syntax' may not be used in a decoration style."); }; #[allow(non_snake_case)] let (BOX, UL, OL, EMPTY) = ( DecorationAttributes::BOX, DecorationAttributes::UNDERLINE, DecorationAttributes::OVERLINE, DecorationAttributes::EMPTY, ); match special_attributes { bits if bits == EMPTY => DecorationStyle::NoDecoration, bits if bits == BOX => DecorationStyle::Box(style), bits if bits == UL => DecorationStyle::Underline(style), bits if bits == OL => DecorationStyle::Overline(style), bits if bits == UL | OL => DecorationStyle::UnderOverline(style), bits if bits == BOX | UL => DecorationStyle::BoxWithUnderline(style), bits if bits == BOX | OL => DecorationStyle::BoxWithOverline(style), bits if bits == BOX | UL | OL => DecorationStyle::BoxWithUnderOverline(style), _ if is_omitted => DecorationStyle::NoDecoration, _ => delta_unreachable("Unreachable code path reached in parse_decoration_style."), } } fn apply_special_decoration_attributes( style: &mut Style, special_attributes: DecorationAttributes, ) -> DecorationStyle { let ansi_term_style = match style.decoration_style { DecorationStyle::Box(ansi_term_style) => ansi_term_style, DecorationStyle::Underline(ansi_term_style) => ansi_term_style, DecorationStyle::Overline(ansi_term_style) => ansi_term_style, DecorationStyle::UnderOverline(ansi_term_style) => ansi_term_style, DecorationStyle::BoxWithUnderline(ansi_term_style) => ansi_term_style, DecorationStyle::BoxWithOverline(ansi_term_style) => ansi_term_style, DecorationStyle::BoxWithUnderOverline(ansi_term_style) => ansi_term_style, DecorationStyle::NoDecoration => ansi_term::Style::new(), }; #[allow(non_snake_case)] let (BOX, UL, OL, EMPTY) = ( DecorationAttributes::BOX, DecorationAttributes::UNDERLINE, DecorationAttributes::OVERLINE, DecorationAttributes::EMPTY, ); match special_attributes { bits if bits == EMPTY => style.decoration_style, bits if bits == BOX => DecorationStyle::Box(ansi_term_style), bits if bits == UL => DecorationStyle::Underline(ansi_term_style), bits if bits == OL => DecorationStyle::Overline(ansi_term_style), bits if bits == UL | OL => DecorationStyle::UnderOverline(ansi_term_style), bits if bits == BOX | UL => DecorationStyle::BoxWithUnderline(ansi_term_style), bits if bits == BOX | OL => DecorationStyle::BoxWithOverline(ansi_term_style), bits if bits == BOX | UL | OL => DecorationStyle::BoxWithUnderOverline(ansi_term_style), _ => DecorationStyle::NoDecoration, } } } fn parse_ansi_term_style( s: &str, default: Option