syntax: Hide the TSParser internally, borrowing when needed.

pull/8/head
Blaž Hrastnik 3 years ago
parent 6cbfb050e2
commit 3445abf88e

@ -234,7 +234,6 @@ impl Syntax {
/// Iterate over the highlighted regions for a given slice of source code. /// Iterate over the highlighted regions for a given slice of source code.
pub fn highlight_iter<'a>( pub fn highlight_iter<'a>(
&self, &self,
ts_parser: &'a mut TSParser,
source: &'a [u8], source: &'a [u8],
range: Option<std::ops::Range<usize>>, range: Option<std::ops::Range<usize>>,
cancellation_flag: Option<&'a AtomicUsize>, cancellation_flag: Option<&'a AtomicUsize>,
@ -288,7 +287,6 @@ impl Syntax {
byte_offset: range.map(|r| r.start).unwrap_or(0), // TODO: simplify byte_offset: range.map(|r| r.start).unwrap_or(0), // TODO: simplify
injection_callback, injection_callback,
cancellation_flag, cancellation_flag,
highlighter: ts_parser,
iter_count: 0, iter_count: 0,
layers: vec![layer], layers: vec![layer],
next_event: None, next_event: None,
@ -659,7 +657,6 @@ where
{ {
source: &'a [u8], source: &'a [u8],
byte_offset: usize, byte_offset: usize,
highlighter: &'a mut TSParser,
injection_callback: F, injection_callback: F,
cancellation_flag: Option<&'a AtomicUsize>, cancellation_flag: Option<&'a AtomicUsize>,
layers: Vec<HighlightIterLayer<'a>>, layers: Vec<HighlightIterLayer<'a>>,
@ -846,7 +843,6 @@ impl<'a> HighlightIterLayer<'a> {
/// added to the returned vector. /// added to the returned vector.
fn new<F: FnMut(&str) -> Option<&'a HighlightConfiguration> + 'a>( fn new<F: FnMut(&str) -> Option<&'a HighlightConfiguration> + 'a>(
source: &'a [u8], source: &'a [u8],
highlighter: &mut TSParser,
cancellation_flag: Option<&'a AtomicUsize>, cancellation_flag: Option<&'a AtomicUsize>,
injection_callback: &mut F, injection_callback: &mut F,
mut config: &'a HighlightConfiguration, mut config: &'a HighlightConfiguration,
@ -858,86 +854,103 @@ impl<'a> HighlightIterLayer<'a> {
loop { loop {
// --> Tree parsing part // --> Tree parsing part
if highlighter.parser.set_included_ranges(&ranges).is_ok() { PARSER.with(|ts_parser| {
highlighter let highlighter = &mut ts_parser.borrow_mut();
.parser
.set_language(config.language) if highlighter.parser.set_included_ranges(&ranges).is_ok() {
.map_err(|_| Error::InvalidLanguage)?; highlighter
.parser
unsafe { highlighter.parser.set_cancellation_flag(cancellation_flag) }; .set_language(config.language)
let tree = highlighter .map_err(|_| Error::InvalidLanguage)?;
.parser
.parse(source, None) unsafe { highlighter.parser.set_cancellation_flag(cancellation_flag) };
.ok_or(Error::Cancelled)?; let tree = highlighter
unsafe { highlighter.parser.set_cancellation_flag(None) }; .parser
let mut cursor = highlighter.cursors.pop().unwrap_or_else(QueryCursor::new); .parse(source, None)
.ok_or(Error::Cancelled)?;
// Process combined injections. unsafe { highlighter.parser.set_cancellation_flag(None) };
if let Some(combined_injections_query) = &config.combined_injections_query { let mut cursor = highlighter.cursors.pop().unwrap_or_else(QueryCursor::new);
let mut injections_by_pattern_index =
vec![(None, Vec::new(), false); combined_injections_query.pattern_count()]; // Process combined injections.
let matches = if let Some(combined_injections_query) = &config.combined_injections_query {
cursor.matches(combined_injections_query, tree.root_node(), |n: Node| { let mut injections_by_pattern_index = vec![
&source[n.byte_range()] (None, Vec::new(), false);
}); combined_injections_query
for mat in matches { .pattern_count()
let entry = &mut injections_by_pattern_index[mat.pattern_index]; ];
let (language_name, content_node, include_children) = let matches = cursor.matches(
injection_for_match(config, combined_injections_query, &mat, source); combined_injections_query,
if language_name.is_some() { tree.root_node(),
entry.0 = language_name; |n: Node| &source[n.byte_range()],
} );
if let Some(content_node) = content_node { for mat in matches {
entry.1.push(content_node); let entry = &mut injections_by_pattern_index[mat.pattern_index];
} let (language_name, content_node, include_children) =
entry.2 = include_children; injection_for_match(
} config,
for (lang_name, content_nodes, includes_children) in injections_by_pattern_index combined_injections_query,
{ &mat,
if let (Some(lang_name), false) = (lang_name, content_nodes.is_empty()) { source,
if let Some(next_config) = (injection_callback)(lang_name) {
let ranges = Self::intersect_ranges(
&ranges,
&content_nodes,
includes_children,
); );
if !ranges.is_empty() { if language_name.is_some() {
queue.push((next_config, depth + 1, ranges)); entry.0 = language_name;
}
if let Some(content_node) = content_node {
entry.1.push(content_node);
}
entry.2 = include_children;
}
for (lang_name, content_nodes, includes_children) in
injections_by_pattern_index
{
if let (Some(lang_name), false) = (lang_name, content_nodes.is_empty())
{
if let Some(next_config) = (injection_callback)(lang_name) {
let ranges = Self::intersect_ranges(
&ranges,
&content_nodes,
includes_children,
);
if !ranges.is_empty() {
queue.push((next_config, depth + 1, ranges));
}
} }
} }
} }
} }
// --> Highlighting query part
// The `captures` iterator borrows the `Tree` and the `QueryCursor`, which
// prevents them from being moved. But both of these values are really just
// pointers, so it's actually ok to move them.
let tree_ref = unsafe { mem::transmute::<_, &'static Tree>(&tree) };
let cursor_ref =
unsafe { mem::transmute::<_, &'static mut QueryCursor>(&mut cursor) };
let captures = cursor_ref
.captures(&config.query, tree_ref.root_node(), move |n: Node| {
&source[n.byte_range()]
})
.peekable();
result.push(HighlightIterLayer {
highlight_end_stack: Vec::new(),
scope_stack: vec![LocalScope {
inherits: false,
range: 0..usize::MAX,
local_defs: Vec::new(),
}],
cursor,
depth,
_tree: Some(tree),
captures,
config,
ranges,
});
} }
// --> Highlighting query part Ok(()) // so we can use the try operator
})?;
// The `captures` iterator borrows the `Tree` and the `QueryCursor`, which
// prevents them from being moved. But both of these values are really just
// pointers, so it's actually ok to move them.
let tree_ref = unsafe { mem::transmute::<_, &'static Tree>(&tree) };
let cursor_ref =
unsafe { mem::transmute::<_, &'static mut QueryCursor>(&mut cursor) };
let captures = cursor_ref
.captures(&config.query, tree_ref.root_node(), move |n: Node| {
&source[n.byte_range()]
})
.peekable();
result.push(HighlightIterLayer {
highlight_end_stack: Vec::new(),
scope_stack: vec![LocalScope {
inherits: false,
range: 0..usize::MAX,
local_defs: Vec::new(),
}],
cursor,
depth,
_tree: Some(tree),
captures,
config,
ranges,
});
}
if queue.is_empty() { if queue.is_empty() {
break; break;
@ -1114,7 +1127,10 @@ where
break; break;
} else { } else {
let layer = self.layers.remove(0); let layer = self.layers.remove(0);
self.highlighter.cursors.push(layer.cursor); PARSER.with(|ts_parser| {
let highlighter = &mut ts_parser.borrow_mut();
highlighter.cursors.push(layer.cursor);
});
} }
} }
} }
@ -1228,7 +1244,6 @@ where
if !ranges.is_empty() { if !ranges.is_empty() {
match HighlightIterLayer::new( match HighlightIterLayer::new(
self.source, self.source,
self.highlighter,
self.cancellation_flag, self.cancellation_flag,
&mut self.injection_callback, &mut self.injection_callback,
config, config,

@ -92,18 +92,10 @@ impl EditorView {
// TODO: only recalculate when state.doc is actually modified // TODO: only recalculate when state.doc is actually modified
let highlights: Vec<_> = match &view.doc.syntax { let highlights: Vec<_> = match &view.doc.syntax {
Some(syntax) => { Some(syntax) => {
syntax::PARSER.with(|ts_parser| { syntax
syntax .highlight_iter(source_code.as_bytes(), Some(range), None, |_| None)
.highlight_iter( .unwrap()
&mut ts_parser.borrow_mut(), .collect() // TODO: we collect here to avoid holding the lock, fix later
source_code.as_bytes(),
Some(range),
None,
|_| None,
)
.unwrap()
.collect() // TODO: we collect here to avoid holding the lock, fix later
})
} }
None => vec![Ok(HighlightEvent::Source { None => vec![Ok(HighlightEvent::Source {
start: range.start, start: range.start,

Loading…
Cancel
Save