use crate::ContainerBody;
use tree_sitter::Node;
fn analyze_delimited_body(
body_node: &Node,
content: &str,
inner_indent: &str,
open: u8,
close: u8,
) -> Option<ContainerBody> {
let body_start = body_node.start_byte();
let body_end = body_node.end_byte();
let mut content_start = body_start;
for (i, byte) in content[body_start..body_end].bytes().enumerate() {
if byte == open {
content_start = body_start + i + 1;
while content_start < body_end {
let b = content.as_bytes()[content_start];
if b == b'\n' {
content_start += 1;
break;
} else if b.is_ascii_whitespace() {
content_start += 1;
} else {
break;
}
}
break;
}
}
let mut content_end = body_end;
for (i, byte) in content[body_start..body_end].bytes().rev().enumerate() {
if byte == close {
content_end = body_end - i - 1;
while content_end > content_start && content.as_bytes()[content_end - 1] == b' ' {
content_end -= 1;
}
break;
}
}
let is_empty = content[content_start..content_end].trim().is_empty();
Some(ContainerBody {
content_start,
content_end,
inner_indent: inner_indent.to_string(),
is_empty,
})
}
pub(crate) fn analyze_brace_body(
body_node: &Node,
content: &str,
inner_indent: &str,
) -> Option<ContainerBody> {
analyze_delimited_body(body_node, content, inner_indent, b'{', b'}')
}
pub(crate) fn analyze_end_body(
body_node: &Node,
content: &str,
inner_indent: &str,
) -> Option<ContainerBody> {
let body_start = body_node.start_byte();
let body_end = body_node.end_byte();
let content_start = if body_start < body_end && content.as_bytes()[body_start] == b'\n' {
body_start + 1
} else {
body_start
};
let is_empty = content[content_start..body_end].trim().is_empty();
Some(ContainerBody {
content_start,
content_end: body_end,
inner_indent: inner_indent.to_string(),
is_empty,
})
}
pub(crate) fn analyze_paren_body(
body_node: &Node,
content: &str,
inner_indent: &str,
) -> Option<ContainerBody> {
analyze_delimited_body(body_node, content, inner_indent, b'(', b')')
}
pub(crate) fn analyze_is_begin_end_body(
body_node: &Node,
content: &str,
inner_indent: &str,
) -> Option<ContainerBody> {
let start = body_node.start_byte();
let end = body_node.end_byte();
let bytes = content.as_bytes();
let mut content_start = start;
let mut c = body_node.walk();
for child in body_node.children(&mut c) {
if matches!(child.kind(), "is" | "begin") {
content_start = child.end_byte();
if content_start < end && bytes[content_start] == b'\n' {
content_start += 1;
}
}
}
let mut content_end = end;
let mut c2 = body_node.walk();
for child in body_node.children(&mut c2) {
if child.kind() == "end" {
content_end = child.start_byte();
while content_end > content_start && matches!(bytes[content_end - 1], b' ' | b'\t') {
content_end -= 1;
}
break;
}
}
let is_empty = content[content_start..content_end].trim().is_empty();
Some(ContainerBody {
content_start,
content_end,
inner_indent: inner_indent.to_string(),
is_empty,
})
}
pub(crate) fn analyze_do_end_body(
body_node: &Node,
content: &str,
inner_indent: &str,
) -> Option<ContainerBody> {
analyze_keyword_end_body(body_node, content, inner_indent)
}
pub(crate) fn analyze_keyword_end_body(
body_node: &Node,
content: &str,
inner_indent: &str,
) -> Option<ContainerBody> {
let body_start = body_node.start_byte();
let body_end = body_node.end_byte();
let bytes = content.as_bytes();
let mut content_start = body_start;
while content_start < body_end && bytes[content_start] != b'\n' {
content_start += 1;
}
if content_start < body_end && bytes[content_start] == b'\n' {
content_start += 1;
}
let mut content_end = body_end;
if body_end >= 3 && bytes.get(body_end - 3..body_end) == Some(b"end") {
content_end = body_end - 3;
while content_end > content_start && matches!(bytes[content_end - 1], b' ' | b'\t') {
content_end -= 1;
}
}
let is_empty = content[content_start..content_end].trim().is_empty();
Some(ContainerBody {
content_start,
content_end,
inner_indent: inner_indent.to_string(),
is_empty,
})
}