Skip to main content

sh_layer3/lsp/
protocol.rs

1//! LSP 协议实现
2//!
3//! 实现 LSP JSON-RPC 协议的消息编码和解码。
4
5use super::types::*;
6use super::LspError;
7use serde::{Deserialize, Serialize};
8use std::io::{BufRead, Write};
9
10/// JSON-RPC 请求 ID
11#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
12#[serde(untagged)]
13pub enum RequestId {
14    Number(i64),
15    String(String),
16}
17
18/// JSON-RPC 请求消息
19#[derive(Debug, Clone, Serialize, Deserialize)]
20pub struct LspRequest<P> {
21    pub jsonrpc: String,
22    pub id: RequestId,
23    pub method: String,
24    #[serde(skip_serializing_if = "Option::is_none")]
25    pub params: Option<P>,
26}
27
28/// JSON-RPC 响应消息
29#[derive(Debug, Clone, Serialize, Deserialize)]
30pub struct LspResponse<R> {
31    pub jsonrpc: String,
32    pub id: RequestId,
33    #[serde(skip_serializing_if = "Option::is_none")]
34    pub result: Option<R>,
35    #[serde(skip_serializing_if = "Option::is_none")]
36    pub error: Option<RpcError>,
37}
38
39/// JSON-RPC 通知消息
40#[derive(Debug, Clone, Serialize, Deserialize)]
41pub struct LspNotification<P> {
42    pub jsonrpc: String,
43    pub method: String,
44    #[serde(skip_serializing_if = "Option::is_none")]
45    pub params: Option<P>,
46}
47
48/// JSON-RPC 错误
49#[derive(Debug, Clone, Serialize, Deserialize)]
50pub struct RpcError {
51    pub code: i32,
52    pub message: String,
53    #[serde(skip_serializing_if = "Option::is_none")]
54    pub data: Option<serde_json::Value>,
55}
56
57/// LSP 消息类型
58#[derive(Debug, Clone)]
59pub enum LspMessage {
60    Request(LspRequest<serde_json::Value>),
61    Response(LspResponse<serde_json::Value>),
62    Notification(LspNotification<serde_json::Value>),
63}
64
65/// 消息内容类型(用于 Content-Length 头)
66pub trait MessageContent {
67    fn content(&self) -> Result<String, LspError>;
68}
69
70impl<P: Serialize> MessageContent for LspRequest<P> {
71    fn content(&self) -> Result<String, LspError> {
72        serde_json::to_string(self).map_err(LspError::Json)
73    }
74}
75
76impl<R: Serialize> MessageContent for LspResponse<R> {
77    fn content(&self) -> Result<String, LspError> {
78        serde_json::to_string(self).map_err(LspError::Json)
79    }
80}
81
82impl<P: Serialize> MessageContent for LspNotification<P> {
83    fn content(&self) -> Result<String, LspError> {
84        serde_json::to_string(self).map_err(LspError::Json)
85    }
86}
87
88/// 写消息到输出流
89pub fn write_message<W: Write, M: MessageContent>(
90    output: &mut W,
91    message: &M,
92) -> Result<(), LspError> {
93    let content = message.content()?;
94    let header = format!("Content-Length: {}\r\n\r\n", content.len());
95    output.write_all(header.as_bytes())?;
96    output.write_all(content.as_bytes())?;
97    output.flush()?;
98    Ok(())
99}
100
101/// 从输入流读取消息
102pub fn read_message<R: BufRead>(input: &mut R) -> Result<LspMessage, LspError> {
103    // 读取 Content-Length 头
104    let mut content_length: Option<usize> = None;
105
106    loop {
107        let mut line = String::new();
108        input.read_line(&mut line)?;
109
110        let line = line.trim();
111        if line.is_empty() {
112            break;
113        }
114
115        if let Some(stripped) = line.strip_prefix("Content-Length:") {
116            let value = stripped.trim();
117            content_length = Some(
118                value
119                    .parse()
120                    .map_err(|_| LspError::InvalidMessage("Invalid Content-Length".to_string()))?,
121            );
122        }
123    }
124
125    let content_length = content_length
126        .ok_or_else(|| LspError::InvalidMessage("Missing Content-Length header".to_string()))?;
127
128    // 读取内容
129    let mut content = vec![0u8; content_length];
130    input.read_exact(&mut content)?;
131
132    // 解析消息
133    let content_str = String::from_utf8(content)
134        .map_err(|_| LspError::InvalidMessage("Invalid UTF-8 content".to_string()))?;
135
136    // 尝试解析为各种消息类型
137    let value: serde_json::Value = serde_json::from_str(&content_str)?;
138
139    if let Some(_id) = value.get("id") {
140        if value.get("error").is_some() {
141            let response: LspResponse<serde_json::Value> = serde_json::from_str(&content_str)?;
142            Ok(LspMessage::Response(response))
143        } else {
144            let request: LspRequest<serde_json::Value> = serde_json::from_str(&content_str)?;
145            Ok(LspMessage::Request(request))
146        }
147    } else {
148        let notification: LspNotification<serde_json::Value> = serde_json::from_str(&content_str)?;
149        Ok(LspMessage::Notification(notification))
150    }
151}
152
153/// 创建初始化请求
154pub fn create_initialize_request(
155    id: RequestId,
156    root_uri: Option<String>,
157    client_name: &str,
158    client_version: &str,
159) -> LspRequest<InitializeParams> {
160    LspRequest {
161        jsonrpc: "2.0".to_string(),
162        id,
163        method: "initialize".to_string(),
164        params: Some(InitializeParams {
165            process_id: Some(std::process::id()),
166            client_info: Some(ClientInfo {
167                name: client_name.to_string(),
168                version: Some(client_version.to_string()),
169            }),
170            root_uri,
171            capabilities: ClientCapabilities {
172                text_document: Some(TextDocumentClientCapabilities {
173                    completion: Some(CompletionClientCapabilities {
174                        completion_item: Some(CompletionItemCapability {
175                            documentation_format: Some(vec!["markdown".to_string()]),
176                        }),
177                    }),
178                    hover: Some(HoverClientCapabilities {
179                        content_format: Some(vec!["markdown".to_string()]),
180                    }),
181                }),
182            },
183        }),
184    }
185}
186
187/// 创建 didOpen 通知
188pub fn create_did_open_notification(
189    uri: DocumentUri,
190    language_id: &str,
191    version: i32,
192    text: &str,
193) -> LspNotification<DidOpenTextDocumentParams> {
194    LspNotification {
195        jsonrpc: "2.0".to_string(),
196        method: "textDocument/didOpen".to_string(),
197        params: Some(DidOpenTextDocumentParams {
198            text_document: TextDocumentItem {
199                uri,
200                language_id: language_id.to_string(),
201                version,
202                text: text.to_string(),
203            },
204        }),
205    }
206}
207
208/// 创建 didChange 通知
209pub fn create_did_change_notification(
210    uri: DocumentUri,
211    version: i32,
212    changes: Vec<TextDocumentContentChangeEvent>,
213) -> LspNotification<DidChangeTextDocumentParams> {
214    LspNotification {
215        jsonrpc: "2.0".to_string(),
216        method: "textDocument/didChange".to_string(),
217        params: Some(DidChangeTextDocumentParams {
218            text_document: VersionedTextDocumentIdentifier { uri, version },
219            content_changes: changes,
220        }),
221    }
222}
223
224/// 创建 didClose 通知
225pub fn create_did_close_notification(
226    uri: DocumentUri,
227) -> LspNotification<DidCloseTextDocumentParams> {
228    LspNotification {
229        jsonrpc: "2.0".to_string(),
230        method: "textDocument/didClose".to_string(),
231        params: Some(DidCloseTextDocumentParams {
232            text_document: TextDocumentIdentifier { uri },
233        }),
234    }
235}
236
237/// 创建定义请求
238pub fn create_definition_request(
239    id: RequestId,
240    uri: DocumentUri,
241    position: Position,
242) -> LspRequest<DefinitionParams> {
243    LspRequest {
244        jsonrpc: "2.0".to_string(),
245        id,
246        method: "textDocument/definition".to_string(),
247        params: Some(DefinitionParams {
248            text_document: TextDocumentIdentifier { uri },
249            position,
250        }),
251    }
252}
253
254/// 创建引用请求
255pub fn create_references_request(
256    id: RequestId,
257    uri: DocumentUri,
258    position: Position,
259    include_declaration: bool,
260) -> LspRequest<ReferenceParams> {
261    LspRequest {
262        jsonrpc: "2.0".to_string(),
263        id,
264        method: "textDocument/references".to_string(),
265        params: Some(ReferenceParams {
266            text_document: TextDocumentIdentifier { uri },
267            position,
268            context: ReferenceContext {
269                include_declaration,
270            },
271        }),
272    }
273}
274
275/// 创建 Hover 请求
276pub fn create_hover_request(
277    id: RequestId,
278    uri: DocumentUri,
279    position: Position,
280) -> LspRequest<HoverParams> {
281    LspRequest {
282        jsonrpc: "2.0".to_string(),
283        id,
284        method: "textDocument/hover".to_string(),
285        params: Some(HoverParams {
286            text_document: TextDocumentIdentifier { uri },
287            position,
288        }),
289    }
290}
291
292/// 创建重命名请求
293pub fn create_rename_request(
294    id: RequestId,
295    uri: DocumentUri,
296    position: Position,
297    new_name: &str,
298) -> LspRequest<RenameParams> {
299    LspRequest {
300        jsonrpc: "2.0".to_string(),
301        id,
302        method: "textDocument/rename".to_string(),
303        params: Some(RenameParams {
304            text_document: TextDocumentIdentifier { uri },
305            position,
306            new_name: new_name.to_string(),
307        }),
308    }
309}
310
311/// 创建文档符号请求
312pub fn create_document_symbol_request(
313    id: RequestId,
314    uri: DocumentUri,
315) -> LspRequest<DocumentSymbolParams> {
316    LspRequest {
317        jsonrpc: "2.0".to_string(),
318        id,
319        method: "textDocument/documentSymbol".to_string(),
320        params: Some(DocumentSymbolParams {
321            text_document: TextDocumentIdentifier { uri },
322        }),
323    }
324}
325
326// ============================================================================
327// 参数类型
328// ============================================================================
329
330/// didOpen 参数
331#[derive(Debug, Clone, Serialize, Deserialize)]
332pub struct DidOpenTextDocumentParams {
333    pub text_document: TextDocumentItem,
334}
335
336/// didChange 参数
337#[derive(Debug, Clone, Serialize, Deserialize)]
338pub struct DidChangeTextDocumentParams {
339    pub text_document: VersionedTextDocumentIdentifier,
340    pub content_changes: Vec<TextDocumentContentChangeEvent>,
341}
342
343/// didClose 参数
344#[derive(Debug, Clone, Serialize, Deserialize)]
345pub struct DidCloseTextDocumentParams {
346    pub text_document: TextDocumentIdentifier,
347}
348
349/// 定义请求参数
350#[derive(Debug, Clone, Serialize, Deserialize)]
351pub struct DefinitionParams {
352    pub text_document: TextDocumentIdentifier,
353    pub position: Position,
354}
355
356/// 引用请求参数
357#[derive(Debug, Clone, Serialize, Deserialize)]
358pub struct ReferenceParams {
359    pub text_document: TextDocumentIdentifier,
360    pub position: Position,
361    pub context: ReferenceContext,
362}
363
364/// Hover 请求参数
365#[derive(Debug, Clone, Serialize, Deserialize)]
366pub struct HoverParams {
367    pub text_document: TextDocumentIdentifier,
368    pub position: Position,
369}
370
371/// 重命名请求参数
372#[derive(Debug, Clone, Serialize, Deserialize)]
373pub struct RenameParams {
374    pub text_document: TextDocumentIdentifier,
375    pub position: Position,
376    pub new_name: String,
377}
378
379/// 文档符号请求参数
380#[derive(Debug, Clone, Serialize, Deserialize)]
381pub struct DocumentSymbolParams {
382    pub text_document: TextDocumentIdentifier,
383}
384
385/// 工作区符号请求参数
386#[derive(Debug, Clone, Serialize, Deserialize)]
387pub struct WorkspaceSymbolParams {
388    pub query: String,
389}
390
391/// 代码动作请求参数
392#[derive(Debug, Clone, Serialize, Deserialize)]
393pub struct CodeActionParams {
394    pub text_document: TextDocumentIdentifier,
395    pub range: Range,
396    pub context: CodeActionContext,
397}
398
399/// 签名帮助请求参数
400#[derive(Debug, Clone, Serialize, Deserialize)]
401pub struct SignatureHelpParams {
402    pub text_document: TextDocumentIdentifier,
403    pub position: Position,
404}
405
406/// 文档高亮请求参数
407#[derive(Debug, Clone, Serialize, Deserialize)]
408pub struct DocumentHighlightParams {
409    pub text_document: TextDocumentIdentifier,
410    pub position: Position,
411}
412
413/// 格式化请求参数
414#[derive(Debug, Clone, Serialize, Deserialize)]
415pub struct DocumentFormattingParams {
416    pub text_document: TextDocumentIdentifier,
417    pub options: FormattingOptions,
418}
419
420/// 范围格式化请求参数
421#[derive(Debug, Clone, Serialize, Deserialize)]
422pub struct DocumentRangeFormattingParams {
423    pub text_document: TextDocumentIdentifier,
424    pub range: Range,
425    pub options: FormattingOptions,
426}
427
428/// 创建工作区符号请求
429pub fn create_workspace_symbol_request(
430    id: RequestId,
431    query: &str,
432) -> LspRequest<WorkspaceSymbolParams> {
433    LspRequest {
434        jsonrpc: "2.0".to_string(),
435        id,
436        method: "workspace/symbol".to_string(),
437        params: Some(WorkspaceSymbolParams {
438            query: query.to_string(),
439        }),
440    }
441}
442
443/// 创建代码动作请求
444pub fn create_code_action_request(
445    id: RequestId,
446    uri: DocumentUri,
447    range: Range,
448    context: CodeActionContext,
449) -> LspRequest<CodeActionParams> {
450    LspRequest {
451        jsonrpc: "2.0".to_string(),
452        id,
453        method: "textDocument/codeAction".to_string(),
454        params: Some(CodeActionParams {
455            text_document: TextDocumentIdentifier { uri },
456            range,
457            context,
458        }),
459    }
460}
461
462/// 创建签名帮助请求
463pub fn create_signature_help_request(
464    id: RequestId,
465    uri: DocumentUri,
466    position: Position,
467) -> LspRequest<SignatureHelpParams> {
468    LspRequest {
469        jsonrpc: "2.0".to_string(),
470        id,
471        method: "textDocument/signatureHelp".to_string(),
472        params: Some(SignatureHelpParams {
473            text_document: TextDocumentIdentifier { uri },
474            position,
475        }),
476    }
477}
478
479/// 创建文档高亮请求
480pub fn create_document_highlight_request(
481    id: RequestId,
482    uri: DocumentUri,
483    position: Position,
484) -> LspRequest<DocumentHighlightParams> {
485    LspRequest {
486        jsonrpc: "2.0".to_string(),
487        id,
488        method: "textDocument/documentHighlight".to_string(),
489        params: Some(DocumentHighlightParams {
490            text_document: TextDocumentIdentifier { uri },
491            position,
492        }),
493    }
494}
495
496/// 创建格式化请求
497pub fn create_formatting_request(
498    id: RequestId,
499    uri: DocumentUri,
500    options: FormattingOptions,
501) -> LspRequest<DocumentFormattingParams> {
502    LspRequest {
503        jsonrpc: "2.0".to_string(),
504        id,
505        method: "textDocument/formatting".to_string(),
506        params: Some(DocumentFormattingParams {
507            text_document: TextDocumentIdentifier { uri },
508            options,
509        }),
510    }
511}
512
513/// 创建完成请求
514pub fn create_completion_request(
515    id: RequestId,
516    uri: DocumentUri,
517    position: Position,
518) -> LspRequest<CompletionParams> {
519    LspRequest {
520        jsonrpc: "2.0".to_string(),
521        id,
522        method: "textDocument/completion".to_string(),
523        params: Some(CompletionParams {
524            text_document: TextDocumentIdentifier { uri },
525            position,
526        }),
527    }
528}
529
530/// 完成请求参数
531#[derive(Debug, Clone, Serialize, Deserialize)]
532pub struct CompletionParams {
533    pub text_document: TextDocumentIdentifier,
534    pub position: Position,
535}
536
537/// 实现请求参数
538#[derive(Debug, Clone, Serialize, Deserialize)]
539pub struct ImplementationParams {
540    pub text_document: TextDocumentIdentifier,
541    pub position: Position,
542}
543
544/// 类型定义请求参数
545#[derive(Debug, Clone, Serialize, Deserialize)]
546pub struct TypeDefinitionParams {
547    pub text_document: TextDocumentIdentifier,
548    pub position: Position,
549}
550
551/// 创建实现请求
552pub fn create_implementation_request(
553    id: RequestId,
554    uri: DocumentUri,
555    position: Position,
556) -> LspRequest<ImplementationParams> {
557    LspRequest {
558        jsonrpc: "2.0".to_string(),
559        id,
560        method: "textDocument/implementation".to_string(),
561        params: Some(ImplementationParams {
562            text_document: TextDocumentIdentifier { uri },
563            position,
564        }),
565    }
566}
567
568/// 创建类型定义请求
569pub fn create_type_definition_request(
570    id: RequestId,
571    uri: DocumentUri,
572    position: Position,
573) -> LspRequest<TypeDefinitionParams> {
574    LspRequest {
575        jsonrpc: "2.0".to_string(),
576        id,
577        method: "textDocument/typeDefinition".to_string(),
578        params: Some(TypeDefinitionParams {
579            text_document: TextDocumentIdentifier { uri },
580            position,
581        }),
582    }
583}