diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/cli.rs | 5 | ||||
-rw-r--r-- | src/config.rs | 13 | ||||
-rw-r--r-- | src/features/line_numbers.rs | 10 | ||||
-rw-r--r-- | src/features/side_by_side.rs | 285 | ||||
-rw-r--r-- | src/handlers/blame.rs | 3 | ||||
-rw-r--r-- | src/handlers/hunk_header.rs | 4 | ||||
-rw-r--r-- | src/options/set.rs | 1 | ||||
-rw-r--r-- | src/paint.rs | 81 | ||||
-rw-r--r-- | src/subcommands/show_config.rs | 6 | ||||
-rw-r--r-- | src/tests/ansi_test_utils.rs | 2 |
10 files changed, 246 insertions, 164 deletions
@@ -526,6 +526,11 @@ pub struct Opt { /// delta will be slow on very long lines (e.g. minified .js) if truncation is disabled. pub max_line_length: usize, + /// How to extend the background color to the end of the line in side-by-side mode. Can + /// be ansi (default) or spaces. Has no effect if --width=variable is given. + #[structopt(long = "line-fill-method")] + pub line_fill_method: Option<String>, + /// The width of underline/overline decorations. Use --width=variable to extend decorations and /// background colors to the end of the text only. Otherwise background colors extend to the /// full terminal width. diff --git a/src/config.rs b/src/config.rs index 1b035f2b..fbd58044 100644 --- a/src/config.rs +++ b/src/config.rs @@ -16,6 +16,7 @@ use crate::env; use crate::features::navigate; use crate::features::side_by_side; use crate::git_config::{GitConfig, GitConfigEntry}; +use crate::paint::BgFillMethod; use crate::style::{self, Style}; pub struct Config { @@ -51,6 +52,7 @@ pub struct Config { pub hyperlinks_file_link_format: String, pub inspect_raw_lines: cli::InspectRawLines, pub keep_plus_minus_markers: bool, + pub line_fill_method: BgFillMethod, pub line_numbers: bool, pub line_numbers_left_format: String, pub line_numbers_left_style: Style, @@ -187,6 +189,16 @@ impl From<cli::Opt> for Config { let file_renamed_label = opt.file_renamed_label; let hunk_label = opt.hunk_label; + let line_fill_method = match opt.line_fill_method.as_deref() { + // Note that "default" is not documented + Some("ansi") | Some("default") | None => BgFillMethod::TryAnsiSequence, + Some("spaces") => BgFillMethod::Spaces, + _ => { + eprintln!("Invalid option for line-fill-method: Expected \"ansi\" or \"spaces\"."); + process::exit(1); + } + }; + let navigate_regexp = if opt.navigate || opt.show_themes { Some(navigate::make_navigate_regexp( opt.show_themes, @@ -245,6 +257,7 @@ impl From<cli::Opt> for Config { hyperlinks_file_link_format: opt.hyperlinks_file_link_format, inspect_raw_lines: opt.computed.inspect_raw_lines, keep_plus_minus_markers: opt.keep_plus_minus_markers, + line_fill_method, line_numbers: opt.line_numbers, line_numbers_left_format: opt.line_numbers_left_format, line_numbers_left_style, diff --git a/src/features/line_numbers.rs b/src/features/line_numbers.rs index 3032bc00..0d282557 100644 --- a/src/features/line_numbers.rs +++ b/src/features/line_numbers.rs @@ -383,7 +383,7 @@ pub mod tests { let mut lines = output.lines().skip(7); let (line_1, line_2) = (lines.next().unwrap(), lines.next().unwrap()); assert_eq!(strip_ansi_codes(line_1), " 1 ⋮ │a = 1"); - assert_eq!(strip_ansi_codes(line_2), " 2 ⋮ │b = 2"); + assert_eq!(strip_ansi_codes(line_2), " 2 ⋮ │b = 23456"); } #[test] @@ -407,7 +407,7 @@ pub mod tests { let mut lines = output.lines().skip(7); let (line_1, line_2) = (lines.next().unwrap(), lines.next().unwrap()); assert_eq!(strip_ansi_codes(line_1), " ⋮ 1 │a = 1"); - assert_eq!(strip_ansi_codes(line_2), " ⋮ 2 │b = 2"); + assert_eq!(strip_ansi_codes(line_2), " ⋮ 2 │b = 234567"); } #[test] @@ -489,7 +489,7 @@ pub mod tests { let mut lines = output.lines().skip(5); let (line_1, line_2) = (lines.next().unwrap(), lines.next().unwrap()); assert_eq!(strip_ansi_codes(line_1), " 1 ⋮ │-a = 1"); - assert_eq!(strip_ansi_codes(line_2), " 2 ⋮ │-b = 2"); + assert_eq!(strip_ansi_codes(line_2), " 2 ⋮ │-b = 23456"); } #[test] @@ -514,7 +514,7 @@ index 223ca50..e69de29 100644 +++ w/a.py @@ -1,2 +0,0 @@ -a = 1 --b = 2 +-b = 23456 "; pub const TWO_PLUS_LINES_DIFF: &str = "\ @@ -525,7 +525,7 @@ index 0000000..223ca50 +++ i/a.py @@ -0,0 +1,2 @@ +a = 1 -+b = 2 ++b = 234567 "; pub const ONE_MINUS_ONE_PLUS_LINE_DIFF: &str = "\ diff --git a/src/features/side_by_side.rs b/src/features/side_by_side.rs index ae5911ef..6d85b7af 100644 --- a/src/features/side_by_side.rs +++ b/src/features/side_by_side.rs @@ -10,6 +10,7 @@ use crate::delta::State; use crate::features::line_numbers; use crate::features::OptionValueFunction; use crate::paint::Painter; +use crate::paint::{BgFillMethod, BgShouldFill}; use crate::plusminus::*; use crate::style::Style; @@ -92,7 +93,7 @@ pub fn paint_minus_and_plus_lines_side_by_side<'a>( output_buffer: &mut String, config: &Config, line_numbers_data: &mut Option<&mut line_numbers::LineNumbersData>, - background_color_extends_to_terminal_width: Option<bool>, + background_color_extends_to_terminal_width: PlusMinus<BgShouldFill>, ) { for (minus_line_index, plus_line_index) in line_alignment { output_buffer.push_str(&paint_left_panel_minus_line( @@ -109,7 +110,7 @@ pub fn paint_minus_and_plus_lines_side_by_side<'a>( } else { None }, - background_color_extends_to_terminal_width, + background_color_extends_to_terminal_width[Left], config, )); output_buffer.push_str(&paint_right_panel_plus_line( @@ -126,7 +127,7 @@ pub fn paint_minus_and_plus_lines_side_by_side<'a>( } else { None }, - background_color_extends_to_terminal_width, + background_color_extends_to_terminal_width[Right], config, )); output_buffer.push('\n'); @@ -137,63 +138,50 @@ pub fn paint_minus_and_plus_lines_side_by_side<'a>( pub fn paint_zero_lines_side_by_side( syntax_style_sections: Vec<Vec<(SyntectStyle, &str)>>, diff_style_sections: Vec<Vec<(Style, &str)>>, - state: &State, output_buffer: &mut String, config: &Config, line_numbers_data: &mut Option<&mut line_numbers::LineNumbersData>, painted_prefix: Option<ansi_term::ANSIString>, - background_color_extends_to_terminal_width: Option<bool>, + background_color_extends_to_terminal_width: BgShouldFill, ) { + let state = State::HunkZero; + for (line_index, (syntax_sections, diff_sections)) in syntax_style_sections .iter() .zip_eq(diff_style_sections.iter()) .enumerate() { - let (mut left_panel_line, left_panel_line_is_empty) = Painter::paint_line( - syntax_sections, - diff_sections, - state, - line_numbers_data, - Some(PanelSide::Left), - painted_prefix.clone(), - config, - ); - // TODO: Avoid doing the superimpose_style_sections work twice. - // HACK: These are getting incremented twice, so knock them back down once. - if let Some(d) = line_numbers_data.as_mut() { - d.line_number[Left] -= 1; - d.line_number[Right] -= 1; - } - right_pad_left_panel_line( - &mut left_panel_line, - left_panel_line_is_empty, - Some(line_index), - &diff_style_sections, - &State::HunkZero, - background_color_extends_to_terminal_width, - config, - ); - output_buffer.push_str(&left_panel_line); + for panel_side in &[Left, Right] { + let (mut panel_line, panel_line_is_empty) = Painter::paint_line( + syntax_sections, + diff_sections, + &state, + line_numbers_data, + Some(*panel_side), + painted_prefix.clone(), + config, + ); + pad_panel_line_to_width( + &mut panel_line, + panel_line_is_empty, + Some(line_index), + &diff_style_sections, + &state, + *panel_side, + background_color_extends_to_terminal_width, + config, + ); + output_buffer.push_str(&panel_line); - let (mut right_panel_line, right_panel_line_is_empty) = Painter::paint_line( - syntax_sections, - diff_sections, - state, - line_numbers_data, - Some(PanelSide::Right), - painted_prefix.clone(), - config, - ); - right_fill_right_panel_line( - &mut right_panel_line, - right_panel_line_is_empty, - Some(line_index), - &diff_style_sections, - &State::HunkZero, - background_color_extends_to_terminal_width, - config, - ); - output_buffer.push_str(&right_panel_line); + if panel_side == &Left { + // TODO: Avoid doing the superimpose_style_sections work twice. + // HACK: These are getting incremented twice, so knock them back down once. + if let Some(d) = line_numbers_data.as_mut() { + d.line_number[Left] -= 1; + d.line_number[Right] -= 1; + } + } + } output_buffer.push('\n'); } } @@ -206,7 +194,7 @@ fn paint_left_panel_minus_line<'a>( state: &'a State, line_numbers_data: &mut Option<&mut line_numbers::LineNumbersData>, painted_prefix: Option<ansi_term::ANSIString>, - background_color_extends_to_terminal_width: Option<bool>, + background_color_extends_to_terminal_width: BgShouldFill, config: &Config, ) -> String { let (mut panel_line, panel_line_is_empty) = paint_minus_or_plus_panel_line( @@ -219,12 +207,13 @@ fn paint_left_panel_minus_line<'a>( painted_prefix, config, ); - right_pad_left_panel_line( + pad_panel_line_to_width( &mut panel_line, panel_line_is_empty, line_index, diff_style_sections, state, + Left, background_color_extends_to_terminal_width, config, ); @@ -240,7 +229,7 @@ fn paint_right_panel_plus_line<'a>( state: &'a State, line_numbers_data: &mut Option<&mut line_numbers::LineNumbersData>, painted_prefix: Option<ansi_term::ANSIString>, - background_color_extends_to_terminal_width: Option<bool>, + background_color_extends_to_terminal_width: BgShouldFill, config: &Config, ) -> String { let (mut panel_line, panel_line_is_empty) = paint_minus_or_plus_panel_line( @@ -253,41 +242,53 @@ fn paint_right_panel_plus_line<'a>( painted_prefix, config, ); - right_fill_right_panel_line( + + pad_panel_line_to_width( &mut panel_line, panel_line_is_empty, line_index, diff_style_sections, state, + Right, background_color_extends_to_terminal_width, config, ); + panel_line } -fn get_right_fill_style_for_left_panel( +fn get_right_fill_style_for_panel( line_is_empty: bool, line_index: Option<usize>, diff_style_sections: &[Vec<(Style, &str)>], state: &State, - background_color_extends_to_terminal_width: Option<bool>, + panel_side: PanelSide, + background_color_extends_to_terminal_width: BgShouldFill, config: &Config, -) -> Style { +) -> (Option<BgFillMethod>, Style) { + // If in the the left panel then it must be filled with spaces. + let none_or_override = if panel_side == Left { + Some(BgFillMethod::Spaces) + } else { + None + }; + match (line_is_empty, line_index) { - (true, _) => config.null_style, - (false, None) => config.null_style, + (true, _) => (none_or_override, config.null_style), + (false, None) => (none_or_override, config.null_style), (false, Some(index)) => { - let (should_fill, fill_style) = + let (bg_fill_mode, fill_style) = Painter::get_should_right_fill_background_color_and_fill_style( &diff_style_sections[index], state, background_color_extends_to_terminal_width, config, ); - if should_fill { - fill_style - } else { - config.null_style + + match bg_fill_mode { + None => (none_or_override, config.null_style), + _ if panel_side == Left => (Some(BgFillMethod::Spaces), fill_style), + _ => (bg_fill_mode, fill_style), } } } @@ -375,21 +376,20 @@ fn paint_minus_or_plus_panel_line( (line, line_is_empty) } -/// Right-pad a line in the left panel with (possibly painted) spaces. A line in the left panel is -/// either a minus line or a zero line. -#[allow(clippy::comparison_chain)] -fn right_pad_left_panel_line( +/// Right-fill the background color of a line in a panel. If in the left panel this is always +/// done with spaces. The right panel can be filled with spaces or using ANSI sequences +/// instructing the terminal emulator to fill the background color rightwards. +#[allow(clippy::too_many_arguments, clippy::comparison_chain)] +fn pad_panel_line_to_width( panel_line: &mut String, panel_line_is_empty: bool, line_index: Option<usize>, diff_style_sections: &[Vec<(Style, &str)>], state: &State, - background_color_extends_to_terminal_width: Option<bool>, + panel_side: PanelSide, + background_color_extends_to_terminal_width: BgShouldFill, config: &Config, ) { - // The left panel uses spaces to pad to the midpoint. This differs from the right panel, - // and from the non-side-by-side implementation. - // Emit empty line marker if the panel line is empty but not empty-by-construction. IOW if the // other panel contains a real line, and we are currently emitting an empty counterpart panel // to form the other half of the line, then don't emit the empty line marker. @@ -400,81 +400,46 @@ fn right_pad_left_panel_line( panel_line, Some(" "), ), + State::HunkPlus(_) => Painter::mark_empty_line( + &config.plus_empty_line_marker_style, + panel_line, + Some(" "), + ), State::HunkZero => {} _ => unreachable!(), }; }; - // Pad with (maybe painted) spaces to the panel width. + let text_width = ansi::measure_text_width(panel_line); - let panel_width = config.side_by_side_data[Left].width; - if text_width < panel_width { - let fill_style = get_right_fill_style_for_left_panel( - panel_line_is_empty, - line_index, - diff_style_sections, - state, - background_color_extends_to_terminal_width, - config, - ); - panel_line.push_str( - &fill_style - .paint(" ".repeat(panel_width - text_width)) - .to_string(), - ); - } else if text_width > panel_width { + let panel_width = config.side_by_side_data[panel_side].width; + + if text_width > panel_width { *panel_line = ansi::truncate_str(panel_line, panel_width, &config.truncation_symbol).to_string(); } -} -/// Right-fill the background color of a line in the right panel. A line in the right panel is -/// either a zero line or a plus line. The fill is achieved using ANSI sequences instructing the -/// terminal emulator to fill the background color rightwards; it does not involve appending spaces -/// to the line. -fn right_fill_right_panel_line( - panel_line: &mut String, - panel_line_is_empty: bool, - line_index: Option<usize>, - diff_style_sections: &[Vec<(Style, &str)>], - state: &State, - background_color_extends_to_terminal_width: Option<bool>, - config: &Config, -) { - *panel_line = ansi::truncate_str( - &panel_line, - config.side_by_side_data[Right].width, - &config.truncation_symbol, - ) - .to_string(); - - // Unlike `right_pad_left_panel_line`, the line-end emissions here are basically the same as - // the non side-by-side implementation in Painter::paint_lines. - let (should_right_fill_background_color, fill_style) = if let Some(index) = line_index { - Painter::get_should_right_fill_background_color_and_fill_style( - &diff_style_sections[index], - state, - background_color_extends_to_terminal_width, - config, - ) - } else { - (false, config.null_style) - }; + let (bg_fill_mode, fill_style) = get_right_fill_style_for_panel( + panel_line_is_empty, + line_index, + diff_style_sections, + state, + panel_side, + background_color_extends_to_terminal_width, + config, + ); - if should_right_fill_background_color { - Painter::right_fill_background_color(panel_line, fill_style); - } else if panel_line_is_empty && line_index.is_some() { - // Emit empty line marker when the panel line is empty but not empty-by-construction. See - // parallel comment in `paint_left_panel_minus_line`. - match state { - State::HunkPlus(_) => Painter::mark_empty_line( - &config.plus_empty_line_marker_style, - panel_line, - Some(" "), - ), - State::HunkZero => {} - _ => unreachable!(), + match bg_fill_mode { + Some(BgFillMethod::TryAnsiSequence) => { + Painter::right_fill_background_color(panel_line, fill_style) } - }; + Some(BgFillMethod::Spaces) if text_width >= panel_width => (), + Some(BgFillMethod::Spaces) => panel_line.push_str( + &fill_style + .paint(" ".repeat(panel_width - text_width)) + .to_string(), + ), + None => (), + } } #[cfg(test)] @@ -490,7 +455,23 @@ pub mod tests { let mut lines = output.lines().skip(7); let (line_1, line_2) = (lines.next().unwrap(), lines.next().unwrap()); assert_eq!("│ 1 │a = 1 │ │", strip_ansi_codes(line_1)); - assert_eq!("│ 2 │b = 2 │ │", strip_ansi_codes(line_2)); + assert_eq!("│ 2 │b = 23456 │ │", strip_ansi_codes(line_2)); + } + + #[test] + fn test_two_minus_lines_truncated() { + let mut config = make_config_from_args(&[ + "--side-by-side", + "--width", + "28", + "--line-fill-method=spaces", + ]); + config.truncation_symbol = ">".into(); + let output = run_delta(TWO_MINUS_LINES_DIFF, &config); + let mut lines = output.lines().skip(7); + let (line_1, line_2) = (lines.next().unwrap(), lines.next().unwrap()); + assert_eq!("│ 1 │a = 1 │ │", strip_ansi_codes(line_1)); + assert_eq!("│ 2 │b = 234>│ │", strip_ansi_codes(line_2)); } #[test] @@ -499,8 +480,36 @@ pub mod tests { let output = run_delta(TWO_PLUS_LINES_DIFF, &config); let mut lines = output.lines().skip(7); let (line_1, line_2) = (lines.next().unwrap(), lines.next().unwrap()); - assert_eq!("│ │ │ 1 │a = 1", strip_ansi_codes(line_1)); - assert_eq!("│ │ │ 2 │b = 2", strip_ansi_codes(line_2)); + let sac = strip_ansi_codes; // alias to help with `cargo fmt`-ing: + assert_eq!("│ │ │ 1 │a = 1", sac(line_1)); + assert_eq!("│ │ │ 2 │b = 234567", sac(line_2)); + } + + #[test] + fn test_two_plus_lines_truncated() { + let mut config = make_config_from_args(&[ + "--side-by-side", + "--width", + "30", + "--line-fill-method=spaces", + ]); + config.truncation_symbol = ">".into(); + let output = run_delta(TWO_PLUS_LINES_DIFF, &config); + let mut lines = output.lines().skip(7); + let (line_1, line_2) = (lines.next().unwrap(), lines.next().unwrap()); + assert_eq!("│ │ │ 1 │a = 1 ", strip_ansi_codes(line_1)); + assert_eq!("│ │ │ 2 │b = 2345>", strip_ansi_codes(line_2)); + } + + #[test] + fn test_two_plus_lines_exact_fit() { + let mut config = make_config_from_args(&["--side-by-side", "--width", "32"]); + config.truncation_symbol = ">".into(); + let output = run_delta(TWO_PLUS_LINES_DIFF, &config); + let mut lines = output.lines().skip(7); + let (line_1, line_2) = (lines.next().unwrap(), lines.next().unwrap()); + assert_eq!("│ │ │ 1 │a = 1", strip_ansi_codes(line_1)); + assert_eq!("│ │ │ 2 │b = 234567", strip_ansi_codes(line_2)); } #[test] diff --git a/src/handlers/blame.rs b/src/handlers/blame.rs index d7486303..af1057d9 100644 --- a/src/handlers/blame.rs +++ b/src/handlers/blame.rs @@ -6,6 +6,7 @@ use crate::color; use crate::config; use crate::delta::{self, State, StateMachine}; use crate::format; +use crate::paint::BgShouldFill; use crate::style::Style; impl<'a> StateMachine<'a> { @@ -56,7 +57,7 @@ impl<'a> StateMachine<'a> { blame.code, style, self.state.clone(), - true, + BgShouldFill::default(), ); handled_line = true } diff --git a/src/handlers/hunk_header.rs b/src/handlers/hunk_header.rs index 1d10d4fb..b601ef54 100644 --- a/src/handlers/hunk_header.rs +++ b/src/handlers/hunk_header.rs @@ -28,7 +28,7 @@ use super::draw; use crate::config::Config; use crate::delta::{self, State, StateMachine}; use crate::features; -use crate::paint::Painter; +use crate::paint::{BgShouldFill, Painter}; use crate::style::DecorationStyle; impl<'a> StateMachine<'a> { @@ -247,7 +247,7 @@ fn write_to_output_buffer( &line, config.hunk_header_style, delta::State::HunkHeader("".to_owned(), "".to_owned()), - false, + BgShouldFill::No, ); painter.output_buffer.pop(); // trim newline } diff --git a/src/options/set.rs b/src/options/set.rs index a896820a..1f533269 100644 --- a/src/options/set.rs +++ b/src/options/set.rs @@ -158,6 +158,7 @@ pub fn set_options( minus_non_emph_style, minus_non_emph_style, navigate, + line_fill_method, line_numbers, line_numbers_left_format, line_numbers_left_style, diff --git a/src/paint.rs b/src/paint.rs index 7b31047d..3015187a 100644 --- a/src/paint.rs +++ b/src/paint.rs @@ -28,6 +28,28 @@ pub struct Painter<'a> { pub line_numbers_data: line_numbers::LineNumbersData<'a>, } +// How the background of a line is filled up to the end +#[derive(Debug, PartialEq, Clone, Copy)] +pub enum BgFillMethod { + // Fill the background with ANSI spaces if possible, + // but might fallback to Spaces (e.g. in the left side-by-side panel) + TryAnsiSequence, + Spaces, +} + +// If the background of a line extends to the end, and if configured to do so, how. +#[derive(Debug, PartialEq, Clone, Copy)] +pub enum BgShouldFill { + With(BgFillMethod), + No, +} + +impl Default for BgShouldFill { + fn default() -> Self { + BgShouldFill::With(BgFillMethod::TryAnsiSequence) + } +} + impl<'a> Painter<'a> { pub fn new(writer: &'a mut dyn Write, config: &'a config::Config) -> Self { let default_syntax = Self::get_syntax(&config.syntax_set, None); @@ -154,6 +176,13 @@ impl<'a> Painter<'a> { self.plus_lines.iter().map(|(_, state)| state).collect(), ); + let bg_fill_left_right = PlusMinus::new( + // Using an ANSI sequence to fill the left panel would not work + BgShouldFill::With(BgFillMethod::Spaces), + // Use the configured method for the right panel + BgShouldFill::With(self.config.line_fill_method), + ); + side_by_side::paint_minus_and_plus_lines_side_by_side( syntax_left_right, diff_left_right, @@ -162,7 +191,7 @@ impl<'a> Painter<'a> { &mut self.output_buffer, self.config, &mut Some(&mut self.line_numbers_data), - None, + bg_fill_left_right, ); } else { if !self.minus_lines.is_empty() { @@ -179,7 +208,7 @@ impl<'a> Painter<'a> { None }, Some(self.config.minus_empty_line_marker_style), - None, + BgShouldFill::default(), ); } if !self.plus_lines.is_empty() { @@ -196,7 +225,7 @@ impl<'a> Painter<'a> { None }, Some(self.config.plus_empty_line_marker_style), - None, + BgShouldFill::default(), ); } } @@ -224,12 +253,11 @@ impl<'a> Painter<'a> { side_by_side::paint_zero_lines_side_by_side( syntax_style_sections, vec![diff_style_sections], - &State::HunkZero, &mut self.output_buffer, self.config, &mut Some(&mut self.line_numbers_data), painted_prefix, - None, + BgShouldFill::With(BgFillMethod::Spaces), ); } else { Painter::paint_lines( @@ -241,7 +269,7 @@ impl<'a> Painter<'a> { &mut Some(&mut self.line_numbers_data), painted_prefix, None, - None, + BgShouldFill::With(BgFillMethod::Spaces), ); } } @@ -258,7 +286,7 @@ impl<'a> Painter<'a> { line_numbers_data: &mut Option<&mut line_numbers::LineNumbersData>, painted_prefix: Option<ansi_term::ANSIString>, empty_line_style: Option<Style>, // a style with background color to highlight an empty line - background_color_extends_to_terminal_width: Option<bool>, + background_color_extends_to_terminal_width: BgShouldFill, ) { // There's some unfortunate hackery going on here for two reasons: // @@ -281,15 +309,23 @@ impl<'a> Painter<'a> { painted_prefix.clone(), config, ); - let (should_right_fill_background_color, fill_style) = + let (bg_fill_mode, fill_style) = Painter::get_should_right_fill_background_color_and_fill_style( diff_sections, state, background_color_extends_to_terminal_width, config, ); - if should_right_fill_background_color { + + if let Some(BgFillMethod::TryAnsiSequence) = bg_fill_mode { Painter::right_fill_background_color(&mut line, fill_style); + } else if let Some(BgFillMethod::Spaces) = bg_fill_mode { + let text_width = ansi::measure_text_width(&line); + line.push_str( + &fill_style + .paint(" ".repeat(config.available_terminal_width - text_width)) + .to_string(), + ); } else if line_is_empty { if let Some(empty_line_style) = empty_line_style { |