diff options
author | Dan Davison <dandavison7@gmail.com> | 2021-11-22 15:00:52 -0500 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-11-22 15:00:52 -0500 |
commit | 78dac7b34e486ad03371fdb4dc5e83b1f43938e3 (patch) | |
tree | fd4e4c75d9f95ae0765246e7ac4cab5c9bcf09cd | |
parent | d000e40e61871d2bf8609a0db1beb71f48228147 (diff) |
Allow custom colors to be defined in gitconfig (#788)
Similar to 7a64fa5a26314c05c811d7c1276388a4963fa0bd which allowed
custom styles. Custom styles must end in -style, but colors can be
anything. It unfortunately seems not to be possible currently to store
a global reference to git config, hence the size of this
commit (passing the reference down the call stack).
-rw-r--r-- | src/color.rs | 18 | ||||
-rw-r--r-- | src/handlers/blame.rs | 5 | ||||
-rw-r--r-- | src/parse_style.rs | 74 | ||||
-rw-r--r-- | src/parse_styles.rs | 105 | ||||
-rw-r--r-- | src/style.rs | 10 | ||||
-rw-r--r-- | src/subcommands/show_config.rs | 2 | ||||
-rw-r--r-- | src/tests/ansi_test_utils.rs | 8 | ||||
-rw-r--r-- | src/tests/test_example_diffs.rs | 2 |
8 files changed, 168 insertions, 56 deletions
diff --git a/src/color.rs b/src/color.rs index 6f617baf..52904b65 100644 --- a/src/color.rs +++ b/src/color.rs @@ -6,9 +6,10 @@ use lazy_static::lazy_static; use syntect::highlighting::Color as SyntectColor; use crate::fatal; +use crate::git_config::GitConfig; use crate::utils; -pub fn parse_color(s: &str, true_color: bool) -> Option<Color> { +pub fn parse_color(s: &str, true_color: bool, git_config: Option<&GitConfig>) -> Option<Color> { if s == "normal" { return None; } @@ -18,12 +19,21 @@ pub fn parse_color(s: &str, true_color: bool) -> Option<Color> { let syntect_color = if s.starts_with('#') { SyntectColor::from_str(s).unwrap_or_else(|_| die()) } else { - s.parse::<u8>() + let syntect_color = s + .parse::<u8>() .ok() .and_then(utils::syntect::syntect_color_from_ansi_number) .or_else(|| utils::syntect::syntect_color_from_ansi_name(s)) - .or_else(|| utils::syntect::syntect_color_from_name(s)) - .unwrap_or_else(die) + .or_else(|| utils::syntect::syntect_color_from_name(s)); + if syntect_color.is_none() { + if let Some(git_config) = git_config { + if let Some(val) = git_config.get::<String>(&format!("delta.{}", s)) { + return parse_color(&val, true_color, None); + } + } + die(); + } + syntect_color.unwrap() }; utils::bat::terminal::to_ansi_color(syntect_color, true_color) } diff --git a/src/handlers/blame.rs b/src/handlers/blame.rs index ed645c6d..629dc705 100644 --- a/src/handlers/blame.rs +++ b/src/handlers/blame.rs @@ -36,7 +36,10 @@ impl<'a> StateMachine<'a> { { let is_repeat = previous_commit == Some(blame.commit); let color = self.get_color(blame.commit, previous_commit, is_repeat); - let mut style = Style::from_colors(None, color::parse_color(&color, true)); + let mut style = Style::from_colors( + None, + color::parse_color(&color, true, self.config.git_config.as_ref()), + ); // TODO: This will often be pointlessly updating a key with the // value it already has. It might be nicer to do this (and // compute the style) in get_color(), but as things stand the diff --git a/src/parse_style.rs b/src/parse_style.rs index 6cdefe84..7c9ce347 100644 --- a/src/parse_style.rs +++ b/src/parse_style.rs @@ -3,6 +3,7 @@ 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 { @@ -15,11 +16,15 @@ impl Style { default: Option<Self>, 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); - let decoration_style = - DecorationStyle::from_str(decoration_style_string.unwrap_or(""), true_color); + 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, @@ -31,7 +36,7 @@ impl Style { } pub fn from_git_str(git_style_string: &str) -> Self { - Self::from_str(git_style_string, None, None, true) + Self::from_str(git_style_string, None, None, true, None) } /// Construct Style but interpreting 'ul', 'box', etc as applying to the decoration style. @@ -40,11 +45,17 @@ impl Style { default: Option<Self>, 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); + 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, @@ -61,18 +72,22 @@ impl Style { decoration_style_string: Option<&str>, deprecated_foreground_color_arg: Option<&str>, true_color: bool, + git_config: Option<&GitConfig>, ) -> Self { let mut style = Self::from_str_with_handling_of_special_decoration_attributes( style_string, default, decoration_style_string, true_color, + git_config, ); if let Some(s) = deprecated_foreground_color_arg { // The deprecated --{commit,file,hunk}-color args functioned to set the decoration // foreground color. In the case of file, it set the text foreground color also. let foreground_from_deprecated_arg = - parse_ansi_term_style(s, None, true_color).0.foreground; + parse_ansi_term_style(s, None, true_color, git_config) + .0 + .foreground; style.ansi_term_style.foreground = foreground_from_deprecated_arg; style.decoration_style = match style.decoration_style { DecorationStyle::Box(mut ansi_term_style) => { @@ -120,11 +135,11 @@ bitflags! { } impl DecorationStyle { - pub fn from_str(style_string: &str, true_color: bool) -> Self { + 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); + parse_ansi_term_style(&style_string, None, true_color, git_config); if is_raw { fatal("'raw' may not be used in a decoration style."); }; @@ -191,6 +206,7 @@ fn parse_ansi_term_style( s: &str, default: Option<Style>, true_color: bool, + git_config: Option<&GitConfig>, ) -> (ansi_term::Style, bool, bool, bool) { let mut style = ansi_term::Style::new(); let mut seen_foreground = false; @@ -239,7 +255,7 @@ fn parse_ansi_term_style( style.foreground = default.and_then(|s| s.ansi_term_style.foreground); is_syntax_highlighted = default.map(|s| s.is_syntax_highlighted).unwrap_or(false); } else { - style.foreground = color::parse_color(word, true_color); + style.foreground = color::parse_color(word, true_color, git_config); } seen_foreground = true; } else if !seen_background { @@ -253,7 +269,7 @@ fn parse_ansi_term_style( background_is_auto = true; style.background = default.and_then(|s| s.ansi_term_style.background); } else { - style.background = color::parse_color(word, true_color); + style.background = color::parse_color(word, true_color, git_config); } seen_background = true; } else { @@ -321,11 +337,11 @@ mod tests { #[test] fn test_parse_ansi_term_style() { assert_eq!( - parse_ansi_term_style("", None, false), + parse_ansi_term_style("", None, false, None), (ansi_term::Style::new(), false, false, false) ); assert_eq!( - parse_ansi_term_style("red", None, false), + parse_ansi_term_style("red", None, false, None), ( ansi_term::Style { foreground: Some(ansi_term::Color::Red), @@ -337,7 +353,7 @@ mod tests { ) ); assert_eq!( - parse_ansi_term_style("red green", None, false), + parse_ansi_term_style("red green", None, false, None), ( ansi_term::Style { foreground: Some(ansi_term::Color::Red), @@ -350,7 +366,7 @@ mod tests { ) ); assert_eq!( - parse_ansi_term_style("bold red underline green blink", None, false), + parse_ansi_term_style("bold red underline green blink", None, false, None), ( ansi_term::Style { foreground: Some(ansi_term::Color::Red), @@ -370,11 +386,11 @@ mod tests { #[test] fn test_parse_ansi_term_style_with_special_syntax_color() { assert_eq!( - parse_ansi_term_style("syntax", None, false), + parse_ansi_term_style("syntax", None, false, None), (ansi_term::Style::new(), false, false, true) ); assert_eq!( - parse_ansi_term_style("syntax italic white hidden", None, false), + parse_ansi_term_style("syntax italic white hidden", None, false, None), ( ansi_term::Style { background: Some(ansi_term::Color::White), @@ -388,7 +404,7 @@ mod tests { ) ); assert_eq!( - parse_ansi_term_style("bold syntax italic white hidden", None, false), + parse_ansi_term_style("bold syntax italic white hidden", None, false, None), ( ansi_term::Style { background: Some(ansi_term::Color::White), @@ -407,12 +423,12 @@ mod tests { #[test] fn test_parse_ansi_term_style_with_special_omit_attribute() { assert_eq!( - parse_ansi_term_style("omit", None, false), + parse_ansi_term_style("omit", None, false, None), (ansi_term::Style::new(), true, false, false) ); // It doesn't make sense for omit to be combined with anything else, but it is not an error. assert_eq!( - parse_ansi_term_style("omit syntax italic white hidden", None, false), + parse_ansi_term_style("omit syntax italic white hidden", None, false, None), ( ansi_term::Style { background: Some(ansi_term::Color::White), @@ -430,12 +446,12 @@ mod tests { #[test] fn test_parse_ansi_term_style_with_special_raw_attribute() { assert_eq!( - parse_ansi_term_style("raw", None, false), + parse_ansi_term_style("raw", None, false, None), (ansi_term::Style::new(), false, true, false) ); // It doesn't make sense for raw to be combined with anything else, but it is not an error. assert_eq!( - parse_ansi_term_style("raw syntax italic white hidden", None, false), + parse_ansi_term_style("raw syntax italic white hidden", None, false, None), ( ansi_term::Style { background: Some(ansi_term::Color::White), @@ -496,7 +512,7 @@ mod tests { #[test] fn test_decoration_style_from_str_empty_string() { assert_eq!( - DecorationStyle::from_str("", true), + DecorationStyle::from_str("", true, None), DecorationStyle::NoDecoration, ) } @@ -504,7 +520,7 @@ mod tests { #[test] fn test_decoration_style_from_str() { assert_eq!( - DecorationStyle::from_str("ol red box bold green ul", true), + DecorationStyle::from_str("ol red box bold green ul", true, None), DecorationStyle::BoxWithUnderOverline(ansi_term::Style { foreground: Some(ansi_term::Color::Red), background: Some(ansi_term::Color::Green), @@ -521,6 +537,7 @@ mod tests { None, Some("ol red box bold green ul"), true, + None, ); let red_green_bold = ansi_term::Style { foreground: Some(ansi_term::Color::Red), @@ -540,7 +557,7 @@ mod tests { #[test] fn test_style_from_str_raw_with_box() { - let actual_style = Style::from_str("raw", None, Some("box"), true); + let actual_style = Style::from_str("raw", None, Some("box"), true, None); let empty_ansi_term_style = ansi_term::Style::new(); assert_eq!( actual_style, @@ -555,7 +572,7 @@ mod tests { #[test] fn test_style_from_str_decoration_style_only() { - let actual_style = Style::from_str("", None, Some("ol red box bold green ul"), true); + let actual_style = Style::from_str("", None, Some("ol red box bold green ul"), true, None); let red_green_bold = ansi_term::Style { foreground: Some(ansi_term::Color::Red), background: Some(ansi_term::Color::Green), @@ -578,6 +595,7 @@ mod tests { None, Some("ol red box bold green ul"), true, + None, ); let expected_decoration_style = DecorationStyle::BoxWithUnderOverline(ansi_term::Style { foreground: Some(ansi_term::Color::Red), @@ -601,6 +619,7 @@ mod tests { None, Some("box"), true, + None, ); let empty_ansi_term_style = ansi_term::Style::new(); assert_eq!( @@ -624,7 +643,7 @@ mod tests { ..ansi_term::Style::new() }); let actual_style = Style::from_str_with_handling_of_special_decoration_attributes_and_respecting_deprecated_foreground_color_arg( - "", None, Some("ol red box bold green ul"), None, true + "", None, Some("ol red box bold green ul"), None, true, None ); assert_eq!( actual_style, @@ -644,6 +663,7 @@ mod tests { Some("box"), None, true, + None, ); let empty_ansi_term_style = ansi_term::Style::new(); assert_eq!( diff --git a/src/parse_styles.rs b/src/parse_styles.rs index 24b895a9..86d869ea 100644 --- a/src/parse_styles.rs +++ b/src/parse_styles.rs @@ -3,7 +3,7 @@ use std::collections::{HashMap, HashSet}; use crate::cli; use crate::color; use crate::fatal; -use crate::git_config::GitConfigEntry; +use crate::git_config::{GitConfig, GitConfigEntry}; use crate::style::{self, Style}; #[derive(Debug, Clone)] @@ -26,7 +26,13 @@ pub fn parse_styles(opt: &cli::Opt) -> HashMap<String, Style> { styles.insert( "inline-hint-style", - style_from_str(&opt.inline_hint_style, None, None, opt.computed.true_color), + style_from_str( + &opt.inline_hint_style, + None, + None, + opt.computed.true_color, + opt.git_config.as_ref(), + ), ); styles.insert( "git-minus-style", @@ -111,6 +117,7 @@ fn make_hunk_styles<'a>(opt: &'a cli::Opt, styles: &'a mut HashMap<&str, StyleRe )), None, true_color, + opt.git_config.as_ref(), ); let minus_emph_style = style_from_str( @@ -124,9 +131,16 @@ fn make_hunk_styles<'a>(opt: &'a cli::Opt, styles: &'a mut HashMap<&str, StyleRe )), None, true_color, + opt.git_config.as_ref(), ); - let minus_non_emph_style = style_from_str(&opt.minus_non_emph_style, None, None, true_color); + let minus_non_emph_style = style_from_str( + &opt.minus_non_emph_style, + None, + None, + true_color, + opt.git_config.as_ref(), + ); // The style used to highlight a removed empty line when otherwise it would be invisible due to // lack of background color in minus-style. @@ -141,9 +155,16 @@ fn make_hunk_styles<'a>(opt: &'a cli::Opt, styles: &'a mut HashMap<&str, StyleRe )), None, true_color, + opt.git_config.as_ref(), ); - let zero_style = style_from_str(&opt.zero_style, None, None, true_color); + let zero_style = style_from_str( + &opt.zero_style, + None, + None, + true_color, + opt.git_config.as_ref(), + ); let plus_style = style_from_str( &opt.plus_style, @@ -156,6 +177,7 @@ fn make_hunk_styles<'a>(opt: &'a cli::Opt, styles: &'a mut HashMap<&str, StyleRe )), None, true_color, + opt.git_config.as_ref(), ); let plus_emph_style = style_from_str( @@ -169,9 +191,16 @@ fn make_hunk_styles<'a>(opt: &'a cli::Opt, styles: &'a mut HashMap<&str, StyleRe )), None, true_color, + opt.git_config.as_ref(), ); - let plus_non_emph_style = style_from_str(&opt.plus_non_emph_style, None, None, true_color); + let plus_non_emph_style = style_from_str( + &opt.plus_non_emph_style, + None, + None, + true_color, + opt.git_config.as_ref(), + ); // The style used to highlight an added empty line when otherwise it would be invisible due to // lack of background color in plus-style. @@ -186,10 +215,16 @@ fn make_hunk_styles<'a>(opt: &'a cli::Opt, styles: &'a mut HashMap<&str, StyleRe )), None, true_color, + opt.git_config.as_ref(), ); - let whitespace_error_style = - style_from_str(&opt.whitespace_error_style, None, None, true_color); + let whitespace_error_style = style_from_str( + &opt.whitespace_error_style, + None, + None, + true_color, + opt.git_config.as_ref(), + ); styles.extend([ ("minus-style", minus_style), @@ -210,20 +245,45 @@ fn make_hunk_styles<'a>(opt: &'a cli::Opt, styles: &'a mut HashMap<&str, StyleRe fn make_line_number_styles(opt: &cli::Opt, styles: &mut HashMap<&str, StyleReference>) { let true_color = opt.computed.true_color; - let line_numbers_left_style = - style_from_str(&opt.line_numbers_left_style, None, None, true_color); + let line_numbers_left_style = style_from_str( + &opt.line_numbers_left_style, + None, + None, + true_color, + opt.git_config.as_ref(), + ); - let line_numbers_minus_style = - style_from_str(&opt.line_numbers_minus_style, None, None, true_color); + let line_numbers_minus_style = style_from_str( + &opt.line_numbers_minus_style, + None, + None, + true_color, + opt.git_config.as_ref(), + ); - let line_numbers_zero_style = - style_from_str(&opt.line_numbers_zero_style, None, None, true_color); + let line_numbers_zero_style = style_from_str( + &opt.line_numbers_zero_style, + None, + None, + true_color, + opt.git_config.as_ref(), + ); - let line_numbers_plus_style = - style_from_str(&opt.line_numbers_plus_style, None, None, true_color); + let line_numbers_plus_style = style_from_str( + &opt.line_numbers_plus_style, + None, + None, + true_color, + opt.git_config.as_ref(), + ); - let line_numbers_right_style = - style_from_str(&opt.line_numbers_right_style, None, None, true_color); + let line_numbers_right_style = style_from_str( + &opt.line_numbers_right_style, + None, + None, + true_color, + opt.git_config.as_ref(), + ); styles.extend([ ("line-numbers-minus-style", line_numbers_minus_style), @@ -244,6 +304,7 @@ fn make_commit_file_hunk_header_styles(opt: &cli::Opt, styles: &mut HashMap<&str Some(&opt.commit_decoration_style), opt.deprecated_commit_color.as_deref(), true_color, + opt.git_config.as_ref(), ) ), ("file-style", @@ -253,6 +314,7 @@ fn make_commit_file_hunk_header_styles(opt: &cli::Opt, styles: &mut HashMap<&str Some(&opt.file_decoration_style), opt.deprecated_file_color.as_deref(), true_color, + opt.git_config.as_ref(), ) ), ("hunk-header-style", @@ -262,6 +324,7 @@ fn make_commit_file_hunk_header_styles(opt: &cli::Opt, styles: &mut HashMap<&str Some(&opt.hunk_header_decoration_style), opt.deprecated_hunk_color.as_deref(), true_color, + opt.git_config.as_ref(), ) ), ("hunk-header-file-style", @@ -270,6 +333,7 @@ fn make_commit_file_hunk_header_styles(opt: &cli::Opt, styles: &mut HashMap<&str None, None, true_color, + opt.git_config.as_ref(), ) ), ("hunk-header-line-number-style", @@ -278,6 +342,7 @@ fn make_commit_file_hunk_header_styles(opt: &cli::Opt, styles: &mut HashMap<&str None, None, true_color, + opt.git_config.as_ref(), ) ), ]); @@ -333,6 +398,7 @@ fn style_from_str( default: Option<Style>, decoration_style_string: Option<&str>, true_color: bool, + git_config: Option<&GitConfig>, ) -> StyleReference { if is_style_reference(style_string) { StyleReference::Reference(style_string.to_owned()) @@ -342,6 +408,7 @@ fn style_from_str( default, decoration_style_string, true_color, + git_config, )) } } @@ -351,6 +418,7 @@ fn style_from_str_with_handling_of_special_decoration_attributes( default: Option<Style>, decoration_style_string: Option<&str>, true_color: bool, + git_config: Option<&GitConfig>, ) -> StyleReference { if is_style_reference(style_string) { StyleReference::Reference(style_string.to_owned()) @@ -361,6 +429,7 @@ fn style_from_str_with_handling_of_special_decoration_attributes( default, decoration_style_string, true_color, + git_config, ), ) } @@ -372,6 +441,7 @@ fn style_from_str_with_handling_of_special_decoration_attributes_and_respecting_ decoration_style_string: Option<&str>, deprecated_foreground_color_arg: Option<&str>, true_color: bool, + git_config: Option<&GitConfig>, ) -> StyleReference { if is_style_reference(style_string) { StyleReference::Reference(style_string.to_owned()) @@ -382,6 +452,7 @@ fn style_from_str_with_handling_of_special_decoration_attributes_and_respecting_ decoration_style_string, deprecated_foreground_color_arg, true_color, + git_config, )) } } diff --git a/src/style.rs b/src/style.rs index 8ce78875..b745cf33 100644 --- a/src/style.rs +++ b/src/style.rs @@ -5,6 +5,7 @@ use lazy_static::lazy_static; use crate::ansi; use crate::color; +use crate::git_config::GitConfig; #[derive(Clone, Copy, PartialEq, Default)] pub struct Style { @@ -128,11 +129,12 @@ impl Style { } /// Interpret `color_string` as a color specifier and return it painted accordingly. -pub fn paint_color_string( - color_string: &str, +pub fn paint_color_string<'a>( + color_string: &'a str, true_color: bool, -) -> ansi_term::ANSIGenericString<str> { - if let Some(color) = color::parse_color(color_string, true_color) { + git_config: Option<&GitConfig>, +) -> ansi_term::ANSIGenericString<'a, str> { + if let Some(color) = color::parse_color(color_string, true_color, git_config) { let style = ansi_term::Style { background: Some(color), ..ansi_term::Style::default() diff --git a/src/subcommands/show_config.rs b/src/subcommands/show_config.rs index ae45e877..594dca68 100644 --- a/src/subcommands/show_config.rs +++ b/src/subcommands/show_config.rs @@ -31,7 +31,7 @@ pub fn show_config(config: &config::Config, writer: &mut dyn Write) -> std::io:: blame_palette = config .blame_palette .iter() - .map(|s| style::paint_color_string(s, config.true_color)) + .map(|s| style::paint_color_string(s, config.true_color, config.git_config.as_ref())) .join(" "), commit_style = config.commit_style.to_painted_string(), file_style = config.file_style.to_painted_string(), diff --git a/src/tests/ansi_test_utils.rs b/src/tests/ansi_test_utils.rs index 259c43b8..7d8c5641 100644 --- a/src/tests/ansi_test_utils.rs +++ b/src/tests/ansi_test_utils.rs @@ -167,7 +167,13 @@ pub mod ansi_test_utils { ) -> bool { let line = output.lines().nth(line_number).unwrap(); assert!(ansi::strip_ansi_codes(line).starts_with(expected_prefix)); - let mut style = Style::from_str(expected_style, None, None, config.true_color); + let mut style = Style::from_str( + expected_style, + None, + None, + config.true_color, + config.git_config.as_ref(), + ); if _4_bit_color { style.ansi_term_style.foreground = style .ansi_term_style diff --git a/src/tests/test_example_diffs.rs b/src/tests/test_example_diffs.rs index 9b92af45..faecd2a1 100644 --- a/src/tests/test_example_diffs.rs +++ b/src/tests/test_example_diffs.rs @@ -1471,7 +1471,7 @@ src/align.rs:71: impl<'a> Alignment<'a> { │ let output = integration_test_utils::run_delta(example_diff, &config); let line = output.lines().nth(8).unwrap(); if base_style_has_background_color { - let style = style::Style::from_str(base_style, None, None, true); + let style = style::Style::from_str(base_style, None, None, true, None); assert_eq!( line, &style |