1use serde::{Deserialize, Serialize};
7use strum::{EnumString, Display};
8
9#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
11pub struct Span {
12 pub start_line: usize,
14 pub end_line: usize,
16}
17
18impl Span {
19 pub fn new(start_line: usize, start_col: usize, end_line: usize, end_col: usize) -> Self {
20 let _ = (start_col, end_col);
22 Self {
23 start_line,
24 end_line,
25 }
26 }
27}
28
29#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, EnumString, Display)]
31#[strum(serialize_all = "PascalCase")]
32pub enum SymbolKind {
33 Function,
34 Class,
35 Struct,
36 Enum,
37 Interface,
38 Trait,
39 Constant,
40 Variable,
41 Method,
42 Module,
43 Namespace,
44 Type,
45 Macro,
46 Property,
47 Event,
48 Import,
49 Export,
50 Attribute,
51 #[strum(default)]
55 Unknown(String),
56}
57
58#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq, Default)]
60#[serde(rename_all = "lowercase")]
61pub enum Language {
62 #[default]
63 Rust,
64 Python,
65 JavaScript,
66 TypeScript,
67 Vue,
68 Svelte,
69 Go,
70 Java,
71 PHP,
72 C,
73 Cpp,
74 CSharp,
75 Ruby,
76 Kotlin,
77 Swift,
78 Zig,
79 Unknown,
80}
81
82impl Language {
83 pub fn from_extension(ext: &str) -> Self {
84 match ext {
85 "rs" => Language::Rust,
86 "py" => Language::Python,
87 "js" | "mjs" | "cjs" | "jsx" => Language::JavaScript,
88 "ts" | "mts" | "cts" | "tsx" => Language::TypeScript,
89 "vue" => Language::Vue,
90 "svelte" => Language::Svelte,
91 "go" => Language::Go,
92 "java" => Language::Java,
93 "php" => Language::PHP,
94 "c" | "h" => Language::C,
95 "cpp" | "cc" | "cxx" | "hpp" | "hxx" | "C" | "H" => Language::Cpp,
96 "cs" => Language::CSharp,
97 "rb" | "rake" | "gemspec" => Language::Ruby,
98 "kt" | "kts" => Language::Kotlin,
99 "swift" => Language::Swift,
100 "zig" => Language::Zig,
101 _ => Language::Unknown,
102 }
103 }
104
105 pub fn is_supported(&self) -> bool {
110 match self {
111 Language::Rust => true,
112 Language::TypeScript => true,
113 Language::JavaScript => true,
114 Language::Vue => true,
115 Language::Svelte => true,
116 Language::Python => true,
117 Language::Go => true,
118 Language::Java => true,
119 Language::PHP => true,
120 Language::C => true,
121 Language::Cpp => true,
122 Language::CSharp => true,
123 Language::Ruby => true,
124 Language::Kotlin => true,
125 Language::Swift => false, Language::Zig => true,
127 Language::Unknown => false,
128 }
129 }
130}
131
132#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
134#[serde(rename_all = "lowercase")]
135pub enum ImportType {
136 Internal,
138 External,
140 Stdlib,
142}
143
144#[derive(Debug, Clone, Serialize, Deserialize)]
147pub struct DependencyInfo {
148 pub path: String,
150 #[serde(skip_serializing_if = "Option::is_none")]
152 pub line: Option<usize>,
153 #[serde(skip_serializing_if = "Option::is_none")]
155 pub symbols: Option<Vec<String>>,
156}
157
158#[derive(Debug, Clone)]
160pub struct Dependency {
161 pub file_id: i64,
163 pub imported_path: String,
165 pub resolved_file_id: Option<i64>,
167 pub import_type: ImportType,
169 pub line_number: usize,
171 pub imported_symbols: Option<Vec<String>>,
173}
174
175fn is_unknown_kind(kind: &SymbolKind) -> bool {
177 matches!(kind, SymbolKind::Unknown(_))
178}
179
180#[derive(Debug, Clone, Serialize, Deserialize)]
182pub struct SearchResult {
183 pub path: String,
185 #[serde(skip)]
187 pub lang: Language,
188 #[serde(skip_serializing_if = "is_unknown_kind")]
190 pub kind: SymbolKind,
191 #[serde(skip_serializing_if = "Option::is_none")]
194 pub symbol: Option<String>,
195 pub span: Span,
197 pub preview: String,
199 #[serde(skip_serializing_if = "Option::is_none")]
202 pub dependencies: Option<Vec<DependencyInfo>>,
203}
204
205#[derive(Debug, Clone, Serialize, Deserialize)]
207pub struct MatchResult {
208 #[serde(skip_serializing_if = "is_unknown_kind")]
210 pub kind: SymbolKind,
211 #[serde(skip_serializing_if = "Option::is_none")]
213 pub symbol: Option<String>,
214 pub span: Span,
216 pub preview: String,
218 #[serde(skip_serializing_if = "Vec::is_empty")]
220 pub context_before: Vec<String>,
221 #[serde(skip_serializing_if = "Vec::is_empty")]
223 pub context_after: Vec<String>,
224}
225
226#[derive(Debug, Clone, Serialize, Deserialize)]
228pub struct FileGroupedResult {
229 pub path: String,
231 #[serde(skip_serializing_if = "Option::is_none")]
233 pub dependencies: Option<Vec<DependencyInfo>>,
234 pub matches: Vec<MatchResult>,
236}
237
238impl SearchResult {
239 pub fn new(
240 path: String,
241 lang: Language,
242 kind: SymbolKind,
243 symbol: Option<String>,
244 span: Span,
245 scope: Option<String>,
246 preview: String,
247 ) -> Self {
248 let _ = scope;
250 Self {
251 path,
252 lang,
253 kind,
254 symbol,
255 span,
256 preview,
257 dependencies: None,
258 }
259 }
260}
261
262#[derive(Debug, Clone, Serialize, Deserialize)]
264pub struct IndexConfig {
265 pub languages: Vec<Language>,
267 pub include_patterns: Vec<String>,
269 pub exclude_patterns: Vec<String>,
271 pub follow_symlinks: bool,
273 pub max_file_size: usize,
275 pub parallel_threads: usize,
277 pub query_timeout_secs: u64,
279}
280
281impl Default for IndexConfig {
282 fn default() -> Self {
283 Self {
284 languages: vec![],
285 include_patterns: vec![],
286 exclude_patterns: vec![],
287 follow_symlinks: false,
288 max_file_size: 10 * 1024 * 1024, parallel_threads: 0, query_timeout_secs: 30, }
292 }
293}
294
295#[derive(Debug, Clone, Serialize, Deserialize)]
297pub struct IndexStats {
298 pub total_files: usize,
300 pub index_size_bytes: u64,
302 pub last_updated: String,
304 pub files_by_language: std::collections::HashMap<String, usize>,
306 pub lines_by_language: std::collections::HashMap<String, usize>,
308}
309
310#[derive(Debug, Clone, Serialize, Deserialize)]
312pub struct IndexedFile {
313 pub path: String,
315 pub language: String,
317 pub last_indexed: String,
319}
320
321#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
323#[serde(rename_all = "snake_case")]
324pub enum IndexStatus {
325 Fresh,
327 Stale,
329}
330
331#[derive(Debug, Clone, Serialize, Deserialize)]
333pub struct IndexWarning {
334 pub reason: String,
336 pub action_required: String,
338 #[serde(skip_serializing_if = "Option::is_none")]
340 pub details: Option<IndexWarningDetails>,
341}
342
343#[derive(Debug, Clone, Serialize, Deserialize)]
345pub struct IndexWarningDetails {
346 #[serde(skip_serializing_if = "Option::is_none")]
348 pub current_branch: Option<String>,
349 #[serde(skip_serializing_if = "Option::is_none")]
351 pub indexed_branch: Option<String>,
352 #[serde(skip_serializing_if = "Option::is_none")]
354 pub current_commit: Option<String>,
355 #[serde(skip_serializing_if = "Option::is_none")]
357 pub indexed_commit: Option<String>,
358}
359
360#[derive(Debug, Clone, Serialize, Deserialize)]
362pub struct PaginationInfo {
363 pub total: usize,
365 pub count: usize,
367 pub offset: usize,
369 #[serde(skip_serializing_if = "Option::is_none")]
371 pub limit: Option<usize>,
372 pub has_more: bool,
374}
375
376#[derive(Debug, Clone, Serialize, Deserialize)]
378pub struct QueryResponse {
379 #[serde(skip_serializing_if = "Option::is_none")]
383 pub ai_instruction: Option<String>,
384 pub status: IndexStatus,
386 pub can_trust_results: bool,
388 #[serde(skip_serializing_if = "Option::is_none")]
390 pub warning: Option<IndexWarning>,
391 pub pagination: PaginationInfo,
393 pub results: Vec<FileGroupedResult>,
396}
397
398#[derive(Debug, Clone, Serialize, Deserialize)]
400pub struct CompactionReport {
401 pub files_removed: usize,
403 pub space_saved_bytes: u64,
405 pub duration_ms: u64,
407}