AirLibrary/Indexing/Language/
ParseRust.rs1use std::path::PathBuf;
67
68use crate::Indexing::State::CreateState::{SymbolInfo, SymbolKind};
69
70pub fn ExtractRustSymbols(content:&str, file_path:&PathBuf) -> Vec<SymbolInfo> {
72 let mut symbols = Vec::new();
73 let lines:Vec<&str> = content.lines().collect();
74
75 for (line_idx, line) in lines.iter().enumerate() {
76 let line_content = line.trim();
77 let line_num = line_idx as u32 + 1;
78
79 if line_content.starts_with("//") || line_content.starts_with("/*") || line_content.starts_with("*") {
81 continue;
82 }
83
84 symbols.extend(ExtractRustSymbolsFromLine(line_content, line_num, line, file_path));
86 }
87
88 symbols
89}
90
91fn ExtractRustSymbolsFromLine(line_content:&str, line_num:u32, line:&str, file_path:&PathBuf) -> Vec<SymbolInfo> {
93 let mut symbols = Vec::new();
94
95 if let Some(rest) = line_content.strip_prefix("struct ") {
97 let name = rest.split_whitespace().next().unwrap_or("").trim_end_matches('{');
98 if !name.is_empty() {
99 if let Some(col) = line.find("struct") {
100 symbols.push(SymbolInfo {
101 name:name.to_string(),
102 kind:SymbolKind::Struct,
103 line:line_num,
104 column:col as u32,
105 full_path:format!("{}::{}", file_path.display(), name),
106 });
107 }
108 }
109 }
110
111 if let Some(rest) = line_content.strip_prefix("impl ") {
113 let name = rest.split_whitespace().next().unwrap_or("").trim_end_matches('{');
114 if !name.is_empty() {
115 if let Some(col) = line.find("impl") {
116 symbols.push(SymbolInfo {
117 name:name.to_string(),
118 kind:SymbolKind::Method,
119 line:line_num,
120 column:col as u32,
121 full_path:format!("{}::{}::", file_path.display(), name),
122 });
123 }
124 }
125 }
126
127 if let Some(rest) = line_content.strip_prefix("fn ") {
129 let name = rest.split(|c| c == '(' || c == '<' || c == ':').next().unwrap_or("").trim();
130 if !name.is_empty() {
131 if let Some(col) = line.find("fn") {
132 symbols.push(SymbolInfo {
133 name:name.to_string(),
134 kind:SymbolKind::Function,
135 line:line_num,
136 column:col as u32,
137 full_path:format!("{}::{}", file_path.display(), name),
138 });
139 }
140 }
141 }
142
143 if let Some(rest) = line_content.strip_prefix("mod ") {
145 let name = rest.split_whitespace().next().unwrap_or("").trim_end_matches('{');
146 if !name.is_empty() {
147 if let Some(col) = line.find("mod") {
148 symbols.push(SymbolInfo {
149 name:name.to_string(),
150 kind:SymbolKind::Module,
151 line:line_num,
152 column:col as u32,
153 full_path:format!("{}::{}::", file_path.display(), name),
154 });
155 }
156 }
157 }
158
159 if let Some(rest) = line_content.strip_prefix("enum ") {
161 let name = rest.split_whitespace().next().unwrap_or("").trim_end_matches('{');
162 if !name.is_empty() {
163 if let Some(col) = line.find("enum") {
164 symbols.push(SymbolInfo {
165 name:name.to_string(),
166 kind:SymbolKind::Enum,
167 line:line_num,
168 column:col as u32,
169 full_path:format!("{}::{}", file_path.display(), name),
170 });
171 }
172 }
173 }
174
175 if let Some(rest) = line_content.strip_prefix("trait ") {
177 let name = rest.split_whitespace().next().unwrap_or("").trim_end_matches('{');
178 if !name.is_empty() {
179 if let Some(col) = line.find("trait") {
180 symbols.push(SymbolInfo {
181 name:name.to_string(),
182 kind:SymbolKind::Interface,
183 line:line_num,
184 column:col as u32,
185 full_path:format!("{}::{}", file_path.display(), name),
186 });
187 }
188 }
189 }
190
191 if let Some(rest) = line_content.strip_prefix("type ") {
193 let name = rest.split('=').next().unwrap_or("").trim().trim_end_matches(';');
194 if !name.is_empty() {
195 if let Some(col) = line.find("type") {
196 symbols.push(SymbolInfo {
197 name:name.to_string(),
198 kind:SymbolKind::TypeParameter,
199 line:line_num,
200 column:col as u32,
201 full_path:format!("{}::{}", file_path.display(), name),
202 });
203 }
204 }
205 }
206
207 if line_content.starts_with("const ") && !line_content.contains('=') {
209 if let Some(rest) = line_content.strip_prefix("const ") {
210 let name = rest.split(|c| c == ':' || c == '=').next().unwrap_or("").trim();
211 if !name.is_empty() {
212 if let Some(col) = line.find("const") {
213 symbols.push(SymbolInfo {
214 name:name.to_string(),
215 kind:SymbolKind::Constant,
216 line:line_num,
217 column:col as u32,
218 full_path:format!("{}::{}", file_path.display(), name),
219 });
220 }
221 }
222 }
223 }
224
225 if line_content.starts_with("static ") {
227 if let Some(rest) = line_content.strip_prefix("static ") {
228 let name = rest.split(|c| c == ':' || c == '=').next().unwrap_or("").trim();
229 if !name.is_empty() {
230 if let Some(col) = line.find("static") {
231 symbols.push(SymbolInfo {
232 name:name.to_string(),
233 kind:SymbolKind::Variable,
234 line:line_num,
235 column:col as u32,
236 full_path:format!("{}::{}", file_path.display(), name),
237 });
238 }
239 }
240 }
241 }
242
243 symbols
244}
245
246pub fn IsRustStruct(line:&str) -> bool {
248 let trimmed = line.trim();
249 let after_keywords = trimmed
250 .strip_prefix("pub ")
251 .or_else(|| trimmed.strip_prefix("unsafe "))
252 .or_else(|| trimmed.strip_prefix("pub(crate) "))
253 .unwrap_or(trimmed);
254 after_keywords.starts_with("struct ")
255}
256
257pub fn IsRustFunction(line:&str) -> bool {
259 let trimmed = line.trim();
260 let after_keywords = trimmed
261 .strip_prefix("pub ")
262 .or_else(|| trimmed.strip_prefix("pub(crate) "))
263 .or_else(|| trimmed.strip_prefix("unsafe "))
264 .or_else(|| trimmed.strip_prefix("async "))
265 .unwrap_or(trimmed);
266 after_keywords.starts_with("fn ")
267}
268
269pub fn IsRustImpl(line:&str) -> bool {
271 let trimmed = line.trim();
273 let after_keywords = trimmed
274 .strip_prefix("pub ")
275 .or_else(|| trimmed.strip_prefix("unsafe "))
276 .unwrap_or(trimmed);
277 after_keywords.starts_with("impl ")
278}
279
280pub fn ExtractVisibilityModifier(line:&str) -> Option<&str> {
282 let trimmed = line.trim();
283 if trimmed.starts_with("pub ") {
284 Some("pub")
285 } else if trimmed.starts_with("pub(crate) ") {
286 Some("pub(crate)")
287 } else if trimmed.starts_with("pub(super) ") {
288 Some("pub(super)")
289 } else if trimmed.starts_with("pub(in ") {
290 let rest = trimmed.strip_prefix("pub(in ").unwrap_or("");
292 let path = rest.split(')').next().unwrap_or("");
293 if !path.is_empty() {
294 Some(&trimmed[0..trimmed.find(')').unwrap_or(trimmed.len()) + 1])
295 } else {
296 None
297 }
298 } else {
299 None
300 }
301}