use tree_sitter::{Language, Node};
use crate::indexer::SymbolChunk;
pub(crate) struct HeadingNode {
pub(crate) level: u8,
pub(crate) text: String,
}
pub(crate) struct HierarchyTracker {
pub(crate) stack: Vec<HeadingNode>,
}
impl HierarchyTracker {
pub(crate) fn new() -> Self {
Self { stack: Vec::new() }
}
pub(crate) fn enter_heading(&mut self, level: u8, text: String) -> String {
while let Some(top) = self.stack.last() {
if top.level >= level {
self.stack.pop();
} else {
break;
}
}
let parent_path = if self.stack.is_empty() {
String::new()
} else {
self.stack
.iter()
.map(|node| node.text.as_str())
.collect::<Vec<_>>()
.join(" > ")
};
self.stack.push(HeadingNode { level, text });
parent_path
}
pub(crate) fn get_current_path(&self) -> String {
if self.stack.is_empty() {
String::new()
} else {
self.stack
.iter()
.map(|node| node.text.as_str())
.collect::<Vec<_>>()
.join(" > ")
}
}
}
pub(crate) fn lang_python() -> Language {
tree_sitter_python::language()
}
pub(crate) fn lang_rust() -> Language {
tree_sitter_rust::language()
}
pub(crate) fn lang_go() -> Language {
tree_sitter_go::language()
}
pub(crate) fn lang_ruby() -> Language {
tree_sitter_ruby::language()
}
pub(crate) fn lang_c() -> Language {
tree_sitter_c::language()
}
pub(crate) fn lang_csharp() -> Language {
tree_sitter_c_sharp::language()
}
pub(crate) fn lang_java() -> Language {
tree_sitter_java::language()
}
pub(crate) fn lang_cpp() -> Language {
tree_sitter_cpp::language()
}
pub(crate) fn extract_visibility_from_modifiers(
node: &Node,
source: &str,
visibility_keywords: &[&str],
default: &str,
) -> String {
let mut access_modifiers = Vec::new();
for child in node.children(&mut node.walk()) {
if child.kind() == "modifier" {
if let Ok(modifier_text) = child.utf8_text(source.as_bytes()) {
if visibility_keywords.contains(&modifier_text) {
access_modifiers.push(modifier_text.to_string());
}
}
}
}
if access_modifiers.is_empty() {
default.to_string()
} else {
access_modifiers.join(" ")
}
}
pub(crate) fn push_chunk(
source: &str,
node: Node,
name: Option<String>,
kind: &str,
out: &mut Vec<SymbolChunk>,
) {
let start = node.start_position();
let end = node.end_position();
let start_line = (start.row + 1) as i32;
let end_line = (end.row + 1) as i32;
let _preview = extract_preview(source, start_line, end_line);
out.push(SymbolChunk {
symbol_name: name,
kind: kind.to_string(),
signature: None,
docstring: None,
start_line,
end_line,
metadata: None,
});
}
pub(crate) fn extract_preview(source: &str, start_line: i32, end_line: i32) -> String {
let start = start_line.max(1) as usize - 1;
let end = end_line.max(start_line) as usize;
source
.lines()
.skip(start)
.take(end - start)
.take(60)
.collect::<Vec<_>>()
.join("\n")
}