summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorDan Davison <dandavison7@gmail.com>2020-07-17 18:49:55 -0400
committerDan Davison <dandavison7@gmail.com>2020-08-01 11:35:50 -0400
commitcd7953c176c2bc71b34cc2aaa1618f6ab208538f (patch)
tree9571d07e3a9f5015b58afd4abb884f59e6157067 /src
parent27dec271018c589ba1119a180158903b9dba8c64 (diff)
Initial implementation of color-moved support
- Inspect the raw hunk line - If it does not appear to be a standard minus/plus line, treat it as moved - Apply special delta color-moved-* styles
Diffstat (limited to 'src')
-rw-r--r--src/cli.rs18
-rw-r--r--src/config.rs55
-rw-r--r--src/delta.rs38
-rw-r--r--src/edits.rs42
-rw-r--r--src/features/color_moved.rs24
-rw-r--r--src/features/line_numbers.rs4
-rw-r--r--src/features/mod.rs5
-rw-r--r--src/features/side_by_side.rs24
-rw-r--r--src/git_config_entry.rs3
-rw-r--r--src/options/set.rs23
-rw-r--r--src/paint.rs67
-rw-r--r--src/style.rs4
-rw-r--r--src/tests/ansi_test_utils.rs4
13 files changed, 217 insertions, 94 deletions
diff --git a/src/cli.rs b/src/cli.rs
index 0532a6f2..384db044 100644
--- a/src/cli.rs
+++ b/src/cli.rs
@@ -234,6 +234,14 @@ pub struct Opt {
/// --file-renamed-label.
pub navigate: bool,
+ #[structopt(long = "color-moved")]
+ /// Detect moved code lines and apply the styles color-moved-minus-style and
+ /// color-moved-plus-style. This option requires the git config setting `diff.colorMoved =
+ /// true` (or that you pass --color-moved to git on the command line). It can only work if
+ /// delta receives colored input from git. So it works with `core.pager = delta` in git config,
+ /// but if you pipe git's output to delta, you must pass --color=always to git.
+ pub color_moved: bool,
+
#[structopt(long = "hyperlinks")]
/// Render commit hashes, file names, and line numbers as hyperlinks, according to the
/// hyperlink spec for terminal emulators:
@@ -427,6 +435,16 @@ pub struct Opt {
#[structopt(long = "line-numbers-right-style", default_value = "auto")]
pub line_numbers_right_style: String,
+ #[structopt(long = "color-moved-minus-style", default_value = "auto")]
+ /// Style (foreground, background, attributes) for moved lines in their old location. See
+ /// STYLES section.
+ pub color_moved_minus_style: String,
+
+ #[structopt(long = "color-moved-plus-style", default_value = "auto")]
+ /// Style (foreground, background, attributes) for moved lines in their new location. See
+ /// STYLES section.
+ pub color_moved_plus_style: String,
+
#[structopt(long = "file-modified-label", default_value = "")]
/// Text to display in front of a modified file path.
pub file_modified_label: String,
diff --git a/src/config.rs b/src/config.rs
index 13a0c9c5..4703e38e 100644
--- a/src/config.rs
+++ b/src/config.rs
@@ -46,6 +46,7 @@ pub struct Config {
pub minus_emph_style: Style,
pub minus_empty_line_marker_style: Style,
pub minus_file: Option<PathBuf>,
+ pub minus_moved_style: Style,
pub minus_non_emph_style: Style,
pub minus_style: Style,
pub navigate: bool,
@@ -55,8 +56,11 @@ pub struct Config {
pub plus_emph_style: Style,
pub plus_empty_line_marker_style: Style,
pub plus_file: Option<PathBuf>,
+ pub plus_moved_style: Style,
pub plus_non_emph_style: Style,
pub plus_style: Style,
+ pub raw_expected_minus_style: Style,
+ pub raw_expected_plus_style: Style,
pub side_by_side: bool,
pub side_by_side_data: side_by_side::SideBySideData,
pub syntax_dummy_theme: SyntaxTheme,
@@ -73,6 +77,10 @@ pub struct Config {
impl Config {
pub fn get_style(&self, state: &State) -> &Style {
match state {
+ State::HunkMinus(false) => &self.minus_style,
+ State::HunkMinus(true) => &self.minus_moved_style,
+ State::HunkPlus(false) => &self.plus_style,
+ State::HunkPlus(true) => &self.plus_moved_style,
State::CommitMeta => &self.commit_style,
State::FileMeta => &self.file_style,
State::HunkHeader => &self.hunk_header_style,
@@ -87,11 +95,13 @@ impl From<cli::Opt> for Config {
minus_style,
minus_emph_style,
minus_non_emph_style,
+ minus_moved_style,
minus_empty_line_marker_style,
zero_style,
plus_style,
plus_emph_style,
plus_non_emph_style,
+ plus_moved_style,
plus_empty_line_marker_style,
whitespace_error_style,
) = make_hunk_styles(&opt);
@@ -127,6 +137,27 @@ impl From<cli::Opt> for Config {
&opt.computed.available_terminal_width,
);
+ let raw_expected_minus_style = Style::from_str(
+ match opt.git_config_entries.get("color.diff.old") {
+ Some(GitConfigEntry::Style(s)) => s,
+ _ => "red",
+ },
+ None,
+ None,
+ opt.computed.true_color,
+ false,
+ );
+ let raw_expected_plus_style = Style::from_str(
+ match opt.git_config_entries.get("color.diff.new") {
+ Some(GitConfigEntry::Style(s)) => s,
+ _ => "green",
+ },
+ None,
+ None,
+ opt.computed.true_color,
+ false,
+ );
+
Self {
available_terminal_width: opt.computed.available_terminal_width,
background_color_extends_to_terminal_width: opt
@@ -158,6 +189,7 @@ impl From<cli::Opt> for Config {
minus_emph_style,
minus_empty_line_marker_style,
minus_file: opt.minus_file.map(|s| s.clone()),
+ minus_moved_style,
minus_non_emph_style,
minus_style,
navigate: opt.navigate,
@@ -167,8 +199,11 @@ impl From<cli::Opt> for Config {
plus_emph_style,
plus_empty_line_marker_style,
plus_file: opt.plus_file.map(|s| s.clone()),
+ plus_moved_style,
plus_non_emph_style,
plus_style,
+ raw_expected_minus_style,
+ raw_expected_plus_style,
side_by_side: opt.side_by_side,
side_by_side_data,
syntax_dummy_theme: SyntaxTheme::default(),
@@ -197,6 +232,8 @@ fn make_hunk_styles<'a>(
Style,
Style,
Style,
+ Style,
+ Style,
) {
let is_light_mode = opt.computed.is_light_mode;
let true_color = opt.computed.true_color;
@@ -236,6 +273,14 @@ fn make_hunk_styles<'a>(
false,
);
+ let minus_moved_style = Style::from_str(
+ &opt.color_moved_minus_style,
+ Some(minus_style),
+ None,
+ true_color,
+ 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(
@@ -290,6 +335,14 @@ fn make_hunk_styles<'a>(
false,
);
+ let plus_moved_style = Style::from_str(
+ &opt.color_moved_plus_style,
+ Some(plus_style),
+ None,
+ true_color,
+ 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(
@@ -313,11 +366,13 @@ fn make_hunk_styles<'a>(
minus_style,
minus_emph_style,
minus_non_emph_style,
+ minus_moved_style,
minus_empty_line_marker_style,
zero_style,
plus_style,
plus_emph_style,
plus_non_emph_style,
+ plus_moved_style,
plus_empty_line_marker_style,
whitespace_error_style,
)
diff --git a/src/delta.rs b/src/delta.rs
index fa36f016..5b3de991 100644
--- a/src/delta.rs
+++ b/src/delta.rs
@@ -16,12 +16,12 @@ use crate::style::DecorationStyle;
#[derive(Clone, Debug, PartialEq)]
pub enum State {
- CommitMeta, // In commit metadata section
- FileMeta, // In diff metadata section, between (possible) commit metadata and first hunk
- HunkHeader, // In hunk metadata line
- HunkZero, // In hunk; unchanged line
- HunkMinus, // In hunk; removed line
- HunkPlus, // In hunk; added line
+ CommitMeta, // In commit metadata section
+ FileMeta, // In diff metadata section, between (possible) commit metadata and first hunk
+ HunkHeader, // In hunk metadata line
+ HunkZero, // In hunk; unchanged line
+ HunkMinus(bool), // In hunk; removed line (is_moved)
+ HunkPlus(bool), // In hunk; added line (is_moved)
Unknown,
}
@@ -35,7 +35,7 @@ pub enum Source {
impl State {
fn is_in_hunk(&self) -> bool {
match *self {
- State::HunkHeader | State::HunkZero | State::HunkMinus | State::HunkPlus => true,
+ State::HunkHeader | State::HunkZero | State::HunkMinus(_) | State::HunkPlus(_) => true,
_ => false,
}
}
@@ -415,7 +415,7 @@ fn handle_hunk_header_line(
};
writeln!(painter.writer)?;
if !line.is_empty() {
- let lines = vec![line];
+ let lines = vec![(line, State::HunkHeader)];
let syntax_style_sections = Painter::get_syntax_style_sections_for_lines(
&lines,
&State::HunkHeader,
@@ -424,8 +424,8 @@ fn handle_hunk_header_line(
);
Painter::paint_lines(
syntax_style_sections,
- vec![vec![(config.hunk_header_style, &lines[0])]],
- &State::HunkHeader,
+ vec![vec![(config.hunk_header_style, &lines[0].0)]], // TODO: compute style from state
+ [State::HunkHeader].iter(),
&mut painter.output_buffer,
config,
&mut None,
@@ -499,15 +499,23 @@ fn handle_hunk_line(
}
match line.chars().next() {
Some('-') => {
- if state == State::HunkPlus {
+ if let State::HunkPlus(_) = state {
painter.paint_buffered_minus_and_plus_lines();
}
- painter.minus_lines.push(painter.prepare(&line, true));
- State::HunkMinus
+ let is_moved = !config.raw_expected_minus_style.is_applied_to(raw_line);
+ let state = State::HunkMinus(is_moved);
+ painter
+ .minus_lines
+ .push((painter.prepare(&line, true), state.clone()));
+ state
}
Some('+') => {
- painter.plus_lines.push(painter.prepare(&line, true));
- State::HunkPlus
+ let is_moved = !config.raw_expected_plus_style.is_applied_to(raw_line);
+ let state = State::HunkPlus(is_moved);
+ painter
+ .plus_lines
+ .push((painter.prepare(&line, true), state.clone()));
+ state
}
Some(' ') => {
painter.paint_buffered_minus_and_plus_lines();
diff --git a/src/edits.rs b/src/edits.rs
index 510b6f76..870ce2d3 100644
--- a/src/edits.rs
+++ b/src/edits.rs
@@ -9,13 +9,15 @@ use crate::align;
/// lines. A "line" is a string. An annotated line is a Vec of (op, &str) pairs, where the &str
/// slices are slices of the line, and their concatenation equals the line. Return the input minus
/// and plus lines, in annotated form. Also return a specification of the inferred alignment of
-/// minus and plus lines.
+/// minus and plus lines. `noop_deletions[i]` is the appropriate deletion operation tag to be used
+/// for `minus_lines[i]`; `noop_deletions` is guaranteed to be the same length as `minus_lines`.
+/// The equivalent statements hold for `plus_insertions` and `plus_lines`.
pub fn infer_edits<'a, EditOperation>(
- minus_lines: &'a [String],
- plus_lines: &'a [String],
- noop_deletion: EditOperation,
+ minus_lines: Vec<&'a str>,
+ plus_lines: Vec<&'a str>,
+ noop_deletions: Vec<EditOperation>,
deletion: EditOperation,
- noop_insertion: EditOperation,
+ noop_insertions: Vec<EditOperation>,
insertion: EditOperation,
tokenization_regex: &Regex,
max_line_distance: f64,
@@ -44,9 +46,9 @@ where
);
let (annotated_minus_line, annotated_plus_line, distance) = annotate(
alignment,
- noop_deletion,
+ noop_deletions[minus_index],
deletion,
- noop_insertion,
+ noop_insertions[plus_index],
insertion,
minus_line,
plus_line,
@@ -59,7 +61,7 @@ where
// Emit as unpaired the plus lines already considered and rejected
for plus_line in &plus_lines[plus_index..(plus_index + considered)] {
- annotated_plus_lines.push(vec![(noop_insertion, plus_line)]);
+ annotated_plus_lines.push(vec![(noop_insertions[plus_index], plus_line)]);
line_alignment.push((None, Some(plus_index)));
plus_index += 1;
}
@@ -75,12 +77,12 @@ where
}
}
// No homolog was found for minus i; emit as unpaired.
- annotated_minus_lines.push(vec![(noop_deletion, minus_line)]);
+ annotated_minus_lines.push(vec![(noop_deletions[minus_index], minus_line)]);
line_alignment.push((Some(minus_index), None));
}
// Emit any remaining plus lines
for plus_line in &plus_lines[plus_index..] {
- annotated_plus_lines.push(vec![(noop_insertion, plus_line)]);
+ annotated_plus_lines.push(vec![(noop_insertions[plus_index], plus_line)]);
line_alignment.push((None, Some(plus_index)));
plus_index += 1;
}
@@ -724,20 +726,16 @@ mod tests {
expected_edits: Edits,
max_line_distance: f64,
) {
- let minus_lines = minus_lines
- .into_iter()
- .map(|s| s.to_string())
- .collect::<Vec<String>>();
- let plus_lines = plus_lines
- .into_iter()
- .map(|s| s.to_string())
- .collect::<Vec<String>>();
+ let (minus_lines, noop_deletions): (Vec<&str>, Vec<EditOperation>) =
+ minus_lines.into_iter().map(|s| (s, MinusNoop)).unzip();
+ let (plus_lines, noop_insertions): (Vec<&str>, Vec<EditOperation>) =
+ plus_lines.into_iter().map(|s| (s, PlusNoop)).unzip();
let actual_edits = infer_edits(
- &minus_lines,
- &plus_lines,
- MinusNoop,
+ minus_lines,
+ plus_lines,
+ noop_deletions,
Deletion,
- PlusNoop,
+ noop_insertions,
Insertion,
&*DEFAULT_TOKENIZATION_REGEXP,
max_line_distance,
diff --git a/src/features/color_moved.rs b/src/features/color_moved.rs
new file mode 100644
index 00000000..2879fb8d
--- /dev/null
+++ b/src/features/color_moved.rs
@@ -0,0 +1,24 @@
+use crate::features::OptionValueFunction;
+
+pub fn make_feature() -> Vec<(String, OptionValueFunction)> {
+ builtin_feature!([
+ (
+ "color-moved",
+ bool,
+ None,
+ _opt => true
+ ),
+ (
+ "color-moved-minus-style",
+ bool,
+ Some("color.diff.oldMoved"),
+ _opt => "red black"
+ ),
+ (
+ "color-moved-plus-style",
+ bool,
+ Some("color.diff.newMoved"),
+ _opt => "green black"
+ )
+ ])
+}
diff --git a/src/features/line_numbers.rs b/src/features/line_numbers.rs
index 1543f46d..092629c1 100644
--- a/src/features/line_numbers.rs
+++ b/src/features/line_numbers.rs
@@ -76,7 +76,7 @@ pub fn format_and_paint_line_numbers<'a>(
config.line_numbers_plus_style,
);
let ((minus_number, plus_number), (minus_style, plus_style)) = match state {
- State::HunkMinus => {
+ State::HunkMinus(_) => {
let m = *m_ref;
*m_ref += 1;
((Some(m), None), (minus_style, plus_style))
@@ -87,7 +87,7 @@ pub fn format_and_paint_line_numbers<'a>(
*p_ref += 1;
((Some(m), Some(p)), (zero_style, zero_style))
}
- State::HunkPlus => {
+ State::HunkPlus(_) => {
let p = *p_ref;
*p_ref += 1;
((None, Some(p)), (minus_style, plus_style))
diff --git a/src/features/mod.rs b/src/features/mod.rs
index 67dbd6ba..89081e4f 100644
--- a/src/features/mod.rs
+++ b/src/features/mod.rs
@@ -27,6 +27,10 @@ type OptionValueFunction = Box<dyn Fn(&cli::Opt, &Option<GitConfig>) -> Provenan
pub fn make_builtin_features() -> HashMap<String, BuiltinFeature> {
vec![
(
+ "color-moved".to_string(),
+ color_moved::make_feature().into_iter().collect(),
+ ),
+ (
"color-only".to_string(),
color_only::make_feature().into_iter().collect(),
),
@@ -82,6 +86,7 @@ macro_rules! builtin_feature {
}
}
+pub mod color_moved;
pub mod color_only;
pub mod diff_highlight;
pub mod diff_so_fancy;
diff --git a/src/features/side_by_side.rs b/src/features/side_by_side.rs
index eb224f16..3feb6e90 100644
--- a/src/features/side_by_side.rs
+++ b/src/features/side_by_side.rs
@@ -179,7 +179,7 @@ fn paint_left_panel_minus_line(
line_index,
&syntax_style_sections,
&diff_style_sections,
- &State::HunkMinus,
+ &State::HunkMinus(false),
line_numbers_data,
PanelSide::Left,
prefix,
@@ -190,7 +190,7 @@ fn paint_left_panel_minus_line(
panel_line_is_empty,
line_index,
diff_style_sections,
- &State::HunkMinus,
+ &State::HunkMinus(false),
background_color_extends_to_terminal_width,
config,
);
@@ -211,7 +211,7 @@ fn paint_right_panel_plus_line(
line_index,
&syntax_style_sections,
&diff_style_sections,
- &State::HunkPlus,
+ &State::HunkPlus(false),
line_numbers_data,
PanelSide::Right,
prefix,
@@ -222,7 +222,7 @@ fn paint_right_panel_plus_line(
panel_line_is_empty,
line_index,
diff_style_sections,
- &State::HunkPlus,
+ &State::HunkPlus(false),
background_color_extends_to_terminal_width,
config,
);
@@ -295,12 +295,12 @@ fn paint_minus_or_plus_panel_line(
(
&syntax_style_sections[index],
&diff_style_sections[index],
- state,
+ state.clone(),
)
} else {
let opposite_state = match *state {
- State::HunkMinus => &State::HunkPlus,
- State::HunkPlus => &State::HunkMinus,
+ State::HunkMinus(x) => State::HunkPlus(x),
+ State::HunkPlus(x) => State::HunkMinus(x),
_ => unreachable!(),
};
(
@@ -321,14 +321,14 @@ fn paint_minus_or_plus_panel_line(
);
// Knock back down spuriously incremented line numbers. See comment above.
- match (state, state_for_line_numbers_field) {
+ match (state, &state_for_line_numbers_field) {
(s, t) if s == t => {}
- (State::HunkPlus, State::HunkMinus) => {
+ (State::HunkPlus(_), State::HunkMinus(_)) => {
line_numbers_data
.as_mut()
.map(|d| d.hunk_minus_line_number -= 1);
}
- (State::HunkMinus, State::HunkPlus) => {
+ (State::HunkMinus(_), State::HunkPlus(_)) => {
line_numbers_data
.as_mut()
.map(|d| d.hunk_plus_line_number -= 1);
@@ -357,7 +357,7 @@ fn right_pad_left_panel_line(
// to form the other half of the line, then don't emit the empty line marker.
if panel_line_is_empty && line_index.is_some() {
match state {
- State::HunkMinus => Painter::mark_empty_line(
+ State::HunkMinus(_) => Painter::mark_empty_line(
&config.minus_empty_line_marker_style,
panel_line,
Some(" "),
@@ -428,7 +428,7 @@ fn right_fill_right_panel_line(
// 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(
+ State::HunkPlus(_) => Painter::mark_empty_line(
&config.plus_empty_line_marker_style,
panel_line,
Some(" "),
diff --git a/src/git_config_entry.rs b/src/git_config_entry.rs
index f6a59400..2764e2bd 100644
--- a/src/git_config_entry.rs
+++ b/src/git_config_entry.rs
@@ -6,11 +6,10 @@ use lazy_static::lazy_static;
use regex::Regex;
use crate::errors::*;
-use crate::style::Style;
#[derive(Clone, Debug)]
pub enum GitConfigEntry {
- Style(Style),
+ Style(String),
GitRemote(GitRemoteRepo),
Path(PathBuf),
}
diff --git a/src/options/set.rs b/src/options/set.rs
index b1d69b0c..e7932e4b 100644
--- a/src/options/set.rs
+++ b/src/options/set.rs
@@ -15,7 +15,6 @@ use crate::git_config;
use crate::git_config_entry::{self, GitConfigEntry};
use crate::options::option_value::{OptionValue, ProvenancedOptionValue};
use crate::options::theme;
-use crate::style::Style;
macro_rules! set_options {
([$( $field_ident:ident ),* ],
@@ -116,6 +115,9 @@ pub fn set_options(
set_options!(
[
+ color_moved,
+ color_moved_minus_style,
+ color_moved_plus_style,
color_only,
commit_decoration_style,
commit_style,
@@ -523,18 +525,15 @@ fn set_widths(
fn set_git_config_entries(opt: &mut cli::Opt, git_config: &mut git_config::GitConfig) {
// Styles
- for key in &["color.diff.old", "color.diff.new"] {
+ for key in &[
+ "color.diff.old",
+ "color.diff.new",
+ "color.diff.oldMoved",
+ "color.diff.newMoved",
+ ] {
if let Some(style_string) = git_config.get::<String>(key) {
- opt.git_config_entries.insert(
- key.to_string(),
- GitConfigEntry::Style(Style::from_str(
- &style_string,
- None,
- None,
- opt.computed.true_color,
- false,
- )),
- );
+ opt.git_config_entries
+ .insert(key.to_string(), GitConfigEntry::Style(style_string));
}
}
diff --git a/src/paint.rs b/src/paint.rs
index da158326..e10b4840 100644
--- a/src/paint.rs
+++ b/src/paint.rs
@@ -19,8 +19,8 @@ use crate::paint::superimpose_style_sections::superimpose_style_sections;
use crate::style::Style;
pub struct Painter<'a> {
- pub minus_lines: Vec<String>,
- pub plus_lines: Vec<String>,
+ pub minus_lines: Vec<(String, State)>,
+ pub plus_lines: Vec<(String, State)>,
pub writer: &'a mut dyn Write,
pub syntax: &'a SyntaxReference,
pub highlighter: HighlightLines<'a>,
@@ -117,15 +117,16 @@ impl<'a> Painter<'a> {
}
pub fn paint_buffered_minus_and_plus_lines(&mut self) {
+ let __ = false;
let minus_line_syntax_style_sections = Self::get_syntax_style_sections_for_lines(
&self.minus_lines,
- &State::HunkMinus,
+ &State::HunkMinus(__),
&mut self.highlighter,
self.config,
);
let plus_line_syntax_style_sections = Self::get_syntax_style_sections_for_lines(
&self.plus_lines,
- &State::HunkPlus,
+ &State::HunkPlus(__),
&mut self.highlighter,
self.config,
);
@@ -149,7 +150,7 @@ impl<'a> Painter<'a> {
Painter::paint_lines(
minus_line_syntax_style_sections,
minus_line_diff_style_sections,
- &State::HunkMinus,
+ self.minus_lines.iter().map(|(_, state)| state),
&mut self.output_buffer,
self.config,
&mut Some(&mut self.line_numbers_data),
@@ -166,7 +167,7 @@ impl<'a> Painter<'a> {
Painter::paint_lines(
plus_line_syntax_style_sections,
plus_line_diff_style_sections,
- &State::HunkPlus,
+ self.plus_lines.iter().map(|(_, state)| state),
&mut self.output_buffer,
self.config,
&mut Some(&mut self.line_numbers_data),
@@ -185,19 +186,20 @@ impl<'a> Painter<'a> {
}
pub fn paint_zero_line(&mut self, line: &str) {
+ let state = State::HunkZero;
let prefix = if self.config.keep_plus_minus_markers && !line.is_empty() {
&line[..1]
} else {
""
};
- let lines = vec![self.prepare(line, true)];
+ let lines = vec![(self.prepare(line, true), state.clone())];
let syntax_style_sections = Painter::get_syntax_style_sections_for_lines(
&lines,
- &State::HunkZero,
+ &state,
&mut self.highlighter,
&self.config,
);
- let diff_style_sections = vec![(self.config.zero_style, lines[0].as_str())];
+ 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 {
side_by_side::paint_zero_lines_side_by_side(
@@ -214,7 +216,7 @@ impl<'a> Painter<'a> {
Painter::paint_lines(
syntax_style_sections,
vec![diff_style_sections],
- &State::HunkZero,
+ [state].iter(),
&mut self.output_buffer,
self.config,
&mut Some(&mut self.line_numbers_data),
@@ -230,7 +232,7 @@ impl<'a> Painter<'a> {
pub fn paint_lines(
syntax_style_sections: Vec<Vec<(SyntectStyle, &str)>>,
diff_style_sections: Vec<Vec<(Style, &str)>>,
- state: &State,
+ states: impl Iterator<Item = &'a State>,
output_buffer: &mut String,
config: &config::Config,
line_numbers_data: &mut Option<&mut line_numbers::LineNumbersData>,
@@ -246,10 +248,11 @@ impl<'a> Painter<'a> {
// 2. We must ensure that we fill rightwards with the appropriate
// non-emph background color. In that case we don't use the last
// style of the line, because this might be emph.
- for (syntax_sections, diff_sections) in syntax_style_sections
- .iter()
- .zip_eq(diff_style_sections.iter())
- {
+ for (state, (syntax_sections, diff_sections)) in states.zip_eq(
+ syntax_style_sections
+ .iter()
+ .zip_eq(diff_style_sections.iter()),
+ ) {
let (mut line, line_is_empty) = Painter::paint_line(
syntax_sections,
diff_sections,
@@ -293,9 +296,11 @@ 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 => (config.minus_style, config.minus_non_emph_style),
+ State::HunkMinus(false) => (config.minus_style, config.minus_non_emph_style),
State::HunkZero => (config.zero_style, config.zero_style),