Skip to content

Commit d7e2fb9

Browse files
ekropotinclaude
andauthored
perf: optimize TreeSitterWalker cursor usage (#148)
* 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> * chore: fix formatting --------- Co-authored-by: Claude <noreply@anthropic.com>
1 parent cfae6bd commit d7e2fb9

3 files changed

Lines changed: 34 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: 34 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -25,25 +25,50 @@ 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(
37+
&self,
38+
cursor: &mut tree_sitter::TreeCursor,
39+
callback: &mut impl FnMut(Node),
40+
) {
41+
let node = cursor.node();
3742
callback(node);
38-
for child in node.children(&mut node.walk()) {
39-
self.walk_pre_order(child, callback);
43+
44+
if cursor.goto_first_child() {
45+
loop {
46+
self.walk_pre_order(cursor, callback);
47+
if !cursor.goto_next_sibling() {
48+
break;
49+
}
50+
}
51+
cursor.goto_parent();
4052
}
4153
}
54+
4255
#[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);
56+
fn walk_post_order(
57+
&self,
58+
cursor: &mut tree_sitter::TreeCursor,
59+
callback: &mut impl FnMut(Node),
60+
) {
61+
if cursor.goto_first_child() {
62+
loop {
63+
self.walk_post_order(cursor, callback);
64+
if !cursor.goto_next_sibling() {
65+
break;
66+
}
67+
}
68+
cursor.goto_parent();
4669
}
70+
71+
let node = cursor.node();
4772
callback(node);
4873
}
4974
}

0 commit comments

Comments
 (0)