Skip to main content

sh_layer3/
lsp_client.rs

1//! # LSP Client
2//!
3//! Language Server Protocol 客户端。
4
5use crate::query_engine::{SymbolInfo, SymbolKind};
6use crate::types::{CodeLocation, CodeRange, Layer3Result};
7use async_trait::async_trait;
8use std::path::PathBuf;
9
10/// LSP 客户端 trait
11///
12/// 与 Language Server 通信的接口。
13#[async_trait]
14pub trait LspClient: Send + Sync {
15    /// 初始化连接
16    async fn initialize(&self, root_uri: String) -> Layer3Result<LspCapabilities>;
17
18    /// 关闭连接
19    async fn shutdown(&self) -> Layer3Result<bool>;
20
21    /// 打开文档
22    async fn open_document(
23        &self,
24        uri: String,
25        language_id: String,
26        content: String,
27    ) -> Layer3Result<bool>;
28
29    /// 关闭文档
30    async fn close_document(&self, uri: String) -> Layer3Result<bool>;
31
32    /// 更新文档内容
33    async fn change_document(&self, uri: String, changes: Vec<TextChange>) -> Layer3Result<bool>;
34
35    /// 保存文档
36    async fn save_document(&self, uri: String) -> Layer3Result<bool>;
37
38    /// 检查是否就绪
39    fn is_ready(&self) -> bool;
40
41    /// 获取支持的语言
42    fn supported_languages(&self) -> Vec<String>;
43}
44
45/// 文本变更
46#[derive(Debug, Clone)]
47pub struct TextChange {
48    /// 变更范围
49    pub range: CodeRange,
50    /// 变更范围长度(旧文本长度)
51    pub range_length: u32,
52    /// 新文本
53    pub text: String,
54}
55
56/// LSP 能力描述
57#[derive(Debug, Clone)]
58pub struct LspCapabilities {
59    /// 支持文本同步
60    pub text_document_sync: bool,
61    /// 支持悬停
62    pub hover_provider: bool,
63    /// 支持定义跳转
64    pub definition_provider: bool,
65    /// 支持引用查找
66    pub references_provider: bool,
67    /// 支持实现查找
68    pub implementation_provider: bool,
69    /// 支持类型定义
70    pub type_definition_provider: bool,
71    /// 支持文档符号
72    pub document_symbol_provider: bool,
73    /// 支持工作区符号
74    pub workspace_symbol_provider: bool,
75    /// 支持重命名
76    pub rename_provider: bool,
77    /// 支持代码补全
78    pub completion_provider: Option<CompletionOptions>,
79    /// 支持签名帮助
80    pub signature_help_provider: Option<SignatureHelpOptions>,
81}
82
83impl Default for LspCapabilities {
84    fn default() -> Self {
85        Self {
86            text_document_sync: true,
87            hover_provider: true,
88            definition_provider: true,
89            references_provider: true,
90            implementation_provider: false,
91            type_definition_provider: false,
92            document_symbol_provider: true,
93            workspace_symbol_provider: false,
94            rename_provider: false,
95            completion_provider: None,
96            signature_help_provider: None,
97        }
98    }
99}
100
101/// 补全选项
102#[derive(Debug, Clone)]
103pub struct CompletionOptions {
104    /// 触发字符
105    pub trigger_characters: Vec<String>,
106    /// 是否支持所有触发字符
107    pub all_commit_characters: Vec<String>,
108}
109
110/// 签名帮助选项
111#[derive(Debug, Clone)]
112pub struct SignatureHelpOptions {
113    /// 触发字符
114    pub trigger_characters: Vec<String>,
115    /// 重触发字符
116    pub retrigger_characters: Vec<String>,
117}
118
119/// LSP 请求 trait
120///
121/// 发送 LSP 请求的具体方法。
122#[async_trait]
123pub trait LspRequester: LspClient {
124    /// 发送定义请求
125    async fn request_definition(
126        &self,
127        uri: String,
128        position: Position,
129    ) -> Layer3Result<Option<LocationLink>>;
130
131    /// 发送引用请求
132    async fn request_references(
133        &self,
134        uri: String,
135        position: Position,
136        include_declaration: bool,
137    ) -> Layer3Result<Vec<LocationLink>>;
138
139    /// 发送悬停请求
140    async fn request_hover(
141        &self,
142        uri: String,
143        position: Position,
144    ) -> Layer3Result<Option<HoverResult>>;
145
146    /// 发送文档符号请求
147    async fn request_document_symbols(&self, uri: String) -> Layer3Result<Vec<DocumentSymbol>>;
148
149    /// 发送工作区符号请求
150    async fn request_workspace_symbols(&self, query: String) -> Layer3Result<Vec<SymbolInfo>>;
151}
152
153/// LSP 位置(行号从 0 开始)
154#[derive(Debug, Clone, Copy)]
155pub struct Position {
156    pub line: u32,
157    pub character: u32,
158}
159
160impl From<CodeLocation> for Position {
161    fn from(loc: CodeLocation) -> Self {
162        Self {
163            line: loc.line - 1, // LSP 行号从 0 开始
164            character: loc.column - 1,
165        }
166    }
167}
168
169/// 位置链接
170#[derive(Debug, Clone)]
171pub struct LocationLink {
172    /// 目标 URI
173    pub target_uri: String,
174    /// 目标范围
175    pub target_range: Range,
176    /// 目标选择范围
177    pub target_selection_range: Range,
178}
179
180/// LSP 范围
181#[derive(Debug, Clone, Copy)]
182pub struct Range {
183    pub start: Position,
184    pub end: Position,
185}
186
187/// 悬停结果
188#[derive(Debug, Clone)]
189pub struct HoverResult {
190    /// 内容
191    pub contents: MarkupContent,
192    /// 范围(可选)
193    pub range: Option<Range>,
194}
195
196/// 标记内容
197#[derive(Debug, Clone)]
198pub struct MarkupContent {
199    /// 内容类型
200    pub kind: MarkupKind,
201    /// 内容文本
202    pub value: String,
203}
204
205/// 标记类型
206#[derive(Debug, Clone, Copy, PartialEq, Eq)]
207pub enum MarkupKind {
208    PlainText,
209    Markdown,
210}
211
212/// 文档符号
213#[derive(Debug, Clone)]
214pub struct DocumentSymbol {
215    /// 符号名称
216    pub name: String,
217    /// 详细信息
218    pub detail: Option<String>,
219    /// 符号类型
220    pub kind: SymbolKind,
221    /// 是否deprecated
222    pub deprecated: bool,
223    /// 范围
224    pub range: Range,
225    /// 选择范围
226    pub selection_range: Range,
227    /// 子符号
228    pub children: Vec<DocumentSymbol>,
229}
230
231/// LSP 服务器管理器 trait
232#[async_trait]
233pub trait LspServerManager: Send + Sync {
234    /// 启动指定语言的 LSP 服务器
235    async fn start_server(&self, language: String, root_path: PathBuf) -> Layer3Result<String>;
236
237    /// 停止 LSP 服务器
238    async fn stop_server(&self, server_id: &str) -> Layer3Result<bool>;
239
240    /// 获取服务器的客户端
241    fn get_client(&self, server_id: &str) -> Option<&dyn LspClient>;
242
243    /// 列出活跃服务器
244    fn list_servers(&self) -> Vec<(String, String)>;
245}
246
247#[cfg(test)]
248mod tests {
249    use super::*;
250
251    #[test]
252    fn test_position_from_code_location() {
253        let loc = CodeLocation {
254            file: PathBuf::from("test.rs"),
255            line: 10,
256            column: 5,
257        };
258        let pos: Position = loc.into();
259        assert_eq!(pos.line, 9);
260        assert_eq!(pos.character, 4);
261    }
262
263    #[test]
264    fn test_lsp_capabilities_default() {
265        let caps = LspCapabilities::default();
266        assert!(caps.hover_provider);
267        assert!(caps.definition_provider);
268    }
269}