From 0c9bc37f108554dfec2a0f0f9c5d40efeb8524ed Mon Sep 17 00:00:00 2001 From: Yuya Nishihara Date: Tue, 27 Aug 2024 20:02:36 +0900 Subject: [PATCH] diff: buffer color-words context lines I'm testing simple conflicts diffs locally, and we'll probably need to handle consecutive context hunks when we add some form of unmaterialized conflicts diffs. Let's buffer context hunks (up to 1 right now.) The new code looks simpler. --- cli/src/diff_util.rs | 63 ++++++++++++++++++-------------------------- 1 file changed, 25 insertions(+), 38 deletions(-) diff --git a/cli/src/diff_util.rs b/cli/src/diff_util.rs index 5a206645a..8fcae42d2 100644 --- a/cli/src/diff_util.rs +++ b/cli/src/diff_util.rs @@ -461,65 +461,52 @@ fn show_color_words_diff_hunks( options: &ColorWordsOptions, ) -> io::Result<()> { let line_diff = Diff::by_line([left, right]); - let mut line_diff_hunks = line_diff.hunks().peekable(); let mut line_number = DiffLineNumber { left: 1, right: 1 }; + // Matching entries shouldn't appear consecutively in diff of two inputs. + // However, if the inputs have conflicts, there may be a hunk that can be + // resolved, resulting [matching, resolved, matching] sequence. + let mut contexts = Vec::new(); + let mut emitted = false; - // First "before" context - if let Some(DiffHunk::Matching(content)) = - line_diff_hunks.next_if(|hunk| matches!(hunk, DiffHunk::Matching(_))) - { - if line_diff_hunks.peek().is_some() { - line_number = show_color_words_context_lines( - formatter, - content, - line_number, - 0, - options.context, - )?; - } - } - while let Some(hunk) = line_diff_hunks.next() { + for hunk in line_diff.hunks() { match hunk { - // Middle "after"/"before" context - DiffHunk::Matching(content) if line_diff_hunks.peek().is_some() => { - line_number = show_color_words_context_lines( - formatter, - content, - line_number, - options.context, - options.context, - )?; - } - // Last "after" context - DiffHunk::Matching(content) => { - line_number = show_color_words_context_lines( - formatter, - content, - line_number, - options.context, - 0, - )?; - } + DiffHunk::Matching(content) => contexts.push(content), DiffHunk::Different(contents) => { + let num_after = if emitted { options.context } else { 0 }; + line_number = show_color_words_context_lines( + formatter, + &contexts, + line_number, + num_after, + options.context, + )?; + contexts.clear(); + emitted = true; line_number = show_color_words_diff_lines(formatter, &contents, line_number, options)?; } } } + if emitted { + show_color_words_context_lines(formatter, &contexts, line_number, options.context, 0)?; + } Ok(()) } /// Prints `num_after` lines, ellipsis, and `num_before` lines. fn show_color_words_context_lines( formatter: &mut dyn Formatter, - content: &[u8], + contents: &[&BStr], mut line_number: DiffLineNumber, num_after: usize, num_before: usize, ) -> io::Result { const SKIPPED_CONTEXT_LINE: &str = " ...\n"; - let mut lines = content.split_inclusive(|b| *b == b'\n').fuse(); + let mut lines = contents + .iter() + .flat_map(|content| content.split_inclusive(|b| *b == b'\n')) + .fuse(); for line in lines.by_ref().take(num_after) { show_color_words_line_number(formatter, Some(line_number.left), Some(line_number.right))?; show_color_words_inline_hunks(formatter, &[(DiffLineHunkSide::Both, line.as_ref())])?;