1use crate::query_engine::{SymbolInfo, SymbolKind};
6use crate::types::{CodeLocation, CodeRange, Layer3Result};
7use async_trait::async_trait;
8use std::path::PathBuf;
9
10#[async_trait]
14pub trait LspClient: Send + Sync {
15 async fn initialize(&self, root_uri: String) -> Layer3Result<LspCapabilities>;
17
18 async fn shutdown(&self) -> Layer3Result<bool>;
20
21 async fn open_document(
23 &self,
24 uri: String,
25 language_id: String,
26 content: String,
27 ) -> Layer3Result<bool>;
28
29 async fn close_document(&self, uri: String) -> Layer3Result<bool>;
31
32 async fn change_document(&self, uri: String, changes: Vec<TextChange>) -> Layer3Result<bool>;
34
35 async fn save_document(&self, uri: String) -> Layer3Result<bool>;
37
38 fn is_ready(&self) -> bool;
40
41 fn supported_languages(&self) -> Vec<String>;
43}
44
45#[derive(Debug, Clone)]
47pub struct TextChange {
48 pub range: CodeRange,
50 pub range_length: u32,
52 pub text: String,
54}
55
56#[derive(Debug, Clone)]
58pub struct LspCapabilities {
59 pub text_document_sync: bool,
61 pub hover_provider: bool,
63 pub definition_provider: bool,
65 pub references_provider: bool,
67 pub implementation_provider: bool,
69 pub type_definition_provider: bool,
71 pub document_symbol_provider: bool,
73 pub workspace_symbol_provider: bool,
75 pub rename_provider: bool,
77 pub completion_provider: Option<CompletionOptions>,
79 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#[derive(Debug, Clone)]
103pub struct CompletionOptions {
104 pub trigger_characters: Vec<String>,
106 pub all_commit_characters: Vec<String>,
108}
109
110#[derive(Debug, Clone)]
112pub struct SignatureHelpOptions {
113 pub trigger_characters: Vec<String>,
115 pub retrigger_characters: Vec<String>,
117}
118
119#[async_trait]
123pub trait LspRequester: LspClient {
124 async fn request_definition(
126 &self,
127 uri: String,
128 position: Position,
129 ) -> Layer3Result<Option<LocationLink>>;
130
131 async fn request_references(
133 &self,
134 uri: String,
135 position: Position,
136 include_declaration: bool,
137 ) -> Layer3Result<Vec<LocationLink>>;
138
139 async fn request_hover(
141 &self,
142 uri: String,
143 position: Position,
144 ) -> Layer3Result<Option<HoverResult>>;
145
146 async fn request_document_symbols(&self, uri: String) -> Layer3Result<Vec<DocumentSymbol>>;
148
149 async fn request_workspace_symbols(&self, query: String) -> Layer3Result<Vec<SymbolInfo>>;
151}
152
153#[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, character: loc.column - 1,
165 }
166 }
167}
168
169#[derive(Debug, Clone)]
171pub struct LocationLink {
172 pub target_uri: String,
174 pub target_range: Range,
176 pub target_selection_range: Range,
178}
179
180#[derive(Debug, Clone, Copy)]
182pub struct Range {
183 pub start: Position,
184 pub end: Position,
185}
186
187#[derive(Debug, Clone)]
189pub struct HoverResult {
190 pub contents: MarkupContent,
192 pub range: Option<Range>,
194}
195
196#[derive(Debug, Clone)]
198pub struct MarkupContent {
199 pub kind: MarkupKind,
201 pub value: String,
203}
204
205#[derive(Debug, Clone, Copy, PartialEq, Eq)]
207pub enum MarkupKind {
208 PlainText,
209 Markdown,
210}
211
212#[derive(Debug, Clone)]
214pub struct DocumentSymbol {
215 pub name: String,
217 pub detail: Option<String>,
219 pub kind: SymbolKind,
221 pub deprecated: bool,
223 pub range: Range,
225 pub selection_range: Range,
227 pub children: Vec<DocumentSymbol>,
229}
230
231#[async_trait]
233pub trait LspServerManager: Send + Sync {
234 async fn start_server(&self, language: String, root_path: PathBuf) -> Layer3Result<String>;
236
237 async fn stop_server(&self, server_id: &str) -> Layer3Result<bool>;
239
240 fn get_client(&self, server_id: &str) -> Option<&dyn LspClient>;
242
243 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}