Repository: dandavison/delta
Pull request #834 (2021-12-07 04:35:01)

#833 refactoring
Refactoring for https://github.com/dandavison/delta/pull/833


Patch:
diff --git a/README.md b/README.md
index 83407a6..525a5eb 100644
--- a/README.md
+++ b/README.md
@@ -1007,9 +1007,10 @@ OPTIONS:
             How to extend the background color to the end of the line in side-by-side mode. Can be ansi (default) or
             spaces (default if output is not to a terminal). Has no effect if --width=variable is given
     -w, --width <width>
-            The width of underline/overline decorations. Examples: "72" (exactly 72 characters), 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
+            The width of underline/overline decorations. Examples: "72" (exactly 72 characters), "-2" (auto-detected
+            terminal width minus 2). An expression such as "74-2" is also valid (equivalent to 72 but may be useful if
+            the caller has a variable holding the value "74"). 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-stat-align-width <diff-stat-align-width>
             Width allocated for file paths in a diff stat section. If a relativized file path exceeds this width then
             the diff stat will be misaligned [default: 48]
diff --git a/src/cli.rs b/src/cli.rs
index 19b200f..e047889 100644
--- a/src/cli.rs
+++ b/src/cli.rs
@@ -674,8 +674,8 @@ pub struct Opt {
     pub line_fill_method: Option<String>,
 
     /// The width of underline/overline decorations. Examples: "72" (exactly 72 characters),
-    // "-2" (auto-detected terminal width minus 2). An expression such as "74-2" is also valid
-    // (equivalent to 72 but may be useful if the caller has a variable holding the value "74").
+    /// "-2" (auto-detected terminal width minus 2). An expression such as "74-2" is also valid
+    /// (equivalent to 72 but may be useful if the caller has a variable holding the value "74").
     /// 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.
     #[structopt(short = "w", long = "width")]
diff --git a/src/delta.rs b/src/delta.rs
index 8ad33b1..7fbcdf4 100644
--- a/src/delta.rs
+++ b/src/delta.rs
@@ -19,9 +19,9 @@ pub enum State {
     CommitMeta,                                             // In commit metadata section
     DiffHeader(DiffType), // In diff metadata section, between (possible) commit metadata and first hunk
     HunkHeader(DiffType, ParsedHunkHeader, String, String), // In hunk metadata line (diff_type, parsed, line, raw_line)
-    HunkZero(DiffType),                                     // In hunk; unchanged line (prefix)
+    HunkZero(DiffType, Option<String>), // In hunk; unchanged line (prefix, raw_line)
     HunkMinus(DiffType, Option<String>), // In hunk; removed line (diff_type, raw_line)
-    HunkPlus(DiffType, Option<String>),  // In hunk; added line (diff_type, raw_line)
+    HunkPlus(DiffType, Option<String>), // In hunk; added line (diff_type, raw_line)
     MergeConflict(MergeParents, merge_conflict::MergeConflictCommit),
     SubmoduleLog, // In a submodule section, with gitconfig diff.submodule = log
     SubmoduleShort(String), // In a submodule section, with gitconfig diff.submodule = short
diff --git a/src/features/line_numbers.rs b/src/features/line_numbers.rs
index 35674f9..fd2232f 100644
--- a/src/features/line_numbers.rs
+++ b/src/features/line_numbers.rs
@@ -81,7 +81,7 @@ pub fn linenumbers_and_styles<'a>(
             ((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))
diff --git a/src/features/side_by_side.rs b/src/features/side_by_side.rs
index e92be3b..44f17a6 100644
--- a/src/features/side_by_side.rs
+++ b/src/features/side_by_side.rs
@@ -234,7 +234,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(DiffType::Unified)];
+    let states = vec![State::HunkZero(DiffType::Unified, None)];
 
     let (states, syntax_style_sections, diff_style_sections) = wrap_zero_block(
         config,
@@ -496,7 +496,7 @@ fn pad_panel_line_to_width<'a>(
                 panel_line,
                 Some(" "),
             ),
-            State::HunkZero(_) => {}
+            State::HunkZero(_, _) => {}
             _ => unreachable!(),
         };
     };
diff --git a/src/handlers/hunk.rs b/src/handlers/hunk.rs
index e580dfa..bd6f636 100644
--- a/src/handlers/hunk.rs
+++ b/src/handlers/hunk.rs
@@ -30,7 +30,7 @@ impl<'a> StateMachine<'a> {
         matches!(
             self.state,
             State::HunkHeader(_, _, _, _)
-                | State::HunkZero(_)
+                | State::HunkZero(_, _)
                 | State::HunkMinus(_, _)
                 | State::HunkPlus(_, _)
         ) && !&*IS_WORD_DIFF
@@ -71,46 +71,36 @@ impl<'a> StateMachine<'a> {
                 }
                 let n_parents = diff_type.n_parents();
                 let line = self.painter.prepare(&self.line, n_parents);
-                let state = match self.config.inspect_raw_lines {
-                    cli::InspectRawLines::True
-                        if style::line_has_style_other_than(
-                            &self.raw_line,
-                            [*style::GIT_DEFAULT_MINUS_STYLE, self.config.git_minus_style].iter(),
-                        ) =>
-                    {
-                        let raw_line = self.painter.prepare_raw_line(&self.raw_line, n_parents);
-                        HunkMinus(diff_type, Some(raw_line))
-                    }
-                    _ => HunkMinus(diff_type, None),
-                };
+                let raw_line = self.maybe_raw_line(
+                    n_parents,
+                    &[*style::GIT_DEFAULT_MINUS_STYLE, self.config.git_minus_style],
+                );
+                let state = HunkMinus(diff_type, raw_line);
                 self.painter.minus_lines.push((line, state.clone()));
                 state
             }
             Some(HunkPlus(diff_type, _)) => {
                 let n_parents = diff_type.n_parents();
                 let line = self.painter.prepare(&self.line, n_parents);
-                let state = match self.config.inspect_raw_lines {
-                    cli::InspectRawLines::True
-                        if style::line_has_style_other_than(
-                            &self.raw_line,
-                            [*style::GIT_DEFAULT_PLUS_STYLE, self.config.git_plus_style].iter(),
-                        ) =>
-                    {
-                        let raw_line = self.painter.prepare_raw_line(&self.raw_line, n_parents);
-                        HunkPlus(diff_type, Some(raw_line))
-                    }
-                    _ => HunkPlus(diff_type, None),
-                };
+                let raw_line = self.maybe_raw_line(
+                    n_parents,
+                    &[*style::GIT_DEFAULT_PLUS_STYLE, self.config.git_plus_style],
+                );
+                let state = HunkPlus(diff_type, raw_line);
                 self.painter.plus_lines.push((line, state.clone()));
                 state
             }
-            Some(HunkZero(diff_type)) => {
+            Some(HunkZero(diff_type, _)) => {
                 // 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, diff_type.clone());
-                HunkZero(diff_type)
+                let n_parents = diff_type.n_parents();
+                let line = self.painter.prepare(&self.line, n_parents);
+                let raw_line = self.maybe_raw_line(n_parents, &[]);
+                let state = State::HunkZero(diff_type, raw_line);
+                self.painter.paint_zero_line(&line, state.clone());
+                state
             }
             _ => {
                 // The first character here could be e.g. '\' from '\ No newline at end of file'. This
@@ -121,12 +111,22 @@ impl<'a> StateMachine<'a> {
                     .output_buffer
                     .push_str(&self.painter.expand_tabs(self.raw_line.graphemes(true)));
                 self.painter.output_buffer.push('\n');
-                State::HunkZero(Unified)
+                State::HunkZero(Unified, None)
             }
         };
         self.painter.emit()?;
         Ok(true)
     }
+
+    fn maybe_raw_line(&self, n_parents: usize, non_raw_styles: &[style::Style]) -> Option<String> {
+        let emit_raw_line = self.config.inspect_raw_lines == cli::InspectRawLines::True
+            && style::line_has_style_other_than(&self.raw_line, non_raw_styles);
+        if emit_raw_line {
+            Some(self.painter.prepare_raw_line(&self.raw_line, n_parents))
+        } else {
+            None
+        }
+    }
 }
 
 // Return the new state corresponding to `new_line`, given the previous state. A return value of
@@ -138,7 +138,7 @@ fn new_line_state(new_line: &str, prev_state: &State) -> Option<State> {
 
     let diff_type = match prev_state {
         HunkMinus(Unified, _)
-        | HunkZero(Unified)
+        | HunkZero(Unified, _)
         | HunkPlus(Unified, _)
         | HunkHeader(Unified, _, _, _) => Unified,
         HunkHeader(Combined(Number(n), InMergeConflict::No), _, _, _) => {
@@ -150,12 +150,12 @@ fn new_line_state(new_line: &str, prev_state: &State) -> Option<State> {
             Combined(Number(prefix.len()), InMergeConflict::No)
         }
         HunkMinus(Combined(Prefix(prefix), in_merge_conflict), _)
-        | HunkZero(Combined(Prefix(prefix), in_merge_conflict))
+        | HunkZero(Combined(Prefix(prefix), in_merge_conflict), _)
         | HunkPlus(Combined(Prefix(prefix), in_merge_conflict), _) => {
             Combined(Number(prefix.len()), in_merge_conflict.clone())
         }
         HunkMinus(Combined(Number(n), in_merge_conflict), _)
-        | HunkZero(Combined(Number(n), in_merge_conflict))
+        | HunkZero(Combined(Number(n), in_merge_conflict), _)
         | HunkPlus(Combined(Number(n), in_merge_conflict), _) => {
             Combined(Number(*n), in_merge_conflict.clone())
         }
@@ -187,13 +187,13 @@ fn new_line_state(new_line: &str, prev_state: &State) -> Option<State> {
 
     match (prefix_char, prefix, in_merge_conflict) {
         (Some('-'), None, None) => Some(HunkMinus(Unified, None)),
-        (Some(' '), None, None) => Some(HunkZero(Unified)),
+        (Some(' '), None, None) => Some(HunkZero(Unified, None)),
         (Some('+'), None, None) => Some(HunkPlus(Unified, None)),
         (Some('-'), Some(prefix), Some(in_merge_conflict)) => {
             Some(HunkMinus(Combined(Prefix(prefix), in_merge_conflict), None))
         }
         (Some(' '), Some(prefix), Some(in_merge_conflict)) => {
-            Some(HunkZero(Combined(Prefix(prefix), in_merge_conflict)))
+            Some(HunkZero(Combined(Prefix(prefix), in_merge_conflict), None))
         }
         (Some('+'), Some(prefix), Some(in_merge_conflict)) => {
             Some(HunkPlus(Combined(Prefix(prefix), in_merge_conflict), None))
diff --git a/src/handlers/hunk_header.rs b/src/handlers/hunk_header.rs
index ee109f6..833bfc8 100644
--- a/src/handlers/hunk_header.rs
+++ b/src/handlers/hunk_header.rs
@@ -61,7 +61,7 @@ impl<'a> StateMachine<'a> {
                 }
                 DiffHeader(diff_type)
                 | HunkMinus(diff_type, _)
-                | HunkZero(diff_type)
+                | HunkZero(diff_type, _)
                 | HunkPlus(diff_type, _) => diff_type.clone(),
                 _ => Unified,
             };
diff --git a/src/handlers/merge_conflict.rs b/src/handlers/merge_conflict.rs
index 1ff06fc..d73060c 100644
--- a/src/handlers/merge_conflict.rs
+++ b/src/handlers/merge_conflict.rs
@@ -42,7 +42,7 @@ impl<'a> StateMachine<'a> {
         match self.state.clone() {
             HunkHeader(Combined(merge_parents, InMergeConflict::No), _, _, _)
             | HunkMinus(Combined(merge_parents, InMergeConflict::No), _)
-            | HunkZero(Combined(merge_parents, InMergeConflict::No))
+            | HunkZero(Combined(merge_parents, InMergeConflict::No), _)
             | HunkPlus(Combined(merge_parents, InMergeConflict::No), _) => {
                 handled_line = self.enter_merge_conflict(&merge_parents)
             }
@@ -120,7 +120,7 @@ impl<'a> StateMachine<'a> {
 
     fn store_line(&mut self, commit: MergeConflictCommit, state: State) -> bool {
         use State::*;
-        if let HunkMinus(diff_type, _) | HunkZero(diff_type) | HunkPlus(diff_type, _) = &state {
+        if let HunkMinus(diff_type, _) | HunkZero(diff_type, _) | HunkPlus(diff_type, _) = &state {
             let line = self.painter.prepare(&self.line, diff_type.n_parents());
             self.painter.merge_conflict_lines[commit].push((line, state));
             true
@@ -172,7 +172,7 @@ impl<'a> StateMachine<'a> {
             self.config,
         )?;
         self.painter.merge_conflict_lines.clear();
-        self.state = HunkZero(Combined(merge_parents.clone(), InMergeConflict::No));
+        self.state = HunkZero(Combined(merge_parents.clone(), InMergeConflict::No), None);
         Ok(())
     }
 }
diff --git a/src/paint.rs b/src/paint.rs
index 1ce7bf0..59dd38a 100644
--- a/src/paint.rs
+++ b/src/paint.rs
@@ -176,12 +176,10 @@ impl<'p> Painter<'p> {
         self.plus_lines.clear();
     }
 
-    pub fn paint_zero_line(&mut self, line: &str, diff_type: DiffType) {
-        let line = self.prepare(line, diff_type.n_parents());
-        let state = State::HunkZero(diff_type);
-        let lines = vec![(line, state.clone())];
+    pub fn paint_zero_line(&mut self, line: &str, state: State) {
+        let lines = &[(line.to_string(), state.clone())];
         let syntax_style_sections =
-            get_syntax_style_sections_for_lines(&lines, self.highlighter.as_mut(), self.config);
+            get_syntax_style_sections_for_lines(lines, self.highlighter.as_mut(), self.config);
         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 {
@@ -198,7 +196,7 @@ impl<'p> Painter<'p> {
             );
         } else {
             Painter::paint_lines(
-                &lines,
+                lines,
                 &syntax_style_sections,
                 &[diff_style_sections],
                 &[false],
@@ -328,7 +326,7 @@ impl<'p> Painter<'p> {
                     config.minus_style
                 }
             }
-            State::HunkZero(_) | State::HunkZeroWrapped => config.zero_style,
+            State::HunkZero(_, None) | State::HunkZeroWrapped => config.zero_style,
             State::HunkPlus(_, None) | State::HunkPlusWrapped => {
                 if let Some(true) = line_has_homolog {
                     config.plus_non_emph_style
@@ -336,7 +334,9 @@ impl<'p> Painter<'p> {
                     config.plus_style
                 }
             }
-            State::HunkMinus(_, Some(_)) | State::HunkPlus(_, Some(_)) => {
+            State::HunkMinus(_, Some(_))
+            | State::HunkZero(_, Some(_))
+            | State::HunkPlus(_, Some(_)) => {
                 // Consider the following raw line, from git colorMoved:
                 // ␛[1;36m+␛[m␛[1;36mclass·X:·pass␛[m␊ The last style section returned by
                 // parse_style_sections will be a default style associated with the terminal newline
@@ -472,14 +472,16 @@ impl<'p> Painter<'p> {
                     || config.minus_emph_style.is_syntax_highlighted
                     || config.minus_non_emph_style.is_syntax_highlighted
             }
-            State::HunkZero(_) => config.zero_style.is_syntax_highlighted,
+            State::HunkZero(_, None) => config.zero_style.is_syntax_highlighted,
             State::HunkPlus(_, None) => {
                 config.plus_style.is_syntax_highlighted
                     || config.plus_emph_style.is_syntax_highlighted
                     || config.plus_non_emph_style.is_syntax_highlighted
             }
             State::HunkHeader(_, _, _, _) => true,
-            State::HunkMinus(_, Some(_raw_line)) | State::HunkPlus(_, Some(_raw_line)) => {
+            State::HunkMinus(_, Some(_raw_line))
+            | State::HunkZero(_, Some(_raw_line))
+            | State::HunkPlus(_, Some(_raw_line)) => {
                 // It is possible that the captured raw line contains an ANSI
                 // style that has been mapped (via map-styles) to a delta Style
                 // with syntax-highlighting.
@@ -730,7 +732,7 @@ fn painted_prefix(state: State, config: &config::Config) -> Option<ANSIString> {
         (HunkMinus(Combined(MergeParents::Prefix(prefix), InMergeConflict::No), _), _) => {
             Some(config.minus_style.paint(prefix))
         }
-        (HunkZero(Combined(MergeParents::Prefix(prefix), InMergeConflict::No)), _) => {
+        (HunkZero(Combined(MergeParents::Prefix(prefix), InMergeConflict::No), _), _) => {
             Some(config.zero_style.paint(prefix))
         }
         (HunkPlus(Combined(MergeParents::Prefix(prefix), InMergeConflict::No), _), _) => {
@@ -738,7 +740,7 @@ fn painted_prefix(state: State, config: &config::Config) -> Option<ANSIString> {
         }
         // But otherwise we honor keep_plus_minus_markers
         (HunkMinus(_, _), true) => Some(config.minus_style.paint("-".to_string())),
-        (HunkZero(_), true) => Some(config.zero_style.paint(" ".to_string())),
+        (HunkZero(_, _), true) => Some(config.zero_style.paint(" ".to_string())),
         (HunkPlus(_, _), true) => Some(config.plus_style.paint("+".to_string())),
         _ => None,
     }
diff --git a/src/style.rs b/src/style.rs
index 6ffb1f0..fe0da88 100644
--- a/src/style.rs
+++ b/src/style.rs
@@ -355,7 +355,7 @@ lazy_static! {
     };
 }
 
-pub fn line_has_style_other_than<'a>(line: &str, styles: impl Iterator<Item = &'a Style>) -> bool {
+pub fn line_has_style_other_than(line: &str, styles: &[Style]) -> bool {
     if !ansi::string_starts_with_ansi_style_sequence(line) {
         return false;
     }
@@ -443,38 +443,35 @@ pub mod tests {
         let plus_line_from_unconfigured_git = "\x1b[32m+\x1b[m\x1b[32m____\x1b[m\n";
 
         // Unstyled lines should test negative, regardless of supplied styles.
-        assert!(!line_has_style_other_than("", [].iter()));
-        assert!(!line_has_style_other_than(
-            "",
-            [*GIT_DEFAULT_MINUS_STYLE].iter()
-        ));
+        assert!(!line_has_style_other_than("", &[]));
+        assert!(!line_has_style_other_than("", &[*GIT_DEFAULT_MINUS_STYLE]));
 
         // Lines from git should test negative when corresponding default is supplied
         assert!(!line_has_style_other_than(
             minus_line_from_unconfigured_git,
-            [*GIT_DEFAULT_MINUS_STYLE].iter()
+            &[*GIT_DEFAULT_MINUS_STYLE]
         ));
         assert!(!line_has_style_other_than(
             plus_line_from_unconfigured_git,
-            [*GIT_DEFAULT_PLUS_STYLE].iter()
+            &[*GIT_DEFAULT_PLUS_STYLE]
         ));
 
         // Styled lines should test positive when unless their style is supplied.
         assert!(line_has_style_other_than(
             minus_line_from_unconfigured_git,
-            [*GIT_DEFAULT_PLUS_STYLE].iter()
+            &[*GIT_DEFAULT_PLUS_STYLE]
         ));
         assert!(line_has_style_other_than(
             minus_line_from_unconfigured_git,
-            [].iter()
+            &[]
         ));
         assert!(line_has_style_other_than(
             plus_line_from_unconfigured_git,
-            [*GIT_DEFAULT_MINUS_STYLE].iter()
+            &[*GIT_DEFAULT_MINUS_STYLE]
         ));
         assert!(line_has_style_other_than(
             plus_line_from_unconfigured_git,
-            [].iter()
+            &[]
         ));
     }
 
diff --git a/src/subcommands/show_colors.rs b/src/subcommands/show_colors.rs
index b51dd8a..1c93970 100644
--- a/src/subcommands/show_colors.rs
+++ b/src/subcommands/show_colors.rs
@@ -45,7 +45,7 @@ pub fn show_colors() -> std::io::Result<()> {
                 painter.syntax_highlight_and_paint_line(
                     line,
                     paint::StyleSectionSpecifier::Style(style),
-                    delta::State::HunkZero(DiffType::Unified),
+                    delta::State::HunkZero(DiffType::Unified, None),
                     BgShouldFill::default(),
                 )
             }
@@ -64,7 +64,7 @@ pub fn show_colors() -> std::io::Result<()> {
                 painter.syntax_highlight_and_paint_line(
                     line,
                     paint::StyleSectionSpecifier::Style(style),
-                    delta::State::HunkZero(DiffType::Unified),
+                    delta::State::HunkZero(DiffType::Unified, None),
                     BgShouldFill::default(),
                 )
             }


Test patch:
diff --git a/src/tests/test_example_diffs.rs b/src/tests/test_example_diffs.rs
index 0244ef8..ce917c3 100644
--- a/src/tests/test_example_diffs.rs
+++ b/src/tests/test_example_diffs.rs
@@ -1543,7 +1543,7 @@ src/align.rs:71: impl<'a> Alignment<'a> { │
             1,
             "        for (i, x_i) in self.x.iter().enumerate() {",
             "rs",
-            State::HunkZero(DiffType::Unified),
+            State::HunkZero(DiffType::Unified, None),
             &config,
         );
     }