type_sitter_lib/node/
tree.rs

1use crate::{raw, InputEdit, LanguageRef, Node, NodeResult, Range, TreeCursor};
2#[cfg(feature = "yak-sitter")]
3use std::iter::Once;
4use std::marker::PhantomData;
5#[cfg(unix)]
6use std::os::unix::io::AsRawFd;
7#[cfg(windows)]
8use std::os::windows::io::AsRawHandle;
9#[cfg(feature = "yak-sitter")]
10use std::path::Path;
11#[cfg(feature = "yak-sitter")]
12use tree_sitter::TextProvider;
13
14#[derive(Clone, Debug)]
15#[repr(transparent)]
16pub struct Tree<Root: Node<'static>>(pub raw::Tree, PhantomData<Root>);
17
18impl<Root: Node<'static>> Tree<Root> {
19    /// Convert a tree-sitter tree into a typed tree by specifying the correct root node type.
20    ///
21    /// This will succeed even if `Root` is not the language's root node, because
22    /// [`root_node`](Self::root_node) checks that the root node is the correct type.
23    pub fn wrap(tree: raw::Tree) -> Self {
24        Self(tree, PhantomData)
25    }
26
27    /// Version of [`wrap`](Self::wrap) for an immutable reference.
28    pub fn wrap_ref(tree: &raw::Tree) -> &Self {
29        // SAFETY: Same repr
30        unsafe { &*(tree as *const raw::Tree as *const Self) }
31    }
32
33    /// Version of [`wrap`](Self::wrap) for a mutable reference.
34    pub fn wrap_mut(tree: &mut raw::Tree) -> &mut Self {
35        // SAFETY: Same repr
36        unsafe { &mut *(tree as *mut raw::Tree as *mut Self) }
37    }
38
39    /// Get the underlying text. This includes text which isn't in the [`Self::included_ranges`]
40    #[inline]
41    #[cfg(feature = "yak-sitter")]
42    pub fn text(&self) -> &str {
43        self.0.text()
44    }
45
46    /// Get the path the tree is associated with, if any.
47    ///
48    /// The path may be virtual, it's used for stable node comparison between trees.
49    #[inline]
50    #[cfg(feature = "yak-sitter")]
51    pub fn path(&self) -> Option<&Path> {
52        self.0.path()
53    }
54
55    /// Get the root node of this tree.
56    ///
57    /// Returns `Err` if the root is the wrong type, which may happen even if the language is
58    /// correct if the entire tree is an error node.
59    pub fn root_node(&self) -> NodeResult<'_, Root::WithLifetime<'_>> {
60        Root::WithLifetime::try_from_raw(self.0.root_node())
61    }
62
63    /// Create a cursor starting at the root node
64    #[inline]
65    pub fn walk(&self) -> TreeCursor<'_> {
66        TreeCursor(self.0.walk())
67    }
68
69    /// Get the included ranges used to parse the tree
70    #[inline]
71    pub fn included_ranges(&self) -> Vec<Range> {
72        self.0.included_ranges()
73    }
74
75    /// Get the changed ranges. See [`tree_sitter::Tree::changed_ranges`]
76    #[inline]
77    pub fn changed_ranges(&self, other: &Tree<Root>) -> impl ExactSizeIterator<Item = Range> {
78        self.0.changed_ranges(&other.0)
79    }
80
81    /// Get the language used to parse the tree.
82    #[inline]
83    pub fn language(&self) -> LanguageRef<'_> {
84        self.0.language()
85    }
86
87    //noinspection RsIncorrectFunctionArgumentCount - IntelliJ inspection bug.
88    /// Print a dot graph of the tree to the given file. See [`tree_sitter::Tree::print_dot_graph`]
89    #[inline]
90    pub fn print_dot_graph(
91        &self,
92        #[cfg(unix)] file: &impl AsRawFd,
93        #[cfg(windows)] file: &impl AsRawHandle,
94    ) {
95        self.0.print_dot_graph(file)
96    }
97
98    /// Edit the tree. See [`tree_sitter::Tree::edit`]
99    #[inline]
100    pub fn edit(&mut self, edit: &InputEdit) {
101        self.0.edit(edit)
102    }
103}
104
105#[cfg(feature = "yak-sitter")]
106impl<'tree, Root: Node<'static>> TextProvider<&'tree str> for &'tree Tree<Root> {
107    type I = Once<&'tree str>;
108
109    fn text(&mut self, node: tree_sitter::Node) -> Self::I {
110        TextProvider::text(&mut &self.0, node)
111    }
112}