1use serde::{Deserialize, Serialize};
2use std::collections::HashMap;
3
4use crate::{
5 CacheInfo, CallNode, FileInfo, LocationInfo, SymbolInfo, WorkspaceInfo, DEFAULT_HEAD_LIMIT,
6};
7
8#[derive(Debug, Clone, Serialize, Deserialize)]
10#[serde(tag = "type", rename_all = "snake_case")]
11pub enum StreamMessage {
12 Symbol(SymbolInfo),
13 File(FileInfo),
14 Done(StreamDone),
15 Error { message: String },
16}
17
18#[derive(Debug, Clone, Default, Serialize, Deserialize)]
19pub struct StreamDone {
20 #[serde(skip_serializing_if = "Option::is_none")]
21 pub warning: Option<String>,
22 pub truncated: bool,
23 pub total_count: u32,
24 #[serde(skip_serializing_if = "Option::is_none")]
25 pub profiling: Option<ProfilingData>,
26}
27
28#[derive(Debug, Clone, Serialize, Deserialize)]
29pub struct FunctionStats {
30 pub name: String,
31 pub calls: u32,
32 pub total_us: u64,
33 pub avg_us: u64,
34 pub p90_us: u64,
35 pub max_us: u64,
36}
37
38#[derive(Debug, Clone, Serialize, Deserialize)]
39pub struct SpanNode {
40 pub name: String,
41 pub self_us: u64,
42 pub total_us: u64,
43 pub calls: u32,
44 pub children: Vec<SpanNode>,
45 pub is_parallel: bool,
46 #[serde(default, skip_serializing_if = "Vec::is_empty")]
47 pub properties: Vec<(String, String)>,
48}
49
50#[derive(Debug, Clone, Default, Serialize, Deserialize)]
51pub struct SpanTree {
52 pub roots: Vec<SpanNode>,
53 pub total_us: u64,
54 pub functions: Vec<FunctionStats>,
55}
56
57#[derive(Debug, Clone, Default, Serialize, Deserialize)]
58pub struct CacheStats {
59 pub symbol_hits: u32,
60 pub symbol_misses: u32,
61 pub hover_hits: u32,
62 pub hover_misses: u32,
63}
64
65impl CacheStats {
66 pub fn symbol_hit_rate(&self) -> f64 {
67 let total = self.symbol_hits + self.symbol_misses;
68 if total == 0 {
69 0.0
70 } else {
71 self.symbol_hits as f64 / total as f64 * 100.0
72 }
73 }
74
75 pub fn hover_hit_rate(&self) -> f64 {
76 let total = self.hover_hits + self.hover_misses;
77 if total == 0 {
78 0.0
79 } else {
80 self.hover_hits as f64 / total as f64 * 100.0
81 }
82 }
83}
84
85#[derive(Debug, Clone, Default, Serialize, Deserialize)]
86pub struct ProfilingData {
87 pub functions: Vec<FunctionStats>,
88 pub cache: CacheStats,
89 #[serde(skip_serializing_if = "Option::is_none")]
90 pub span_tree: Option<SpanTree>,
91}
92
93#[derive(Debug, Clone, Default, Serialize, Deserialize)]
94pub struct ServerStartupStats {
95 pub server_name: String,
96 pub workspace_root: String,
97 pub init_time_ms: u64,
98 pub ready_time_ms: u64,
99 pub total_time_ms: u64,
100 pub functions: Vec<FunctionStats>,
101}
102
103#[derive(Debug, Clone, Default, Serialize, Deserialize)]
104pub struct ServerIndexingStats {
105 pub server_name: String,
106 pub file_count: u32,
107 pub total_time_ms: u64,
108 pub functions: Vec<FunctionStats>,
109 pub cache: CacheStats,
110}
111
112#[derive(Debug, Clone, Default, Serialize, Deserialize)]
113pub struct WorkspaceProfilingData {
114 pub workspace_root: String,
115 pub total_files: u32,
116 pub total_time_ms: u64,
117 pub server_profiles: Vec<ServerProfilingData>,
118}
119
120#[derive(Debug, Clone, Default, Serialize, Deserialize)]
121pub struct ServerProfilingData {
122 pub server_name: String,
123 pub startup: Option<ServerStartupStats>,
124 pub indexing: Option<ServerIndexingStats>,
125}
126
127#[derive(Debug, Clone, Serialize, Deserialize)]
132pub struct RpcRequest<P> {
133 pub method: String,
134 pub params: P,
135 #[serde(default)]
136 pub profile: bool,
137}
138
139#[derive(Debug, Clone, Serialize, Deserialize)]
140pub struct RpcSuccessResponse<R> {
141 pub result: R,
142 #[serde(skip_serializing_if = "Option::is_none")]
143 pub profiling: Option<ProfilingData>,
144}
145
146#[derive(Debug, Clone, Serialize, Deserialize)]
147#[serde(untagged)]
148pub enum RpcResponse<R> {
149 Success(RpcSuccessResponse<R>),
150 Error { error: String },
151}
152
153impl<R> RpcResponse<R> {
154 pub fn success(result: R) -> Self {
155 RpcResponse::Success(RpcSuccessResponse {
156 result,
157 profiling: None,
158 })
159 }
160
161 pub fn success_with_profiling(result: R, profiling: ProfilingData) -> Self {
162 let profiling = if profiling.functions.is_empty() {
163 None
164 } else {
165 Some(profiling)
166 };
167 RpcResponse::Success(RpcSuccessResponse { result, profiling })
168 }
169
170 pub fn error(message: impl Into<String>) -> Self {
171 RpcResponse::Error {
172 error: message.into(),
173 }
174 }
175
176 pub fn into_result(self) -> Result<R, String> {
177 match self {
178 RpcResponse::Success(s) => Ok(s.result),
179 RpcResponse::Error { error } => Err(error),
180 }
181 }
182}
183
184#[derive(Debug, Clone, Default, Serialize, Deserialize)]
189pub struct ShutdownParams {}
190
191#[derive(Debug, Clone, Serialize, Deserialize)]
192pub struct ShutdownResult {
193 pub status: String,
194}
195
196#[derive(Debug, Clone, Default, Serialize, Deserialize)]
201pub struct DescribeSessionParams {
202 #[serde(default)]
203 pub include_profiling: bool,
204}
205
206#[derive(Debug, Clone, Serialize, Deserialize)]
207pub struct DescribeSessionResult {
208 pub daemon_pid: u32,
209 pub caches: HashMap<String, CacheInfo>,
210 pub workspaces: Vec<WorkspaceInfo>,
211 #[serde(skip_serializing_if = "Option::is_none")]
212 pub profiling: Option<Vec<WorkspaceProfilingData>>,
213}
214
215#[derive(Debug, Clone, Serialize, Deserialize)]
220pub struct GrepParams {
221 pub workspace_root: String,
222 #[serde(default = "default_pattern")]
223 pub pattern: String,
224 #[serde(skip_serializing_if = "Option::is_none")]
225 pub kinds: Option<Vec<String>>,
226 #[serde(default)]
227 pub case_sensitive: bool,
228 #[serde(default)]
229 pub include_docs: bool,
230 #[serde(skip_serializing_if = "Option::is_none")]
231 pub path_pattern: Option<String>,
232 #[serde(default)]
233 pub exclude_patterns: Vec<String>,
234 #[serde(default = "default_head_limit")]
235 pub limit: u32,
236}
237
238fn default_head_limit() -> u32 {
239 DEFAULT_HEAD_LIMIT
240}
241
242fn default_pattern() -> String {
243 ".*".to_string()
244}
245
246#[derive(Debug, Clone, Serialize, Deserialize)]
247pub struct GrepResult {
248 #[serde(default)]
249 pub symbols: Vec<SymbolInfo>,
250 #[serde(skip_serializing_if = "Option::is_none")]
251 pub warning: Option<String>,
252 #[serde(default)]
253 pub truncated: bool,
254 #[serde(skip_serializing_if = "Option::is_none")]
255 pub total_count: Option<u32>,
256}
257
258#[derive(Debug, Clone, Serialize, Deserialize)]
263pub struct FilesParams {
264 pub workspace_root: String,
265 #[serde(skip_serializing_if = "Option::is_none")]
266 pub subpath: Option<String>,
267 #[serde(default)]
268 pub exclude_patterns: Vec<String>,
269 #[serde(default)]
270 pub include_patterns: Vec<String>,
271 #[serde(skip_serializing_if = "Option::is_none")]
272 pub filter_pattern: Option<String>,
273 #[serde(default = "default_head_limit")]
274 pub head: u32,
275}
276
277#[derive(Debug, Clone, Serialize, Deserialize)]
278pub struct FilesResult {
279 pub files: HashMap<String, FileInfo>,
280 pub total_files: u32,
281 pub total_bytes: u64,
282 pub total_lines: u32,
283 #[serde(default)]
284 pub excluded_dirs: Vec<String>,
285 #[serde(default)]
286 pub truncated: bool,
287}
288
289#[derive(Debug, Clone, Serialize, Deserialize)]
294pub struct ShowParams {
295 pub workspace_root: String,
296 pub path: String,
297 pub line: u32,
298 #[serde(default)]
299 pub column: u32,
300 #[serde(default)]
301 pub context: u32,
302 #[serde(skip_serializing_if = "Option::is_none")]
303 pub head: Option<u32>,
304 #[serde(skip_serializing_if = "Option::is_none", alias = "symbol")]
305 pub symbol_name: Option<String>,
306 #[serde(skip_serializing_if = "Option::is_none", alias = "kind")]
307 pub symbol_kind: Option<String>,
308 #[serde(skip_serializing_if = "Option::is_none")]
309 pub range_start_line: Option<u32>,
310 #[serde(skip_serializing_if = "Option::is_none")]
311 pub range_end_line: Option<u32>,
312 #[serde(default)]
313 pub direct_location: bool,
314}
315
316#[derive(Debug, Clone, Serialize, Deserialize)]
317pub struct ShowResult {
318 pub path: String,
319 pub start_line: u32,
320 pub end_line: u32,
321 pub content: String,
322 #[serde(skip_serializing_if = "Option::is_none")]
323 pub symbol: Option<String>,
324 #[serde(default)]
325 pub truncated: bool,
326 #[serde(skip_serializing_if = "Option::is_none")]
327 pub total_lines: Option<u32>,
328}
329
330#[derive(Debug, Clone, Serialize, Deserialize)]
335pub struct ReferencesParams {
336 pub workspace_root: String,
337 pub path: String,
338 pub line: u32,
339 #[serde(default)]
340 pub column: u32,
341 #[serde(default)]
342 pub context: u32,
343 #[serde(default = "default_head_limit")]
344 pub head: u32,
345}
346
347#[derive(Debug, Clone, Serialize, Deserialize)]
348pub struct ReferencesResult {
349 pub locations: Vec<LocationInfo>,
350 #[serde(default)]
351 pub truncated: bool,
352 #[serde(skip_serializing_if = "Option::is_none")]
353 pub total_count: Option<u32>,
354}
355
356#[derive(Debug, Clone, Serialize, Deserialize)]
361pub struct DeclarationParams {
362 pub workspace_root: String,
363 pub path: String,
364 pub line: u32,
365 #[serde(default)]
366 pub column: u32,
367 #[serde(default)]
368 pub context: u32,
369 #[serde(default = "default_head_limit")]
370 pub head: u32,
371}
372
373#[derive(Debug, Clone, Serialize, Deserialize)]
374pub struct DeclarationResult {
375 pub locations: Vec<LocationInfo>,
376 #[serde(default)]
377 pub truncated: bool,
378 #[serde(skip_serializing_if = "Option::is_none")]
379 pub total_count: Option<u32>,
380}
381
382#[derive(Debug, Clone, Serialize, Deserialize)]
387pub struct ImplementationsParams {
388 pub workspace_root: String,
389 pub path: String,
390 pub line: u32,
391 #[serde(default)]
392 pub column: u32,
393 #[serde(default)]
394 pub context: u32,
395 #[serde(default = "default_head_limit")]
396 pub head: u32,
397}
398
399#[derive(Debug, Clone, Serialize, Deserialize)]
400pub struct ImplementationsResult {
401 #[serde(default)]
402 pub locations: Vec<LocationInfo>,
403 #[serde(skip_serializing_if = "Option::is_none")]
404 pub error: Option<String>,
405 #[serde(default)]
406 pub truncated: bool,
407 #[serde(skip_serializing_if = "Option::is_none")]
408 pub total_count: Option<u32>,
409}
410
411#[derive(Debug, Clone, Serialize, Deserialize)]
416pub struct SubtypesParams {
417 pub workspace_root: String,
418 pub path: String,
419 pub line: u32,
420 #[serde(default)]
421 pub column: u32,
422 #[serde(default)]
423 pub context: u32,
424 #[serde(default = "default_head_limit")]
425 pub head: u32,
426}
427
428#[derive(Debug, Clone, Serialize, Deserialize)]
429pub struct SubtypesResult {
430 pub locations: Vec<LocationInfo>,
431 #[serde(default)]
432 pub truncated: bool,
433 #[serde(skip_serializing_if = "Option::is_none")]
434 pub total_count: Option<u32>,
435}
436
437#[derive(Debug, Clone, Serialize, Deserialize)]
442pub struct SupertypesParams {
443 pub workspace_root: String,
444 pub path: String,
445 pub line: u32,
446 #[serde(default)]
447 pub column: u32,
448 #[serde(default)]
449 pub context: u32,
450 #[serde(default = "default_head_limit")]
451 pub head: u32,
452}
453
454#[derive(Debug, Clone, Serialize, Deserialize)]
455pub struct SupertypesResult {
456 pub locations: Vec<LocationInfo>,
457 #[serde(default)]
458 pub truncated: bool,
459 #[serde(skip_serializing_if = "Option::is_none")]
460 pub total_count: Option<u32>,
461}
462
463#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
468#[serde(rename_all = "lowercase")]
469pub enum CallsMode {
470 Outgoing,
471 Incoming,
472 Path,
473}
474
475#[derive(Debug, Clone, Serialize, Deserialize)]
476pub struct CallsParams {
477 pub workspace_root: String,
478 pub mode: CallsMode,
479 #[serde(skip_serializing_if = "Option::is_none")]
480 pub from_path: Option<String>,
481 #[serde(skip_serializing_if = "Option::is_none")]
482 pub from_line: Option<u32>,
483 #[serde(skip_serializing_if = "Option::is_none")]
484 pub from_column: Option<u32>,
485 #[serde(skip_serializing_if = "Option::is_none")]
486 pub from_symbol: Option<String>,
487 #[serde(skip_serializing_if = "Option::is_none")]
488 pub to_path: Option<String>,
489 #[serde(skip_serializing_if = "Option::is_none")]
490 pub to_line: Option<u32>,
491 #[serde(skip_serializing_if = "Option::is_none")]
492 pub to_column: Option<u32>,
493 #[serde(skip_serializing_if = "Option::is_none")]
494 pub to_symbol: Option<String>,
495 #[serde(default = "default_max_depth")]
496 pub max_depth: u32,
497 #[serde(default)]
498 pub include_non_workspace: bool,
499 #[serde(default = "default_head_limit")]
500 pub head: u32,
501}
502
503fn default_max_depth() -> u32 {
504 3
505}
506
507#[derive(Debug, Clone, Serialize, Deserialize)]
508pub struct CallsResult {
509 #[serde(skip_serializing_if = "Option::is_none")]
510 pub root: Option<CallNode>,
511 #[serde(skip_serializing_if = "Option::is_none")]
512 pub path: Option<Vec<CallNode>>,
513 #[serde(skip_serializing_if = "Option::is_none")]
514 pub message: Option<String>,
515 #[serde(skip_serializing_if = "Option::is_none")]
516 pub error: Option<String>,
517 #[serde(default)]
518 pub truncated: bool,
519}
520
521#[derive(Debug, Clone, Serialize, Deserialize)]
526pub struct RenameParams {
527 pub workspace_root: String,
528 pub path: String,
529 pub line: u32,
530 #[serde(default)]
531 pub column: u32,
532 pub new_name: String,
533}
534
535#[derive(Debug, Clone, Serialize, Deserialize)]
536pub struct RenameResult {
537 pub files_changed: Vec<String>,
538}
539
540#[derive(Debug, Clone, Serialize, Deserialize)]
545pub struct MoveFileParams {
546 pub workspace_root: String,
547 pub old_path: String,
548 pub new_path: String,
549}
550
551#[derive(Debug, Clone, Serialize, Deserialize)]
552pub struct MoveFileResult {
553 pub files_changed: Vec<String>,
554 pub imports_updated: bool,
555}
556
557#[derive(Debug, Clone, Serialize, Deserialize)]
562pub struct RawLspRequestParams {
563 pub workspace_root: String,
564 pub method: String,
565 #[serde(default)]
566 pub params: serde_json::Value,
567 #[serde(default = "default_language")]
568 pub language: String,
569}
570
571fn default_language() -> String {
572 "python".to_string()
573}
574
575#[derive(Debug, Clone, Serialize, Deserialize)]
580pub struct RestartWorkspaceParams {
581 pub workspace_root: String,
582}
583
584#[derive(Debug, Clone, Serialize, Deserialize)]
585pub struct RestartWorkspaceResult {
586 pub restarted: Vec<String>,
587}
588
589#[derive(Debug, Clone, Serialize, Deserialize)]
590pub struct RemoveWorkspaceParams {
591 pub workspace_root: String,
592}
593
594#[derive(Debug, Clone, Serialize, Deserialize)]
595pub struct RemoveWorkspaceResult {
596 pub servers_stopped: Vec<String>,
597}
598
599#[derive(Debug, Clone, Serialize, Deserialize)]
604pub struct AddWorkspaceParams {
605 pub workspace_root: String,
606}
607
608#[derive(Debug, Clone, Serialize, Deserialize)]
609pub struct AddWorkspaceResult {
610 pub added: bool,
611 pub workspace_root: String,
612 pub message: String,
613}
614
615#[derive(Debug, Clone, Serialize, Deserialize)]
620pub struct ResolveSymbolParams {
621 pub workspace_root: String,
622 pub symbol_path: String,
623}
624
625#[derive(Debug, Clone, Serialize, Deserialize)]
626pub struct ResolveSymbolResult {
627 #[serde(skip_serializing_if = "Option::is_none")]
628 pub path: Option<String>,
629 #[serde(skip_serializing_if = "Option::is_none")]
630 pub line: Option<u32>,
631 #[serde(skip_serializing_if = "Option::is_none")]
632 pub column: Option<u32>,
633 #[serde(skip_serializing_if = "Option::is_none")]
634 pub name: Option<String>,
635 #[serde(skip_serializing_if = "Option::is_none")]
636 pub kind: Option<String>,
637 #[serde(skip_serializing_if = "Option::is_none")]
638 pub container: Option<String>,
639 #[serde(skip_serializing_if = "Option::is_none")]
640 pub range_start_line: Option<u32>,
641 #[serde(skip_serializing_if = "Option::is_none")]
642 pub range_end_line: Option<u32>,
643 #[serde(skip_serializing_if = "Option::is_none")]
644 pub error: Option<String>,
645 #[serde(skip_serializing_if = "Option::is_none")]
646 pub matches: Option<Vec<SymbolInfo>>,
647 #[serde(skip_serializing_if = "Option::is_none")]
648 pub total_matches: Option<u32>,
649}
650
651#[derive(Default)]
652pub struct ResolveSymbolResultBuilder {
653 pub path: String,
654 pub line: u32,
655 pub column: u32,
656 pub name: Option<String>,
657 pub kind: Option<String>,
658 pub container: Option<String>,
659 pub range_start_line: Option<u32>,
660 pub range_end_line: Option<u32>,
661}
662
663impl ResolveSymbolResult {
664 pub fn success(builder: ResolveSymbolResultBuilder) -> Self {
665 Self {
666 path: Some(builder.path),
667 line: Some(builder.line),
668 column: Some(builder.column),
669 name: builder.name,
670 kind: builder.kind,
671 container: builder.container,
672 range_start_line: builder.range_start_line,
673 range_end_line: builder.range_end_line,
674 error: None,
675 matches: None,
676 total_matches: None,
677 }
678 }
679
680 pub fn not_found(symbol: &str) -> Self {
681 Self {
682 error: Some(format!("Symbol '{}' not found", symbol)),
683 path: None,
684 line: None,
685 column: None,
686 name: None,
687 kind: None,
688 container: None,
689 range_start_line: None,
690 range_end_line: None,
691 matches: None,
692 total_matches: None,
693 }
694 }
695
696 pub fn ambiguous(symbol: &str, matches: Vec<SymbolInfo>, total: u32) -> Self {
697 Self {
698 error: Some(format!(
699 "Symbol '{}' is ambiguous ({} matches)",
700 symbol, total
701 )),
702 matches: Some(matches),
703 total_matches: Some(total),
704 path: None,
705 line: None,
706 column: None,
707 name: None,
708 kind: None,
709 container: None,
710 range_start_line: None,
711 range_end_line: None,
712 }
713 }
714}