AirLibrary/Indexing/Process/
ExtractSymbols.rs1use std::path::PathBuf;
65
66use crate::{
67 Indexing::{
68 Language::{ParseRust::ExtractRustSymbols, ParseTypeScript::ExtractTypeScriptSymbols},
69 State::CreateState::{SymbolInfo, SymbolKind, SymbolLocation},
70 },
71 Result,
72};
73
74pub async fn ExtractSymbols(file_path:&PathBuf, content:&[u8], language:&str) -> Result<Vec<SymbolInfo>> {
82 let content_str = String::from_utf8_lossy(content);
83 let mut symbols = Vec::new();
84
85 match language.to_lowercase().as_str() {
86 "rust" => symbols.extend(ExtractRustSymbols(&content_str, file_path)),
87 "typescript" | "javascript" => symbols.extend(ExtractTypeScriptSymbols(&content_str, file_path)),
88 _ => {},
89 }
90
91 Ok(symbols)
92}
93
94pub fn GroupSymbolsByKind(symbols:&[SymbolInfo]) -> std::collections::HashMap<SymbolKind, Vec<&SymbolInfo>> {
96 let mut grouped = std::collections::HashMap::new();
97
98 for symbol in symbols {
99 grouped.entry(symbol.kind.clone()).or_insert_with(Vec::new).push(symbol);
100 }
101
102 grouped
103}
104
105pub fn SortSymbolsByLine(symbols:&mut Vec<SymbolInfo>) { symbols.sort_by(|a, b| a.line.cmp(&b.line)); }
107
108pub fn FilterSymbolsByName<'a>(symbols:&'a [SymbolInfo], pattern:&str) -> Vec<&'a SymbolInfo> {
110 let pattern_lower = pattern.to_lowercase();
111 symbols
112 .iter()
113 .filter(|s| s.name.to_lowercase().contains(&pattern_lower))
114 .collect()
115}
116
117pub fn GetSymbolsByKind(symbols:&[SymbolInfo], kind:SymbolKind) -> Vec<&SymbolInfo> {
119 symbols.iter().filter(|s| s.kind == kind).collect()
120}
121
122pub fn FindSymbolAtLine(symbols:&[SymbolInfo], line:u32) -> Option<&SymbolInfo> {
124 symbols.iter().find(|s| s.line == line)
125}
126
127pub fn FindSymbolsInRange(symbols:&[SymbolInfo], start_line:u32, end_line:u32) -> Vec<&SymbolInfo> {
129 symbols.iter().filter(|s| s.line >= start_line && s.line <= end_line).collect()
130}
131
132pub fn GetSymbolStatistics(symbols:&[SymbolInfo]) -> SymbolStatistics {
134 let mut stats = SymbolStatistics { total:symbols.len(), by_kind:std::collections::HashMap::new() };
135
136 for symbol in symbols {
137 *stats.by_kind.entry(symbol.kind.clone()).or_insert(0) += 1;
138 }
139
140 stats
141}
142
143#[derive(Debug, Clone)]
145pub struct SymbolStatistics {
146 pub total:usize,
147 pub by_kind:std::collections::HashMap<SymbolKind, usize>,
148}
149
150impl std::fmt::Display for SymbolStatistics {
151 fn fmt(&self, f:&mut std::fmt::Formatter<'_>) -> std::fmt::Result {
152 write!(f, "Total symbols: {}", self.total)?;
153 for (kind, count) in &self.by_kind {
154 write!(f, ", {:?}: {}", kind, count)?;
155 }
156 Ok(())
157 }
158}
159
160pub fn ValidateSymbol(symbol:&SymbolInfo) -> bool {
162 !symbol.name.is_empty() && symbol.line > 0 && !symbol.full_path.is_empty()
163}
164
165pub fn DeduplicateSymbols(symbols:Vec<SymbolInfo>) -> Vec<SymbolInfo> {
167 let mut seen = std::collections::HashSet::new();
168 symbols.into_iter().filter(|s| seen.insert((s.name.clone(), s.line))).collect()
169}
170
171pub fn MergeSymbolLists(symbol_lists:Vec<Vec<SymbolInfo>>) -> Vec<SymbolInfo> {
173 let mut merged = Vec::new();
174 for symbols in symbol_lists {
175 merged.extend(symbols);
176 }
177 DeduplicateSymbols(merged)
178}
179
180pub fn DeduplicateLists(symbol_lists:Vec<Vec<SymbolInfo>>) -> Vec<Vec<SymbolInfo>> {
182 symbol_lists.into_iter().map(|list| DeduplicateSymbols(list)).collect()
183}
184
185pub fn CreateSymbolIndex(symbols:&[SymbolInfo]) -> std::collections::HashMap<String, Vec<usize>> {
187 let mut index = std::collections::HashMap::new();
188 for (idx, symbol) in symbols.iter().enumerate() {
189 index.entry(symbol.name.to_lowercase()).or_insert_with(Vec::new).push(idx);
190 }
191 index
192}
193
194pub fn FindSymbolsMatching<'a>(
196 symbols:&'a [SymbolInfo],
197 name_pattern:Option<&'a str>,
198 kind:&Option<SymbolKind>,
199 line_range:Option<(u32, u32)>,
200) -> Vec<&'a SymbolInfo> {
201 symbols
202 .iter()
203 .filter(|s| {
204 if let Some(pattern) = name_pattern {
205 if !s.name.to_lowercase().contains(&pattern.to_lowercase()) {
206 return false;
207 }
208 }
209 if let Some(k) = kind {
210 if s.kind != *k {
211 return false;
212 }
213 }
214 if let Some((start, end)) = line_range {
215 if s.line < start || s.line > end {
216 return false;
217 }
218 }
219 true
220 })
221 .collect()
222}