From 92fa3fb3de67a0e1d26e30bccded9025581c6738 Mon Sep 17 00:00:00 2001 From: Wilfred Hughes Date: Sat, 20 Jul 2024 23:09:06 -0700 Subject: [PATCH] Ensure files with no common content are aligned --- CHANGELOG.md | 5 +++++ sample_files/all_changed_1.js | 1 + sample_files/all_changed_2.js | 1 + sample_files/compare.expected | 7 +++++-- src/line_parser.rs | 32 +++++++++++++++++++++++++++- src/parse/syntax.rs | 39 +++++++++++++++++++++++++++++++++-- 6 files changed, 80 insertions(+), 5 deletions(-) create mode 100644 sample_files/all_changed_1.js create mode 100644 sample_files/all_changed_2.js diff --git a/CHANGELOG.md b/CHANGELOG.md index b4a8d33a45..cb956cf550 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,10 @@ ## 0.60 (unreleased) +### Display + +Fixed an issue where files with no common content would show duplicate +hunks. + ## 0.59 (released 20th July 2024) ### Diffing diff --git a/sample_files/all_changed_1.js b/sample_files/all_changed_1.js new file mode 100644 index 0000000000..7898192261 --- /dev/null +++ b/sample_files/all_changed_1.js @@ -0,0 +1 @@ +a diff --git a/sample_files/all_changed_2.js b/sample_files/all_changed_2.js new file mode 100644 index 0000000000..6178079822 --- /dev/null +++ b/sample_files/all_changed_2.js @@ -0,0 +1 @@ +b diff --git a/sample_files/compare.expected b/sample_files/compare.expected index d7b192402c..abf93c3298 100644 --- a/sample_files/compare.expected +++ b/sample_files/compare.expected @@ -10,6 +10,9 @@ sample_files/added_line_1.txt sample_files/added_line_2.txt sample_files/align_footer_1.txt sample_files/align_footer_2.txt d640bd2de31e56a39f0efb92aff0f379 - +sample_files/all_changed_1.js sample_files/all_changed_2.js +40eb536d8b626e27ae227a090fb05f25 - + sample_files/apex_1.cls sample_files/apex_2.cls 8e477350907734ac4d5201752523dff3 - @@ -134,7 +137,7 @@ sample_files/load_1.js sample_files/load_2.js 22365043359164f717d495336d86b996 - sample_files/long_line_1.txt sample_files/long_line_2.txt -40e22d364bb714421eec24b8ef808f01 - +7fc50bd547f0c20fda89a1931e5eb61e - sample_files/lua_1.lua sample_files/lua_2.lua 8318115b642361955346cc620bc3ad86 - @@ -227,7 +230,7 @@ sample_files/simple_1.scss sample_files/simple_2.scss 265261e79df78abfc09392d72a0273d8 - sample_files/simple_1.txt sample_files/simple_2.txt -416d05b8a02e41cb70b78d28cd3153d9 - +6fd97a544afd0a3be7eebba75f82f696 - sample_files/slider_1.rs sample_files/slider_2.rs d10128f3d9ffc4a8670f417a9371bacc - diff --git a/src/line_parser.rs b/src/line_parser.rs index d54731d598..208652916d 100644 --- a/src/line_parser.rs +++ b/src/line_parser.rs @@ -1,7 +1,7 @@ //! A fallback "parser" for plain text. use lazy_static::lazy_static; -use line_numbers::LinePositions; +use line_numbers::{LinePositions, SingleLineSpan}; use regex::Regex; use crate::words::split_words; @@ -118,9 +118,12 @@ pub(crate) fn change_positions(lhs_src: &str, rhs_src: &str) -> Vec let mut rhs_offset = 0; let mut mps = vec![]; + + let mut seen_unchanged = false; for (kind, lhs_lines, rhs_lines) in changed_parts(lhs_src, rhs_src) { match kind { TextChangeKind::Unchanged => { + seen_unchanged = true; for (lhs_line, rhs_line) in lhs_lines.iter().zip(rhs_lines) { let lhs_pos = lhs_lp.from_region(lhs_offset, lhs_offset + line_len_in_bytes(lhs_line)); @@ -210,6 +213,33 @@ pub(crate) fn change_positions(lhs_src: &str, rhs_src: &str) -> Vec } } + // If there are no unchanged items, insert a dummy item at the + // beginning of both files with a width of zero. This gives + // display something to use when aligning. + if !seen_unchanged { + let lhs_pos = SingleLineSpan { + line: 0.into(), + start_col: 0, + end_col: 0, + }; + let rhs_pos = SingleLineSpan { + line: 0.into(), + start_col: 0, + end_col: 0, + }; + mps.insert( + 0, + MatchedPos { + kind: MatchKind::UnchangedToken { + highlight: TokenKind::Atom(AtomKind::Normal), + self_pos: vec![lhs_pos], + opposite_pos: vec![rhs_pos], + }, + pos: lhs_pos, + }, + ); + } + mps } diff --git a/src/parse/syntax.rs b/src/parse/syntax.rs index 65167fda32..1f08333457 100644 --- a/src/parse/syntax.rs +++ b/src/parse/syntax.rs @@ -875,7 +875,37 @@ pub(crate) fn change_positions<'a>( change_map: &ChangeMap<'a>, ) -> Vec { let mut positions = Vec::new(); - change_positions_(nodes, change_map, &mut positions); + let mut seen_unchanged = false; + + change_positions_(nodes, change_map, &mut positions, &mut seen_unchanged); + + // If there are no unchanged items, insert a dummy item at the + // beginning of both files with a width of zero. This gives + // display something to use when aligning. + if !seen_unchanged { + let lhs_pos = SingleLineSpan { + line: 0.into(), + start_col: 0, + end_col: 0, + }; + let rhs_pos = SingleLineSpan { + line: 0.into(), + start_col: 0, + end_col: 0, + }; + positions.insert( + 0, + MatchedPos { + kind: MatchKind::UnchangedToken { + highlight: TokenKind::Atom(AtomKind::Normal), + self_pos: vec![lhs_pos], + opposite_pos: vec![rhs_pos], + }, + pos: lhs_pos, + }, + ); + } + positions } @@ -883,12 +913,17 @@ fn change_positions_<'a>( nodes: &[&'a Syntax<'a>], change_map: &ChangeMap<'a>, positions: &mut Vec, + seen_unchanged: &mut bool, ) { for node in nodes { let change = change_map .get(node) .unwrap_or_else(|| panic!("Should have changes set in all nodes: {:#?}", node)); + if matches!(change, ChangeKind::Unchanged(_)) { + *seen_unchanged = true; + } + match node { List { open_position, @@ -903,7 +938,7 @@ fn change_positions_<'a>( false, )); - change_positions_(children, change_map, positions); + change_positions_(children, change_map, positions, seen_unchanged); positions.extend(MatchedPos::new( change,