summaryrefslogtreecommitdiffstats
path: root/src/paint.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/paint.rs')
-rw-r--r--src/paint.rs87
1 files changed, 69 insertions, 18 deletions
diff --git a/src/paint.rs b/src/paint.rs
index 3015187a..929b9643 100644
--- a/src/paint.rs
+++ b/src/paint.rs
@@ -11,11 +11,11 @@ use crate::config::{self, delta_unreachable};
use crate::delta::State;
use crate::edits;
use crate::features::line_numbers;
-use crate::features::side_by_side;
-use crate::features::side_by_side::PanelSide;
+use crate::features::side_by_side::{self, available_line_width, LineSegments, PanelSide};
use crate::paint::superimpose_style_sections::superimpose_style_sections;
use crate::plusminus::*;
use crate::style::Style;
+use crate::wrapping::wrap_plusminus_block;
pub struct Painter<'a> {
pub minus_lines: Vec<(String, State)>,
@@ -110,6 +110,7 @@ impl<'a> Painter<'a> {
// in effect in which case we replace it with the appropriate marker).
// TODO: Things should, but do not, work if this leading space is omitted at this stage.
// See comment in align::Alignment::new.
+ // Note that a wrapped line also has a leading character added to remain compatible.
line.next();
format!(" {}\n", self.expand_tabs(line))
} else {
@@ -172,21 +173,65 @@ impl<'a> Painter<'a> {
);
let states_left_right = PlusMinus::new(
- self.minus_lines.iter().map(|(_, state)| state).collect(),
- self.plus_lines.iter().map(|(_, state)| state).collect(),
+ self.minus_lines
+ .iter()
+ .map(|(_, state)| state.clone())
+ .collect(),
+ self.plus_lines
+ .iter()
+ .map(|(_, state)| state.clone())
+ .collect(),
);
let bg_fill_left_right = PlusMinus::new(
- // Using an ANSI sequence to fill the left panel would not work
+ // Using an ANSI sequence to fill the left panel would not work.
BgShouldFill::With(BgFillMethod::Spaces),
- // Use the configured method for the right panel
+ // Use what is configured for the right side.
BgShouldFill::With(self.config.line_fill_method),
);
+ // Only set `should_wrap` to true if wrapping is wanted and lines which are
+ // too long are found.
+ // If so, remember the calculated line width and which of the lines are too
+ // long for later re-use.
+ let (should_wrap, line_width, long_lines) = {
+ if self.config.wrap_config.max_lines == 1 {
+ (false, PlusMinus::default(), PlusMinus::default())
+ } else {
+ let line_width = available_line_width(self.config, &self.line_numbers_data);
+
+ let lines = PlusMinus::new(&self.minus_lines, &self.plus_lines);
+
+ let (should_wrap, long_lines) =
+ side_by_side::has_long_lines(&lines, &line_width);
+
+ (should_wrap, line_width, long_lines)
+ }
+ };
+
+ let (line_alignment, line_states, syntax_left_right, diff_left_right) = if should_wrap {
+ // Calculated for syntect::highlighting::style::Style and delta::Style
+ wrap_plusminus_block(
+ self.config,
+ syntax_left_right,
+ diff_left_right,
+ &line_alignment,
+ &line_width,
+ &long_lines,
+ )
+ } else {
+ (
+ line_alignment,
+ states_left_right,
+ syntax_left_right,
+ diff_left_right,
+ )
+ };
+
side_by_side::paint_minus_and_plus_lines_side_by_side(
syntax_left_right,
diff_left_right,
- states_left_right,
+ line_states,
line_alignment,
&mut self.output_buffer,
self.config,
@@ -250,7 +295,9 @@ impl<'a> Painter<'a> {
let diff_style_sections = vec![(self.config.zero_style, lines[0].0.as_str())]; // TODO: compute style from state
if self.config.side_by_side {
+ // `lines[0].0` so the line has the '\n' already added (as in the +- case)
side_by_side::paint_zero_lines_side_by_side(
+ &lines[0].0,
syntax_style_sections,
vec![diff_style_sections],
&mut self.output_buffer,
@@ -277,10 +324,10 @@ impl<'a> Painter<'a> {
/// Superimpose background styles and foreground syntax
/// highlighting styles, and write colored lines to output buffer.
#[allow(clippy::too_many_arguments)]
- pub fn paint_lines(
- syntax_style_sections: Vec<Vec<(SyntectStyle, &str)>>,
- diff_style_sections: Vec<Vec<(Style, &str)>>,
- states: impl Iterator<Item = &'a State>,
+ pub fn paint_lines<'b>(
+ syntax_style_sections: Vec<LineSegments<'b, SyntectStyle>>,
+ diff_style_sections: Vec<LineSegments<'b, Style>>,
+ states: impl Iterator<Item = &'b State>,
output_buffer: &mut String,
config: &config::Config,
line_numbers_data: &mut Option<&mut line_numbers::LineNumbersData>,
@@ -381,7 +428,9 @@ impl<'a> Painter<'a> {
// style: for right fill if line contains no emph sections
// non_emph_style: for right fill if line contains emph sections
let (style, non_emph_style) = match state {
- State::HunkMinus(None) => (config.minus_style, config.minus_non_emph_style),
+ State::HunkMinus(None) | State::HunkMinusWrapped => {
+ (config.minus_style, config.minus_non_emph_style)
+ }
State::HunkMinus(Some(raw_line)) => {
// TODO: This is the second time we are parsing the ANSI sequences
if let Some(ansi_term_style) = ansi::parse_first_style(raw_line) {
@@ -394,8 +443,10 @@ impl<'a> Painter<'a> {
(config.minus_style, config.minus_non_emph_style)
}
}
- State::HunkZero => (config.zero_style, config.zero_style),
- State::HunkPlus(None) => (config.plus_style, config.plus_non_emph_style),
+ State::HunkZero | State::HunkZeroWrapped => (config.zero_style, config.zero_style),
+ State::HunkPlus(None) | State::HunkPlusWrapped => {
+ (config.plus_style, config.plus_non_emph_style)
+ }
State::HunkPlus(Some(raw_line)) => {
// TODO: This is the second time we are parsing the ANSI sequences
if let Some(ansi_term_style) = ansi::parse_first_style(raw_line) {
@@ -568,7 +619,7 @@ impl<'a> Painter<'a> {
state: &State,
highlighter: Option<&mut HighlightLines>,
config: &config::Config,
- ) -> Vec<Vec<(SyntectStyle, &'s str)>> {
+ ) -> Vec<LineSegments<'s, SyntectStyle>> {
let mut line_sections = Vec::new();
match (
highlighter,
@@ -600,8 +651,8 @@ impl<'a> Painter<'a> {
plus_lines: &'b [(String, State)],
config: &config::Config,
) -> (
- Vec<Vec<(Style, &'b str)>>,
- Vec<Vec<(Style, &'b str)>>,
+ Vec<LineSegments<'b, Style>>,
+ Vec<LineSegments<'b, Style>>,
Vec<(Option<usize>, Option<usize>)>,
) {
let (minus_lines, minus_styles): (Vec<&str>, Vec<Style>) = minus_lines
@@ -652,7 +703,7 @@ impl<'a> Painter<'a> {
/// 2. If the line constitutes a whitespace error, then the whitespace error style
/// should be applied to the added material.
fn update_styles(
- style_sections: &mut Vec<Vec<(Style, &str)>>,
+ style_sections: &mut Vec<LineSegments<'_, Style>>,
whitespace_error_style: Option<Style>,
non_emph_style: Option<Style>,
) {