highlighter: Avoid reusing parse tree when adding an injection range

This commit is contained in:
Michael Davis
2025-03-15 11:57:16 -04:00
parent 19b9c8e16e
commit 8b94086018

View File

@@ -95,9 +95,31 @@ impl LayerData {
parser
.set_included_ranges(&self.ranges)
.map_err(|_| Error::InvalidRanges)?;
let tree = parser
.parse(source, self.parse_tree.as_ref())
.ok_or(Error::Timeout)?;
// HACK:
// This is a workaround for a bug within the lexer (in the C library) or maybe within
// tree-sitter-markdown which needs more debugging. When adding a new range to a combined
// injection and passing the old tree, if the old tree doesn't already cover a wider range
// than the newly added range, some assumptions are violated in the lexer and it tries to
// access some invalid memory, resulting in a segfault. This workaround avoids that
// situation by avoiding passing the old tree when the old tree's range doesn't cover the
// total range of `self.ranges`.
//
// See <https://github.com/helix-editor/helix/pull/12972#issuecomment-2725410409>.
let tree = self.parse_tree.as_ref().filter(|tree| {
let included_ranges_range = self.ranges.first().map(|r| r.start_byte).unwrap_or(0)
..self.ranges.last().map(|r| r.end_byte).unwrap_or(u32::MAX);
// Allow re-parsing the root layer even though the range is larger. The root always
// covers `0..u32::MAX`:
if included_ranges_range == (0..u32::MAX) {
return true;
}
let tree_range = tree.root_node().byte_range();
tree_range.start <= included_ranges_range.start
&& tree_range.end >= included_ranges_range.end
});
let tree = parser.parse(source, tree).ok_or(Error::Timeout)?;
self.parse_tree = Some(tree);
Ok(())
}