Skip to main content

code_moniker_core/lang/
tree_util.rs

1use 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}