Skip to content

Instantly share code, notes, and snippets.

@mgsloan
Last active December 27, 2024 23:40
Show Gist options
  • Save mgsloan/e1820867f597a31b465b513f2b24431b to your computer and use it in GitHub Desktop.
Save mgsloan/e1820867f597a31b465b513f2b24431b to your computer and use it in GitHub Desktop.
Find tree sitter node enclosing range, could be used in zed-industries/refactor
// Look up a TreeSitter node based on a range from SCIP.
pub fn find_node<'a>(
start_node: tree_sitter::Node<'a>,
range: &Range<tree_sitter::Point>,
) -> Result<tree_sitter::Node<'a>> {
let mut cursor = start_node.walk();
// Descend to the first leaf that touches the start of the range, and if the range is
// non-empty, extends beyond the start.
while cursor.goto_first_child_for_point(range.start).is_some() {
if !range.is_empty() && cursor.node().end_position() == range.start {
cursor.goto_next_sibling();
}
}
// Ascend to the smallest ancestor that strictly contains the range.
loop {
let node = cursor.node();
let node_range = node.range();
if node_range.start_point <= range.start && node_range.end_point >= range.end {
if node_range.start_point == range.start && node_range.end_point == range.end {
return Ok(node);
} else {
return Err(anyhow::anyhow!(
"Mismatch between SCIP index and TreeSitter parse. \
Expected to find node at {}-{}, but containing ancestor is {}-{}.",
range.start,
range.end,
node_range.start_point,
node_range.end_point,
));
}
}
if !cursor.goto_parent() {
return Err(anyhow::anyhow!(
"Mismatch between SCIP index and TreeSitter parse. \
Expected to find node at {}-{}, but ran out of ancestor nodes.",
range.start,
range.end,
));
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment