Skip to content

Commit 9e2063c

Browse files
committed
highlighter: Fix condition checking for overlapping injection ranges
This fixes a case which could cause injections to become out of order. The test case has two patterns that emit overlapping captures for an injection, one at bytes 11..52 and another at 20..51. If the pattern shown in the test case comes later in the file than the pattern in Rust injections that highlights macro invocation token tree nodes, then the larger capture (11..52) comes after the smaller one (20..51). The part of the injections that decides precedence didn't handle this case as the larger range ends after the smaller range. We change this condition to do a generic intersection/overlap check.
1 parent 74f8bbf commit 9e2063c

File tree

3 files changed

+29
-1
lines changed

3 files changed

+29
-1
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
some_macro!((), (), "`rust` injection happens here");
2+
// ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┹─ rust

highlighter/src/injections_query.rs

+6-1
Original file line numberDiff line numberDiff line change
@@ -409,7 +409,7 @@ impl Syntax {
409409
// that injections get sorted to the correct position
410410
if let Some(last_injection) = injections
411411
.last()
412-
.filter(|injection| injection.range.end >= matched_node_range.end)
412+
.filter(|injection| ranges_intersect(&injection.range, &matched_node_range))
413413
{
414414
// this condition is not needed but serves as fast path
415415
// for common cases
@@ -703,3 +703,8 @@ fn intersect_ranges_impl(
703703
push_range(start..range.end)
704704
}
705705
}
706+
707+
fn ranges_intersect(a: &Range, b: &Range) -> bool {
708+
// Adapted from <https://github.com/helix-editor/helix/blob/8df58b2e1779dcf0046fb51ae1893c1eebf01e7c/helix-core/src/selection.rs#L156-L163>
709+
a.start == b.start || (a.end > b.start && b.end > a.start)
710+
}

highlighter/src/tests.rs

+21
Original file line numberDiff line numberDiff line change
@@ -341,6 +341,7 @@ fn injection_precedence() {
341341
"#,
342342
);
343343
highlight_fixture(&loader, "highlighter/rust_doc_comment.rs");
344+
344345
loader.shadow_injections(
345346
"rust",
346347
r#"
@@ -355,4 +356,24 @@ fn injection_precedence() {
355356
);
356357
highlight_fixture(&loader, "highlighter/rust_no_doc_comment.rs");
357358
injection_fixture(&loader, "injections/rust_no_doc_comment.rs");
359+
360+
loader.shadow_injections(
361+
"rust",
362+
r#"
363+
((macro_invocation
364+
macro:
365+
[
366+
(scoped_identifier
367+
name: (_) @_macro_name)
368+
(identifier) @_macro_name
369+
]
370+
(token_tree . (_) . (_) . (string_literal) @injection.content))
371+
(#any-of? @_macro_name
372+
; std
373+
"some_macro")
374+
(#set! injection.language "rust")
375+
(#set! injection.include-children))
376+
"#,
377+
);
378+
injection_fixture(&loader, "injections/overlapping_injection.rs");
358379
}

0 commit comments

Comments
 (0)