summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDan Davison <dandavison7@gmail.com>2021-11-29 10:37:35 -0500
committerDan Davison <dandavison7@gmail.com>2021-12-05 11:25:05 -0500
commit422954164f68b95fe9578ab1e0e1d1c80ca9345e (patch)
tree2b766093a5d57d683192da7e0cb4125375beae37
parentf73f0a8cbd8f66340817ab8b143f5a4459380647 (diff)
Handle combined diff format
With this commit combined diff format (https://git-scm.com/docs/git-diff#_combined_diff_format) is handled appropriately. However, there is no special handling of merge conflict markers. Fixes #189, #736
-rw-r--r--src/config.rs8
-rw-r--r--src/delta.rs34
-rw-r--r--src/features/line_numbers.rs6
-rw-r--r--src/features/side_by_side.rs16
-rw-r--r--src/handlers/diff_header.rs8
-rw-r--r--src/handlers/diff_header_diff.rs9
-rw-r--r--src/handlers/diff_header_misc.rs7
-rw-r--r--src/handlers/hunk.rs93
-rw-r--r--src/handlers/hunk_header.rs14
-rw-r--r--src/handlers/submodule.rs4
-rw-r--r--src/paint.rs101
-rw-r--r--src/subcommands/show_colors.rs4
-rw-r--r--src/tests/ansi_test_utils.rs7
-rw-r--r--src/tests/test_example_diffs.rs6
-rw-r--r--src/wrapping.rs4
15 files changed, 196 insertions, 125 deletions
diff --git a/src/config.rs b/src/config.rs
index af9ade09..5858afe5 100644
--- a/src/config.rs
+++ b/src/config.rs
@@ -145,11 +145,11 @@ pub struct Config {
impl Config {
pub fn get_style(&self, state: &State) -> &Style {
match state {
- State::HunkMinus(_) => &self.minus_style,
- State::HunkPlus(_) => &self.plus_style,
+ State::HunkMinus(_, _) => &self.minus_style,
+ State::HunkPlus(_, _) => &self.plus_style,
State::CommitMeta => &self.commit_style,
- State::DiffHeader => &self.file_style,
- State::HunkHeader(_, _) => &self.hunk_header_style,
+ State::DiffHeader(_) => &self.file_style,
+ State::HunkHeader(_, _, _) => &self.hunk_header_style,
State::SubmoduleLog => &self.file_style,
_ => delta_unreachable("Unreachable code reached in get_style."),
}
diff --git a/src/delta.rs b/src/delta.rs
index bbbce519..3f1a79d4 100644
--- a/src/delta.rs
+++ b/src/delta.rs
@@ -14,17 +14,17 @@ use crate::style::DecorationStyle;
#[derive(Clone, Debug, PartialEq)]
pub enum State {
- CommitMeta, // In commit metadata section
- DiffHeader, // In diff header section, between (possible) commit metadata and first hunk
- HunkHeader(String, String), // In hunk metadata line (line, raw_line)
- HunkZero, // In hunk; unchanged line
- HunkMinus(Option<String>), // In hunk; removed line (raw_line)
- HunkPlus(Option<String>), // In hunk; added line (raw_line)
- SubmoduleLog, // In a submodule section, with gitconfig diff.submodule = log
+ CommitMeta, // In commit metadata section
+ DiffHeader(DiffType), // In diff metadata section, between (possible) commit metadata and first hunk
+ HunkHeader(DiffType, String, String), // In hunk metadata line (line, raw_line)
+ HunkZero(Option<String>), // In hunk; unchanged line (prefix)
+ HunkMinus(Option<String>, Option<String>), // In hunk; removed line (prefix, raw_line)
+ HunkPlus(Option<String>, Option<String>), // In hunk; added line (prefix, raw_line)
+ SubmoduleLog, // In a submodule section, with gitconfig diff.submodule = log
SubmoduleShort(String), // In a submodule section, with gitconfig diff.submodule = short
Blame(String, Option<String>), // In a line of `git blame` output (commit, repeat_blame_line).
- GitShowFile, // In a line of `git show $revision:./path/to/file.ext` output
- Grep, // In a line of `git grep` output
+ GitShowFile, // In a line of `git show $revision:./path/to/file.ext` output
+ Grep, // In a line of `git grep` output
Unknown,
// The following elements are created when a line is wrapped to display it:
HunkZeroWrapped, // Wrapped unchanged line
@@ -32,6 +32,12 @@ pub enum State {
HunkPlusWrapped, // Wrapped added line
}
+#[derive(Clone, Debug, PartialEq)]
+pub enum DiffType {
+ Unified,
+ Combined(usize), // number of parent commits: https://git-scm.com/docs/git-diff#_combined_diff_format
+}
+
#[derive(Debug, PartialEq)]
pub enum Source {
GitDiff, // Coming from a `git diff` command
@@ -171,7 +177,9 @@ impl<'a> StateMachine<'a> {
/// Skip file metadata lines unless a raw diff style has been requested.
pub fn should_skip_line(&self) -> bool {
- self.state == State::DiffHeader && self.should_handle() && !self.config.color_only
+ matches!(self.state, State::DiffHeader(_))
+ && self.should_handle()
+ && !self.config.color_only
}
/// Emit unchanged any line that delta does not handle.
@@ -211,7 +219,11 @@ pub fn format_raw_line<'a>(line: &'a str, config: &Config) -> Cow<'a, str> {
/// * git diff
/// * diff -u
fn detect_source(line: &str) -> Source {
- if line.starts_with("commit ") || line.starts_with("diff --git ") {
+ if line.starts_with("commit ")
+ || line.starts_with("diff --git ")
+ || line.starts_with("diff --cc ")
+ || line.starts_with("diff --combined ")
+ {
Source::GitDiff
} else if line.starts_with("diff -u")
|| line.starts_with("diff -ru")
diff --git a/src/features/line_numbers.rs b/src/features/line_numbers.rs
index 0d366f8a..59218f75 100644
--- a/src/features/line_numbers.rs
+++ b/src/features/line_numbers.rs
@@ -76,18 +76,18 @@ pub fn linenumbers_and_styles<'a>(
config.line_numbers_style_minusplus[Plus],
);
let ((minus_number, plus_number), (minus_style, plus_style)) = match state {
- State::HunkMinus(_) => {
+ State::HunkMinus(_, _) => {
line_numbers_data.line_number[Left] += increment as usize;
((Some(nr_left), None), (minus_style, plus_style))
}
State::HunkMinusWrapped => ((None, None), (minus_style, plus_style)),
- State::HunkZero => {
+ State::HunkZero(_) => {
line_numbers_data.line_number[Left] += increment as usize;
line_numbers_data.line_number[Right] += increment as usize;
((Some(nr_left), Some(nr_right)), (zero_style, zero_style))
}
State::HunkZeroWrapped => ((None, None), (zero_style, zero_style)),
- State::HunkPlus(_) => {
+ State::HunkPlus(_, _) => {
line_numbers_data.line_number[Right] += increment as usize;
((None, Some(nr_right)), (minus_style, plus_style))
}
diff --git a/src/features/side_by_side.rs b/src/features/side_by_side.rs
index f4960d76..85b066cb 100644
--- a/src/features/side_by_side.rs
+++ b/src/features/side_by_side.rs
@@ -180,7 +180,7 @@ pub fn paint_minus_and_plus_lines_side_by_side(
&lines_have_homolog[Left],
match minus_line_index {
Some(i) => &line_states[Left][i],
- None => &State::HunkMinus(None),
+ None => &State::HunkMinus(None, None),
},
&mut Some(line_numbers_data),
bg_should_fill[Left],
@@ -201,7 +201,7 @@ pub fn paint_minus_and_plus_lines_side_by_side(
&lines_have_homolog[Right],
match plus_line_index {
Some(i) => &line_states[Right][i],
- None => &State::HunkPlus(None),
+ None => &State::HunkPlus(None, None),
},
&mut Some(line_numbers_data),
bg_should_fill[Right],
@@ -222,7 +222,7 @@ pub fn paint_zero_lines_side_by_side<'a>(
painted_prefix: Option<ansi_term::ANSIString>,
background_color_extends_to_terminal_width: BgShouldFill,
) {
- let states = vec![State::HunkZero];
+ let states = vec![State::HunkZero(None)];
let (states, syntax_style_sections, diff_style_sections) = wrap_zero_block(
config,
@@ -418,8 +418,8 @@ fn paint_minus_or_plus_panel_line<'a>(
)
} else {
let opposite_state = match state {
- State::HunkMinus(x) => State::HunkPlus(x.clone()),
- State::HunkPlus(x) => State::HunkMinus(x.clone()),
+ State::HunkMinus(_, s) => State::HunkPlus(None, s.clone()),
+ State::HunkPlus(_, s) => State::HunkMinus(None, s.clone()),
_ => unreachable!(),
};
(
@@ -470,17 +470,17 @@ fn pad_panel_line_to_width<'a>(
// 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(" "),
),
- State::HunkPlus(_) => Painter::mark_empty_line(
+ State::HunkPlus(_, _) => Painter::mark_empty_line(
&config.plus_empty_line_marker_style,
panel_line,
Some(" "),
),
- State::HunkZero => {}
+ State::HunkZero(_) => {}
_ => unreachable!(),
};
};
diff --git a/src/handlers/diff_header.rs b/src/handlers/diff_header.rs
index e2888797..1a703393 100644
--- a/src/handlers/diff_header.rs
+++ b/src/handlers/diff_header.rs
@@ -5,7 +5,7 @@ use unicode_segmentation::UnicodeSegmentation;
use super::draw;
use crate::config::Config;
-use crate::delta::{Source, State, StateMachine};
+use crate::delta::{DiffType, Source, State, StateMachine};
use crate::features;
use crate::paint::Painter;
@@ -24,7 +24,7 @@ pub enum FileEvent {
impl<'a> StateMachine<'a> {
#[inline]
fn test_diff_header_minus_line(&self) -> bool {
- (self.state == State::DiffHeader || self.source == Source::DiffUnified)
+ (matches!(self.state, State::DiffHeader(_)) || self.source == Source::DiffUnified)
&& (self.line.starts_with("--- ")
|| self.line.starts_with("rename from ")
|| self.line.starts_with("copy from ")
@@ -57,7 +57,7 @@ impl<'a> StateMachine<'a> {
self.minus_file_event = file_event;
if self.source == Source::DiffUnified {
- self.state = State::DiffHeader;
+ self.state = State::DiffHeader(DiffType::Unified);
self.painter
.set_syntax(get_file_extension_from_marker_line(&self.line));
} else {
@@ -85,7 +85,7 @@ impl<'a> StateMachine<'a> {
#[inline]
fn test_diff_header_plus_line(&self) -> bool {
- (self.state == State::DiffHeader || self.source == Source::DiffUnified)
+ (matches!(self.state, State::DiffHeader(_)) || self.source == Source::DiffUnified)
&& (self.line.starts_with("+++ ")
|| self.line.starts_with("rename to ")
|| self.line.starts_with("copy to ")
diff --git a/src/handlers/diff_header_diff.rs b/src/handlers/diff_header_diff.rs
index 78ec2a98..869e40ef 100644
--- a/src/handlers/diff_header_diff.rs
+++ b/src/handlers/diff_header_diff.rs
@@ -1,4 +1,4 @@
-use crate::delta::{State, StateMachine};
+use crate::delta::{DiffType, State, StateMachine};
impl<'a> StateMachine<'a> {
#[inline]
@@ -12,7 +12,12 @@ impl<'a> StateMachine<'a> {
return Ok(false);
}
self.painter.paint_buffered_minus_and_plus_lines();
- self.state = State::DiffHeader;
+ self.state =
+ if self.line.starts_with("diff --cc ") || self.line.starts_with("diff --combined ") {
+ State::DiffHeader(DiffType::Combined(2)) // We will confirm the number of parents when we see the hunk header
+ } else {
+ State::DiffHeader(DiffType::Unified)
+ };
self.handled_diff_header_header_line_file_pair = None;
self.diff_line = self.line.clone();
if !self.should_skip_line() {
diff --git a/src/handlers/diff_header_misc.rs b/src/handlers/diff_header_misc.rs
index f112d46b..eb0833de 100644
--- a/src/handlers/diff_header_misc.rs
+++ b/src/handlers/diff_header_misc.rs
@@ -1,4 +1,4 @@
-use crate::delta::{Source, State, StateMachine};
+use crate::delta::{DiffType, Source, State, StateMachine};
impl<'a> StateMachine<'a> {
#[inline]
@@ -11,6 +11,9 @@ impl<'a> StateMachine<'a> {
if !self.test_diff_header_misc_cases() {
return Ok(false);
}
- self.handle_additional_cases(State::DiffHeader)
+ self.handle_additional_cases(match self.state {
+ State::DiffHeader(_) => self.state.clone(),
+ _ => State::DiffHeader(DiffType::Unified),
+ })
}
}
diff --git a/src/handlers/hunk.rs b/src/handlers/hunk.rs
index 75e0bb6f..93ac70ca 100644
--- a/src/handlers/hunk.rs
+++ b/src/handlers/hunk.rs
@@ -1,7 +1,10 @@
+use std::cmp::min;
+
use lazy_static::lazy_static;
use crate::cli;
-use crate::delta::{State, StateMachine};
+use crate::config::delta_unreachable;
+use crate::delta::{DiffType, State, StateMachine};
use crate::style;
use crate::utils::process::{self, CallingProcess};
use unicode_segmentation::UnicodeSegmentation;
@@ -26,7 +29,10 @@ impl<'a> StateMachine<'a> {
fn test_hunk_line(&self) -> bool {
matches!(
self.state,
- State::HunkHeader(_, _) | State::HunkZero | State::HunkMinus(_) | State::HunkPlus(_)
+ State::HunkHeader(_, _, _)
+ | State::HunkZero(_)
+ | State::HunkMinus(_, _)
+ | State::HunkPlus(_, _)
) && !&*IS_WORD_DIFF
}
@@ -37,6 +43,7 @@ impl<'a> StateMachine<'a> {
// highlighting according to inferred edit operations. In the case of
// an unchanged line, we paint it immediately.
pub fn handle_hunk_line(&mut self) -> std::io::Result<bool> {
+ use State::*;
// A true hunk line should start with one of: '+', '-', ' '. However, handle_hunk_line
// handles all lines until the state transitions away from the hunk states.
if !self.test_hunk_line() {
@@ -50,16 +57,17 @@ impl<'a> StateMachine<'a> {
{
self.painter.paint_buffered_minus_and_plus_lines();
}
- if let State::HunkHeader(line, raw_line) = &self.state.clone() {
+ if let State::HunkHeader(_, line, raw_line) = &self.state.clone() {
self.emit_hunk_header_line(line, raw_line)?;
}
- self.state = match self.line.chars().next() {
- Some('-') => {
- if let State::HunkPlus(_) = self.state {
+ self.state = match new_line_state(&self.line, &self.state) {
+ Some(HunkMinus(prefix, _)) => {
+ if let HunkPlus(_, _) = self.state {
// We have just entered a new subhunk; process the previous one
// and flush the line buffers.
self.painter.paint_buffered_minus_and_plus_lines();
}
+ let line = self.painter.prepare(&self.line, prefix.as_deref());
let state = match self.config.inspect_raw_lines {
cli::InspectRawLines::True
if style::line_has_style_other_than(
@@ -67,16 +75,18 @@ impl<'a> StateMachine<'a> {
[*style::GIT_DEFAULT_MINUS_STYLE, self.config.git_minus_style].iter(),
) =>
{
- State::HunkMinus(Some(self.painter.prepare_raw_line(&self.raw_line)))
+ let raw_line = self
+ .painter
+ .prepare_raw_line(&self.raw_line, prefix.as_deref());
+ HunkMinus(prefix, Some(raw_line))
}
- _ => State::HunkMinus(None),
+ _ => HunkMinus(prefix, None),
};
- self.painter
- .minus_lines
- .push((self.painter.prepare(&self.line), state.clone()));
+ self.painter.minus_lines.push((line, state.clone()));
state
}
- Some('+') => {
+ Some(HunkPlus(prefix, _)) => {
+ let line = self.painter.prepare(&self.line, prefix.as_deref());
let state = match self.config.inspect_raw_lines {
cli::InspectRawLines::True
if style::line_has_style_other_than(
@@ -84,37 +94,70 @@ impl<'a> StateMachine<'a> {
[*style::GIT_DEFAULT_PLUS_STYLE, self.config.git_plus_style].iter(),
) =>
{
- State::HunkPlus(Some(self.painter.prepare_raw_line(&self.raw_line)))
+ let raw_line = self
+ .painter
+ .prepare_raw_line(&self.raw_line, prefix.as_deref());
+ HunkPlus(prefix, Some(raw_line))
}
- _ => State::HunkPlus(None),
+ _ => HunkPlus(prefix, None),
};
- self.painter
- .plus_lines
- .push((self.painter.prepare(&self.line), state.clone()));
+ self.painter.plus_lines.push((line, state.clone()));
state
}
- Some(' ') => {
+ Some(HunkZero(prefix)) => {
+ // We are in a zero (unchanged) line, therefore we have just exited a subhunk (a
+ // sequence of consecutive minus (removed) and/or plus (added) lines). Process that
+ // subhunk and flush the line buffers.
self.painter.paint_buffered_minus_and_plus_lines();
- self.painter.paint_zero_line(&self.line);
- State::HunkZero
+ self.painter.paint_zero_line(&self.line, prefix.clone());
+ HunkZero(prefix)
}
_ => {
// The first character here could be e.g. '\' from '\ No newline at end of file'. This
// is not a hunk line, but the parser does not have a more accurate state corresponding
// to this.
-
- // We are in a zero (unchanged) line, therefore we have just exited a subhunk (a
- // sequence of consecutive minus (removed) and/or plus (added) lines). Process that
- // subhunk and flush the line buffers.
self.painter.paint_buffered_minus_and_plus_lines();
self.painter
.output_buffer
.push_str(&self.painter.expand_tabs(self.raw_line.graphemes(true)));
self.painter.output_buffer.push('\n');
- State::HunkZero
+ State::HunkZero(None)
}
};
self.painter.emit()?;
Ok(true)
}
}
+
+fn new_line_state(new_line: &str, prev_state: &State) -> Option<State> {
+ use State::*;
+ let diff_type = match prev_state {
+ HunkMinus(None, _) | HunkZero(None) | HunkPlus(None, _) => DiffType::Unified,
+ HunkHeader(diff_type, _, _) => diff_type.clone(),
+ HunkMinus(Some(prefix), _) | HunkZero(Some(prefix)) | HunkPlus(Some(prefix), _) => {
+ DiffType::Combined(prefix.len())
+ }
+ _ => delta_unreachable(&format!("diff_type: unexpected state: {:?}", prev_state)),
+ };
+
+ let (prefix_char, prefix) = match diff_type {
+ DiffType::Unified => (new_line.chars().next(), None),
+ DiffType::Combined(n_parents) => {
+ let prefix = &new_line[..min(n_parents, new_line.len())];
+ let prefix_char = match prefix.chars().find(|c| c == &'-' || c == &'+') {
+ Some(c) => Some(c),
+ None => match prefix.chars().find(|c| c != &' ') {
+ None => Some(' '),
+ Some(_) => None,
+ },
+ };
+ (prefix_char, Some(prefix.to_string()))
+ }
+ };
+ match prefix_char {
+ Some('-') => Some(HunkMinus(prefix, None)),
+ Some(' ') => Some(HunkZero(prefix)),
+ Some('+') => Some(HunkPlus(prefix, None)),
+ _ => None,
+ }
+}
diff --git a/src/handlers/hunk_header.rs b/src/handlers/hunk_header.rs
index dd851509..39c223d6 100644
--- a/src/handlers/hunk_header.rs
+++ b/src/handlers/hunk_header.rs
@@ -26,7 +26,7 @@ use regex::Regex;
use super::draw;
use crate::config::Config;
-use crate::delta::{self, State, StateMachine};
+use crate::delta::{self, DiffType, State, StateMachine};
use crate::paint::{self, BgShouldFill, Painter, StyleSectionSpecifier};
use crate::style::DecorationStyle;
@@ -40,7 +40,15 @@ impl<'a> StateMachine<'a> {
if !self.test_hunk_header_line() {
return Ok(false);
}
- self.state = State::HunkHeader(self.line.clone(), self.raw_line.clone());
+ let diff_type = match &self.state {
+ State::DiffHeader(DiffType::Combined(_)) => {
+ // https://git-scm.com/docs/git-diff#_combined_diff_format
+ let n_parents = self.line.chars().take_while(|c| c == &'@').count() - 1;
+ DiffType::Combined(n_parents)
+ }
+ _ => DiffType::Unified,
+ };
+ self.state = State::HunkHeader(diff_type, self.line.clone(), self.raw_line.clone());
Ok(true)
}
@@ -251,7 +259,7 @@ fn write_to_output_buffer(
painter.syntax_highlight_and_paint_line(
&line,
StyleSectionSpecifier::Style(config.hunk_header_style),
- delta::State::HunkHeader("".to_owned(), "".to_owned()),
+ delta::State::HunkHeader(DiffType::Unified, "".to_owned(), "".to_owned()),
BgShouldFill::No,
);
painter.output_buffer.pop(); // trim newline
diff --git a/src/handlers/submodule.rs b/src/handlers/submodule.rs
index 4350c561..04e273e9 100644
--- a/src/handlers/submodule.rs
+++ b/src/handlers/submodule.rs
@@ -18,7 +18,7 @@ impl<'a> StateMachine<'a> {
#[inline]
fn test_submodule_short_line(&self) -> bool {
- matches!(self.state, State::HunkHeader(_, _))
+ matches!(self.state, State::HunkHeader(_, _, _))
&& self.line.starts_with("-Subproject commit ")
|| matches!(self.state, State::SubmoduleShort(_))
&& self.line.starts_with("+Subproject commit ")
@@ -29,7 +29,7 @@ impl<'a> StateMachine<'a> {
return Ok(false);
}
if let Some(commit) = get_submodule_short_commit(&self.line) {
- if let State::HunkHeader(_, _) = self.state {
+ if let State::HunkHeader(_, _, _) = self.state {
self.state = State::SubmoduleShort(commit.to_owned());
} else if let State::SubmoduleShort(minus_commit) = &self.state {
self.painter.emit()?;
diff --git a/src/paint.rs b/src/paint.rs
index 5821ee92..0ef92dbd 100644
--- a/src/paint.rs
+++ b/src/paint.rs
@@ -1,6 +1,7 @@
use std::collections::HashMap;
use std::io::Write;
+use ansi_term::ANSIString;
use itertools::Itertools;
use syntect::easy::HighlightLines;
use syntect::highlighting::Style as SyntectStyle;
@@ -122,26 +123,33 @@ impl<'p> Painter<'p> {
// Terminating with newline character is necessary for many of the sublime syntax definitions to
// highlight correctly.
// See https://docs.rs/syntect/3.2.0/syntect/parsing/struct.SyntaxSetBuilder.html#method.add_from_folder
- pub fn prepare(&self, line: &str) -> String {
+ pub fn prepare(&self, line: &str, prefix: Option<&str>) -> String {
if !line.is_empty() {
let mut line = line.graphemes(true);
- // The first column contains a -/+/space character, added by git. We remove it now so that
- // it is not present during syntax highlighting or wrapping. If --keep-plus-minus-markers is
- // in effect this character is re-inserted in Painter::paint_line.
- line.next();
+ // The initial columns contain -/+/space characters, added by git. Remove them now so
+ // they are not present during syntax highlighting or wrapping. If
+ // --keep-plus-minus-markers is in effect this prefix is re-inserted in
+ // Painter::paint_line.
+ let prefix_length = prefix.map(|s| s.len()).unwrap_or(1);
+ for _ in 0..prefix_length {
+ line.next();
+ }
format!("{}\n", self.expand_tabs(line))
} else {
"\n".to_string()
}
}
- // Remove initial -/+ character, expand tabs as spaces, retaining ANSI sequences. Terminate with
+ // Remove initial -/+ characters, expand tabs as spaces, retaining ANSI sequences. Terminate with
// newline character.
- pub fn prepare_raw_line(&self, raw_line: &str) -> String {
+ pub fn prepare_raw_line(&self, raw_line: &str, prefix: Option<&str>) -> String {
format!(
"{}\n",
- ansi::ansi_preserving_slice(&self.expand_tabs(raw_line.graphemes(true)), 1),
+ ansi::ansi_preserving_slice(
+ &self.expand_tabs(raw_line.graphemes(true)),
+ prefix.map(|s| s.len()).unwrap_or(1)
+ ),
)
}
@@ -207,11 +215,6 @@ impl<'p> Painter<'p> {
&mut self.output_buffer,
self.config,
&mut self.line_numbers_data.as_mut(),
- if self.config.keep_plus_minus_markers {
- Some(self.config.minus_style.paint("-"))
- } else {
- None
- },
Some(self.config.minus_empty_line_marker_style),
BgShouldFill::default(),
);
@@ -225,11 +228,6 @@ impl<'p> Painter<'p> {
&mut self.output_buffer,
self.config,
&mut self.line_numbers_data.as_mut(),
- if self.config.keep_plus_minus_markers {
- Some(self.config.plus_style.paint("+"))
- } else {
- None
- },
Some(self.config.plus_empty_line_marker_style),
BgShouldFill::default(),
);
@@ -239,16 +237,10 @@ impl<'p> Painter<'p> {
self.plus_lines.clear();
}
- pub fn paint_zero_line(&mut self, line: &str) {
- let state = State::HunkZero;
- let painted_prefix = if self.config.keep_plus_minus_markers && !line.is_empty() {
- // A zero line here still contains the " " prefix, so use it.
- Some(self.config.zero_style.paint(&line[..1]))
- } else {
- None
- };
-
- let lines = vec![(self.prepare(line), state)];
+ pub fn paint_zero_line(&mut self, line: &str, prefix: Option<String>) {
+ let line = self.prepare(line, prefix.as_deref());
+ let state = State::HunkZero(prefix);
+ let lines = vec![(line, state.clone())];
let syntax_style_sections = Painter::get_syntax_style_sections_for_lines(
&lines,
self.highlighter.as_mut(),
@@ -265,7 +257,7 @@ impl<'p> Painter<'p> {
&mut self.output_buffer,
self.config,
&mut self.line_numbers_data.as_mut(),
- painted_prefix,
+ painted_prefix(state, self.config),
BgShouldFill::With(BgFillMethod::Spaces),
);
} else {
@@ -277,7 +269,6 @@ impl<'p> Painter<'p> {
&mut self.output_buffer,
self.config,
&mut self.line_numbers_data.as_mut(),
- painted_prefix,
None,
BgShouldFill::With(BgFillMethod::Spaces),
);
@@ -295,7 +286,6 @@ impl<'p> Painter<'p> {
output_buffer: &mut String,
config: &config::Config,
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: BgShouldFill,
) {
@@ -318,7 +308,7 @@ impl<'p> Painter<'p> {
state,
line_numbers_data,
None,
- painted_prefix.clone(),
+ painted_prefix(state.clone(), config),
config,
);
let (bg_fill_mode, fill_style) =
@@ -384,7 +374,6 @@ impl<'p> Painter<'p> {
self.config,
&mut None,
None,
- None,
background_color_extends_to_terminal_width,
);
}
@@ -399,22 +388,22 @@ impl<'p> Painter<'p> {
config: &config::Config,
) -> (Option<BgFillMethod>, Style) {
let fill_style = match state {
- State::HunkMinus(None) | State::HunkMinusWrapped => {
+ State::HunkMinus(_, None) | State::HunkMinusWrapped => {
if let Some(true) = line_has_homolog {
config.minus_non_emph_style
} else {
config.minus_style
}
}
- State::HunkZero | State::HunkZeroWrapped => config.zero_s