Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'helix-syntax/src/tree_sitter/query_cursor.rs')
-rw-r--r--helix-syntax/src/tree_sitter/query_cursor.rs32
1 files changed, 28 insertions, 4 deletions
diff --git a/helix-syntax/src/tree_sitter/query_cursor.rs b/helix-syntax/src/tree_sitter/query_cursor.rs
index 368aeadf..83df365d 100644
--- a/helix-syntax/src/tree_sitter/query_cursor.rs
+++ b/helix-syntax/src/tree_sitter/query_cursor.rs
@@ -1,4 +1,5 @@
use core::slice;
+use std::cell::UnsafeCell;
use std::marker::PhantomData;
use std::mem::replace;
use std::ops::Range;
@@ -10,6 +11,15 @@ use crate::tree_sitter::{SyntaxTree, SyntaxTreeNode, TsInput};
enum QueryCursorData {}
+thread_local! {
+ static CURSOR_CACHE: UnsafeCell<Vec<InactiveQueryCursor>> = UnsafeCell::new(Vec::with_capacity(8));
+}
+
+/// SAFETY: must not call itself recuresively
+unsafe fn with_cache<T>(f: impl FnOnce(&mut Vec<InactiveQueryCursor>) -> T) -> T {
+ CURSOR_CACHE.with(|cache| f(&mut *cache.get()))
+}
+
pub struct QueryCursor<'a, 'tree, I: TsInput> {
query: &'a Query,
ptr: *mut QueryCursorData,
@@ -115,8 +125,8 @@ impl<I: TsInput> Drop for QueryCursor<'_, '_, I> {
fn drop(&mut self) {
// we allow moving the cursor data out so we need the null check here
// would be cleaner with a subtype but doesn't really matter at the end of the day
- if !self.ptr.is_null() {
- unsafe { ts_query_cursor_delete(self.ptr) }
+ if let Some(ptr) = NonNull::new(self.ptr) {
+ unsafe { with_cache(|cache| cache.push(InactiveQueryCursor { ptr })) }
}
}
}
@@ -128,8 +138,12 @@ pub struct InactiveQueryCursor {
impl InactiveQueryCursor {
pub fn new() -> Self {
- InactiveQueryCursor {
- ptr: unsafe { NonNull::new_unchecked(ts_query_cursor_new()) },
+ unsafe {
+ with_cache(|cache| {
+ cache.pop().unwrap_or_else(|| InactiveQueryCursor {
+ ptr: NonNull::new_unchecked(ts_query_cursor_new()),
+ })
+ })
}
}
@@ -208,6 +222,16 @@ impl<'tree> QueryMatch<'_, 'tree> {
self.matched_nodes.iter()
}
+ pub fn nodes_for_capture(
+ &self,
+ capture: Capture,
+ ) -> impl Iterator<Item = &SyntaxTreeNode<'tree>> {
+ self.matched_nodes
+ .iter()
+ .filter(move |mat| mat.capture == capture)
+ .map(|mat| &mat.syntax_node)
+ }
+
pub fn matched_node(&self, i: MatchedNodeIdx) -> &MatchedNode {
&self.matched_nodes[i as usize]
}