Skip to content

Commit fa5a5c7

Browse files
committed
highlighter: Finish layers when all highlights on the layer are done
In the test cases the edoc layer (the backtick and single quote within the comments) is recognized by `QueryIter` as being finished after it highlights the inline code block - its only capture. The highlighter needs to "deactivate" the layer rather than finishing (and removing it) however, because the code block highlight extends to the next comment. So when exiting an injection we check that the `QueryIter` considers a layer to be finished and also that all highlights in the layer are done as well.
1 parent 130363b commit fa5a5c7

File tree

5 files changed

+68
-5
lines changed

5 files changed

+68
-5
lines changed
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
%% `
2+
// ┡━┛╰─ comment markup.raw.inline
3+
// ╰─ comment
4+
foo
5+
// ┗━┹─ string.special.symbol
6+
%% '
7+
// ┡┛┡┛╰─ comment
8+
// │ ╰─ comment markup.raw.inline
9+
// ╰─ comment
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
```erlang
2+
// ┡━┛┡━━━━┛╰─ markup.raw.block
3+
// │ ╰─ markup.raw.block label
4+
// ╰─ markup.raw.block punctuation.bracket
5+
%% `
6+
// ┡━┛╰─ markup.raw.block comment markup.raw.inline
7+
// ╰─ markup.raw.block comment
8+
foo
9+
// ┡━┛╰─ markup.raw.block
10+
// ╰─ markup.raw.block string.special.symbol
11+
%% '
12+
// ┡┛┡┛╰─ markup.raw.block comment
13+
// │ ╰─ markup.raw.block comment markup.raw.inline
14+
// ╰─ markup.raw.block comment
15+
```
16+
// ┡━┛╰─ markup.raw.block
17+
// ╰─ markup.raw.block punctuation.bracket
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
%% `
2+
// ┗┹─ edoc
3+
foo
4+
%% '
5+
// ┗┹─ edoc

highlighter/src/highlighter.rs

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -272,13 +272,27 @@ impl<'a, 'tree: 'a, Loader: LanguageLoader> Highlighter<'a, 'tree, Loader> {
272272
QueryIterEvent::EnterInjection(injection) => self.enter_injection(injection.layer),
273273
QueryIterEvent::Match(node) => self.start_highlight(node, &mut first_highlight),
274274
QueryIterEvent::ExitInjection { injection, state } => {
275-
// state is returned if the layer is finished, if it isn't we have
276-
// a combined injection and need to deactivate its highlights
277-
if state.is_none() {
275+
// `state` is returned if the layer is finished according to the `QueryIter`.
276+
// The highlighter should only consider a layer finished, though, when it also
277+
// has no remaining ranges to highlight. If the injection is combined and has
278+
// highlight(s) past this injection's range then we should deactivate it
279+
// (saving the highlights for the layer's next injection range) rather than
280+
// removing it.
281+
let parent_start = self
282+
.layer_states
283+
.get(&self.current_layer)
284+
.map(|layer| layer.parent_highlights)
285+
.unwrap_or_default()
286+
.min(self.active_highlights.len());
287+
let layer_is_finished = state.is_some()
288+
&& self.active_highlights[parent_start..]
289+
.iter()
290+
.all(|h| h.end <= injection.range.end);
291+
if layer_is_finished {
292+
self.layer_states.remove(&injection.layer);
293+
} else {
278294
self.deactivate_layer(injection);
279295
refresh = true;
280-
} else {
281-
self.layer_states.remove(&injection.layer);
282296
}
283297
let active_language = self.query.syntax().layer(self.current_layer).language;
284298
self.active_config = self.query.loader().0.get_config(active_language);

highlighter/src/tests.rs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -538,3 +538,21 @@ fn css_parent_child_highlight_precedence() {
538538
// preserved.
539539
highlight_fixture(&loader, "highlighter/parent_child_highlight_precedence.css");
540540
}
541+
542+
#[test]
543+
fn edoc_code_combined_injection() {
544+
let loader = TestLanguageLoader::new();
545+
546+
highlight_fixture(&loader, "highlighter/edoc_code_combined_injection.erl");
547+
injection_fixture(&loader, "injections/edoc_code_combined_injection.erl");
548+
}
549+
550+
#[test]
551+
fn edoc_code_combined_injection_in_markdown() {
552+
let loader = TestLanguageLoader::new();
553+
// Same as the above but within markdown to add extra layers.
554+
highlight_fixture(
555+
&loader,
556+
"highlighter/edoc_code_combined_injection_in_markdown.md",
557+
);
558+
}

0 commit comments

Comments
 (0)