use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub enum Language {
Rust,
Python,
TypeScript,
JavaScript,
Go,
CSharp,
Java,
C,
Cpp,
Ruby,
Php,
Swift,
Kotlin,
Scala,
Dart,
Zig,
Lua,
Elixir,
Haskell,
R,
Bash,
Html,
Css,
Json,
}
impl Language {
pub fn from_extension(ext: &str) -> Option<Self> {
match ext {
"rs" => Some(Self::Rust),
"py" | "pyi" => Some(Self::Python),
"ts" | "tsx" => Some(Self::TypeScript),
"js" | "jsx" | "mjs" | "cjs" => Some(Self::JavaScript),
"go" => Some(Self::Go),
"cs" | "csx" => Some(Self::CSharp),
"java" => Some(Self::Java),
"c" | "h" => Some(Self::C),
"cpp" | "cxx" | "cc" | "hpp" | "hxx" | "hh" => Some(Self::Cpp),
"rb" | "rake" | "gemspec" => Some(Self::Ruby),
"php" => Some(Self::Php),
"swift" => Some(Self::Swift),
"kt" | "kts" => Some(Self::Kotlin),
"scala" | "sc" => Some(Self::Scala),
"dart" => Some(Self::Dart),
"zig" => Some(Self::Zig),
"lua" => Some(Self::Lua),
"ex" | "exs" => Some(Self::Elixir),
"hs" => Some(Self::Haskell),
"r" | "R" => Some(Self::R),
"sh" | "bash" | "zsh" => Some(Self::Bash),
"html" | "htm" => Some(Self::Html),
"css" => Some(Self::Css),
"json" => Some(Self::Json),
_ => 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,
},
}