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