summaryrefslogtreecommitdiffstats
path: root/src/features/side_by_side.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/features/side_by_side.rs')
-rw-r--r--src/features/side_by_side.rs285
1 files changed, 147 insertions, 138 deletions
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]