Add highlighting for ignored syntactic elements

This finishes --ignore-comment support.

Fixes #449.
pull/464/head
Wilfred Hughes 2023-01-13 08:17:30 +07:00
parent f3b02f7b47
commit a488efd63b
7 changed files with 99 additions and 7 deletions

@ -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.

@ -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<LineNumber, HashSet<L
opposite_lines.insert(opposite_span.line);
}
}
MatchKind::Novel { .. } | MatchKind::NovelWord { .. } => {}
MatchKind::Novel { .. } | MatchKind::NovelWord { .. } | MatchKind::Ignored { .. } => {}
}
}

@ -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,

@ -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 {

@ -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,

@ -341,6 +341,30 @@ impl<'a> Syntax<'a> {
}
}
pub fn comment_positions<'a>(nodes: &[&'a Syntax<'a>]) -> Vec<SingleLineSpan> {
fn walk_comment_positions(node: &Syntax<'_>, positions: &mut Vec<SingleLineSpan>) {
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 { .. }
)
}
}

@ -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 <script> nodes containing
/// JavaScript). This contains how to identify such nodes, and what
@ -1089,6 +1092,24 @@ fn print_cursor(src: &str, cursor: &mut ts::TreeCursor, depth: usize) {
}
}
pub fn comment_positions(src: &str, config: &TreeSitterConfig) -> Vec<MatchedPos> {
let arena = Arena::new();
let ignore_comments = false;
let nodes = parse(&arena, src, config, ignore_comments);
let positions = syntax::comment_positions(&nodes);
positions
.into_iter()
.map(|pos| MatchedPos {
kind: syntax::MatchKind::Ignored {
highlight: syntax::TokenKind::Atom(AtomKind::Comment),
},
pos,
})
.collect()
}
/// Parse `src` with tree-sitter and convert to difftastic Syntax.
pub fn parse<'a>(
arena: &'a Arena<Syntax<'a>>,