Skip to content

Commit 8d3ef74

Browse files
ekropotinclaude
andcommitted
perf: optimize TreeSitterWalker cursor usage
Replace per-node cursor creation with single reusable cursor for tree traversal. This eliminates repeated allocations and improves performance for large documents. Changes: - Create single TreeCursor in walk() method instead of per-node cursors - Refactor walk_pre_order and walk_post_order to use cursor navigation - Use goto_first_child/goto_next_sibling/goto_parent for efficient traversal - Maintain correct pre-order and post-order semantics 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
1 parent 56bfbd0 commit 8d3ef74

3 files changed

Lines changed: 26 additions & 13 deletions

File tree

.claude/commands/publish.md

Lines changed: 0 additions & 3 deletions
This file was deleted.

.claude/commands/review.md

Lines changed: 0 additions & 1 deletion
This file was deleted.

crates/quickmark-core/src/tree_sitter_walker.rs

Lines changed: 26 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -25,25 +25,42 @@ impl<'a> TreeSitterWalker<'a> {
2525
}
2626

2727
pub fn walk(&self, mut callback: impl FnMut(Node)) {
28-
let root = self.tree.root_node();
28+
let mut cursor = self.tree.walk();
2929
match self.order {
30-
TraversalOrder::PreOrder => self.walk_pre_order(root, &mut callback),
31-
TraversalOrder::PostOrder => self.walk_post_order(root, &mut callback),
30+
TraversalOrder::PreOrder => self.walk_pre_order(&mut cursor, &mut callback),
31+
TraversalOrder::PostOrder => self.walk_post_order(&mut cursor, &mut callback),
3232
}
3333
}
3434

3535
#[allow(clippy::only_used_in_recursion)]
36-
fn walk_pre_order(&self, node: Node, callback: &mut impl FnMut(Node)) {
36+
fn walk_pre_order(&self, cursor: &mut tree_sitter::TreeCursor, callback: &mut impl FnMut(Node)) {
37+
let node = cursor.node();
3738
callback(node);
38-
for child in node.children(&mut node.walk()) {
39-
self.walk_pre_order(child, callback);
39+
40+
if cursor.goto_first_child() {
41+
loop {
42+
self.walk_pre_order(cursor, callback);
43+
if !cursor.goto_next_sibling() {
44+
break;
45+
}
46+
}
47+
cursor.goto_parent();
4048
}
4149
}
50+
4251
#[allow(clippy::only_used_in_recursion)]
43-
fn walk_post_order(&self, node: Node, callback: &mut impl FnMut(Node)) {
44-
for child in node.children(&mut node.walk()) {
45-
self.walk_post_order(child, callback);
52+
fn walk_post_order(&self, cursor: &mut tree_sitter::TreeCursor, callback: &mut impl FnMut(Node)) {
53+
if cursor.goto_first_child() {
54+
loop {
55+
self.walk_post_order(cursor, callback);
56+
if !cursor.goto_next_sibling() {
57+
break;
58+
}
59+
}
60+
cursor.goto_parent();
4661
}
62+
63+
let node = cursor.node();
4764
callback(node);
4865
}
4966
}

0 commit comments

Comments
 (0)