Skip to main content

spring_lsp/
diagnostic.rs

1//! 诊断引擎模块
2
3use dashmap::DashMap;
4use lsp_server::Connection;
5use lsp_types::{Diagnostic, PublishDiagnosticsParams, Url};
6
7/// 诊断引擎
8pub struct DiagnosticEngine {
9    /// 诊断缓存(DashMap 本身就是并发安全的)
10    diagnostics: DashMap<Url, Vec<Diagnostic>>,
11}
12
13impl DiagnosticEngine {
14    /// 创建新的诊断引擎
15    pub fn new() -> Self {
16        Self {
17            diagnostics: DashMap::new(),
18        }
19    }
20
21    /// 添加诊断
22    pub fn add(&self, uri: Url, diagnostic: Diagnostic) {
23        self.diagnostics.entry(uri).or_default().push(diagnostic);
24    }
25
26    /// 清除文档的诊断
27    pub fn clear(&self, uri: &Url) {
28        self.diagnostics.remove(uri);
29    }
30
31    /// 获取文档的诊断(返回克隆)
32    pub fn get(&self, uri: &Url) -> Vec<Diagnostic> {
33        self.diagnostics
34            .get(uri)
35            .map(|v| v.clone())
36            .unwrap_or_default()
37    }
38
39    /// 发布诊断到客户端
40    ///
41    /// 通过 LSP 的 `textDocument/publishDiagnostics` 通知将诊断信息发送给客户端。
42    /// 如果文档没有诊断信息,将发送空的诊断列表以清除之前的诊断。
43    ///
44    /// # 参数
45    ///
46    /// * `connection` - LSP 连接,用于发送通知
47    /// * `uri` - 文档 URI
48    ///
49    /// # 返回
50    ///
51    /// 如果发送成功返回 `Ok(())`,否则返回错误
52    pub fn publish(&self, connection: &Connection, uri: &Url) -> crate::Result<()> {
53        use lsp_server::{Message, Notification};
54        use lsp_types::notification::{Notification as _, PublishDiagnostics};
55
56        // 获取文档的诊断(如果没有则为空列表)
57        let diagnostics = self.get(uri);
58        let diagnostics_count = diagnostics.len();
59
60        // 创建发布诊断参数
61        let params = PublishDiagnosticsParams {
62            uri: uri.clone(),
63            diagnostics,
64            version: None,
65        };
66
67        // 创建通知
68        let notification = Notification {
69            method: PublishDiagnostics::METHOD.to_string(),
70            params: serde_json::to_value(params).map_err(|e| {
71                crate::Error::Other(anyhow::anyhow!("Failed to serialize diagnostics: {}", e))
72            })?,
73        };
74
75        // 发送通知
76        connection
77            .sender
78            .send(Message::Notification(notification))
79            .map_err(|e| {
80                crate::Error::Other(anyhow::anyhow!("Failed to send diagnostics: {}", e))
81            })?;
82
83        tracing::debug!("Published {} diagnostics for {}", diagnostics_count, uri);
84
85        Ok(())
86    }
87}
88
89impl Default for DiagnosticEngine {
90    fn default() -> Self {
91        Self::new()
92    }
93}