highlight: don't include scope in ScopeEnd events

When there are embedded documents, multiple scopes can start or
end at the same position. Previously, there was no guarantee that
the ScopeEnd events would always occur in the reverse order of the
ScopeStart events. The easiest way to avoid exposing inconsistency
is to not surface the scopes being ended.
This commit is contained in:
Max Brunsfeld 2019-02-20 16:45:51 -08:00
parent d2264d597f
commit e239aa8229
3 changed files with 17 additions and 12 deletions

View file

@ -209,7 +209,7 @@ pub fn ansi(
HighlightEvent::ScopeStart(s) => {
scope_stack.push(s);
}
HighlightEvent::ScopeEnd(_) => {
HighlightEvent::ScopeEnd => {
scope_stack.pop();
}
}

View file

@ -162,8 +162,7 @@ fn to_token_vector<'a>(
)? {
match event {
HighlightEvent::ScopeStart(s) => scopes.push(s),
HighlightEvent::ScopeEnd(s) => {
assert_eq!(*scopes.last().unwrap(), s);
HighlightEvent::ScopeEnd => {
scopes.pop();
}
HighlightEvent::Source(s) => {

View file

@ -96,7 +96,7 @@ where
pub enum HighlightEvent<'a> {
Source(&'a str),
ScopeStart(Scope),
ScopeEnd(Scope),
ScopeEnd,
}
#[derive(Debug, Deserialize)]
@ -565,10 +565,7 @@ where
.parse(self.source, None)
.expect("Failed to parse");
let layer = Layer::new(self.source, tree, property_sheet, ranges);
match self
.layers
.binary_search_by_key(&(layer.offset(), 1), |l| (l.offset(), 0))
{
match self.layers.binary_search_by(|l| l.cmp(&layer)) {
Ok(i) | Err(i) => self.layers.insert(i, layer),
};
}
@ -625,7 +622,7 @@ impl<'a, T: Fn(&str) -> Option<(Language, &'a PropertySheet<Properties>)>> Itera
}
scope_event = if self.layers[0].at_node_end {
Some(HighlightEvent::ScopeEnd(scope))
Some(HighlightEvent::ScopeEnd)
} else {
Some(HighlightEvent::ScopeStart(scope))
};
@ -638,7 +635,7 @@ impl<'a, T: Fn(&str) -> Option<(Language, &'a PropertySheet<Properties>)>> Itera
// to re-sort the layers. If the cursor is already at the end of its syntax tree,
// remove it.
if self.layers[0].advance() {
self.layers.sort_unstable_by_key(|layer| layer.offset());
self.layers.sort_unstable_by(|a, b| a.cmp(&b));
} else {
self.layers.remove(0);
}
@ -676,6 +673,15 @@ impl<'a> Layer<'a> {
}
}
fn cmp(&self, other: &Layer) -> cmp::Ordering {
// Events are ordered primarily by their position in the document. But if
// one scope starts at a given position and another scope ends at that
// same position, return the scope end event before the scope start event.
self.offset()
.cmp(&other.offset())
.then_with(|| other.at_node_end.cmp(&self.at_node_end))
}
fn offset(&self) -> usize {
if self.at_node_end {
self.cursor.node().end_byte()
@ -770,8 +776,8 @@ where
scopes.push(s);
renderer.start_scope(s);
}
HighlightEvent::ScopeEnd(s) => {
assert_eq!(scopes.pop(), Some(s));
HighlightEvent::ScopeEnd => {
scopes.pop();
renderer.end_scope();
}
HighlightEvent::Source(src) => {