tree_house_bindings/
tree_cursor.rs

1use ::std::os::raw;
2use std::cell::Cell;
3use std::ffi::{c_char, CStr};
4use std::marker::PhantomData;
5use std::{fmt, mem};
6
7use crate::node::NodeRaw;
8use crate::{Node, Tree};
9
10thread_local! {
11    static CACHE: Cell<Option<TreeCursorGuard>> = const { Cell::new(None) };
12}
13
14#[repr(C)]
15#[derive(Clone)]
16struct TreeCursorRaw {
17    tree: *const raw::c_void,
18    id: *const raw::c_void,
19    context: [u32; 3usize],
20}
21
22#[repr(C)]
23struct TreeCursorGuard(TreeCursorRaw);
24
25impl Drop for TreeCursorGuard {
26    fn drop(&mut self) {
27        unsafe { ts_tree_cursor_delete(&mut self.0) }
28    }
29}
30
31pub struct TreeCursor<'a> {
32    inner: TreeCursorRaw,
33    tree: PhantomData<&'a Tree>,
34}
35
36impl<'tree> TreeCursor<'tree> {
37    pub(crate) fn new(node: &Node<'tree>) -> Self {
38        Self {
39            inner: match CACHE.take() {
40                Some(guard) => unsafe {
41                    let mut cursor = guard.0.clone();
42                    mem::forget(guard);
43                    ts_tree_cursor_reset(&mut cursor, node.as_raw());
44                    cursor
45                },
46                None => unsafe { ts_tree_cursor_new(node.as_raw()) },
47            },
48            tree: PhantomData,
49        }
50    }
51
52    pub fn goto_parent(&mut self) -> bool {
53        unsafe { ts_tree_cursor_goto_parent(&mut self.inner) }
54    }
55
56    pub fn goto_next_sibling(&mut self) -> bool {
57        unsafe { ts_tree_cursor_goto_next_sibling(&mut self.inner) }
58    }
59
60    pub fn goto_previous_sibling(&mut self) -> bool {
61        unsafe { ts_tree_cursor_goto_previous_sibling(&mut self.inner) }
62    }
63
64    pub fn goto_first_child(&mut self) -> bool {
65        unsafe { ts_tree_cursor_goto_first_child(&mut self.inner) }
66    }
67
68    pub fn goto_last_child(&mut self) -> bool {
69        unsafe { ts_tree_cursor_goto_last_child(&mut self.inner) }
70    }
71
72    pub fn goto_first_child_for_byte(&mut self, byte_idx: u32) -> Option<u32> {
73        match unsafe { ts_tree_cursor_goto_first_child_for_byte(&mut self.inner, byte_idx) } {
74            -1 => None,
75            n => Some(n as u32),
76        }
77    }
78
79    pub fn node(&self) -> Node<'tree> {
80        unsafe { Node::from_raw(ts_tree_cursor_current_node(&self.inner)).unwrap_unchecked() }
81    }
82
83    pub fn field_name(&self) -> Option<&'tree str> {
84        unsafe {
85            let ptr = ts_tree_cursor_current_field_name(&self.inner);
86            (!ptr.is_null()).then(|| CStr::from_ptr(ptr).to_str().unwrap())
87        }
88    }
89}
90
91impl fmt::Debug for TreeCursorRaw {
92    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
93        f.debug_struct("InactiveTreeCursor").finish_non_exhaustive()
94    }
95}
96
97impl Drop for TreeCursor<'_> {
98    fn drop(&mut self) {
99        CACHE.set(Some(TreeCursorGuard(self.inner.clone())))
100    }
101}
102
103impl Clone for TreeCursor<'_> {
104    fn clone(&self) -> Self {
105        TreeCursor {
106            inner: unsafe { ts_tree_cursor_copy(&self.inner) },
107            tree: PhantomData,
108        }
109    }
110}
111
112extern "C" {
113    /// Create a new tree cursor starting from the given node.
114    ///
115    /// A tree cursor allows you to walk a syntax tree more efficiently than is
116    /// possible using the `TSNode` functions. It is a mutable object that is always
117    /// on a certain syntax node, and can be moved imperatively to different nodes.
118    ///
119    /// Note that the given node is considered the root of the cursor,
120    /// and the cursor cannot walk outside this node.
121    fn ts_tree_cursor_new(node: NodeRaw) -> TreeCursorRaw;
122    /// Delete a tree cursor, freeing all of the memory that it used.
123    fn ts_tree_cursor_delete(self_: *mut TreeCursorRaw);
124    /// Re-initialize a tree cursor to start at a different node.
125    fn ts_tree_cursor_reset(self_: *mut TreeCursorRaw, node: NodeRaw);
126    // /// Re-initialize a tree cursor to the same position as another cursor.
127    // /// Unlike [`ts_tree_cursor_reset`], this will not lose parent information and
128    // /// allows reusing already created cursors.
129    // fn ts_tree_cursor_reset_to(dst: *mut TreeCursorRaw, src: *const TreeCursorRaw);
130    /// Get the tree cursor's current node.
131    fn ts_tree_cursor_current_node(self_: *const TreeCursorRaw) -> NodeRaw;
132    // /// Get the field name of the tree cursor's current node.
133    // /// This returns `NULL` if the current node doesn't have a field.
134    // /// See also [`ts_node_child_by_field_name`].
135    // fn ts_tree_cursor_current_field_name(self_: *const TreeCursorRaw) -> *const raw::c_char;
136    // /// Get the field id of the tree cursor's current node.
137    // /// This returns zero if the current node doesn't have a field.
138    // /// See also [`ts_node_child_by_field_id`], [`ts_language_field_id_for_name`].
139    // fn ts_tree_cursor_current_field_id(self_: *const TreeCursorRaw) -> TSFieldId;
140    /// Move the cursor to the parent of its current node.
141    /// This returns `true` if the cursor successfully moved, and returns `false`
142    /// if there was no parent node (the cursor was already on the root node).
143    fn ts_tree_cursor_goto_parent(self_: *mut TreeCursorRaw) -> bool;
144    /// Move the cursor to the next sibling of its current node.
145    /// This returns `true` if the cursor successfully moved, and returns `false`
146    /// if there was no next sibling node.
147    fn ts_tree_cursor_goto_next_sibling(self_: *mut TreeCursorRaw) -> bool;
148    /// Move the cursor to the previous sibling of its current node.
149    /// This returns `true` if the cursor successfully moved, and returns `false` if
150    /// there was no previous sibling node.
151    /// Note, that this function may be slower than
152    /// [`ts_tree_cursor_goto_next_sibling`] due to how node positions are stored. In
153    /// the worst case, this will need to iterate through all the children upto the
154    /// previous sibling node to recalculate its position.
155    fn ts_tree_cursor_goto_previous_sibling(self_: *mut TreeCursorRaw) -> bool;
156    /// Move the cursor to the first child of its current node.
157    /// This returns `true` if the cursor successfully moved, and returns `false`
158    /// if there were no children.
159    fn ts_tree_cursor_goto_first_child(self_: *mut TreeCursorRaw) -> bool;
160    /// Move the cursor to the last child of its current node.
161    /// This returns `true` if the cursor successfully moved, and returns `false` if
162    /// there were no children.
163    /// Note that this function may be slower than [`ts_tree_cursor_goto_first_child`]
164    /// because it needs to iterate through all the children to compute the child's
165    /// position.
166    fn ts_tree_cursor_goto_last_child(self_: *mut TreeCursorRaw) -> bool;
167    /*
168    /// Move the cursor to the node that is the nth descendant of
169    /// the original node that the cursor was constructed with, where
170    /// zero represents the original node itself.
171    fn ts_tree_cursor_goto_descendant(self_: *mut TreeCursorRaw, goal_descendant_index: u32);
172    /// Get the index of the cursor's current node out of all of the
173    /// descendants of the original node that the cursor was constructed with.
174    fn ts_tree_cursor_current_descendant_index(self_: *const TreeCursorRaw) -> u32;
175    /// Get the depth of the cursor's current node relative to the original
176    /// node that the cursor was constructed with.
177    fn ts_tree_cursor_current_depth(self_: *const TreeCursorRaw) -> u32;
178    */
179    /// Move the cursor to the first child of its current node that extends beyond
180    /// the given byte offset or point.
181    /// This returns the index of the child node if one was found, and returns -1
182    /// if no such child was found.
183    fn ts_tree_cursor_goto_first_child_for_byte(self_: *mut TreeCursorRaw, goal_byte: u32) -> i64;
184    fn ts_tree_cursor_copy(cursor: *const TreeCursorRaw) -> TreeCursorRaw;
185    /// Get the field name of the tree cursor's curren tnode.
186    ///
187    /// This returns `NULL` if the current node doesn't have a field. See also
188    /// `ts_node_child_by_field_name`.
189    fn ts_tree_cursor_current_field_name(cursor: *const TreeCursorRaw) -> *const c_char;
190}