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