use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub enum Language {
Rust,
Python,
TypeScript,
JavaScript,
Go,
}
impl Language {
pub fn from_extension(ext: &str) -> Option<Self> {
match ext {
"rs" => Some(Self::Rust),
"py" => Some(Self::Python),
"ts" | "tsx" => Some(Self::TypeScript),
"js" | "jsx" | "mjs" | "cjs" => Some(Self::JavaScript),
"go" => Some(Self::Go),
_ => None,
}
}
pub fn from_filename(filename: &str) -> Option<Self> {
let ext = filename.rsplit('.').next()?;
Self::from_extension(ext)
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub struct Span {
pub start_byte: usize,
pub end_byte: usize,
pub start_line: u32,
pub start_col: u32,
pub end_line: u32,
pub end_col: u32,
}
impl Span {
pub fn from_node(node: &tree_sitter::Node) -> Self {
let start = node.start_position();
let end = node.end_position();
Self {
start_byte: node.start_byte(),
end_byte: node.end_byte(),
start_line: start.row as u32,
start_col: start.column as u32,
end_line: end.row as u32,
end_col: end.column as u32,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub enum SymbolKind {
Function,
Method,
Struct,
Class,
Enum,
Trait,
Interface,
Import,
Const,
Module,
TypeAlias,
Impl,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Symbol {
pub name: String,
pub kind: SymbolKind,
pub span: Span,
pub signature: String,
pub doc_comment: Option<String>,
pub parent: Option<String>,
pub children: Vec<Symbol>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Import {
pub path: String,
pub alias: Option<String>,
pub span: Span,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ParsedFile {
pub language: Language,
pub symbols: Vec<Symbol>,
pub imports: Vec<Import>,
}
impl ParsedFile {
pub fn all_symbols(&self) -> Vec<&Symbol> {
let mut out = Vec::new();
for sym in &self.symbols {
out.push(sym);
for child in &sym.children {
out.push(child);
}
}
out
}
pub fn find_symbol(&self, name: &str) -> Vec<&Symbol> {
self.all_symbols()
.into_iter()
.filter(|s| s.name == name)
.collect()
}
pub fn find_symbol_fuzzy(&self, query: &str) -> Vec<&Symbol> {
let query_lower = query.to_lowercase();
self.all_symbols()
.into_iter()
.filter(|s| s.name.to_lowercase().contains(&query_lower))
.collect()
}
}
#[derive(Debug, Clone)]
pub struct SymbolContext {
pub symbol: Symbol,
pub source: String,
pub references_in_file: Vec<Span>,
}
#[derive(Debug, Clone)]
pub enum SymbolChange {
Added(Symbol),
Removed(Symbol),
Modified {
old: Symbol,
new: Symbol,
signature_changed: bool,
},
}