Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'helix-syntax/src/tree_sitter/syntax_tree_node.rs')
-rw-r--r--helix-syntax/src/tree_sitter/syntax_tree_node.rs292
1 files changed, 292 insertions, 0 deletions
diff --git a/helix-syntax/src/tree_sitter/syntax_tree_node.rs b/helix-syntax/src/tree_sitter/syntax_tree_node.rs
new file mode 100644
index 00000000..1afca0e3
--- /dev/null
+++ b/helix-syntax/src/tree_sitter/syntax_tree_node.rs
@@ -0,0 +1,292 @@
+use std::ffi::c_void;
+use std::marker::PhantomData;
+use std::ops::Range;
+use std::ptr::NonNull;
+
+use crate::tree_sitter::syntax_tree::SyntaxTree;
+use crate::tree_sitter::Grammar;
+
+#[repr(C)]
+#[derive(Debug, Clone, Copy)]
+pub(super) struct SyntaxTreeNodeRaw {
+ context: [u32; 4],
+ id: *const c_void,
+ tree: *const c_void,
+}
+
+impl From<SyntaxTreeNode<'_>> for SyntaxTreeNodeRaw {
+ fn from(node: SyntaxTreeNode) -> SyntaxTreeNodeRaw {
+ SyntaxTreeNodeRaw {
+ context: node.context,
+ id: node.id.as_ptr(),
+ tree: node.tree.as_ptr(),
+ }
+ }
+}
+
+#[derive(Debug, Clone)]
+#[repr(C)]
+pub struct SyntaxTreeNode<'tree> {
+ context: [u32; 4],
+ id: NonNull<c_void>,
+ tree: NonNull<c_void>,
+ _phantom: PhantomData<&'tree SyntaxTree>,
+}
+
+impl<'tree> SyntaxTreeNode<'tree> {
+ #[inline]
+ pub(super) unsafe fn from_raw(raw: SyntaxTreeNodeRaw) -> Option<Self> {
+ Some(SyntaxTreeNode {
+ context: raw.context,
+ id: NonNull::new(raw.id as *mut _)?,
+ tree: unsafe { NonNull::new_unchecked(raw.tree as *mut _) },
+ _phantom: PhantomData,
+ })
+ }
+
+ #[inline]
+ pub(crate) fn as_raw(&self) -> SyntaxTreeNodeRaw {
+ SyntaxTreeNodeRaw {
+ context: self.context,
+ id: self.id.as_ptr(),
+ tree: self.tree.as_ptr(),
+ }
+ }
+
+ /// Get this node's type as a numerical id.
+ #[inline]
+ pub fn kind_id(&self) -> u16 {
+ unsafe { ts_node_symbol(self.as_raw()) }
+ }
+
+ /// Get the [`Language`] that was used to parse this node's syntax tree.
+ #[inline]
+ pub fn grammar(&self) -> Grammar {
+ unsafe { ts_node_language(self.as_raw()) }
+ }
+
+ /// Check if this node is *named*.
+ ///
+ /// Named nodes correspond to named rules in the grammar, whereas
+ /// *anonymous* nodes correspond to string literals in the grammar.
+ #[inline]
+ pub fn is_named(&self) -> bool {
+ unsafe { ts_node_is_named(self.as_raw()) }
+ }
+
+ /// Check if this node is *missing*.
+ ///
+ /// Missing nodes are inserted by the parser in order to recover from
+ /// certain kinds of syntax errors.
+ #[inline]
+ pub fn is_missing(&self) -> bool {
+ unsafe { ts_node_is_missing(self.as_raw()) }
+ }
+ /// Get the byte offsets where this node starts.
+ #[inline]
+ pub fn start_byte(&self) -> usize {
+ unsafe { ts_node_start_byte(self.as_raw()) as usize }
+ }
+
+ /// Get the byte offsets where this node end.
+ #[inline]
+ pub fn end_byte(&self) -> usize {
+ unsafe { ts_node_end_byte(self.as_raw()) as usize }
+ }
+
+ /// Get the byte range of source code that this node represents.
+ // TODO: use helix_stdx::Range once available
+ #[inline]
+ pub fn byte_range(&self) -> Range<usize> {
+ self.start_byte()..self.end_byte()
+ }
+
+ /// Get the node's child at the given index, where zero represents the first
+ /// child.
+ ///
+ /// This method is fairly fast, but its cost is technically log(i), so if
+ /// you might be iterating over a long list of children, you should use
+ /// [`SyntaxTreeNode::children`] instead.
+ #[inline]
+ pub fn child(&self, i: usize) -> Option<SyntaxTreeNode<'tree>> {
+ unsafe { SyntaxTreeNode::from_raw(ts_node_child(self.as_raw(), i as u32)) }
+ }
+
+ /// Get this node's number of children.
+ #[inline]
+ pub fn child_count(&self) -> usize {
+ unsafe { ts_node_child_count(self.as_raw()) as usize }
+ }
+
+ /// Get this node's *named* child at the given index.
+ ///
+ /// See also [`SyntaxTreeNode::is_named`].
+ /// This method is fairly fast, but its cost is technically log(i), so if
+ /// you might be iterating over a long list of children, you should use
+ /// [`SyntaxTreeNode::named_children`] instead.
+ #[inline]
+ pub fn named_child(&self, i: usize) -> Option<SyntaxTreeNode<'tree>> {
+ unsafe { SyntaxTreeNode::from_raw(ts_node_named_child(self.as_raw(), i as u32)) }
+ }
+
+ /// Get this node's number of *named* children.
+ ///
+ /// See also [`SyntaxTreeNode::is_named`].
+ #[inline]
+ pub fn named_child_count(&self) -> usize {
+ unsafe { ts_node_named_child_count(self.as_raw()) as usize }
+ }
+
+ #[inline]
+ unsafe fn map(
+ &self,
+ f: unsafe extern "C" fn(SyntaxTreeNodeRaw) -> SyntaxTreeNodeRaw,
+ ) -> Option<SyntaxTreeNode<'tree>> {
+ SyntaxTreeNode::from_raw(f(self.as_raw()))
+ }
+
+ /// Get this node's immediate parent.
+ #[inline]
+ pub fn parent(&self) -> Option<Self> {
+ unsafe { self.map(ts_node_parent) }
+ }
+
+ /// Get this node's next sibling.
+ #[inline]
+ pub fn next_sibling(&self) -> Option<Self> {
+ unsafe { self.map(ts_node_next_sibling) }
+ }
+
+ /// Get this node's previous sibling.
+ #[inline]
+ pub fn prev_sibling(&self) -> Option<Self> {
+ unsafe { self.map(ts_node_prev_sibling) }
+ }
+
+ /// Get this node's next named sibling.
+ #[inline]
+ pub fn next_named_sibling(&self) -> Option<Self> {
+ unsafe { self.map(ts_node_next_named_sibling) }
+ }
+
+ /// Get this node's previous named sibling.
+ #[inline]
+ pub fn prev_named_sibling(&self) -> Option<Self> {
+ unsafe { self.map(ts_node_prev_named_sibling) }
+ }
+
+ /// Get the smallest node within this node that spans the given range.
+ #[inline]
+ pub fn descendant_for_byte_range(&self, start: usize, end: usize) -> Option<Self> {
+ unsafe {
+ Self::from_raw(ts_node_descendant_for_byte_range(
+ self.as_raw(),
+ start as u32,
+ end as u32,
+ ))
+ }
+ }
+
+ /// Get the smallest named node within this node that spans the given range.
+ #[inline]
+ pub fn named_descendant_for_byte_range(&self, start: usize, end: usize) -> Option<Self> {
+ unsafe {
+ Self::from_raw(ts_node_named_descendant_for_byte_range(
+ self.as_raw(),
+ start as u32,
+ end as u32,
+ ))
+ }
+ }
+ // /// Iterate over this node's children.
+ // ///
+ // /// A [`TreeCursor`] is used to retrieve the children efficiently. Obtain
+ // /// a [`TreeCursor`] by calling [`Tree::walk`] or [`SyntaxTreeNode::walk`]. To avoid
+ // /// unnecessary allocations, you should reuse the same cursor for
+ // /// subsequent calls to this method.
+ // ///
+ // /// If you're walking the tree recursively, you may want to use the
+ // /// [`TreeCursor`] APIs directly instead.
+ // pub fn children<'cursor>(
+ // &self,
+ // cursor: &'cursor mut TreeCursor<'tree>,
+ // ) -> impl ExactSizeIterator<Item = SyntaxTreeNode<'tree>> + 'cursor {
+ // cursor.reset(self.to_raw());
+ // cursor.goto_first_child();
+ // (0..self.child_count()).map(move |_| {
+ // let result = cursor.node();
+ // cursor.goto_next_sibling();
+ // result
+ // })
+ // }
+}
+
+unsafe impl Send for SyntaxTreeNode<'_> {}
+unsafe impl Sync for SyntaxTreeNode<'_> {}
+
+extern "C" {
+ /// Get the node's type as a numerical id.
+ fn ts_node_symbol(node: SyntaxTreeNodeRaw) -> u16;
+
+ /// Get the node's language.
+ fn ts_node_language(node: SyntaxTreeNodeRaw) -> Grammar;
+
+ /// Check if the node is *named*. Named nodes correspond to named rules in
+ /// the grammar, whereas *anonymous* nodes correspond to string literals in
+ /// the grammar
+ fn ts_node_is_named(node: SyntaxTreeNodeRaw) -> bool;
+
+ /// Check if the node is *missing*. Missing nodes are inserted by the parser
+ /// in order to recover from certain kinds of syntax errors
+ fn ts_node_is_missing(node: SyntaxTreeNodeRaw) -> bool;
+
+ /// Get the node's immediate parent
+ fn ts_node_parent(node: SyntaxTreeNodeRaw) -> SyntaxTreeNodeRaw;
+
+ /// Get the node's child at the given index, where zero represents the first
+ /// child
+ fn ts_node_child(node: SyntaxTreeNodeRaw, child_index: u32) -> SyntaxTreeNodeRaw;
+
+ /// Get the node's number of children
+ fn ts_node_child_count(node: SyntaxTreeNodeRaw) -> u32;
+
+ /// Get the node's *named* child at the given index. See also
+ /// [`ts_node_is_named`]
+ fn ts_node_named_child(node: SyntaxTreeNodeRaw, child_index: u32) -> SyntaxTreeNodeRaw;
+
+ /// Get the node's number of *named* children. See also [`ts_node_is_named`]
+ fn ts_node_named_child_count(node: SyntaxTreeNodeRaw) -> u32;
+
+ /// Get the node's next sibling
+ fn ts_node_next_sibling(node: SyntaxTreeNodeRaw) -> SyntaxTreeNodeRaw;
+
+ fn ts_node_prev_sibling(node: SyntaxTreeNodeRaw) -> SyntaxTreeNodeRaw;
+
+ /// Get the node's next *named* sibling
+ fn ts_node_next_named_sibling(node: SyntaxTreeNodeRaw) -> SyntaxTreeNodeRaw;
+
+ fn ts_node_prev_named_sibling(node: SyntaxTreeNodeRaw) -> SyntaxTreeNodeRaw;
+
+ /// Get the smallest node within this node that spans the given range of
+ /// bytes or (row, column) positions
+ fn ts_node_descendant_for_byte_range(
+ node: SyntaxTreeNodeRaw,
+
+ start: u32,
+ end: u32,
+ ) -> SyntaxTreeNodeRaw;
+
+ /// Get the smallest named node within this node that spans the given range
+ /// of bytes or (row, column) positions
+ fn ts_node_named_descendant_for_byte_range(
+ node: SyntaxTreeNodeRaw,
+ start: u32,
+ end: u32,
+ ) -> SyntaxTreeNodeRaw;
+
+ /// Get the node's start byte.
+ fn ts_node_start_byte(self_: SyntaxTreeNodeRaw) -> u32;
+
+ /// Get the node's end byte.
+ fn ts_node_end_byte(node: SyntaxTreeNodeRaw) -> u32;
+}