use std::cell::{OnceCell, RefCell};
use std::path::Path;
use super::{Language, Parser};
use crate::types::Symbol;
thread_local! {
static THREAD_PARSER: OnceCell<RefCell<Parser>> = const { OnceCell::new() };
}
pub fn parse_file_symbols(content: &str, path: &Path) -> Vec<Symbol> {
let ext = match path.extension().and_then(|e| e.to_str()) {
Some(ext) => ext,
None => return Vec::new(),
};
let lang = match Language::from_extension(ext) {
Some(lang) => lang,
None => return Vec::new(),
};
THREAD_PARSER.with(|cell| {
let parser = cell.get_or_init(|| RefCell::new(Parser::new()));
parser.borrow_mut().parse(content, lang).unwrap_or_default()
})
}
pub fn parse_with_language(content: &str, language: Language) -> Vec<Symbol> {
THREAD_PARSER.with(|cell| {
let parser = cell.get_or_init(|| RefCell::new(Parser::new()));
parser
.borrow_mut()
.parse(content, language)
.unwrap_or_default()
})
}
#[cfg(test)]
mod tests {
use super::*;
use std::path::PathBuf;
#[test]
fn test_parse_file_symbols_rust() {
let content = "fn main() { println!(\"test\"); }";
let path = PathBuf::from("test.rs");
let symbols = parse_file_symbols(content, &path);
assert!(!symbols.is_empty());
assert!(symbols.iter().any(|s| s.name == "main"));
}
#[test]
fn test_parse_file_symbols_python() {
let content = "def main():\n pass";
let path = PathBuf::from("test.py");
let symbols = parse_file_symbols(content, &path);
assert!(!symbols.is_empty());
}
#[test]
fn test_parse_file_symbols_javascript() {
let content = "function foo() { return 42; }";
let path = PathBuf::from("test.js");
let symbols = parse_file_symbols(content, &path);
assert!(!symbols.is_empty());
}
#[test]
fn test_parse_file_symbols_no_extension() {
let content = "fn main() {}";
let path = PathBuf::from("Makefile");
let symbols = parse_file_symbols(content, &path);
assert!(symbols.is_empty());
}
#[test]
fn test_parse_file_symbols_unsupported_extension() {
let content = "some content";
let path = PathBuf::from("test.unknown");
let symbols = parse_file_symbols(content, &path);
assert!(symbols.is_empty());
}
#[test]
fn test_parse_with_language() {
let content = "fn test() {}";
let symbols = parse_with_language(content, Language::Rust);
assert!(!symbols.is_empty());
}
#[test]
fn test_parse_with_language_multiple_calls() {
let content1 = "fn foo() {}";
let symbols1 = parse_with_language(content1, Language::Rust);
assert!(!symbols1.is_empty());
let content2 = "fn bar() {}";
let symbols2 = parse_with_language(content2, Language::Rust);
assert!(!symbols2.is_empty());
}
#[test]
fn test_parse_file_symbols_empty_content() {
let path = PathBuf::from("test.rs");
let symbols = parse_file_symbols("", &path);
assert!(symbols.is_empty());
}
#[test]
fn test_parse_file_symbols_invalid_syntax() {
let content = "fn main( {{{{{"; let path = PathBuf::from("test.rs");
let symbols = parse_file_symbols(content, &path);
}
}