From 78dac7b34e486ad03371fdb4dc5e83b1f43938e3 Mon Sep 17 00:00:00 2001 From: Dan Davison Date: Mon, 22 Nov 2021 15:00:52 -0500 Subject: 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). --- src/color.rs | 18 +++++-- src/handlers/blame.rs | 5 +- src/parse_style.rs | 74 +++++++++++++++++----------- src/parse_styles.rs | 105 +++++++++++++++++++++++++++++++++------- src/style.rs | 10 ++-- src/subcommands/show_config.rs | 2 +- src/tests/ansi_test_utils.rs | 8 ++- 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 { +pub fn parse_color(s: &str, true_color: bool, git_config: Option<&GitConfig>) -> Option { if s == "normal" { return None; } @@ -18,12 +19,21 @@ pub fn parse_color(s: &str, true_color: bool) -> Option { let syntect_color = if s.starts_with('#') { SyntectColor::from_str(s).unwrap_or_else(|_| die()) } else { - s.parse::() + let syntect_color = s + .parse::() .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::(&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, 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, 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