code_moniker_core/lang/
tree_util.rs1use tree_sitter::Node;
2
3pub(crate) fn node_position(node: Node<'_>) -> (u32, u32) {
4 (node.start_byte() as u32, node.end_byte() as u32)
5}
6
7pub(crate) fn node_slice<'src>(node: Node<'src>, source: &'src [u8]) -> &'src [u8] {
8 &source[node.start_byte()..node.end_byte().min(source.len())]
9}
10
11pub(crate) fn find_named_child<'tree>(parent: Node<'tree>, kind: &str) -> Option<Node<'tree>> {
12 let mut cursor = parent.walk();
13 parent
14 .named_children(&mut cursor)
15 .find(|c| c.kind() == kind)
16}
17
18pub(crate) fn find_descendant<'tree>(node: Node<'tree>, kind: &str) -> Option<Node<'tree>> {
19 if node.kind() == kind {
20 return Some(node);
21 }
22 let mut cursor = node.walk();
23 for c in node.named_children(&mut cursor) {
24 if let Some(d) = find_descendant(c, kind) {
25 return Some(d);
26 }
27 }
28 None
29}
30
31#[cfg(test)]
32mod tests {
33 use super::*;
34
35 fn parse_rust(src: &str) -> tree_sitter::Tree {
36 let mut p = tree_sitter::Parser::new();
37 p.set_language(&tree_sitter_rust::LANGUAGE.into()).unwrap();
38 p.parse(src, None).unwrap()
39 }
40
41 #[test]
42 fn node_position_returns_byte_range() {
43 let tree = parse_rust("pub fn foo() {}");
44 let root = tree.root_node();
45 assert_eq!(node_position(root), (0, 15));
46 }
47
48 #[test]
49 fn node_slice_borrows_from_source() {
50 let src = b"pub fn foo() {}";
51 let tree = parse_rust(std::str::from_utf8(src).unwrap());
52 let root = tree.root_node();
53 let slice = node_slice(root, src);
54 assert_eq!(slice, b"pub fn foo() {}");
55 assert_eq!(slice.as_ptr(), src.as_ptr());
56 }
57
58 #[test]
59 fn find_named_child_returns_first_match() {
60 let tree = parse_rust("pub fn a() {} pub fn b() {}");
61 let root = tree.root_node();
62 let first = find_named_child(root, "function_item").unwrap();
63 assert_eq!(first.start_byte(), 0);
64 }
65
66 #[test]
67 fn find_named_child_returns_none_when_absent() {
68 let tree = parse_rust("pub fn a() {}");
69 let root = tree.root_node();
70 assert!(find_named_child(root, "struct_item").is_none());
71 }
72
73 #[test]
74 fn find_descendant_is_recursive() {
75 let tree = parse_rust("pub fn a() { let x = 1; }");
76 let root = tree.root_node();
77 assert!(find_descendant(root, "let_declaration").is_some());
78 }
79
80 #[test]
81 fn find_descendant_matches_self() {
82 let tree = parse_rust("pub fn a() {}");
83 let root = tree.root_node();
84 assert_eq!(
85 find_descendant(root, "source_file").map(|n| n.start_byte()),
86 Some(0)
87 );
88 }
89}