codive_lsp/
client.rs

1//! LSP client implementation
2//!
3//! This module provides the LSP client that communicates with language servers
4//! using JSON-RPC 2.0 over stdio.
5
6use crate::language::language_id_for_path;
7use crate::server::LspServerHandle;
8use crate::types::*;
9use anyhow::{anyhow, Context, Result};
10use lsp_types::request::{
11    CallHierarchyIncomingCalls, CallHierarchyOutgoingCalls, CallHierarchyPrepare,
12    DocumentSymbolRequest, GotoDefinition, GotoImplementation, HoverRequest, References,
13    WorkspaceSymbolRequest,
14};
15use lsp_types::{
16    CallHierarchyIncomingCallsParams, CallHierarchyOutgoingCallsParams, ClientCapabilities,
17    DidChangeTextDocumentParams, DidOpenTextDocumentParams, DocumentSymbolParams,
18    GotoDefinitionParams, HoverParams, InitializeParams, InitializedParams, PartialResultParams,
19    ReferenceContext, ReferenceParams, TextDocumentContentChangeEvent, TextDocumentItem,
20    VersionedTextDocumentIdentifier, WorkDoneProgressParams, WorkspaceSymbolParams,
21};
22// GotoImplementation uses the same params as GotoDefinition
23use lsp_types::GotoDefinitionParams as GotoImplementationParams;
24use serde::{de::DeserializeOwned, Deserialize, Serialize};
25use std::collections::HashMap;
26use std::io::{BufRead, BufReader, Write};
27use std::path::{Path, PathBuf};
28
29/// Helper function to convert a file path to LSP Uri
30fn path_to_uri(path: &Path) -> Result<Uri> {
31    let url = Url::from_file_path(path).map_err(|_| anyhow!("Invalid file path: {:?}", path))?;
32    url.as_str()
33        .parse()
34        .map_err(|e| anyhow!("Failed to parse URI: {}", e))
35}
36
37/// Helper function to convert LSP Uri to file path
38fn uri_to_path(uri: &Uri) -> Option<PathBuf> {
39    let url: url::Url = uri.as_str().parse().ok()?;
40    url.to_file_path().ok()
41}
42use std::process::{Child, ChildStdin, ChildStdout};
43use std::sync::atomic::{AtomicI64, Ordering};
44use std::sync::{Arc, Mutex, RwLock};
45use tokio::sync::{mpsc, oneshot};
46use tracing::{debug, error, info, trace, warn};
47
48/// Timeout for LSP requests in milliseconds
49const REQUEST_TIMEOUT_MS: u64 = 10_000;
50/// Timeout for initialization in milliseconds
51const INIT_TIMEOUT_MS: u64 = 45_000;
52
53/// JSON-RPC request
54#[derive(Debug, Serialize)]
55struct JsonRpcRequest<T: Serialize> {
56    jsonrpc: &'static str,
57    id: i64,
58    method: &'static str,
59    params: T,
60}
61
62/// JSON-RPC notification (no id)
63#[derive(Debug, Serialize)]
64struct JsonRpcNotification<T: Serialize> {
65    jsonrpc: &'static str,
66    method: &'static str,
67    params: T,
68}
69
70/// JSON-RPC response
71#[derive(Debug, Deserialize)]
72struct JsonRpcResponse<T> {
73    #[allow(dead_code)]
74    jsonrpc: String,
75    id: Option<i64>,
76    result: Option<T>,
77    error: Option<JsonRpcError>,
78}
79
80/// JSON-RPC error
81#[derive(Debug, Deserialize)]
82struct JsonRpcError {
83    code: i64,
84    message: String,
85}
86
87/// Generic JSON-RPC message for routing
88#[derive(Debug, Deserialize)]
89struct JsonRpcMessage {
90    #[allow(dead_code)]
91    jsonrpc: String,
92    id: Option<i64>,
93    method: Option<String>,
94    #[serde(default)]
95    params: serde_json::Value,
96    result: Option<serde_json::Value>,
97    error: Option<JsonRpcError>,
98}
99
100/// Pending request awaiting response
101struct PendingRequest {
102    sender: oneshot::Sender<Result<serde_json::Value>>,
103}
104
105/// Active LSP client connection
106pub struct LspClient {
107    /// Server ID
108    server_id: String,
109    /// Project root
110    root: PathBuf,
111    /// Request ID counter
112    request_id: AtomicI64,
113    /// Pending requests
114    pending: Arc<RwLock<HashMap<i64, PendingRequest>>>,
115    /// Writer to server stdin
116    writer: Arc<Mutex<ChildStdin>>,
117    /// Published diagnostics per file
118    diagnostics: Arc<RwLock<HashMap<PathBuf, Vec<Diagnostic>>>>,
119    /// File versions for text synchronization
120    file_versions: Arc<RwLock<HashMap<PathBuf, i32>>>,
121    /// Channel to signal shutdown
122    shutdown_tx: Option<mpsc::Sender<()>>,
123    /// Child process handle
124    #[allow(dead_code)]
125    process: Child,
126}
127
128impl LspClient {
129    /// Create and initialize a new LSP client
130    pub async fn new(
131        server_id: impl Into<String>,
132        mut handle: LspServerHandle,
133        root: PathBuf,
134    ) -> Result<Self> {
135        let server_id = server_id.into();
136        info!(server_id = %server_id, root = ?root, "Initializing LSP client");
137
138        let stdin = handle
139            .process
140            .stdin
141            .take()
142            .context("Failed to get stdin")?;
143        let stdout = handle
144            .process
145            .stdout
146            .take()
147            .context("Failed to get stdout")?;
148
149        let pending: Arc<RwLock<HashMap<i64, PendingRequest>>> =
150            Arc::new(RwLock::new(HashMap::new()));
151        let diagnostics: Arc<RwLock<HashMap<PathBuf, Vec<Diagnostic>>>> =
152            Arc::new(RwLock::new(HashMap::new()));
153        let file_versions: Arc<RwLock<HashMap<PathBuf, i32>>> =
154            Arc::new(RwLock::new(HashMap::new()));
155
156        let (shutdown_tx, shutdown_rx) = mpsc::channel::<()>(1);
157
158        // Spawn reader task
159        let pending_clone = pending.clone();
160        let diagnostics_clone = diagnostics.clone();
161        let server_id_clone = server_id.clone();
162        std::thread::spawn(move || {
163            Self::reader_loop(stdout, pending_clone, diagnostics_clone, server_id_clone);
164        });
165
166        let writer = Arc::new(Mutex::new(stdin));
167
168        let mut client = Self {
169            server_id,
170            root: root.clone(),
171            request_id: AtomicI64::new(1),
172            pending,
173            writer,
174            diagnostics,
175            file_versions,
176            shutdown_tx: Some(shutdown_tx),
177            process: handle.process,
178        };
179
180        // Initialize the server
181        client.initialize(&root, handle.initialization).await?;
182
183        Ok(client)
184    }
185
186    /// Get the server ID
187    pub fn server_id(&self) -> &str {
188        &self.server_id
189    }
190
191    /// Get the project root
192    pub fn root(&self) -> &Path {
193        &self.root
194    }
195
196    /// Get current diagnostics
197    pub fn diagnostics(&self) -> HashMap<PathBuf, Vec<Diagnostic>> {
198        self.diagnostics.read().unwrap().clone()
199    }
200
201    /// Get diagnostics for a specific file
202    pub fn diagnostics_for_file(&self, path: &Path) -> Vec<Diagnostic> {
203        self.diagnostics
204            .read()
205            .unwrap()
206            .get(path)
207            .cloned()
208            .unwrap_or_default()
209    }
210
211    // ========================================================================
212    // LSP Protocol Methods
213    // ========================================================================
214
215    /// Initialize the LSP server
216    async fn initialize(
217        &mut self,
218        root: &Path,
219        initialization_options: Option<serde_json::Value>,
220    ) -> Result<()> {
221        let root_uri = path_to_uri(root)?;
222
223        let params = InitializeParams {
224            process_id: Some(std::process::id()),
225            root_uri: Some(root_uri.clone()),
226            root_path: None,
227            initialization_options,
228            capabilities: Self::client_capabilities(),
229            trace: None,
230            workspace_folders: Some(vec![lsp_types::WorkspaceFolder {
231                uri: root_uri,
232                name: root
233                    .file_name()
234                    .and_then(|n| n.to_str())
235                    .unwrap_or("workspace")
236                    .to_string(),
237            }]),
238            client_info: Some(lsp_types::ClientInfo {
239                name: "codive-lsp".to_string(),
240                version: Some(env!("CARGO_PKG_VERSION").to_string()),
241            }),
242            locale: None,
243            work_done_progress_params: WorkDoneProgressParams::default(),
244        };
245
246        let _result: lsp_types::InitializeResult =
247            self.request::<lsp_types::request::Initialize>(params).await?;
248
249        // Send initialized notification
250        self.notify::<lsp_types::notification::Initialized>(InitializedParams {})?;
251
252        info!(server_id = %self.server_id, "LSP server initialized");
253        Ok(())
254    }
255
256    /// Notify the server about an opened file
257    pub async fn open_file(&self, path: &Path) -> Result<()> {
258        let path = path.canonicalize().unwrap_or_else(|_| path.to_path_buf());
259
260        // Check if already open (before reading file content)
261        let existing_version = {
262            let versions = self.file_versions.read().unwrap();
263            versions.get(&path).copied()
264        };
265
266        let content = tokio::fs::read_to_string(&path).await?;
267
268        if let Some(version) = existing_version {
269            // File is already open, send didChange instead
270            return self.change_file(&path, &content, version + 1);
271        }
272
273        let uri = path_to_uri(&path)?;
274        let language_id = language_id_for_path(&path);
275
276        debug!(path = ?path, language_id = %language_id, "Opening file in LSP");
277
278        let params = DidOpenTextDocumentParams {
279            text_document: TextDocumentItem {
280                uri,
281                language_id: language_id.to_string(),
282                version: 0,
283                text: content,
284            },
285        };
286
287        self.notify::<lsp_types::notification::DidOpenTextDocument>(params)?;
288
289        // Track the file version
290        self.file_versions.write().unwrap().insert(path, 0);
291
292        Ok(())
293    }
294
295    /// Notify the server about a file change
296    fn change_file(&self, path: &Path, content: &str, version: i32) -> Result<()> {
297        let uri = path_to_uri(path)?;
298
299        let params = DidChangeTextDocumentParams {
300            text_document: VersionedTextDocumentIdentifier { uri, version },
301            content_changes: vec![TextDocumentContentChangeEvent {
302                range: None,
303                range_length: None,
304                text: content.to_string(),
305            }],
306        };
307
308        self.notify::<lsp_types::notification::DidChangeTextDocument>(params)?;
309
310        // Update version
311        self.file_versions.write().unwrap().insert(path.to_path_buf(), version);
312
313        Ok(())
314    }
315
316    /// Get hover information
317    pub async fn hover(&self, path: &Path, line: u32, character: u32) -> Result<Option<Hover>> {
318        let uri = path_to_uri(path)?;
319
320        let params = HoverParams {
321            text_document_position_params: TextDocumentPositionParams {
322                text_document: TextDocumentIdentifier { uri },
323                position: Position { line, character },
324            },
325            work_done_progress_params: WorkDoneProgressParams::default(),
326        };
327
328        self.request::<HoverRequest>(params).await
329    }
330
331    /// Go to definition
332    pub async fn definition(&self, path: &Path, line: u32, character: u32) -> Result<Vec<Location>> {
333        let uri = path_to_uri(path)?;
334
335        let params = GotoDefinitionParams {
336            text_document_position_params: TextDocumentPositionParams {
337                text_document: TextDocumentIdentifier { uri },
338                position: Position { line, character },
339            },
340            work_done_progress_params: WorkDoneProgressParams::default(),
341            partial_result_params: PartialResultParams::default(),
342        };
343
344        let result: Option<GotoDefinitionResponse> =
345            self.request::<GotoDefinition>(params).await?;
346
347        Ok(match result {
348            Some(GotoDefinitionResponse::Scalar(loc)) => vec![loc],
349            Some(GotoDefinitionResponse::Array(locs)) => locs,
350            Some(GotoDefinitionResponse::Link(links)) => links
351                .into_iter()
352                .map(|l| Location {
353                    uri: l.target_uri,
354                    range: l.target_selection_range,
355                })
356                .collect(),
357            None => vec![],
358        })
359    }
360
361    /// Find references
362    pub async fn references(
363        &self,
364        path: &Path,
365        line: u32,
366        character: u32,
367        include_declaration: bool,
368    ) -> Result<Vec<Location>> {
369        let uri = path_to_uri(path)?;
370
371        let params = ReferenceParams {
372            text_document_position: TextDocumentPositionParams {
373                text_document: TextDocumentIdentifier { uri },
374                position: Position { line, character },
375            },
376            work_done_progress_params: WorkDoneProgressParams::default(),
377            partial_result_params: PartialResultParams::default(),
378            context: ReferenceContext {
379                include_declaration,
380            },
381        };
382
383        let result: Option<Vec<Location>> = self.request::<References>(params).await?;
384        Ok(result.unwrap_or_default())
385    }
386
387    /// Go to implementation
388    pub async fn implementation(
389        &self,
390        path: &Path,
391        line: u32,
392        character: u32,
393    ) -> Result<Vec<Location>> {
394        let uri = path_to_uri(path)?;
395
396        let params = GotoImplementationParams {
397            text_document_position_params: TextDocumentPositionParams {
398                text_document: TextDocumentIdentifier { uri },
399                position: Position { line, character },
400            },
401            work_done_progress_params: WorkDoneProgressParams::default(),
402            partial_result_params: PartialResultParams::default(),
403        };
404
405        let result: Option<GotoDefinitionResponse> =
406            self.request::<GotoImplementation>(params).await?;
407
408        Ok(match result {
409            Some(GotoDefinitionResponse::Scalar(loc)) => vec![loc],
410            Some(GotoDefinitionResponse::Array(locs)) => locs,
411            Some(GotoDefinitionResponse::Link(links)) => links
412                .into_iter()
413                .map(|l| Location {
414                    uri: l.target_uri,
415                    range: l.target_selection_range,
416                })
417                .collect(),
418            None => vec![],
419        })
420    }
421
422    /// Get document symbols
423    pub async fn document_symbols(&self, path: &Path) -> Result<DocumentSymbolResponse> {
424        let uri = path_to_uri(path)?;
425
426        let params = DocumentSymbolParams {
427            text_document: TextDocumentIdentifier { uri },
428            work_done_progress_params: WorkDoneProgressParams::default(),
429            partial_result_params: PartialResultParams::default(),
430        };
431
432        let result: Option<DocumentSymbolResponse> =
433            self.request::<DocumentSymbolRequest>(params).await?;
434        Ok(result.unwrap_or(DocumentSymbolResponse::Flat(vec![])))
435    }
436
437    /// Search workspace symbols
438    pub async fn workspace_symbols(&self, query: &str) -> Result<Vec<SymbolInformation>> {
439        let params = WorkspaceSymbolParams {
440            query: query.to_string(),
441            work_done_progress_params: WorkDoneProgressParams::default(),
442            partial_result_params: PartialResultParams::default(),
443        };
444
445        let result: Option<WorkspaceSymbolResponse> =
446            self.request::<WorkspaceSymbolRequest>(params).await?;
447
448        Ok(match result {
449            Some(WorkspaceSymbolResponse::Flat(symbols)) => symbols,
450            Some(WorkspaceSymbolResponse::Nested(symbols)) => {
451                // Convert WorkspaceSymbol to SymbolInformation
452                symbols
453                    .into_iter()
454                    .filter_map(|s| {
455                        let location = match s.location {
456                            lsp_types::OneOf::Left(loc) => loc,
457                            lsp_types::OneOf::Right(doc_id) => Location {
458                                uri: doc_id.uri,
459                                range: Range::default(),
460                            },
461                        };
462                        Some(SymbolInformation {
463                            name: s.name,
464                            kind: s.kind,
465                            tags: s.tags,
466                            deprecated: None,
467                            location,
468                            container_name: s.container_name,
469                        })
470                    })
471                    .collect()
472            }
473            None => vec![],
474        })
475    }
476
477    /// Prepare call hierarchy
478    pub async fn prepare_call_hierarchy(
479        &self,
480        path: &Path,
481        line: u32,
482        character: u32,
483    ) -> Result<Vec<CallHierarchyItem>> {
484        let uri = path_to_uri(path)?;
485
486        let params = lsp_types::CallHierarchyPrepareParams {
487            text_document_position_params: TextDocumentPositionParams {
488                text_document: TextDocumentIdentifier { uri },
489                position: Position { line, character },
490            },
491            work_done_progress_params: WorkDoneProgressParams::default(),
492        };
493
494        let result: Option<Vec<CallHierarchyItem>> =
495            self.request::<CallHierarchyPrepare>(params).await?;
496        Ok(result.unwrap_or_default())
497    }
498
499    /// Get incoming calls
500    pub async fn incoming_calls(
501        &self,
502        item: CallHierarchyItem,
503    ) -> Result<Vec<CallHierarchyIncomingCall>> {
504        let params = CallHierarchyIncomingCallsParams {
505            item,
506            work_done_progress_params: WorkDoneProgressParams::default(),
507            partial_result_params: PartialResultParams::default(),
508        };
509
510        let result: Option<Vec<CallHierarchyIncomingCall>> =
511            self.request::<CallHierarchyIncomingCalls>(params).await?;
512        Ok(result.unwrap_or_default())
513    }
514
515    /// Get outgoing calls
516    pub async fn outgoing_calls(
517        &self,
518        item: CallHierarchyItem,
519    ) -> Result<Vec<CallHierarchyOutgoingCall>> {
520        let params = CallHierarchyOutgoingCallsParams {
521            item,
522            work_done_progress_params: WorkDoneProgressParams::default(),
523            partial_result_params: PartialResultParams::default(),
524        };
525
526        let result: Option<Vec<CallHierarchyOutgoingCall>> =
527            self.request::<CallHierarchyOutgoingCalls>(params).await?;
528        Ok(result.unwrap_or_default())
529    }
530
531    /// Shutdown the client
532    pub async fn shutdown(mut self) {
533        info!(server_id = %self.server_id, "Shutting down LSP client");
534
535        // Send shutdown request
536        let _ = self.request::<lsp_types::request::Shutdown>(()).await;
537
538        // Send exit notification
539        let _ = self.notify::<lsp_types::notification::Exit>(());
540
541        // Signal reader thread to stop
542        if let Some(tx) = self.shutdown_tx.take() {
543            let _ = tx.send(()).await;
544        }
545    }
546
547    // ========================================================================
548    // Internal Methods
549    // ========================================================================
550
551    /// Send a request and wait for response
552    async fn request<R>(&self, params: R::Params) -> Result<R::Result>
553    where
554        R: lsp_types::request::Request,
555        R::Params: Serialize,
556        R::Result: DeserializeOwned,
557    {
558        let id = self.request_id.fetch_add(1, Ordering::SeqCst);
559
560        let request = JsonRpcRequest {
561            jsonrpc: "2.0",
562            id,
563            method: R::METHOD,
564            params,
565        };
566
567        let message = serde_json::to_string(&request)?;
568        let header = format!("Content-Length: {}\r\n\r\n", message.len());
569
570        trace!(id = id, method = R::METHOD, "Sending LSP request");
571
572        // Create response channel
573        let (tx, rx) = oneshot::channel();
574
575        // Register pending request
576        {
577            let mut pending = self.pending.write().unwrap();
578            pending.insert(id, PendingRequest { sender: tx });
579        }
580
581        // Send the request
582        {
583            let mut writer = self.writer.lock().unwrap();
584            writer.write_all(header.as_bytes())?;
585            writer.write_all(message.as_bytes())?;
586            writer.flush()?;
587        }
588
589        // Wait for response with timeout
590        let result = tokio::time::timeout(
591            std::time::Duration::from_millis(REQUEST_TIMEOUT_MS),
592            rx,
593        )
594        .await
595        .map_err(|_| anyhow!("LSP request timed out"))??;
596
597        let value = result?;
598        let result: R::Result = serde_json::from_value(value)?;
599        Ok(result)
600    }
601
602    /// Send a notification (no response expected)
603    fn notify<N>(&self, params: N::Params) -> Result<()>
604    where
605        N: lsp_types::notification::Notification,
606        N::Params: Serialize,
607    {
608        let notification = JsonRpcNotification {
609            jsonrpc: "2.0",
610            method: N::METHOD,
611            params,
612        };
613
614        let message = serde_json::to_string(&notification)?;
615        let header = format!("Content-Length: {}\r\n\r\n", message.len());
616
617        trace!(method = N::METHOD, "Sending LSP notification");
618
619        let mut writer = self.writer.lock().unwrap();
620        writer.write_all(header.as_bytes())?;
621        writer.write_all(message.as_bytes())?;
622        writer.flush()?;
623
624        Ok(())
625    }
626
627    /// Reader loop that processes messages from the server
628    fn reader_loop(
629        stdout: ChildStdout,
630        pending: Arc<RwLock<HashMap<i64, PendingRequest>>>,
631        diagnostics: Arc<RwLock<HashMap<PathBuf, Vec<Diagnostic>>>>,
632        server_id: String,
633    ) {
634        let mut reader = BufReader::new(stdout);
635        let mut headers = String::new();
636
637        loop {
638            headers.clear();
639
640            // Read headers
641            let mut content_length: Option<usize> = None;
642            loop {
643                let mut line = String::new();
644                match reader.read_line(&mut line) {
645                    Ok(0) => {
646                        debug!(server_id = %server_id, "LSP server stdout closed");
647                        return;
648                    }
649                    Ok(_) => {
650                        if line == "\r\n" {
651                            break;
652                        }
653                        if line.to_lowercase().starts_with("content-length:") {
654                            if let Some(len_str) = line.split(':').nth(1) {
655                                content_length = len_str.trim().parse().ok();
656                            }
657                        }
658                    }
659                    Err(e) => {
660                        error!(server_id = %server_id, error = ?e, "Error reading from LSP server");
661                        return;
662                    }
663                }
664            }
665
666            // Read content
667            let content_length = match content_length {
668                Some(len) => len,
669                None => {
670                    warn!(server_id = %server_id, "No Content-Length header");
671                    continue;
672                }
673            };
674
675            let mut content = vec![0u8; content_length];
676            if let Err(e) = std::io::Read::read_exact(&mut reader, &mut content) {
677                error!(server_id = %server_id, error = ?e, "Error reading LSP content");
678                continue;
679            }
680
681            // Parse message
682            let message: JsonRpcMessage = match serde_json::from_slice(&content) {
683                Ok(msg) => msg,
684                Err(e) => {
685                    warn!(server_id = %server_id, error = ?e, "Failed to parse LSP message");
686                    continue;
687                }
688            };
689
690            // Handle response
691            if let Some(id) = message.id {
692                if message.method.is_none() {
693                    // This is a response
694                    let mut pending = pending.write().unwrap();
695                    if let Some(req) = pending.remove(&id) {
696                        let result = if let Some(error) = message.error {
697                            Err(anyhow!("LSP error {}: {}", error.code, error.message))
698                        } else {
699                            Ok(message.result.unwrap_or(serde_json::Value::Null))
700                        };
701                        let _ = req.sender.send(result);
702                    }
703                    continue;
704                }
705            }
706
707            // Handle notification
708            if let Some(method) = &message.method {
709                match method.as_str() {
710                    "textDocument/publishDiagnostics" => {
711                        if let Ok(params) =
712                            serde_json::from_value::<lsp_types::PublishDiagnosticsParams>(
713                                message.params,
714                            )
715                        {
716                            if let Some(path) = uri_to_path(&params.uri) {
717                                debug!(
718                                    server_id = %server_id,
719                                    path = ?path,
720                                    count = params.diagnostics.len(),
721                                    "Received diagnostics"
722                                );
723                                diagnostics.write().unwrap().insert(path, params.diagnostics);
724                            }
725                        }
726                    }
727                    "window/logMessage" | "window/showMessage" => {
728                        // Log server messages
729                        if let Ok(params) =
730                            serde_json::from_value::<lsp_types::LogMessageParams>(message.params)
731                        {
732                            debug!(server_id = %server_id, message = %params.message, "LSP server message");
733                        }
734                    }
735                    _ => {
736                        trace!(server_id = %server_id, method = %method, "Unhandled LSP notification");
737                    }
738                }
739            }
740        }
741    }
742
743    /// Build client capabilities
744    fn client_capabilities() -> ClientCapabilities {
745        ClientCapabilities {
746            text_document: Some(lsp_types::TextDocumentClientCapabilities {
747                synchronization: Some(lsp_types::TextDocumentSyncClientCapabilities {
748                    dynamic_registration: Some(false),
749                    will_save: Some(false),
750                    will_save_wait_until: Some(false),
751                    did_save: Some(true),
752                }),
753                hover: Some(lsp_types::HoverClientCapabilities {
754                    dynamic_registration: Some(false),
755                    content_format: Some(vec![MarkupKind::Markdown, MarkupKind::PlainText]),
756                }),
757                definition: Some(lsp_types::GotoCapability {
758                    dynamic_registration: Some(false),
759                    link_support: Some(true),
760                }),
761                references: Some(lsp_types::DynamicRegistrationClientCapabilities {
762                    dynamic_registration: Some(false),
763                }),
764                implementation: Some(lsp_types::GotoCapability {
765                    dynamic_registration: Some(false),
766                    link_support: Some(true),
767                }),
768                document_symbol: Some(lsp_types::DocumentSymbolClientCapabilities {
769                    dynamic_registration: Some(false),
770                    symbol_kind: None,
771                    hierarchical_document_symbol_support: Some(true),
772                    tag_support: None,
773                }),
774                publish_diagnostics: Some(lsp_types::PublishDiagnosticsClientCapabilities {
775                    related_information: Some(true),
776                    tag_support: None,
777                    version_support: Some(true),
778                    code_description_support: Some(true),
779                    data_support: Some(true),
780                }),
781                call_hierarchy: Some(lsp_types::CallHierarchyClientCapabilities {
782                    dynamic_registration: Some(false),
783                }),
784                ..Default::default()
785            }),
786            workspace: Some(lsp_types::WorkspaceClientCapabilities {
787                workspace_folders: Some(true),
788                symbol: Some(lsp_types::WorkspaceSymbolClientCapabilities {
789                    dynamic_registration: Some(false),
790                    symbol_kind: None,
791                    tag_support: None,
792                    resolve_support: None,
793                }),
794                ..Default::default()
795            }),
796            window: Some(lsp_types::WindowClientCapabilities {
797                work_done_progress: Some(true),
798                show_message: None,
799                show_document: None,
800            }),
801            ..Default::default()
802        }
803    }
804}