diff --git a/CHANGELOG.md b/CHANGELOG.md index 140f66d57..e96ac4e2f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,8 @@ Improved CSS parsing and HTML sublanguage parsing. ### Diffing +Added an `--ignore-comments` option. + Improved textual diffing performance, particularly when the two files have few lines in common. diff --git a/src/display/context.rs b/src/display/context.rs index 4b5bded2d..48cf21373 100644 --- a/src/display/context.rs +++ b/src/display/context.rs @@ -152,7 +152,9 @@ fn matched_lines_from_unchanged( opposite_pos.first().map(|p| p.line) } } - MatchKind::Novel { .. } | MatchKind::NovelWord { .. } => None, + MatchKind::Novel { .. } | MatchKind::NovelWord { .. } | MatchKind::Ignored { .. } => { + None + } }; let should_insert = match highest_line { @@ -349,7 +351,7 @@ pub fn opposite_positions(mps: &[MatchedPos]) -> FxHashMap {} + MatchKind::Novel { .. } | MatchKind::NovelWord { .. } | MatchKind::Ignored { .. } => {} } } diff --git a/src/display/hunks.rs b/src/display/hunks.rs index 08e25505d..2fd0138d2 100644 --- a/src/display/hunks.rs +++ b/src/display/hunks.rs @@ -14,7 +14,7 @@ use crate::{ display::context::{add_context, opposite_positions}, display::side_by_side::lines_with_novel, lines::LineNumber, - parse::syntax::{zip_pad_shorter, MatchedPos}, + parse::syntax::{zip_pad_shorter, MatchKind, MatchedPos}, }; /// A hunk represents a series of modified lines that are displayed @@ -459,6 +459,32 @@ fn sorted_novel_positions( let mut rhs_iter = rhs_mps.iter().peekable(); loop { match (lhs_iter.peek(), rhs_iter.peek()) { + ( + Some(MatchedPos { + kind: MatchKind::Ignored { .. }, + .. + }), + _, + ) => { + // Ignored nodes shouldn't be treated as novel, + // because we don't want to create hunks if we see + // them. However, they don't have corresponding + // positions on the other side, so just skip. + lhs_iter.next(); + } + ( + _, + Some(MatchedPos { + kind: MatchKind::Ignored { .. }, + .. + }), + ) => { + // Ignored nodes shouldn't be treated as novel, + // because we don't want to create hunks if we see + // them. However, they don't have corresponding + // positions on the other side, so just skip. + rhs_iter.next(); + } (Some(lhs_mp), Some(rhs_mp)) if !lhs_mp.kind.is_novel() && !rhs_mp.kind.is_novel() => { res.append(&mut novel_section_in_order( &lhs_novel_section, diff --git a/src/display/style.rs b/src/display/style.rs index a6c197467..3e51bc807 100644 --- a/src/display/style.rs +++ b/src/display/style.rs @@ -334,7 +334,7 @@ pub fn color_positions( for pos in positions { let mut style = Style::new(); match pos.kind { - MatchKind::UnchangedToken { highlight, .. } => { + MatchKind::UnchangedToken { highlight, .. } | MatchKind::Ignored { highlight } => { if syntax_highlight { if let TokenKind::Atom(atom_kind) = highlight { match atom_kind { diff --git a/src/main.rs b/src/main.rs index 6c9a09b0a..f290f366e 100644 --- a/src/main.rs +++ b/src/main.rs @@ -362,6 +362,7 @@ fn diff_file_content( } Some(ts_lang) => { let arena = Arena::new(); + // ignore here. let lhs = tsp::parse(&arena, &lhs_src, &ts_lang, diff_options.ignore_comments); let rhs = tsp::parse(&arena, &rhs_src, &ts_lang, diff_options.ignore_comments); @@ -430,8 +431,19 @@ fn diff_file_content( fix_all_sliders(language, &lhs, &mut change_map); fix_all_sliders(language, &rhs, &mut change_map); - let lhs_positions = syntax::change_positions(&lhs, &change_map); - let rhs_positions = syntax::change_positions(&rhs, &change_map); + let mut lhs_positions = syntax::change_positions(&lhs, &change_map); + let mut rhs_positions = syntax::change_positions(&rhs, &change_map); + + if diff_options.ignore_comments { + let lhs_comments = tsp::comment_positions(&lhs_src, &ts_lang); + lhs_positions.extend(lhs_comments); + + let rhs_comments = tsp::comment_positions(&rhs_src, &ts_lang); + rhs_positions.extend(rhs_comments); + + // TODO: sort positions. + } + ( Some(language_name(language).into()), lhs_positions, diff --git a/src/parse/syntax.rs b/src/parse/syntax.rs index 2d2c40230..a605e7092 100644 --- a/src/parse/syntax.rs +++ b/src/parse/syntax.rs @@ -341,6 +341,30 @@ impl<'a> Syntax<'a> { } } +pub fn comment_positions<'a>(nodes: &[&'a Syntax<'a>]) -> Vec { + fn walk_comment_positions(node: &Syntax<'_>, positions: &mut Vec) { + match node { + List { children, .. } => { + for child in children { + walk_comment_positions(child, positions); + } + } + Atom { position, kind, .. } => { + if matches!(kind, AtomKind::Comment) { + positions.extend(position); + } + } + } + } + + let mut res = vec![]; + for node in nodes { + walk_comment_positions(node, &mut res); + } + + res +} + /// Initialise all the fields in `SyntaxInfo`. pub fn init_all_info<'a>(lhs_roots: &[&'a Syntax<'a>], rhs_roots: &[&'a Syntax<'a>]) { init_info(lhs_roots, rhs_roots); @@ -612,13 +636,18 @@ pub enum MatchKind { NovelWord { highlight: TokenKind, }, + Ignored { + highlight: TokenKind, + }, } impl MatchKind { pub fn is_novel(&self) -> bool { matches!( self, - MatchKind::Novel { .. } | MatchKind::NovelWord { .. } | MatchKind::NovelLinePart { .. } + MatchKind::Novel { .. } + | MatchKind::NovelWord { .. } + | MatchKind::NovelLinePart { .. } ) } } diff --git a/src/parse/tree_sitter_parser.rs b/src/parse/tree_sitter_parser.rs index 24045eacf..3c1724d97 100644 --- a/src/parse/tree_sitter_parser.rs +++ b/src/parse/tree_sitter_parser.rs @@ -12,6 +12,9 @@ use crate::{ parse::syntax::{AtomKind, Syntax}, }; +use super::syntax; +use super::syntax::MatchedPos; + /// A language may contain certain nodes that are in other languages /// and should be parsed as such (e.g. HTML