Use this file to discover all available pages before exploring further.
Tree-sitter is designed for high performance, but achieving optimal speed requires understanding its performance characteristics and following best practices.
// Creates new parser for every filefor file in files { let mut parser = Parser::new(); // Expensive! parser.set_language(&language)?; let tree = parser.parse(&file, None)?;}
Do:
// Reuse parser across fileslet mut parser = Parser::new();parser.set_language(&language)?;for file in files { let tree = parser.parse(&file, None)?; // Fast!}
Creating a parser allocates internal buffers. Reusing parsers amortizes this cost.
// Initial parselet mut tree = parser.parse(&old_source, None)?;// User makes an editlet edit = InputEdit { start_byte: 10, old_end_byte: 15, new_end_byte: 20, start_position: Point::new(0, 10), old_end_position: Point::new(0, 15), new_end_position: Point::new(0, 20),};tree.edit(&edit);// Reparse with old tree - only changed regions are reparsed!let new_tree = parser.parse(&new_source, Some(&tree))?;
for tree in trees { // Compiles query every iteration! let query = Query::new(&language, query_source)?; let matches = cursor.matches(&query, tree.root_node(), source);}
Do:
// Compile oncelet query = Query::new(&language, query_source)?;for tree in trees { // Reuse compiled query let matches = cursor.matches(&query, tree.root_node(), source);}
let query = Query::new(&language, query_source)?;let mut cursor = QueryCursor::new();for tree in trees { // Cursor is automatically reset for each query let matches = cursor.matches(&query, tree.root_node(), source);}
One cursor per thread is optimal. Cursors are NOT thread-safe.
let mut renderer = HtmlRenderer::new();// Pre-allocate based on estimated output sizerenderer.html.reserve(source.len() * 2);for event in events { renderer.render(event, source, &attributes)?;}
HtmlRenderer reserves 10KB by default (BUFFER_HTML_RESERVE_CAPACITY).
use rayon::prelude::*;files.par_iter().for_each(|file| { // Each thread gets its own context let mut context = TagsContext::new(); let tags = context.generate_tags( &config, file.as_bytes(), None, ).unwrap(); index_tags(tags);});
Copying trees is cheap (atomic refcount increment):
// Cheap copy for thread safetylet tree_copy = tree.clone();thread::spawn(move || { process_tree(tree_copy);});// Original tree still usableprocess_tree(tree);
let root = tree.root_node();// root is valid while tree exists// Don't store nodes long-termstruct BadCache<'a> { node: Node<'a>, // Ties cache lifetime to tree}// Instead, store node infostruct GoodCache { node_id: usize, range: Range<usize>,}