use tree_sitter::Node;
use crate::parse::source::SourceFile;
pub fn node_bytes<'a>(source: &'a SourceFile, node: Node<'_>) -> &'a [u8] {
&source.as_bytes()[node.start_byte()..node.end_byte()]
}
pub fn node_text(source: &SourceFile, node: Node<'_>) -> String {
String::from_utf8_lossy(node_bytes(source, node)).into_owned()
}
pub fn node_col(source: &SourceFile, node: Node<'_>) -> usize {
source.offset_to_line_col(node.start_byte()).1
}
pub fn node_line(source: &SourceFile, node: Node<'_>) -> usize {
source.offset_to_line_col(node.start_byte()).0
}
pub fn line_indent(source: &SourceFile, offset: usize) -> usize {
let (line, _) = source.offset_to_line_col(offset);
let Some(start) = source.line_start(line) else {
return 0;
};
let bytes = source.as_bytes();
let mut i = start;
while i < bytes.len() && (bytes[i] == b' ' || bytes[i] == b'\t') {
i += 1;
}
i - start
}
pub fn line_blank(source: &SourceFile, line: usize) -> bool {
let Some(start) = source.line_start(line) else {
return true;
};
let bytes = source.as_bytes();
let mut i = start;
while i < bytes.len() && bytes[i] != b'\n' {
if bytes[i] != b' ' && bytes[i] != b'\t' && bytes[i] != b'\r' {
return false;
}
i += 1;
}
true
}
pub fn child_kind<'a>(node: Node<'a>, kind: &str) -> Option<Node<'a>> {
let mut cur = node.walk();
node.children(&mut cur).find(|c| c.kind() == kind)
}
pub fn last_child_kind<'a>(node: Node<'a>, kind: &str) -> Option<Node<'a>> {
let mut cur = node.walk();
node.children(&mut cur).filter(|c| c.kind() == kind).last()
}
pub fn named_kids<'a>(node: Node<'a>) -> Vec<Node<'a>> {
let mut cur = node.walk();
node.named_children(&mut cur).collect()
}
pub fn end_keyword<'a>(node: Node<'a>) -> Option<Node<'a>> {
let mut cur = node.walk();
node.children(&mut cur)
.filter(|c| !c.is_named() && c.kind() == "end")
.last()
}