Skip to main content

spring_lsp/
server.rs

1//! LSP 服务器核心实现
2//!
3//! 本模块实现了 spring-lsp 的核心 LSP 服务器功能,包括:
4//!
5//! ## 服务器能力
6//!
7//! ### 文档同步 (Text Document Sync)
8//! - 支持文档打开、修改、关闭通知
9//! - 使用增量更新模式 (INCREMENTAL) 提高性能
10//! - 自动缓存和管理文档内容
11//!
12//! ### 智能补全 (Completion)
13//! - TOML 配置文件:配置节、配置项、枚举值补全
14//! - Rust 代码:宏参数补全
15//! - 环境变量:`${VAR:default}` 格式的环境变量补全
16//! - 触发字符:`[`, `.`, `$`, `{`, `#`, `(`
17//!
18//! ### 悬停提示 (Hover)
19//! - 配置项:显示类型、文档、默认值
20//! - 宏:显示宏展开后的代码
21//! - 路由:显示完整路径和 HTTP 方法
22//! - 环境变量:显示当前值(如果可用)
23//!
24//! ### 定义跳转 (Go to Definition)
25//! - 路由路径:跳转到处理器函数定义
26//! - 组件注入:跳转到组件定义
27//!
28//! ### 文档符号 (Document Symbols)
29//! - 显示文档中的所有路由
30//! - 显示配置节和配置项
31//!
32//! ### 工作空间符号 (Workspace Symbols)
33//! - 全局搜索路由
34//! - 全局搜索组件
35//!
36//! ### 诊断 (Diagnostics)
37//! - 配置验证:类型检查、必需项检查、废弃警告
38//! - 路由验证:路径语法、参数类型、冲突检测
39//! - 依赖注入验证:组件存在性、循环依赖检测
40//!
41//! ## LSP 协议版本
42//!
43//! 本实现遵循 LSP 3.17 规范。
44
45use crate::completion::CompletionEngine;
46use crate::config::ServerConfig;
47use crate::diagnostic::DiagnosticEngine;
48use crate::document::DocumentManager;
49use crate::error::{ErrorHandler, RecoveryAction};
50use crate::index::IndexManager;
51use crate::macro_analyzer::MacroAnalyzer;
52use crate::route::RouteNavigator;
53use crate::schema::SchemaProvider;
54use crate::status::ServerStatus;
55use crate::toml_analyzer::TomlAnalyzer;
56use crate::{Error, Result};
57use lsp_server::{Connection, Message, Notification, Request, RequestId, Response};
58use lsp_types::{
59    notification::{
60        DidChangeTextDocument, DidCloseTextDocument, DidOpenTextDocument, Exit, Notification as _,
61    },
62    request::{Completion, GotoDefinition, HoverRequest, Request as _},
63    CompletionParams, CompletionResponse, DidChangeTextDocumentParams, DidCloseTextDocumentParams,
64    DidOpenTextDocumentParams, GotoDefinitionParams, GotoDefinitionResponse, HoverParams,
65    InitializeParams, InitializeResult, ServerCapabilities, ServerInfo,
66};
67use std::sync::Arc;
68
69/// 服务器状态
70#[derive(Debug, Clone, Copy, PartialEq, Eq)]
71pub enum ServerState {
72    /// 未初始化
73    Uninitialized,
74    /// 已初始化
75    Initialized,
76    /// 正在关闭
77    ShuttingDown,
78}
79
80/// LSP 服务器
81pub struct LspServer {
82    /// LSP 连接
83    connection: Connection,
84    /// 服务器状态
85    pub state: ServerState,
86    /// 文档管理器
87    pub document_manager: Arc<DocumentManager>,
88    /// 错误处理器
89    error_handler: ErrorHandler,
90    /// 服务器配置
91    pub config: ServerConfig,
92    /// 服务器状态跟踪器
93    pub status: ServerStatus,
94    /// Schema 提供者
95    pub schema_provider: Arc<SchemaProvider>,
96    /// TOML 分析器
97    pub toml_analyzer: Arc<TomlAnalyzer>,
98    /// 宏分析器
99    pub macro_analyzer: Arc<MacroAnalyzer>,
100    /// 路由导航器
101    pub route_navigator: Arc<RouteNavigator>,
102    /// 补全引擎
103    pub completion_engine: Arc<CompletionEngine>,
104    /// 诊断引擎
105    pub diagnostic_engine: Arc<DiagnosticEngine>,
106    /// 索引管理器
107    pub index_manager: Arc<IndexManager>,
108}
109
110impl LspServer {
111    /// 启动 LSP 服务器
112    ///
113    /// 这个方法创建服务器实例并初始化 LSP 连接
114    pub fn start() -> Result<Self> {
115        tracing::info!("Starting spring-lsp server");
116
117        // 通过标准输入输出创建 LSP 连接
118        let (connection, _io_threads) = Connection::stdio();
119
120        Self::new_with_connection(connection)
121    }
122
123    /// 为测试创建 LSP 服务器(不使用 stdio 连接)
124    pub fn new_for_test() -> Result<Self> {
125        // 创建一个假的连接,用于测试
126        // 我们不会实际使用这个连接发送消息
127        let (connection, _io_threads) = Connection::memory();
128
129        Self::new_with_connection(connection)
130    }
131
132    /// 使用给定连接创建服务器实例
133    fn new_with_connection(connection: Connection) -> Result<Self> {
134        // 加载默认配置(在初始化时会从客户端获取工作空间路径并重新加载)
135        let config = ServerConfig::load(None);
136
137        // 验证配置
138        if let Err(e) = config.validate() {
139            tracing::error!("Invalid configuration: {}", e);
140            return Err(Error::Config(e));
141        }
142
143        // 从配置读取是否启用详细日志
144        let verbose = config.logging.verbose;
145
146        // 初始化所有组件
147        tracing::info!("Initializing components...");
148
149        // 1. Schema 提供者(使用 fallback schema 初始化,避免测试时的异步加载问题)
150        let schema_provider = Arc::new(SchemaProvider::default());
151
152        // 2. TOML 分析器
153        let toml_analyzer = Arc::new(TomlAnalyzer::new((*schema_provider).clone()));
154
155        // 3. 宏分析器
156        let macro_analyzer = Arc::new(MacroAnalyzer::new());
157
158        // 4. 路由导航器
159        let route_navigator = Arc::new(RouteNavigator::new());
160
161        // 5. 补全引擎
162        let completion_engine = Arc::new(CompletionEngine::new((*schema_provider).clone()));
163
164        // 6. 诊断引擎
165        let diagnostic_engine = Arc::new(DiagnosticEngine::new());
166
167        // 7. 索引管理器
168        let index_manager = Arc::new(IndexManager::new());
169
170        tracing::info!("All components initialized successfully");
171
172        Ok(Self {
173            connection,
174            state: ServerState::Uninitialized,
175            document_manager: Arc::new(DocumentManager::new()),
176            error_handler: ErrorHandler::new(verbose),
177            config,
178            status: ServerStatus::new(),
179            schema_provider,
180            toml_analyzer,
181            macro_analyzer,
182            route_navigator,
183            completion_engine,
184            diagnostic_engine,
185            index_manager,
186        })
187    }
188
189    /// 运行服务器主循环
190    ///
191    /// 这个方法处理初始化握手,然后进入主事件循环处理来自客户端的消息
192    pub fn run(&mut self) -> Result<()> {
193        // 处理初始化握手
194        self.initialize()?;
195
196        // 主事件循环
197        self.event_loop()?;
198
199        // 优雅关闭
200        self.shutdown()?;
201
202        Ok(())
203    }
204
205    /// 处理初始化握手
206    fn initialize(&mut self) -> Result<()> {
207        tracing::info!("Waiting for initialize request");
208
209        let (id, params) = self.connection.initialize_start()?;
210        let init_params: InitializeParams = serde_json::from_value(params)?;
211
212        tracing::info!(
213            "Received initialize request from client: {:?}",
214            init_params.client_info
215        );
216
217        let init_result = self.handle_initialize(init_params)?;
218        let init_result_json = serde_json::to_value(init_result)?;
219
220        self.connection.initialize_finish(id, init_result_json)?;
221
222        self.state = ServerState::Initialized;
223        tracing::info!("LSP server initialized successfully");
224
225        Ok(())
226    }
227
228    /// 主事件循环
229    ///
230    /// 处理来自客户端的所有消息,包括请求、响应和通知
231    fn event_loop(&mut self) -> Result<()> {
232        tracing::info!("Entering main event loop");
233
234        loop {
235            // 检查服务器状态
236            if self.state == ServerState::ShuttingDown {
237                tracing::info!("Server is shutting down, stopping event loop");
238                break;
239            }
240
241            // 接收消息
242            let msg = match self.connection.receiver.recv() {
243                Ok(msg) => msg,
244                Err(e) => {
245                    let error = Error::MessageReceive(e.to_string());
246                    let result = self.error_handler.handle(&error);
247
248                    match result.action {
249                        RecoveryAction::RetryConnection => {
250                            tracing::info!("Attempting to recover connection...");
251                            // 短暂等待后继续
252                            std::thread::sleep(std::time::Duration::from_millis(100));
253                            continue;
254                        }
255                        RecoveryAction::Abort => {
256                            tracing::error!("Fatal error receiving message, shutting down");
257                            break;
258                        }
259                        _ => {
260                            tracing::warn!("Unexpected recovery action for message receive error");
261                            break;
262                        }
263                    }
264                }
265            };
266
267            // 处理消息,捕获错误以保持服务器运行
268            if let Err(e) = self.handle_message(msg) {
269                // 记录错误
270                self.status.record_error();
271
272                let result = self.error_handler.handle(&e);
273
274                // 根据恢复策略决定是否继续
275                match result.action {
276                    RecoveryAction::Abort => {
277                        tracing::error!("Fatal error, shutting down server");
278                        self.state = ServerState::ShuttingDown;
279                        break;
280                    }
281                    _ => {
282                        // 其他错误继续运行
283                        if result.notify_client {
284                            // 向客户端发送错误通知
285                            if let Err(notify_err) = self.notify_client_error(&e) {
286                                tracing::error!(
287                                    "Failed to notify client about error: {}",
288                                    notify_err
289                                );
290                            }
291                        }
292                    }
293                }
294            }
295        }
296
297        Ok(())
298    }
299
300    /// 处理单个消息
301    fn handle_message(&mut self, msg: Message) -> Result<()> {
302        match msg {
303            Message::Request(req) => self.handle_request(req),
304            Message::Response(resp) => {
305                tracing::debug!("Received response: {:?}", resp.id);
306                // 响应消息通常不需要处理
307                Ok(())
308            }
309            Message::Notification(not) => self.handle_notification(not),
310        }
311    }
312
313    /// 处理请求
314    fn handle_request(&mut self, req: Request) -> Result<()> {
315        tracing::debug!("Received request: {} (id: {:?})", req.method, req.id);
316
317        // 记录请求
318        self.status.record_request();
319
320        // 处理关闭请求
321        if self.connection.handle_shutdown(&req)? {
322            tracing::info!("Received shutdown request");
323            self.state = ServerState::ShuttingDown;
324            return Ok(());
325        }
326
327        // 根据请求方法分发
328        match req.method.as_str() {
329            // 智能补全请求
330            Completion::METHOD => self.handle_completion(req),
331            // 悬停提示请求
332            HoverRequest::METHOD => self.handle_hover(req),
333            // 定义跳转请求
334            GotoDefinition::METHOD => self.handle_goto_definition(req),
335            // 状态查询请求
336            "spring-lsp/status" => self.handle_status_query(req),
337            _ => {
338                tracing::warn!("Unhandled request method: {}", req.method);
339                // 返回方法未实现错误
340                self.send_error_response(
341                    req.id,
342                    lsp_server::ErrorCode::MethodNotFound as i32,
343                    format!("Method not found: {}", req.method),
344                )
345            }
346        }?;
347
348        Ok(())
349    }
350
351    /// 处理通知
352    fn handle_notification(&mut self, not: Notification) -> Result<()> {
353        tracing::debug!("Received notification: {}", not.method);
354
355        match not.method.as_str() {
356            DidOpenTextDocument::METHOD => {
357                let params: DidOpenTextDocumentParams = serde_json::from_value(not.params)?;
358                self.handle_did_open(params)?;
359            }
360            DidChangeTextDocument::METHOD => {
361                let params: DidChangeTextDocumentParams = serde_json::from_value(not.params)?;
362                self.handle_did_change(params)?;
363            }
364            DidCloseTextDocument::METHOD => {
365                let params: DidCloseTextDocumentParams = serde_json::from_value(not.params)?;
366                self.handle_did_close(params)?;
367            }
368            Exit::METHOD => {
369                tracing::info!("Received exit notification");
370                self.state = ServerState::ShuttingDown;
371            }
372            _ => {
373                tracing::debug!("Unhandled notification method: {}", not.method);
374            }
375        }
376
377        Ok(())
378    }
379
380    /// 处理文档打开通知
381    pub fn handle_did_open(&mut self, params: DidOpenTextDocumentParams) -> Result<()> {
382        let doc = params.text_document;
383        tracing::info!("Document opened: {}", doc.uri);
384
385        self.document_manager.open(
386            doc.uri.clone(),
387            doc.version,
388            doc.text,
389            doc.language_id.clone(),
390        );
391
392        // 更新状态
393        self.status.increment_document_count();
394
395        // 触发文档分析和诊断
396        self.analyze_document(&doc.uri, &doc.language_id)?;
397
398        Ok(())
399    }
400
401    /// 处理文档修改通知
402    pub fn handle_did_change(&mut self, params: DidChangeTextDocumentParams) -> Result<()> {
403        let uri = params.text_document.uri;
404        let version = params.text_document.version;
405        tracing::debug!("Document changed: {} (version: {})", uri, version);
406
407        self.document_manager
408            .change(&uri, version, params.content_changes);
409
410        // 触发增量分析和诊断
411        if let Some(doc) = self.document_manager.get(&uri) {
412            self.analyze_document(&uri, &doc.language_id)?;
413        }
414
415        Ok(())
416    }
417
418    /// 处理文档关闭通知
419    pub fn handle_did_close(&mut self, params: DidCloseTextDocumentParams) -> Result<()> {
420        let uri = params.text_document.uri;
421        tracing::info!("Document closed: {}", uri);
422
423        self.document_manager.close(&uri);
424
425        // 更新状态
426        self.status.decrement_document_count();
427
428        // 清理相关的诊断和缓存
429        self.diagnostic_engine.clear(&uri);
430        let _ = self.diagnostic_engine.publish(&self.connection, &uri);
431
432        Ok(())
433    }
434
435    /// 处理智能补全请求
436    fn handle_completion(&mut self, req: Request) -> Result<()> {
437        tracing::debug!("Handling completion request");
438
439        let params: CompletionParams = serde_json::from_value(req.params)?;
440        self.status.record_completion();
441
442        let response = self.document_manager.with_document(
443            &params.text_document_position.text_document.uri,
444            |doc| {
445                // 根据文件类型选择补全策略
446                match doc.language_id.as_str() {
447                    "toml" => {
448                        if let Ok(toml_doc) = self.toml_analyzer.parse(&doc.content) {
449                            self.completion_engine.complete_toml_document(
450                                &toml_doc,
451                                params.text_document_position.position,
452                            )
453                        } else {
454                            vec![]
455                        }
456                    }
457                    "rust" => {
458                        // TODO: 实现 Rust 补全
459                        vec![]
460                    }
461                    _ => vec![],
462                }
463            },
464        );
465
466        let result = match response {
467            Some(completions) => serde_json::to_value(CompletionResponse::Array(completions))?,
468            None => serde_json::Value::Null,
469        };
470
471        let response = Response {
472            id: req.id,
473            result: Some(result),
474            error: None,
475        };
476
477        self.connection
478            .sender
479            .send(Message::Response(response))
480            .map_err(|e| Error::MessageSend(e.to_string()))?;
481
482        Ok(())
483    }
484
485    /// 处理悬停提示请求
486    fn handle_hover(&mut self, req: Request) -> Result<()> {
487        tracing::debug!("Handling hover request");
488
489        let params: HoverParams = serde_json::from_value(req.params)?;
490        self.status.record_hover();
491
492        let response = self.document_manager.with_document(
493            &params.text_document_position_params.text_document.uri,
494            |doc| {
495                // 根据文件类型选择分析器
496                match doc.language_id.as_str() {
497                    "toml" => {
498                        if let Ok(toml_doc) = self.toml_analyzer.parse(&doc.content) {
499                            self.toml_analyzer
500                                .hover(&toml_doc, params.text_document_position_params.position)
501                        } else {
502                            None
503                        }
504                    }
505                    "rust" => {
506                        // TODO: 实现 Rust 悬停提示
507                        None
508                    }
509                    _ => None,
510                }
511            },
512        );
513
514        let result = match response {
515            Some(Some(hover)) => serde_json::to_value(hover)?,
516            _ => serde_json::Value::Null,
517        };
518
519        let response = Response {
520            id: req.id,
521            result: Some(result),
522            error: None,
523        };
524
525        self.connection
526            .sender
527            .send(Message::Response(response))
528            .map_err(|e| Error::MessageSend(e.to_string()))?;
529
530        Ok(())
531    }
532
533    /// 处理定义跳转请求
534    fn handle_goto_definition(&mut self, req: Request) -> Result<()> {
535        tracing::debug!("Handling goto definition request");
536
537        let _params: GotoDefinitionParams = serde_json::from_value(req.params)?;
538
539        // TODO: 实现定义跳转逻辑
540        let result = GotoDefinitionResponse::Array(vec![]);
541
542        let response = Response {
543            id: req.id,
544            result: Some(serde_json::to_value(result)?),
545            error: None,
546        };
547
548        self.connection
549            .sender
550            .send(Message::Response(response))
551            .map_err(|e| Error::MessageSend(e.to_string()))?;
552
553        Ok(())
554    }
555
556    /// 分析文档并生成诊断
557    pub fn analyze_document(&mut self, uri: &lsp_types::Url, language_id: &str) -> Result<()> {
558        tracing::debug!("Analyzing document: {} ({})", uri, language_id);
559
560        // 清除旧的诊断
561        self.diagnostic_engine.clear(uri);
562
563        let diagnostics = self
564            .document_manager
565            .with_document(uri, |doc| {
566                match language_id {
567                    "toml" => {
568                        // TOML 文档分析
569                        match self.toml_analyzer.parse(&doc.content) {
570                            Ok(toml_doc) => {
571                                let mut diagnostics = Vec::new();
572
573                                // 配置验证
574                                let validation_diagnostics = self.toml_analyzer.validate(&toml_doc);
575                                diagnostics.extend(validation_diagnostics);
576
577                                diagnostics
578                            }
579                            Err(_e) => {
580                                // 解析错误
581                                vec![lsp_types::Diagnostic {
582                                    range: lsp_types::Range {
583                                        start: lsp_types::Position {
584                                            line: 0,
585                                            character: 0,
586                                        },
587                                        end: lsp_types::Position {
588                                            line: 0,
589                                            character: 0,
590                                        },
591                                    },
592                                    severity: Some(lsp_types::DiagnosticSeverity::ERROR),
593                                    code: Some(lsp_types::NumberOrString::String(
594                                        "parse_error".to_string(),
595                                    )),
596                                    code_description: None,
597                                    source: Some("spring-lsp".to_string()),
598                                    message: "TOML parse error".to_string(),
599                                    related_information: None,
600                                    tags: None,
601                                    data: None,
602                                }]
603                            }
604                        }
605                    }
606                    "rust" => {
607                        // Rust 文档分析
608                        // TODO: 实现完整的 Rust 分析
609                        vec![]
610                    }
611                    _ => {
612                        tracing::debug!("Unsupported language: {}", language_id);
613                        vec![]
614                    }
615                }
616            })
617            .unwrap_or_default();
618
619        // 过滤被禁用的诊断
620        let filtered_diagnostics: Vec<_> = diagnostics
621            .into_iter()
622            .filter(|diag| {
623                if let Some(lsp_types::NumberOrString::String(code)) = &diag.code {
624                    !self.config.diagnostics.is_disabled(code)
625                } else {
626                    true
627                }
628            })
629            .collect();
630
631        // 添加诊断
632        for diagnostic in filtered_diagnostics {
633            self.diagnostic_engine.add(uri.clone(), diagnostic);
634        }
635
636        // 发布诊断
637        let _ = self.diagnostic_engine.publish(&self.connection, uri);
638        self.status.record_diagnostic();
639
640        Ok(())
641    }
642
643    /// 处理状态查询请求
644    ///
645    /// 返回服务器的运行状态和性能指标
646    fn handle_status_query(&self, req: Request) -> Result<()> {
647        tracing::debug!("Handling status query request");
648
649        let metrics = self.status.get_metrics();
650        let result = serde_json::to_value(metrics)?;
651
652        let response = Response {
653            id: req.id,
654            result: Some(result),
655            error: None,
656        };
657
658        self.connection
659            .sender
660            .send(Message::Response(response))
661            .map_err(|e| Error::MessageSend(e.to_string()))?;
662
663        Ok(())
664    }
665
666    /// 处理初始化请求
667    ///
668    /// 声明服务器支持的所有能力,包括:
669    /// - 文档同步(增量更新)
670    /// - 智能补全(TOML 配置、宏参数、环境变量)
671    /// - 悬停提示(配置文档、宏展开、路由信息)
672    /// - 诊断(配置验证、路由验证、依赖注入验证)
673    /// - 定义跳转(路由导航)
674    /// - 文档符号(路由列表)
675    pub fn handle_initialize(&mut self, params: InitializeParams) -> Result<InitializeResult> {
676        use lsp_types::{
677            CompletionOptions, HoverProviderCapability, OneOf, TextDocumentSyncCapability,
678            TextDocumentSyncKind, TextDocumentSyncOptions, WorkDoneProgressOptions,
679        };
680
681        // 如果客户端提供了工作空间路径,重新加载配置
682        #[allow(deprecated)]
683        if let Some(root_uri) = params.root_uri {
684            if let Ok(workspace_path) = root_uri.to_file_path() {
685                tracing::info!(
686                    "Loading configuration from workspace: {}",
687                    workspace_path.display()
688                );
689                self.config = ServerConfig::load(Some(&workspace_path));
690
691                // 验证配置
692                if let Err(e) = self.config.validate() {
693                    tracing::error!("Invalid configuration: {}", e);
694                    return Err(Error::Config(e));
695                }
696
697                tracing::info!("Configuration loaded successfully");
698                tracing::debug!(
699                    "Trigger characters: {:?}",
700                    self.config.completion.trigger_characters
701                );
702                tracing::debug!("Schema URL: {}", self.config.schema.url);
703                tracing::debug!(
704                    "Disabled diagnostics: {:?}",
705                    self.config.diagnostics.disabled
706                );
707            }
708        }
709
710        Ok(InitializeResult {
711            capabilities: ServerCapabilities {
712                // 文档同步能力 - 支持增量更新
713                text_document_sync: Some(TextDocumentSyncCapability::Options(
714                    TextDocumentSyncOptions {
715                        open_close: Some(true),
716                        change: Some(TextDocumentSyncKind::INCREMENTAL),
717                        will_save: None,
718                        will_save_wait_until: None,
719                        save: None,
720                    },
721                )),
722
723                // 智能补全能力
724                // 支持 TOML 配置项、宏参数、环境变量补全
725                // 使用配置文件中的触发字符
726                completion_provider: Some(CompletionOptions {
727                    resolve_provider: Some(true),
728                    trigger_characters: Some(self.config.completion.trigger_characters.clone()),
729                    all_commit_characters: None,
730                    work_done_progress_options: WorkDoneProgressOptions {
731                        work_done_progress: None,
732                    },
733                    completion_item: None,
734                }),
735
736                // 悬停提示能力
737                // 支持配置文档、宏展开、路由信息显示
738                hover_provider: Some(HoverProviderCapability::Simple(true)),
739
740                // 定义跳转能力
741                // 支持路由路径跳转到处理器函数
742                definition_provider: Some(OneOf::Left(true)),
743
744                // 文档符号能力
745                // 支持显示文档中的所有路由
746                document_symbol_provider: Some(OneOf::Left(true)),
747
748                // 工作空间符号能力
749                // 支持全局搜索路由和组件
750                workspace_symbol_provider: Some(OneOf::Left(true)),
751
752                // 诊断能力(通过 publishDiagnostics 通知发送)
753                // 支持配置验证、路由验证、依赖注入验证
754
755                // 代码操作能力(未来支持快速修复)
756                // code_action_provider: Some(CodeActionProviderCapability::Simple(true)),
757
758                // 格式化能力(未来支持 TOML 格式化)
759                // document_formatting_provider: Some(OneOf::Left(true)),
760
761                // 重命名能力(未来支持配置项重命名)
762                // rename_provider: Some(OneOf::Left(true)),
763                ..Default::default()
764            },
765            server_info: Some(ServerInfo {
766                name: "spring-lsp".to_string(),
767                version: Some(env!("CARGO_PKG_VERSION").to_string()),
768            }),
769        })
770    }
771
772    /// 发送错误响应
773    fn send_error_response(&self, id: RequestId, code: i32, message: String) -> Result<()> {
774        let response = Response {
775            id,
776            result: None,
777            error: Some(lsp_server::ResponseError {
778                code,
779                message,
780                data: None,
781            }),
782        };
783
784        self.connection
785            .sender
786            .send(Message::Response(response))
787            .map_err(|e| Error::MessageSend(e.to_string()))?;
788
789        Ok(())
790    }
791
792    /// 向客户端发送错误通知
793    ///
794    /// 使用 window/showMessage 通知向客户端显示错误消息
795    fn notify_client_error(&self, error: &Error) -> Result<()> {
796        use lsp_types::{MessageType, ShowMessageParams};
797
798        let message_type = match error.severity() {
799            crate::error::ErrorSeverity::Error => MessageType::ERROR,
800            crate::error::ErrorSeverity::Warning => MessageType::WARNING,
801            crate::error::ErrorSeverity::Info => MessageType::INFO,
802        };
803
804        let params = ShowMessageParams {
805            typ: message_type,
806            message: error.to_string(),
807        };
808
809        let notification = Notification {
810            method: "window/showMessage".to_string(),
811            params: serde_json::to_value(params)?,
812        };
813
814        self.connection
815            .sender
816            .send(Message::Notification(notification))
817            .map_err(|e| Error::MessageSend(e.to_string()))?;
818
819        Ok(())
820    }
821
822    /// 优雅关闭服务器
823    pub fn shutdown(&mut self) -> Result<()> {
824        tracing::info!("Shutting down spring-lsp server");
825
826        // 清理资源
827        tracing::debug!("Clearing all diagnostics...");
828        // TODO: 清理所有文档的诊断
829        // 需要实现 DocumentManager::get_all_uris() 方法
830
831        tracing::debug!("Clearing document cache...");
832        // 清理文档缓存(DocumentManager 会自动清理)
833
834        tracing::debug!("Clearing indexes...");
835        // 索引管理器会自动清理
836
837        tracing::info!("Server shutdown complete");
838        Ok(())
839    }
840}
841
842impl Default for LspServer {
843    fn default() -> Self {
844        Self::start().expect("Failed to start LSP server")
845    }
846}
847
848#[cfg(test)]
849mod tests {
850    use super::*;
851    use lsp_types::{
852        ClientCapabilities, ClientInfo, InitializeParams, TextDocumentItem, Url,
853        VersionedTextDocumentIdentifier, WorkDoneProgressParams,
854    };
855
856    /// 测试服务器状态转换
857    #[test]
858    fn test_server_state_transitions() {
859        // 初始状态应该是未初始化
860        let server = LspServer::new_for_test().unwrap();
861        assert_eq!(server.state, ServerState::Uninitialized);
862    }
863
864    /// 测试文档打开
865    #[test]
866    fn test_document_open() {
867        let mut server = LspServer::new_for_test().unwrap();
868        server.state = ServerState::Initialized;
869
870        let uri = Url::parse("file:///test.toml").unwrap();
871        let params = DidOpenTextDocumentParams {
872            text_document: TextDocumentItem {
873                uri: uri.clone(),
874                language_id: "toml".to_string(),
875                version: 1,
876                text: "host = \"localhost\"".to_string(),
877            },
878        };
879
880        server.handle_did_open(params).unwrap();
881
882        // 验证文档已缓存
883        let doc = server.document_manager.get(&uri);
884        assert!(doc.is_some());
885        let doc = doc.unwrap();
886        assert_eq!(doc.version, 1);
887        assert_eq!(doc.content, "host = \"localhost\"");
888        assert_eq!(doc.language_id, "toml");
889    }
890
891    /// 测试文档修改
892    #[test]
893    fn test_document_change() {
894        let mut server = LspServer::new_for_test().unwrap();
895        server.state = ServerState::Initialized;
896
897        let uri = Url::parse("file:///test.toml").unwrap();
898
899        // 先打开文档
900        let open_params = DidOpenTextDocumentParams {
901            text_document: TextDocumentItem {
902                uri: uri.clone(),
903                language_id: "toml".to_string(),
904                version: 1,
905                text: "host = \"localhost\"".to_string(),
906            },
907        };
908        server.handle_did_open(open_params).unwrap();
909
910        // 修改文档
911        let change_params = DidChangeTextDocumentParams {
912            text_document: VersionedTextDocumentIdentifier {
913                uri: uri.clone(),
914                version: 2,
915            },
916            content_changes: vec![lsp_types::TextDocumentContentChangeEvent {
917                range: None,
918                range_length: None,
919                text: "host = \"127.0.0.1\"".to_string(),
920            }],
921        };
922        server.handle_did_change(change_params).unwrap();
923
924        // 验证文档已更新
925        let doc = server.document_manager.get(&uri).unwrap();
926        assert_eq!(doc.version, 2);
927        assert_eq!(doc.content, "host = \"127.0.0.1\"");
928    }
929
930    /// 测试文档关闭
931    #[test]
932    fn test_document_close() {
933        let mut server = LspServer::new_for_test().unwrap();
934        server.state = ServerState::Initialized;
935
936        let uri = Url::parse("file:///test.toml").unwrap();
937
938        // 先打开文档
939        let open_params = DidOpenTextDocumentParams {
940            text_document: TextDocumentItem {
941                uri: uri.clone(),
942                language_id: "toml".to_string(),
943                version: 1,
944                text: "host = \"localhost\"".to_string(),
945            },
946        };
947        server.handle_did_open(open_params).unwrap();
948
949        // 验证文档已缓存
950        assert!(server.document_manager.get(&uri).is_some());
951
952        // 关闭文档
953        let close_params = DidCloseTextDocumentParams {
954            text_document: lsp_types::TextDocumentIdentifier { uri: uri.clone() },
955        };
956        server.handle_did_close(close_params).unwrap();
957
958        // 验证文档已清理
959        assert!(server.document_manager.get(&uri).is_none());
960    }
961
962    /// 测试初始化响应
963    #[test]
964    fn test_initialize_response() {
965        let mut server = LspServer::new_for_test().unwrap();
966
967        #[allow(deprecated)]
968        let params = InitializeParams {
969            process_id: Some(1234),
970            root_uri: None,
971            capabilities: ClientCapabilities::default(),
972            client_info: Some(ClientInfo {
973                name: "test-client".to_string(),
974                version: Some("1.0.0".to_string()),
975            }),
976            locale: None,
977            root_path: None,
978            initialization_options: None,
979            trace: None,
980            workspace_folders: Some(vec![lsp_types::WorkspaceFolder {
981                uri: Url::parse("file:///workspace").unwrap(),
982                name: "workspace".to_string(),
983            }]),
984            work_done_progress_params: WorkDoneProgressParams::default(),
985        };
986
987        let result = server.handle_initialize(params).unwrap();
988
989        // 验证服务器信息
990        assert!(result.server_info.is_some());
991        let server_info = result.server_info.unwrap();
992        assert_eq!(server_info.name, "spring-lsp");
993        assert!(server_info.version.is_some());
994
995        // 验证服务器能力
996        let capabilities = result.capabilities;
997
998        // 验证文档同步能力
999        assert!(capabilities.text_document_sync.is_some());
1000        if let Some(lsp_types::TextDocumentSyncCapability::Options(sync_options)) =
1001            capabilities.text_document_sync
1002        {
1003            assert_eq!(sync_options.open_close, Some(true));
1004            assert_eq!(
1005                sync_options.change,
1006                Some(lsp_types::TextDocumentSyncKind::INCREMENTAL)
1007            );
1008        } else {
1009            panic!("Expected TextDocumentSyncOptions");
1010        }
1011
1012        // 验证补全能力
1013        assert!(capabilities.completion_provider.is_some());
1014        let completion = capabilities.completion_provider.unwrap();
1015        assert_eq!(completion.resolve_provider, Some(true));
1016        assert!(completion.trigger_characters.is_some());
1017        let triggers = completion.trigger_characters.unwrap();
1018        assert!(triggers.contains(&"[".to_string()));
1019        assert!(triggers.contains(&"$".to_string()));
1020        assert!(triggers.contains(&"{".to_string()));
1021
1022        // 验证悬停能力
1023        assert!(capabilities.hover_provider.is_some());
1024
1025        // 验证定义跳转能力
1026        assert!(capabilities.definition_provider.is_some());
1027
1028        // 验证文档符号能力
1029        assert!(capabilities.document_symbol_provider.is_some());
1030
1031        // 验证工作空间符号能力
1032        assert!(capabilities.workspace_symbol_provider.is_some());
1033    }
1034
1035    /// 测试错误恢复
1036    #[test]
1037    fn test_error_recovery() {
1038        let mut server = LspServer::new_for_test().unwrap();
1039        server.state = ServerState::Initialized;
1040
1041        // 尝试修改不存在的文档(应该不会崩溃)
1042        let uri = Url::parse("file:///nonexistent.toml").unwrap();
1043        let change_params = DidChangeTextDocumentParams {
1044            text_document: VersionedTextDocumentIdentifier {
1045                uri: uri.clone(),
1046                version: 1,
1047            },
1048            content_changes: vec![lsp_types::TextDocumentContentChangeEvent {
1049                range: None,
1050                range_length: None,
1051                text: "test".to_string(),
1052            }],
1053        };
1054
1055        // 这不应该导致错误,只是不会有任何效果
1056        let result = server.handle_did_change(change_params);
1057        assert!(result.is_ok());
1058
1059        // 验证文档仍然不存在
1060        assert!(server.document_manager.get(&uri).is_none());
1061    }
1062}