use tree_sitter::Node;
use crate::parse;
#[derive(Debug, Clone, PartialEq, Eq)]
pub(super) struct Segment {
pub text: String,
pub line: usize,
}
pub(super) fn path_segments(node: Node, src: &[u8]) -> Option<Vec<Segment>> {
let mut out: Vec<Segment> = Vec::new();
let mut current = node;
loop {
match current.kind() {
"identifier" | "type_identifier" | "primitive_type" | "self" | "super" | "crate" => {
out.push(segment(current, src));
break;
}
"generic_type" | "generic_type_with_turbofish" => {
current = current.child_by_field_name("type")?;
}
"scoped_identifier" | "scoped_type_identifier" => {
let name = current.child_by_field_name("name")?;
out.push(segment(name, src));
match current.child_by_field_name("path") {
Some(path) => current = path,
None => {
out.push(Segment {
text: String::new(),
line: name.start_position().row + 1,
});
break;
}
}
}
_ => return None,
}
}
out.reverse();
Some(out)
}
fn segment(node: Node, src: &[u8]) -> Segment {
let text = parse::node_text(node, src);
Segment {
text: text.strip_prefix("r#").unwrap_or(&text).to_string(),
line: node.start_position().row + 1,
}
}
pub(super) fn join(segments: &[Segment]) -> String {
segments
.iter()
.map(|s| s.text.as_str())
.collect::<Vec<_>>()
.join("::")
}
pub(super) fn type_path_node(mut node: Node) -> Option<Node> {
loop {
let field = match node.kind() {
"reference_type" | "pointer_type" => "type",
"dynamic_type" | "abstract_type" => "trait",
"type_identifier"
| "scoped_type_identifier"
| "generic_type"
| "primitive_type"
| "identifier"
| "scoped_identifier" => return Some(node),
_ => return None,
};
node = node.child_by_field_name(field)?;
}
}