diff options
author | Dan Davison <dandavison7@gmail.com> | 2020-06-16 21:15:56 -0400 |
---|---|---|
committer | Dan Davison <dandavison7@gmail.com> | 2020-06-17 15:07:56 -0400 |
commit | c2c279b5fb8b79d5ce2991682ca6a0c5958f87c3 (patch) | |
tree | ec08c517dcade0dda6e8f9d46c14d28aea5949b2 /src | |
parent | 5d5b4a3995e109b24b420daa094773ac4e6dc5bf (diff) |
Highlight added/removed empty lines if they would be invisible
Thanks @phillipwood
Diffstat (limited to 'src')
-rw-r--r-- | src/cli.rs | 11 | ||||
-rw-r--r-- | src/config.rs | 48 | ||||
-rw-r--r-- | src/delta.rs | 2 | ||||
-rw-r--r-- | src/paint.rs | 24 | ||||
-rw-r--r-- | src/set_options.rs | 2 | ||||
-rw-r--r-- | src/style.rs | 8 | ||||
-rw-r--r-- | src/tests/ansi_test_utils.rs | 1 | ||||
-rw-r--r-- | src/tests/test_example_diffs.rs | 118 |
8 files changed, 211 insertions, 3 deletions
@@ -404,6 +404,17 @@ pub struct Opt { #[structopt(parse(from_os_str))] pub plus_file: Option<PathBuf>, + /// Style for removed empty line marker (used only if --minus-style has no background color) + #[structopt( + long = "--minus-empty-line-marker-style", + default_value = "normal auto" + )] + pub minus_empty_line_marker_style: String, + + /// Style for added empty line marker (used only if --plus-style has no background color) + #[structopt(long = "--plus-empty-line-marker-style", default_value = "normal auto")] + pub plus_empty_line_marker_style: String, + #[structopt(long = "minus-color")] /// Deprecated: use --minus-style='normal my_background_color'. pub deprecated_minus_background_color: Option<String>, diff --git a/src/config.rs b/src/config.rs index ee2b4c16..794acc7d 100644 --- a/src/config.rs +++ b/src/config.rs @@ -44,6 +44,7 @@ pub struct Config { pub max_line_distance: f64, pub max_line_distance_for_naively_paired_lines: f64, pub minus_emph_style: Style, + pub minus_empty_line_marker_style: Style, pub minus_file: Option<PathBuf>, pub minus_non_emph_style: Style, pub minus_style: Style, @@ -58,6 +59,7 @@ pub struct Config { pub number_plus_style: Style, pub paging_mode: PagingMode, pub plus_emph_style: Style, + pub plus_empty_line_marker_style: Style, pub plus_file: Option<PathBuf>, pub plus_non_emph_style: Style, pub plus_style: Style, @@ -207,10 +209,12 @@ impl From<cli::Opt> for Config { minus_style, minus_emph_style, minus_non_emph_style, + minus_empty_line_marker_style, zero_style, plus_style, plus_emph_style, plus_non_emph_style, + plus_empty_line_marker_style, ) = make_hunk_styles(&opt, is_light_mode, true_color); let (commit_style, file_style, hunk_header_style) = @@ -268,6 +272,7 @@ impl From<cli::Opt> for Config { max_line_distance: opt.max_line_distance, max_line_distance_for_naively_paired_lines, minus_emph_style, + minus_empty_line_marker_style, minus_file: opt.minus_file.map(|s| s.clone()), minus_non_emph_style, minus_style, @@ -282,6 +287,7 @@ impl From<cli::Opt> for Config { number_plus_style, paging_mode, plus_emph_style, + plus_empty_line_marker_style, plus_file: opt.plus_file.map(|s| s.clone()), plus_non_emph_style, plus_style, @@ -303,7 +309,17 @@ fn make_hunk_styles<'a>( opt: &'a cli::Opt, is_light_mode: bool, true_color: bool, -) -> (Style, Style, Style, Style, Style, Style, Style) { +) -> ( + Style, + Style, + Style, + Style, + Style, + Style, + Style, + Style, + Style, +) { let minus_style = Style::from_str( &opt.minus_style, None, @@ -337,6 +353,20 @@ fn make_hunk_styles<'a>( false, ); + // The style used to highlight a removed empty line when otherwise it would be invisible due to + // lack of background color in minus-style. + let minus_empty_line_marker_style = Style::from_str( + &opt.minus_empty_line_marker_style, + None, + Some(color::get_minus_background_color_default( + is_light_mode, + true_color, + )), + None, + true_color, + false, + ); + let zero_style = Style::from_str(&opt.zero_style, None, None, None, true_color, false); let plus_style = Style::from_str( @@ -372,14 +402,30 @@ fn make_hunk_styles<'a>( false, ); + // The style used to highlight an added empty line when otherwise it would be invisible due to + // lack of background color in plus-style. + let plus_empty_line_marker_style = Style::from_str( + &opt.plus_empty_line_marker_style, + None, + Some(color::get_plus_background_color_default( + is_light_mode, + true_color, + )), + None, + true_color, + false, + ); + ( minus_style, minus_emph_style, minus_non_emph_style, + minus_empty_line_marker_style, zero_style, plus_style, plus_emph_style, plus_non_emph_style, + plus_empty_line_marker_style, ) } diff --git a/src/delta.rs b/src/delta.rs index 36ea6a56..366520ec 100644 --- a/src/delta.rs +++ b/src/delta.rs @@ -405,6 +405,7 @@ fn handle_hunk_header_line( "", config.null_style, config.null_style, + None, Some(false), ); painter.output_buffer.pop(); // trim newline @@ -495,6 +496,7 @@ fn handle_hunk_line( config.zero_style, config.zero_style, None, + None, ); painter.minus_line_number += 1; painter.plus_line_number += 1; diff --git a/src/paint.rs b/src/paint.rs index 62a7f64f..d9dddd62 100644 --- a/src/paint.rs +++ b/src/paint.rs @@ -14,6 +14,8 @@ use crate::paint::superimpose_style_sections::superimpose_style_sections; use crate::style::Style; pub const ANSI_CSI_CLEAR_TO_EOL: &str = "\x1b[0K"; +pub const ANSI_CSI_CLEAR_TO_BOL: &str = "\x1b[1K"; +pub const ANSI_CSI_CURSOR_BACK_1: &str = "\x1b[1D"; pub const ANSI_SGR_RESET: &str = "\x1b[0m"; pub struct Painter<'a> { @@ -103,6 +105,7 @@ impl<'a> Painter<'a> { }, self.config.minus_style, self.config.minus_non_emph_style, + Some(self.config.minus_empty_line_marker_style), None, ); } @@ -120,6 +123,7 @@ impl<'a> Painter<'a> { }, self.config.plus_style, self.config.plus_non_emph_style, + Some(self.config.plus_empty_line_marker_style), None, ); } @@ -138,6 +142,7 @@ impl<'a> Painter<'a> { prefix: &str, style: Style, // style for right fill if line contains no emph sections non_emph_style: Style, // style for right fill if line contains emph sections + empty_line_style: Option<Style>, // a style with background color to highlight an empty line background_color_extends_to_terminal_width: Option<bool>, ) { // There's some unfortunate hackery going on here for two reasons: @@ -214,7 +219,7 @@ impl<'a> Painter<'a> { } // Set style for the right-fill. let mut have_background_for_right_fill = false; - if non_emph_style.ansi_term_style.background.is_some() { + if non_emph_style.has_background_color() { ansi_strings.push(non_emph_style.ansi_term_style.paint("")); have_background_for_right_fill = true; } @@ -224,7 +229,9 @@ impl<'a> Painter<'a> { Some(boolean) => boolean, None => config.background_color_extends_to_terminal_width, }; - if background_color_extends_to_terminal_width && have_background_for_right_fill { + let right_fill_background_color = + background_color_extends_to_terminal_width && have_background_for_right_fill; + if right_fill_background_color { // HACK: How to properly incorporate the ANSI_CSI_CLEAR_TO_EOL into ansi_strings? if line .to_lowercase() @@ -238,6 +245,19 @@ impl<'a> Painter<'a> { } else { output_buffer.push_str(&line); } + if line.is_empty() && !right_fill_background_color { + if let Some(empty_line_style) = empty_line_style { + output_buffer.push_str( + &empty_line_style + .ansi_term_style + .paint(format!( + "{}{}", + ANSI_CSI_CLEAR_TO_BOL, ANSI_CSI_CURSOR_BACK_1 + )) + .to_string(), + ); + } + } output_buffer.push_str("\n"); } } diff --git a/src/set_options.rs b/src/set_options.rs index fe5705c4..007cb326 100644 --- a/src/set_options.rs +++ b/src/set_options.rs @@ -188,6 +188,7 @@ pub fn set_options( // dynamically to the value of the former. ("minus-style", String, minus_style), ("minus-emph-style", String, minus_emph_style), + ("minus-empty-line-marker-style", String, minus_empty_line_marker_style), ("minus-non-emph-style", String, minus_non_emph_style), ("navigate", bool, navigate), ("number", bool, show_line_numbers), @@ -206,6 +207,7 @@ pub fn set_options( // dynamically to the value of the former. ("plus-style", String, plus_style), ("plus-emph-style", String, plus_emph_style), + ("plus-empty-line-marker-style", String, plus_empty_line_marker_style), ("plus-non-emph-style", String, plus_non_emph_style), ("syntax_theme", Option<String>, syntax_theme), ("tabs", usize, tab_width), diff --git a/src/style.rs b/src/style.rs index 6b11725f..7e7bea35 100644 --- a/src/style.rs +++ b/src/style.rs @@ -49,6 +49,14 @@ impl Style { } } + pub fn has_background_color(&self) -> bool { + if self.ansi_term_style.is_reverse { + self.ansi_term_style.foreground.is_some() + } else { + self.ansi_term_style.background.is_some() + } + } + /// 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 diff --git a/src/tests/ansi_test_utils.rs b/src/tests/ansi_test_utils.rs index 7d0ccf36..cc796db8 100644 --- a/src/tests/ansi_test_utils.rs +++ b/src/tests/ansi_test_utils.rs @@ -114,6 +114,7 @@ pub mod ansi_test_utils { config.null_style, config.null_style, None, + None, ); output_buffer } diff --git a/src/tests/test_example_diffs.rs b/src/tests/test_example_diffs.rs index 85123080..1e4bc1d0 100644 --- a/src/tests/test_example_diffs.rs +++ b/src/tests/test_example_diffs.rs @@ -2,6 +2,8 @@ mod tests { use console::strip_ansi_codes; + use crate::paint; + use crate::style; use crate::tests::ansi_test_utils::ansi_test_utils; use crate::tests::integration_test_utils::integration_test_utils; @@ -1007,6 +1009,104 @@ impl<'a> Alignment<'a> { │ )); } + #[test] + fn test_removed_empty_line_highlight() { + let minus_empty_line_marker_style = "bold yellow magenta ul"; + _do_test_removed_empty_line_highlight(minus_empty_line_marker_style, "red reverse", true); + _do_test_removed_empty_line_highlight(minus_empty_line_marker_style, "normal red", true); + _do_test_removed_empty_line_highlight(minus_empty_line_marker_style, "red", false); + _do_test_removed_empty_line_highlight( + minus_empty_line_marker_style, + "normal red reverse", + false, + ); + } + + fn _do_test_removed_empty_line_highlight( + empty_line_marker_style: &str, + base_style: &str, + base_style_has_background_color: bool, + ) { + _do_test_empty_line_highlight( + "--minus-empty-line-marker-style", + empty_line_marker_style, + "--minus-style", + base_style, + base_style_has_background_color, + DIFF_WITH_REMOVED_EMPTY_LINE, + ); + } + + #[test] + fn test_added_empty_line_highlight() { + let plus_empty_line_marker_style = "bold yellow magenta ul"; + _do_test_added_empty_line_highlight(plus_empty_line_marker_style, "green reverse", true); + _do_test_added_empty_line_highlight(plus_empty_line_marker_style, "normal green", true); + _do_test_added_empty_line_highlight(plus_empty_line_marker_style, "green", false); + _do_test_added_empty_line_highlight( + plus_empty_line_marker_style, + "normal green reverse", + false, + ); + } + + fn _do_test_added_empty_line_highlight( + empty_line_marker_style: &str, + base_style: &str, + base_style_has_background_color: bool, + ) { + _do_test_empty_line_highlight( + "--plus-empty-line-marker-style", + empty_line_marker_style, + "--plus-style", + base_style, + base_style_has_background_color, + DIFF_WITH_ADDED_EMPTY_LINE, + ); + } + + fn _do_test_empty_line_highlight( + empty_line_marker_style_name: &str, + empty_line_marker_style: &str, + base_style_name: &str, + base_style: &str, + base_style_has_background_color: bool, + example_diff: &str, + ) { + let config = integration_test_utils::make_config(&[ + base_style_name, + base_style, + empty_line_marker_style_name, + empty_line_marker_style, + ]); + let output = integration_test_utils::run_delta(example_diff, &config); + let line = output.lines().nth(6).unwrap(); + if base_style_has_background_color { + let style = style::Style::from_str(base_style, None, None, None, true, false); + assert_eq!( + line, + &style + .ansi_term_style + .paint(paint::ANSI_CSI_CLEAR_TO_EOL) + .to_string() + ); + } else { + let style = + style::Style::from_str(empty_line_marker_style, None, None, None, true, false); + assert_eq!( + line, + &style + .ansi_term_style + .paint(format!( + "{}{}", + paint::ANSI_CSI_CLEAR_TO_BOL, + paint::ANSI_CSI_CURSOR_BACK_1 + )) + .to_string() + ); + } + } + const GIT_DIFF_SINGLE_HUNK: &str = "\ commit 94907c0f136f46dc46ffae2dc92dca9af7eb7c2e Author: Dan Davison <dandavison7@gmail.com> @@ -1442,4 +1542,22 @@ index cba6064..ba1a4de 100644 - Co + let col = Co "#; + + const DIFF_WITH_REMOVED_EMPTY_LINE: &str = r" +diff --git i/a w/a +index 8b13789..e69de29 100644 +--- i/a ++++ w/a +@@ -1 +0,0 @@ +- +"; + + const DIFF_WITH_ADDED_EMPTY_LINE: &str = r" +diff --git i/a w/a +index e69de29..8b13789 100644 +--- i/a ++++ w/a +@@ -0,0 +1 @@ ++ +"; } |