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