Documentation Index
Fetch the complete documentation index at: https://mintlify.com/tree-sitter/tree-sitter/llms.txt
Use this file to discover all available pages before exploring further.
A Tree represents the syntactic structure of a source code file. Trees are immutable but can be edited to reflect changes in the source code.
Accessing Nodes
root_node
pub fn root_node(&self) -> Node
Get the root node of the syntax tree.
let tree = parser.parse(source_code, None).unwrap();
let root_node = tree.root_node();
root_node_with_offset
pub fn root_node_with_offset(&self, offset_bytes: usize, offset_extent: Point) -> Node
Get the root node of the syntax tree, but with its position shifted forward by the given offset.
The byte offset to shift the node’s position
The row/column offset to shift the node’s position
language
pub fn language(&self) -> LanguageRef
Get the language that was used to parse the syntax tree.
let language = tree.language();
println!("Parsed with: {}", language.name().unwrap());
Tree Editing
edit
pub fn edit(&mut self, edit: &InputEdit)
Edit the syntax tree to keep it in sync with source code that has been edited. You must describe the edit both in terms of byte offsets and in terms of row/column coordinates.
A description of the edit made to the source code
tree.edit(&InputEdit {
start_byte: 8,
old_end_byte: 8,
new_end_byte: 14,
start_position: Point::new(0, 8),
old_end_position: Point::new(0, 8),
new_end_position: Point::new(0, 14),
});
let new_tree = parser.parse(new_source_code, Some(&tree));
Tree Traversal
walk
pub fn walk(&self) -> TreeCursor
Create a new TreeCursor starting from the root of the tree. This is equivalent to calling tree.root_node().walk().
let mut cursor = tree.walk();
while cursor.goto_first_child() {
println!("Node: {}", cursor.node().kind());
}
Comparing Trees
changed_ranges
pub fn changed_ranges(&self, other: &Self) -> impl ExactSizeIterator<Item = Range>
Compare this old edited syntax tree to a new syntax tree representing the same document, returning a sequence of ranges whose syntactic structure has changed.
For this to work correctly, this syntax tree must have been edited such that its ranges match up to the new tree. Generally, you’ll want to call this method right after calling one of the Parser::parse functions. Call it on the old tree that was passed to parse, and pass the new tree that was returned from parse.
The new tree to compare against
Returns: An iterator over the ranges that changed between the two trees.
let old_tree = parser.parse(old_source, None).unwrap();
old_tree.edit(&edit);
let new_tree = parser.parse(new_source, Some(&old_tree)).unwrap();
for range in old_tree.changed_ranges(&new_tree) {
println!("Changed range: {:?}", range);
}
included_ranges
pub fn included_ranges(&self) -> Vec<Range>
Get the included ranges that were used to parse the syntax tree.
Debugging
print_dot_graph
#[cfg(feature = "std")]
pub fn print_dot_graph(&self, file: &impl AsRawFd)
Print a graph of the tree to the given file descriptor. The graph is formatted in the DOT language. You may want to pipe this graph directly to a dot(1) process in order to generate SVG output.
The file descriptor to write the graph to
This method is only available on Unix platforms with the std feature enabled.
Cloning
The Tree struct implements Clone, allowing you to create copies of syntax trees:
let tree = parser.parse(source_code, None).unwrap();
let tree_copy = tree.clone();
The InputEdit struct describes a change to a text document:
pub struct InputEdit {
pub start_byte: usize,
pub old_end_byte: usize,
pub new_end_byte: usize,
pub start_position: Point,
pub old_end_position: Point,
pub new_end_position: Point,
}
The byte offset where the edit begins
The byte offset where the edit ends in the old text
The byte offset where the edit ends in the new text
The row/column position where the edit begins
The row/column position where the edit ends in the old text
The row/column position where the edit ends in the new text
edit_point
pub fn edit_point(&self, point: &mut Point, byte: &mut usize)
Edit a point to keep it in-sync with source code that has been edited. This function updates a single point’s byte offset and row/column position based on this edit operation.
The byte offset to update
edit_range
pub fn edit_range(&self, range: &mut Range)
Edit a range to keep it in-sync with source code that has been edited. This function updates a range’s start and end positions based on this edit operation.
Examples
Basic Tree Access
let tree = parser.parse("fn test() {}", None).unwrap();
let root = tree.root_node();
println!("Root kind: {}", root.kind());
println!("Root range: {:?}", root.range());
Incremental Parsing with Edits
// Parse the original source
let source = "fn test() {}";
let mut tree = parser.parse(source, None).unwrap();
// Make an edit: insert "a: u32" at position 8
let edit = InputEdit {
start_byte: 8,
old_end_byte: 8,
new_end_byte: 14,
start_position: Point::new(0, 8),
old_end_position: Point::new(0, 8),
new_end_position: Point::new(0, 14),
};
tree.edit(&edit);
// Re-parse with the edited tree
let new_source = "fn test(a: u32) {}";
let new_tree = parser.parse(new_source, Some(&tree)).unwrap();
Finding Changed Ranges
let old_source = "fn foo() {}";
let new_source = "fn bar() {}";
let mut old_tree = parser.parse(old_source, None).unwrap();
// Edit the tree to reflect the change from "foo" to "bar"
old_tree.edit(&InputEdit {
start_byte: 3,
old_end_byte: 6,
new_end_byte: 6,
start_position: Point::new(0, 3),
old_end_position: Point::new(0, 6),
new_end_position: Point::new(0, 6),
});
let new_tree = parser.parse(new_source, Some(&old_tree)).unwrap();
for range in old_tree.changed_ranges(&new_tree) {
println!("Changed: {}:{} - {}:{}",
range.start_point.row, range.start_point.column,
range.end_point.row, range.end_point.column);
}
Tree Walking
let tree = parser.parse(source_code, None).unwrap();
let mut cursor = tree.walk();
fn walk_tree(cursor: &mut TreeCursor, depth: usize) {
println!("{}{}", " ".repeat(depth), cursor.node().kind());
if cursor.goto_first_child() {
loop {
walk_tree(cursor, depth + 1);
if !cursor.goto_next_sibling() {
break;
}
}
cursor.goto_parent();
}
}
walk_tree(&mut cursor, 0);