Skip to main content

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<'cursor, 'tree: 'cursor> IntoIterator for &'cursor mut TreeCursor<'tree> {
118    type Item = Node<'tree>;
119    type IntoIter = TreeRecursiveWalker<'cursor, '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<'cursor, 'tree: 'cursor> {
135    cursor: &'cursor 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}