1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
use std::mem::take;
use std::time::Duration;
use ropey::RopeSlice;
use tree_sitter::Parser;
use crate::config::LanguageLoader;
use crate::{Error, LayerData, Syntax};
impl Syntax {
pub fn update(
&mut self,
source: RopeSlice,
timeout: Duration,
edits: &[tree_sitter::InputEdit],
loader: &impl LanguageLoader,
) -> Result<(), Error> {
// size limit of 512MiB, TS just cannot handle files this big (too
// slow). Furthermore, TS uses 32 (signed) bit indices so this limit
// must never be raised above 2GiB
if source.len_bytes() >= 512 * 1024 * 1024 {
return Err(Error::ExceededMaximumSize);
}
let mut queue = Vec::with_capacity(32);
let root_flags = &mut self.layer_mut(self.root).flags;
// The root layer is always considered.
root_flags.touched = true;
// If there was an edit then the root layer must've been modified.
root_flags.modified = true;
queue.push(self.root);
let mut parser = Parser::new();
while let Some(layer) = queue.pop() {
let layer_data = self.layer_mut(layer);
if layer_data.ranges.is_empty() {
// Skip re-parsing and querying layers without any ranges.
continue;
}
if let Some(tree) = &mut layer_data.parse_tree {
if layer_data.flags.moved || layer_data.flags.modified {
for edit in edits.iter().rev() {
// Apply the edits in reverse.
// If we applied them in order then edit 1 would disrupt the positioning
// of edit 2.
tree.edit(edit);
}
}
if layer_data.flags.modified {
// Re-parse the tree.
layer_data.parse(&mut parser, source, timeout, loader)?;
}
} else {
// always parse if this layer has never been parsed before
layer_data.parse(&mut parser, source, timeout, loader)?;
}
self.run_injection_query(layer, edits, source, loader, |layer| queue.push(layer));
self.run_local_query(layer, source, loader);
}
if self.layer(self.root).parse_tree.is_none() {
return Err(Error::NoRootConfig);
}
self.prune_dead_layers();
Ok(())
}
/// Reset all `LayerUpdateFlags` and remove all untouched layers
fn prune_dead_layers(&mut self) {
self.layers
.retain(|_, layer| take(&mut layer.flags).touched);
}
}
impl LayerData {
fn parse(
&mut self,
parser: &mut Parser,
source: RopeSlice,
timeout: Duration,
loader: &impl LanguageLoader,
) -> Result<(), Error> {
let Some(config) = loader.get_config(self.language) else {
return Ok(());
};
if let Err(err) = parser.set_grammar(config.grammar) {
return Err(Error::IncompatibleGrammar(self.language, err));
}
parser
.set_included_ranges(&self.ranges)
.map_err(|_| Error::InvalidRanges)?;
// 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_with_timeout(source, tree, timeout)
.ok_or(Error::Timeout)?;
self.parse_tree = Some(tree);
Ok(())
}
}
#[derive(Debug, PartialEq, Eq, Default, Clone)]
pub(crate) struct LayerUpdateFlags {
pub reused: bool,
pub modified: bool,
pub moved: bool,
pub touched: bool,
}