1mod capabilities;
2mod input_handler;
3
4pub use capabilities::{EffectiveCapability, cap};
5
6pub use lsp_types::request::*;
7pub use lsp_types::*;
8
9use anyhow::{Context as _, Result, anyhow};
10use collections::{BTreeMap, HashMap};
11use futures::{
12 AsyncRead, AsyncWrite, Future, FutureExt,
13 channel::oneshot::{self, Canceled},
14 io::BufWriter,
15 select,
16};
17use gpui::{App, AppContext as _, AsyncApp, BackgroundExecutor, SharedString, Task};
18use notification::DidChangeWorkspaceFolders;
19use parking_lot::{Mutex, RwLock};
20use postage::{barrier, prelude::Stream};
21use schemars::JsonSchema;
22use serde::{Deserialize, Serialize, de::DeserializeOwned};
23use serde_json::{Value, json, value::RawValue};
24use smol::{
25 channel,
26 io::{AsyncBufReadExt, AsyncWriteExt, BufReader},
27 process::Child,
28};
29
30use std::{
31 collections::BTreeSet,
32 ffi::{OsStr, OsString},
33 fmt,
34 io::Write,
35 ops::DerefMut,
36 path::PathBuf,
37 pin::Pin,
38 sync::{
39 Arc, Weak,
40 atomic::{AtomicI32, Ordering::SeqCst},
41 },
42 task::Poll,
43 time::{Duration, Instant},
44};
45use std::{path::Path, process::Stdio};
46use util::{ConnectionResult, ResultExt, TryFutureExt, redact};
47
48const JSON_RPC_VERSION: &str = "2.0";
49const CONTENT_LEN_HEADER: &str = "Content-Length: ";
50
51pub const LSP_REQUEST_TIMEOUT: Duration = Duration::from_secs(60 * 2);
52const SERVER_SHUTDOWN_TIMEOUT: Duration = Duration::from_secs(5);
53
54type NotificationHandler = Box<dyn Send + FnMut(Option<RequestId>, Value, &mut AsyncApp)>;
55type ResponseHandler = Box<dyn Send + FnOnce(Result<String, Error>)>;
56type IoHandler = Box<dyn Send + FnMut(IoKind, &str)>;
57
58/// Kind of language server stdio given to an IO handler.
59#[derive(Debug, Clone, Copy)]
60pub enum IoKind {
61 StdOut,
62 StdIn,
63 StdErr,
64}
65
66/// Represents a launchable language server. This can either be a standalone binary or the path
67/// to a runtime with arguments to instruct it to launch the actual language server file.
68#[derive(Clone, Deserialize)]
69pub struct LanguageServerBinary {
70 pub path: PathBuf,
71 pub arguments: Vec<OsString>,
72 pub env: Option<HashMap<String, String>>,
73}
74
75/// Configures the search (and installation) of language servers.
76#[derive(Debug, Clone, Deserialize)]
77pub struct LanguageServerBinaryOptions {
78 /// Whether the adapter should look at the users system
79 pub allow_path_lookup: bool,
80 /// Whether the adapter should download its own version
81 pub allow_binary_download: bool,
82}
83
84/// A running language server process.
85pub struct LanguageServer {
86 server_id: LanguageServerId,
87 next_id: AtomicI32,
88 outbound_tx: channel::Sender<String>,
89 name: LanguageServerName,
90 process_name: Arc<str>,
91 binary: LanguageServerBinary,
92 static_capabilities: RwLock<ServerCapabilities>,
93 dynamic_capabilities: RwLock<DynamicCapabilities>,
94 /// Configuration sent to the server, stored for display in the language server logs
95 /// buffer. This is represented as the message sent to the LSP in order to avoid cloning it (can
96 /// be large in cases like sending schemas to the json server).
97 configuration: Arc<DidChangeConfigurationParams>,
98 code_action_kinds: Option<Vec<CodeActionKind>>,
99 notification_handlers: Arc<Mutex<HashMap<&'static str, NotificationHandler>>>,
100 response_handlers: Arc<Mutex<Option<HashMap<RequestId, ResponseHandler>>>>,
101 io_handlers: Arc<Mutex<HashMap<i32, IoHandler>>>,
102 executor: BackgroundExecutor,
103 #[allow(clippy::type_complexity)]
104 io_tasks: Mutex<Option<(Task<Option<()>>, Task<Option<()>>)>>,
105 output_done_rx: Mutex<Option<barrier::Receiver>>,
106 server: Arc<Mutex<Option<Child>>>,
107 workspace_folders: Option<Arc<Mutex<BTreeSet<Url>>>>,
108 root_uri: Url,
109}
110
111#[derive(Clone, Debug, PartialEq, Eq, Hash)]
112pub enum LanguageServerSelector {
113 Id(LanguageServerId),
114 Name(LanguageServerName),
115}
116
117/// Identifies a running language server.
118#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
119#[repr(transparent)]
120pub struct LanguageServerId(pub usize);
121
122impl LanguageServerId {
123 pub fn from_proto(id: u64) -> Self {
124 Self(id as usize)
125 }
126
127 pub fn to_proto(self) -> u64 {
128 self.0 as u64
129 }
130}
131
132/// A name of a language server.
133#[derive(
134 Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Deserialize, Serialize, JsonSchema,
135)]
136#[serde(transparent)]
137pub struct LanguageServerName(pub SharedString);
138
139impl std::fmt::Display for LanguageServerName {
140 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
141 std::fmt::Display::fmt(&self.0, f)
142 }
143}
144
145impl AsRef<str> for LanguageServerName {
146 fn as_ref(&self) -> &str {
147 self.0.as_ref()
148 }
149}
150
151impl AsRef<OsStr> for LanguageServerName {
152 fn as_ref(&self) -> &OsStr {
153 self.0.as_ref().as_ref()
154 }
155}
156
157impl LanguageServerName {
158 pub const fn new_static(s: &'static str) -> Self {
159 Self(SharedString::new_static(s))
160 }
161
162 pub fn from_proto(s: String) -> Self {
163 Self(s.into())
164 }
165}
166
167impl<'a> From<&'a str> for LanguageServerName {
168 fn from(str: &'a str) -> LanguageServerName {
169 LanguageServerName(str.to_string().into())
170 }
171}
172
173/// Handle to a language server RPC activity subscription.
174pub enum Subscription {
175 Notification {
176 method: &'static str,
177 notification_handlers: Option<Arc<Mutex<HashMap<&'static str, NotificationHandler>>>>,
178 },
179 Io {
180 id: i32,
181 io_handlers: Option<Weak<Mutex<HashMap<i32, IoHandler>>>>,
182 },
183}
184
185/// Language server protocol RPC request message ID.
186///
187/// [LSP Specification](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#requestMessage)
188#[derive(Debug, Clone, Eq, PartialEq, Hash, Serialize, Deserialize)]
189#[serde(untagged)]
190pub enum RequestId {
191 Int(i32),
192 Str(String),
193}
194
195/// Language server protocol RPC request message.
196///
197/// [LSP Specification](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#requestMessage)
198#[derive(Serialize, Deserialize)]
199pub struct Request<'a, T> {
200 jsonrpc: &'static str,
201 id: RequestId,
202 method: &'a str,
203 params: T,
204}
205
206/// Language server protocol RPC request response message before it is deserialized into a concrete type.
207#[derive(Serialize, Deserialize)]
208struct AnyResponse<'a> {
209 jsonrpc: &'a str,
210 id: RequestId,
211 #[serde(default)]
212 error: Option<Error>,
213 #[serde(borrow)]
214 result: Option<&'a RawValue>,
215}
216
217/// Language server protocol RPC request response message.
218///
219/// [LSP Specification](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#responseMessage)
220#[derive(Serialize)]
221struct Response<T> {
222 jsonrpc: &'static str,
223 id: RequestId,
224 #[serde(flatten)]
225 value: LspResult<T>,
226}
227
228#[derive(Serialize)]
229#[serde(rename_all = "snake_case")]
230enum LspResult<T> {
231 #[serde(rename = "result")]
232 Ok(Option<T>),
233 Error(Option<Error>),
234}
235
236/// Language server protocol RPC notification message.
237///
238/// [LSP Specification](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#notificationMessage)
239#[derive(Serialize, Deserialize)]
240struct Notification<'a, T> {
241 jsonrpc: &'static str,
242 #[serde(borrow)]
243 method: &'a str,
244 params: T,
245}
246
247/// Language server RPC notification message before it is deserialized into a concrete type.
248#[derive(Debug, Clone, Deserialize)]
249struct NotificationOrRequest {
250 #[serde(default)]
251 id: Option<RequestId>,
252 method: String,
253 #[serde(default)]
254 params: Option<Value>,
255}
256
257#[derive(Debug, Serialize, Deserialize)]
258struct Error {
259 code: i64,
260 message: String,
261 #[serde(default)]
262 data: Option<serde_json::Value>,
263}
264
265pub trait LspRequestFuture<O>: Future<Output = ConnectionResult<O>> {
266 fn id(&self) -> i32;
267}
268
269struct LspRequest<F> {
270 id: i32,
271 request: F,
272}
273
274impl<F> LspRequest<F> {
275 pub fn new(id: i32, request: F) -> Self {
276 Self { id, request }
277 }
278}
279
280impl<F: Future> Future for LspRequest<F> {
281 type Output = F::Output;
282
283 fn poll(self: Pin<&mut Self>, cx: &mut std::task::Context<'_>) -> Poll<Self::Output> {
284 // SAFETY: This is standard pin projection, we're pinned so our fields must be pinned.
285 let inner = unsafe { Pin::new_unchecked(&mut self.get_unchecked_mut().request) };
286 inner.poll(cx)
287 }
288}
289
290impl<F, O> LspRequestFuture<O> for LspRequest<F>
291where
292 F: Future<Output = ConnectionResult<O>>,
293{
294 fn id(&self) -> i32 {
295 self.id
296 }
297}
298
299/// Combined capabilities of the server and the adapter.
300#[derive(Debug)]
301pub struct AdapterServerCapabilities {
302 // Reported capabilities by the server
303 pub server_capabilities: ServerCapabilities,
304 // List of code actions supported by the LspAdapter matching the server
305 pub code_action_kinds: Option<Vec<CodeActionKind>>,
306}
307
308#[derive(Debug, Default, Clone)]
309pub struct DynamicCapabilities {
310 pub text_document_sync_did_change:
311 Option<HashMap<String, TextDocumentChangeRegistrationOptions>>,
312 pub text_document_sync_did_save: Option<HashMap<String, TextDocumentSaveRegistrationOptions>>,
313}
314
315impl LanguageServer {
316 /// Starts a language server process.
317 pub fn new(
318 stderr_capture: Arc<Mutex<Option<String>>>,
319 server_id: LanguageServerId,
320 server_name: LanguageServerName,
321 binary: LanguageServerBinary,
322 root_path: &Path,
323 code_action_kinds: Option<Vec<CodeActionKind>>,
324 workspace_folders: Option<Arc<Mutex<BTreeSet<Url>>>>,
325 cx: &mut AsyncApp,
326 ) -> Result<Self> {
327 let working_dir = if root_path.is_dir() {
328 root_path
329 } else {
330 root_path.parent().unwrap_or_else(|| Path::new("/"))
331 };
332 let root_uri = Url::from_file_path(&working_dir)
333 .map_err(|()| anyhow!("{working_dir:?} is not a valid URI"))?;
334
335 log::info!(
336 "starting language server process. binary path: {:?}, working directory: {:?}, args: {:?}",
337 binary.path,
338 working_dir,
339 &binary.arguments
340 );
341
342 let mut server = util::command::new_smol_command(&binary.path)
343 .current_dir(working_dir)
344 .args(&binary.arguments)
345 .envs(binary.env.clone().unwrap_or_default())
346 .stdin(Stdio::piped())
347 .stdout(Stdio::piped())
348 .stderr(Stdio::piped())
349 .kill_on_drop(true)
350 .spawn()
351 .with_context(|| {
352 format!(
353 "failed to spawn command. path: {:?}, working directory: {:?}, args: {:?}",
354 binary.path, working_dir, &binary.arguments
355 )
356 })?;
357
358 let stdin = server.stdin.take().unwrap();
359 let stdout = server.stdout.take().unwrap();
360 let stderr = server.stderr.take().unwrap();
361 let server = Self::new_internal(
362 server_id,
363 server_name,
364 stdin,
365 stdout,
366 Some(stderr),
367 stderr_capture,
368 Some(server),
369 code_action_kinds,
370 binary,
371 root_uri,
372 workspace_folders,
373 cx,
374 move |notification| {
375 log::info!(
376 "Language server with id {} sent unhandled notification {}:\n{}",
377 server_id,
378 notification.method,
379 serde_json::to_string_pretty(¬ification.params).unwrap(),
380 );
381 false
382 },
383 );
384
385 Ok(server)
386 }
387
388 fn new_internal<Stdin, Stdout, Stderr, F>(
389 server_id: LanguageServerId,
390 server_name: LanguageServerName,
391 stdin: Stdin,
392 stdout: Stdout,
393 stderr: Option<Stderr>,
394 stderr_capture: Arc<Mutex<Option<String>>>,
395 server: Option<Child>,
396 code_action_kinds: Option<Vec<CodeActionKind>>,
397 binary: LanguageServerBinary,
398 root_uri: Url,
399 workspace_folders: Option<Arc<Mutex<BTreeSet<Url>>>>,
400 cx: &mut AsyncApp,
401 on_unhandled_notification: F,
402 ) -> Self
403 where
404 Stdin: AsyncWrite + Unpin + Send + 'static,
405 Stdout: AsyncRead + Unpin + Send + 'static,
406 Stderr: AsyncRead + Unpin + Send + 'static,
407 F: Fn(&NotificationOrRequest) -> bool + 'static + Send + Sync + Clone,
408 {
409 let (outbound_tx, outbound_rx) = channel::unbounded::<String>();
410 let (output_done_tx, output_done_rx) = barrier::channel();
411 let notification_handlers =
412 Arc::new(Mutex::new(HashMap::<_, NotificationHandler>::default()));
413 let response_handlers =
414 Arc::new(Mutex::new(Some(HashMap::<_, ResponseHandler>::default())));
415 let io_handlers = Arc::new(Mutex::new(HashMap::default()));
416
417 let stdout_input_task = cx.spawn({
418 let unhandled_notification_wrapper = {
419 let response_channel = outbound_tx.clone();
420 async move |msg: NotificationOrRequest| {
421 let did_handle = on_unhandled_notification(&msg);
422 if !did_handle && let Some(message_id) = msg.id {
423 let response = AnyResponse {
424 jsonrpc: JSON_RPC_VERSION,
425 id: message_id,
426 error: Some(Error {
427 code: -32601,
428 message: format!("Unrecognized method `{}`", msg.method),
429 data: None,
430 }),
431 result: None,
432 };
433 if let Ok(response) = serde_json::to_string(&response) {
434 response_channel.send(response).await.ok();
435 }
436 }
437 }
438 };
439 let notification_handlers = notification_handlers.clone();
440 let response_handlers = response_handlers.clone();
441 let io_handlers = io_handlers.clone();
442 async move |cx| {
443 Self::handle_incoming_messages(
444 stdout,
445 unhandled_notification_wrapper,
446 notification_handlers,
447 response_handlers,
448 io_handlers,
449 cx,
450 )
451 .log_err()
452 .await
453 }
454 });
455 let stderr_input_task = stderr
456 .map(|stderr| {
457 let io_handlers = io_handlers.clone();
458 let stderr_captures = stderr_capture.clone();
459 cx.background_spawn(async move {
460 Self::handle_stderr(stderr, io_handlers, stderr_captures)
461 .log_err()
462 .await
463 })
464 })
465 .unwrap_or_else(|| Task::ready(None));
466 let input_task = cx.background_spawn(async move {
467 let (stdout, stderr) = futures::join!(stdout_input_task, stderr_input_task);
468 stdout.or(stderr)
469 });
470 let output_task = cx.background_spawn({
471 Self::handle_outgoing_messages(
472 stdin,
473 outbound_rx,
474 output_done_tx,
475 response_handlers.clone(),
476 io_handlers.clone(),
477 )
478 .log_err()
479 });
480
481 let configuration = DidChangeConfigurationParams {
482 settings: Value::Null,
483 }
484 .into();
485
486 Self {
487 server_id,
488 notification_handlers,
489 response_handlers,
490 io_handlers,
491 name: server_name,
492 process_name: binary
493 .path
494 .file_name()
495 .map(|name| Arc::from(name.to_string_lossy()))
496 .unwrap_or_default(),
497 binary,
498 static_capabilities: Default::default(),
499 dynamic_capabilities: Default::default(),
500 configuration,
501 code_action_kinds,
502 next_id: Default::default(),
503 outbound_tx,
504 executor: cx.background_executor().clone(),
505 io_tasks: Mutex::new(Some((input_task, output_task))),
506 output_done_rx: Mutex::new(Some(output_done_rx)),
507 server: Arc::new(Mutex::new(server)),
508 workspace_folders,
509 root_uri,
510 }
511 }
512
513 /// List of code action kinds this language server reports being able to emit.
514 pub fn code_action_kinds(&self) -> Option<Vec<CodeActionKind>> {
515 self.code_action_kinds.clone()
516 }
517
518 async fn handle_incoming_messages<Stdout>(
519 stdout: Stdout,
520 on_unhandled_notification: impl AsyncFn(NotificationOrRequest) + 'static + Send,
521 notification_handlers: Arc<Mutex<HashMap<&'static str, NotificationHandler>>>,
522 response_handlers: Arc<Mutex<Option<HashMap<RequestId, ResponseHandler>>>>,
523 io_handlers: Arc<Mutex<HashMap<i32, IoHandler>>>,
524 cx: &mut AsyncApp,
525 ) -> anyhow::Result<()>
526 where
527 Stdout: AsyncRead + Unpin + Send + 'static,
528 {
529 use smol::stream::StreamExt;
530 let stdout = BufReader::new(stdout);
531 let _clear_response_handlers = util::defer({
532 let response_handlers = response_handlers.clone();
533 move || {
534 response_handlers.lock().take();
535 }
536 });
537 let mut input_handler = input_handler::LspStdoutHandler::new(
538 stdout,
539 response_handlers,
540 io_handlers,
541 cx.background_executor().clone(),
542 );
543
544 while let Some(msg) = input_handler.incoming_messages.next().await {
545 let unhandled_message = {
546 let mut notification_handlers = notification_handlers.lock();
547 if let Some(handler) = notification_handlers.get_mut(msg.method.as_str()) {
548 handler(msg.id, msg.params.unwrap_or(Value::Null), cx);
549 None
550 } else {
551 Some(msg)
552 }
553 };
554
555 if let Some(msg) = unhandled_message {
556 on_unhandled_notification(msg).await;
557 }
558
559 // Don't starve the main thread when receiving lots of notifications at once.
560 smol::future::yield_now().await;
561 }
562 input_handler.loop_handle.await
563 }
564
565 async fn handle_stderr<Stderr>(
566 stderr: Stderr,
567 io_handlers: Arc<Mutex<HashMap<i32, IoHandler>>>,
568 stderr_capture: Arc<Mutex<Option<String>>>,
569 ) -> anyhow::Result<()>
570 where
571 Stderr: AsyncRead + Unpin + Send + 'static,
572 {
573 let mut stderr = BufReader::new(stderr);
574 let mut buffer = Vec::new();
575
576 loop {
577 buffer.clear();
578
579 let bytes_read = stderr.read_until(b'\n', &mut buffer).await?;
580 if bytes_read == 0 {
581 return Ok(());
582 }
583
584 if let Ok(message) = std::str::from_utf8(&buffer) {
585 log::trace!("incoming stderr message:{message}");
586 for handler in io_handlers.lock().values_mut() {
587 handler(IoKind::StdErr, message);
588 }
589
590 if let Some(stderr) = stderr_capture.lock().as_mut() {
591 stderr.push_str(message);
592 }
593 }
594
595 // Don't starve the main thread when receiving lots of messages at once.
596 smol::future::yield_now().await;
597 }
598 }
599
600 async fn handle_outgoing_messages<Stdin>(
601 stdin: Stdin,
602 outbound_rx: channel::Receiver<String>,
603 output_done_tx: barrier::Sender,
604 response_handlers: Arc<Mutex<Option<HashMap<RequestId, ResponseHandler>>>>,
605 io_handlers: Arc<Mutex<HashMap<i32, IoHandler>>>,
606 ) -> anyhow::Result<()>
607 where
608 Stdin: AsyncWrite + Unpin + Send + 'static,
609 {
610 let mut stdin = BufWriter::new(stdin);
611 let _clear_response_handlers = util::defer({
612 let response_handlers = response_handlers.clone();
613 move || {
614 response_handlers.lock().take();
615 }
616 });
617 let mut content_len_buffer = Vec::new();
618 while let Ok(message) = outbound_rx.recv().await {
619 log::trace!("outgoing message:{}", message);
620 for handler in io_handlers.lock().values_mut() {
621 handler(IoKind::StdIn, &message);
622 }
623
624 content_len_buffer.clear();
625 write!(content_len_buffer, "{}", message.len()).unwrap();
626 stdin.write_all(CONTENT_LEN_HEADER.as_bytes()).await?;
627 stdin.write_all(&content_len_buffer).await?;
628 stdin.write_all("\r\n\r\n".as_bytes()).await?;
629 stdin.write_all(message.as_bytes()).await?;
630 stdin.flush().await?;
631 }
632 drop(output_done_tx);
633 Ok(())
634 }
635
636 pub fn default_initialize_params(&self, pull_diagnostics: bool, cx: &App) -> InitializeParams {
637 let workspace_folders = self.workspace_folders.as_ref().map_or_else(
638 || {
639 vec![WorkspaceFolder {
640 name: Default::default(),
641 uri: self.root_uri.clone(),
642 }]
643 },
644 |folders| {
645 folders
646 .lock()
647 .iter()
648 .cloned()
649 .map(|uri| WorkspaceFolder {
650 name: Default::default(),
651 uri,
652 })
653 .collect()
654 },
655 );
656
657 #[allow(deprecated)]
658 InitializeParams {
659 process_id: None,
660 root_path: None,
661 root_uri: Some(self.root_uri.clone()),
662 initialization_options: None,
663 capabilities: ClientCapabilities {
664 general: Some(GeneralClientCapabilities {
665 position_encodings: Some(vec![PositionEncodingKind::UTF16]),
666 ..GeneralClientCapabilities::default()
667 }),
668 workspace: Some(WorkspaceClientCapabilities {
669 configuration: Some(true),
670 did_change_watched_files: Some(DidChangeWatchedFilesClientCapabilities {
671 dynamic_registration: Some(true),
672 relative_pattern_support: Some(true),
673 }),
674 did_change_configuration: Some(DynamicRegistrationClientCapabilities {
675 dynamic_registration: Some(true),
676 }),
677 workspace_folders: Some(true),
678 symbol: Some(WorkspaceSymbolClientCapabilities {
679 resolve_support: None,
680 dynamic_registration: Some(true),
681 ..WorkspaceSymbolClientCapabilities::default()
682 }),
683 inlay_hint: Some(InlayHintWorkspaceClientCapabilities {
684 refresh_support: Some(true),
685 }),
686 diagnostics: Some(DiagnosticWorkspaceClientCapabilities {
687 refresh_support: Some(true),
688 })
689 .filter(|_| pull_diagnostics),
690 code_lens: Some(CodeLensWorkspaceClientCapabilities {
691 refresh_support: Some(true),
692 }),
693 workspace_edit: Some(WorkspaceEditClientCapabilities {
694 resource_operations: Some(vec![
695 ResourceOperationKind::Create,
696 ResourceOperationKind::Rename,
697 ResourceOperationKind::Delete,
698 ]),
699 document_changes: Some(true),
700 snippet_edit_support: Some(true),
701 ..WorkspaceEditClientCapabilities::default()
702 }),
703 file_operations: Some(WorkspaceFileOperationsClientCapabilities {
704 dynamic_registration: Some(true),
705 did_rename: Some(true),
706 will_rename: Some(true),
707 ..WorkspaceFileOperationsClientCapabilities::default()
708 }),
709 apply_edit: Some(true),
710 execute_command: Some(ExecuteCommandClientCapabilities {
711 dynamic_registration: Some(true),
712 }),
713 ..WorkspaceClientCapabilities::default()
714 }),
715 text_document: Some(TextDocumentClientCapabilities {
716 definition: Some(GotoCapability {
717 link_support: Some(true),
718 dynamic_registration: Some(true),
719 }),
720 code_action: Some(CodeActionClientCapabilities {
721 code_action_literal_support: Some(CodeActionLiteralSupport {
722 code_action_kind: CodeActionKindLiteralSupport {
723 value_set: vec![
724 CodeActionKind::REFACTOR.as_str().into(),
725 CodeActionKind::QUICKFIX.as_str().into(),
726 CodeActionKind::SOURCE.as_str().into(),
727 ],
728 },
729 }),
730 data_support: Some(true),
731 resolve_support: Some(CodeActionCapabilityResolveSupport {
732 properties: vec![
733 "kind".to_string(),
734 "diagnostics".to_string(),
735 "isPreferred".to_string(),
736 "disabled".to_string(),
737 "edit".to_string(),
738 "command".to_string(),
739 ],
740 }),
741 dynamic_registration: Some(true),
742 ..CodeActionClientCapabilities::default()
743 }),
744 completion: Some(CompletionClientCapabilities {
745 completion_item: Some(CompletionItemCapability {
746 snippet_support: Some(true),
747 resolve_support: Some(CompletionItemCapabilityResolveSupport {
748 properties: vec![
749 "additionalTextEdits".to_string(),
750 "command".to_string(),
751 "documentation".to_string(),
752 // NB: Do not have this resolved, otherwise Zed becomes slow to complete things
753 // "textEdit".to_string(),
754 ],
755 }),
756 insert_replace_support: Some(true),
757 label_details_support: Some(true),
758 insert_text_mode_support: Some(InsertTextModeSupport {
759 value_set: vec![
760 InsertTextMode::AS_IS,
761 InsertTextMode::ADJUST_INDENTATION,
762 ],
763 }),
764 documentation_format: Some(vec![
765 MarkupKind::Markdown,
766 MarkupKind::PlainText,
767 ]),
768 ..CompletionItemCapability::default()
769 }),
770 insert_text_mode: Some(InsertTextMode::ADJUST_INDENTATION),
771 completion_list: Some(CompletionListCapability {
772 item_defaults: Some(vec![
773 "commitCharacters".to_owned(),
774 "editRange".to_owned(),
775 "insertTextMode".to_owned(),
776 "insertTextFormat".to_owned(),
777 "data".to_owned(),
778 ]),
779 }),
780 context_support: Some(true),
781 dynamic_registration: Some(true),
782 ..CompletionClientCapabilities::default()
783 }),
784 rename: Some(RenameClientCapabilities {
785 prepare_support: Some(true),
786 prepare_support_default_behavior: Some(
787 PrepareSupportDefaultBehavior::IDENTIFIER,
788 ),
789 dynamic_registration: Some(true),
790 ..RenameClientCapabilities::default()
791 }),
792 hover: Some(HoverClientCapabilities {
793 content_format: Some(vec![MarkupKind::Markdown]),
794 dynamic_registration: Some(true),
795 }),
796 inlay_hint: Some(InlayHintClientCapabilities {
797 resolve_support: Some(InlayHintResolveClientCapabilities {
798 properties: vec![
799 "textEdits".to_string(),
800 "tooltip".to_string(),
801 "label.tooltip".to_string(),
802 "label.location".to_string(),
803 "label.command".to_string(),
804 ],
805 }),
806 dynamic_registration: Some(true),
807 }),
808 publish_diagnostics: Some(PublishDiagnosticsClientCapabilities {
809 related_information: Some(true),
810 version_support: Some(true),
811 data_support: Some(true),
812 tag_support: Some(TagSupport {
813 value_set: vec![DiagnosticTag::UNNECESSARY, DiagnosticTag::DEPRECATED],
814 }),
815 code_description_support: Some(true),
816 }),
817 formatting: Some(DynamicRegistrationClientCapabilities {
818 dynamic_registration: Some(true),
819 }),
820 range_formatting: Some(DynamicRegistrationClientCapabilities {
821 dynamic_registration: Some(true),
822 }),
823 on_type_formatting: Some(DynamicRegistrationClientCapabilities {
824 dynamic_registration: Some(true),
825 }),
826 signature_help: Some(SignatureHelpClientCapabilities {
827 signature_information: Some(SignatureInformationSettings {
828 documentation_format: Some(vec![
829 MarkupKind::Markdown,
830 MarkupKind::PlainText,
831 ]),
832 parameter_information: Some(ParameterInformationSettings {
833 label_offset_support: Some(true),
834 }),
835 active_parameter_support: Some(true),
836 }),
837 dynamic_registration: Some(true),
838 ..SignatureHelpClientCapabilities::default()
839 }),
840 synchronization: Some(TextDocumentSyncClientCapabilities {
841 did_save: Some(true),
842 dynamic_registration: Some(true),
843 ..TextDocumentSyncClientCapabilities::default()
844 }),
845 code_lens: Some(CodeLensClientCapabilities {
846 dynamic_registration: Some(true),
847 }),
848 document_symbol: Some(DocumentSymbolClientCapabilities {
849 hierarchical_document_symbol_support: Some(true),
850 dynamic_registration: Some(true),
851 ..DocumentSymbolClientCapabilities::default()
852 }),
853 diagnostic: Some(DiagnosticClientCapabilities {
854 dynamic_registration: Some(true),
855 related_document_support: Some(true),
856 })
857 .filter(|_| pull_diagnostics),
858 color_provider: Some(DocumentColorClientCapabilities {
859 dynamic_registration: Some(true),
860 }),
861 ..TextDocumentClientCapabilities::default()
862 }),
863 experimental: Some(json!({
864 "serverStatusNotification": true,
865 "localDocs": true,
866 })),
867 window: Some(WindowClientCapabilities {
868 work_done_progress: Some(true),
869 show_message: Some(ShowMessageRequestClientCapabilities {
870 message_action_item: None,
871 }),
872 ..WindowClientCapabilities::default()
873 }),
874 },
875 trace: None,
876 workspace_folders: Some(workspace_folders),
877 client_info: release_channel::ReleaseChannel::try_global(cx).map(|release_channel| {
878 ClientInfo {
879 name: release_channel.display_name().to_string(),
880 version: Some(release_channel::AppVersion::global(cx).to_string()),
881 }
882 }),
883 locale: None,
884 ..InitializeParams::default()
885 }
886 }
887
888 /// Initializes a language server by sending the `Initialize` request.
889 /// Note that `options` is used directly to construct [`InitializeParams`], which is why it is owned.
890 ///
891 /// [LSP Specification](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#initialize)
892 pub fn initialize(
893 mut self,
894 params: InitializeParams,
895 configuration: Arc<DidChangeConfigurationParams>,
896 cx: &App,
897 ) -> Task<Result<Arc<Self>>> {
898 cx.background_spawn(async move {
899 let response = self
900 .request::<request::Initialize>(params)
901 .await
902 .into_response()
903 .with_context(|| {
904 format!(
905 "initializing server {}, id {}",
906 self.name(),
907 self.server_id()
908 )
909 })?;
910 if let Some(info) = response.server_info {
911 self.process_name = info.name.into();
912 }
913 self.static_capabilities = RwLock::new(response.capabilities);
914 self.configuration = configuration;
915
916 self.notify::<notification::Initialized>(&InitializedParams {})?;
917 Ok(Arc::new(self))
918 })
919 }
920
921 /// Sends a shutdown request to the language server process and prepares the [`LanguageServer`] to be dropped.
922 pub fn shutdown(&self) -> Option<impl 'static + Send + Future<Output = Option<()>> + use<>> {
923 if let Some(tasks) = self.io_tasks.lock().take() {
924 let response_handlers = self.response_handlers.clone();
925 let next_id = AtomicI32::new(self.next_id.load(SeqCst));
926 let outbound_tx = self.outbound_tx.clone();
927 let executor = self.executor.clone();
928 let mut output_done = self.output_done_rx.lock().take().unwrap();
929 let shutdown_request = Self::request_internal::<request::Shutdown>(
930 &next_id,
931 &response_handlers,
932 &outbound_tx,
933 &executor,
934 (),
935 );
936
937 let server = self.server.clone();
938 let name = self.name.clone();
939 let server_id = self.server_id;
940 let mut timer = self.executor.timer(SERVER_SHUTDOWN_TIMEOUT).fuse();
941 Some(async move {
942 log::debug!("language server shutdown started");
943
944 select! {
945 request_result = shutdown_request.fuse() => {
946 match request_result {
947 ConnectionResult::Timeout => {
948 log::warn!("timeout waiting for language server {name} (id {server_id}) to shutdown");
949 },
950 ConnectionResult::ConnectionReset => {
951 log::warn!("language server {name} (id {server_id}) closed the shutdown request connection");
952 },
953 ConnectionResult::Result(Err(e)) => {
954 log::error!("Shutdown request failure, server {name} (id {server_id}): {e:#}");
955 },
956 ConnectionResult::Result(Ok(())) => {}
957 }
958 }
959
960 _ = timer => {
961 log::info!("timeout waiting for language server {name} (id {server_id}) to shutdown");
962 },
963 }
964
965 response_handlers.lock().take();
966 Self::notify_internal::<notification::Exit>(&outbound_tx, &()).ok();
967 outbound_tx.close();
968 output_done.recv().await;
969 server.lock().take().map(|mut child| child.kill());
970 drop(tasks);
971 log::debug!("language server shutdown finished");
972 Some(())
973 })
974 } else {
975 None
976 }
977 }
978
979 /// Register a handler to handle incoming LSP notifications.
980 ///
981 /// [LSP Specification](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#notificationMessage)
982 #[must_use]
983 pub fn on_notification<T, F>(&self, f: F) -> Subscription
984 where
985 T: notification::Notification,
986 F: 'static + Send + FnMut(T::Params, &mut AsyncApp),
987 {
988 self.on_custom_notification(T::METHOD, f)
989 }
990
991 /// Register a handler to handle incoming LSP requests.
992 ///
993 /// [LSP Specification](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#requestMessage)
994 #[must_use]
995 pub fn on_request<T, F, Fut>(&self, f: F) -> Subscription
996 where
997 T: request::Request,
998 T::Params: 'static + Send,
999 F: 'static + FnMut(T::Params, &mut AsyncApp) -> Fut + Send,
1000 Fut: 'static + Future<Output = Result<T::Result>>,
1001 {
1002 self.on_custom_request(T::METHOD, f)
1003 }
1004
1005 /// Registers a handler to inspect all language server process stdio.
1006 #[must_use]
1007 pub fn on_io<F>(&self, f: F) -> Subscription
1008 where
1009 F: 'static + Send + FnMut(IoKind, &str),
1010 {
1011 let id = self.next_id.fetch_add(1, SeqCst);
1012 self.io_handlers.lock().insert(id, Box::new(f));
1013 Subscription::Io {
1014 id,
1015 io_handlers: Some(Arc::downgrade(&self.io_handlers)),
1016 }
1017 }
1018
1019 /// Removes a request handler registers via [`Self::on_request`].
1020 pub fn remove_request_handler<T: request::Request>(&self) {
1021 self.notification_handlers.lock().remove(T::METHOD);
1022 }
1023
1024 /// Removes a notification handler registers via [`Self::on_notification`].
1025 pub fn remove_notification_handler<T: notification::Notification>(&self) {
1026 self.notification_handlers.lock().remove(T::METHOD);
1027 }
1028
1029 /// Checks if a notification handler has been registered via [`Self::on_notification`].
1030 pub fn has_notification_handler<T: notification::Notification>(&self) -> bool {
1031 self.notification_handlers.lock().contains_key(T::METHOD)
1032 }
1033
1034 #[must_use]
1035 fn on_custom_notification<Params, F>(&self, method: &'static str, mut f: F) -> Subscription
1036 where
1037 F: 'static + FnMut(Params, &mut AsyncApp) + Send,
1038 Params: DeserializeOwned,
1039 {
1040 let prev_handler = self.notification_handlers.lock().insert(
1041 method,
1042 Box::new(move |_, params, cx| {
1043 if let Some(params) = serde_json::from_value(params).log_err() {
1044 f(params, cx);
1045 }
1046 }),
1047 );
1048 assert!(
1049 prev_handler.is_none(),
1050 "registered multiple handlers for the same LSP method"
1051 );
1052 Subscription::Notification {
1053 method,
1054 notification_handlers: Some(self.notification_handlers.clone()),
1055 }
1056 }
1057
1058 #[must_use]
1059 fn on_custom_request<Params, Res, Fut, F>(&self, method: &'static str, mut f: F) -> Subscription
1060 where
1061 F: 'static + FnMut(Params, &mut AsyncApp) -> Fut + Send,
1062 Fut: 'static + Future<Output = Result<Res>>,
1063 Params: DeserializeOwned + Send + 'static,
1064 Res: Serialize,
1065 {
1066 let outbound_tx = self.outbound_tx.clone();
1067 let prev_handler = self.notification_handlers.lock().insert(
1068 method,
1069 Box::new(move |id, params, cx| {
1070 if let Some(id) = id {
1071 match serde_json::from_value(params) {
1072 Ok(params) => {
1073 let response = f(params, cx);
1074 cx.foreground_executor()
1075 .spawn({
1076 let outbound_tx = outbound_tx.clone();
1077 async move {
1078 let response = match response.await {
1079 Ok(result) => Response {
1080 jsonrpc: JSON_RPC_VERSION,
1081 id,
1082 value: LspResult::Ok(Some(result)),
1083 },
1084 Err(error) => Response {
1085 jsonrpc: JSON_RPC_VERSION,
1086 id,
1087 value: LspResult::Error(Some(Error {
1088 code: lsp_types::error_codes::REQUEST_FAILED,
1089 message: error.to_string(),
1090 data: None,
1091 })),
1092 },
1093 };
1094 if let Some(response) =
1095 serde_json::to_string(&response).log_err()
1096 {
1097 outbound_tx.try_send(response).ok();
1098 }
1099 }
1100 })
1101 .detach();
1102 }
1103
1104 Err(error) => {
1105 log::error!("error deserializing {} request: {:?}", method, error);
1106 let response = AnyResponse {
1107 jsonrpc: JSON_RPC_VERSION,
1108 id,
1109 result: None,
1110 error: Some(Error {
1111 code: -32700, // Parse error
1112 message: error.to_string(),
1113 data: None,
1114 }),
1115 };
1116 if let Some(response) = serde_json::to_string(&response).log_err() {
1117 outbound_tx.try_send(response).ok();
1118 }
1119 }
1120 }
1121 }
1122 }),
1123 );
1124 assert!(
1125 prev_handler.is_none(),
1126 "registered multiple handlers for the same LSP method"
1127 );
1128 Subscription::Notification {
1129 method,
1130 notification_handlers: Some(self.notification_handlers.clone()),
1131 }
1132 }
1133
1134 /// Get the name of the running language server.
1135 pub fn name(&self) -> LanguageServerName {
1136 self.name.clone()
1137 }
1138
1139 pub fn process_name(&self) -> &str {
1140 &self.process_name
1141 }
1142
1143 /// Get the reported capabilities of the running language server.
1144 pub fn capabilities(&self) -> ServerCapabilities {
1145 self.static_capabilities.read().clone()
1146 }
1147
1148 pub fn update_dynamic_capabilities(&self, update: impl FnOnce(&mut DynamicCapabilities)) {
1149 update(self.dynamic_capabilities.write().deref_mut());
1150 }
1151
1152 /// Get effective capabilities by combining static and dynamic capabilities.
1153 pub fn effective_capability<Cap: EffectiveCapability>(&self) -> Cap::Value {
1154 let static_capabilities = self.capabilities();
1155 let dynamic_capabilities = self.dynamic_capabilities.read().clone();
1156 Cap::compute(&static_capabilities, &dynamic_capabilities)
1157 }
1158
1159 /// Get the reported capabilities of the running language server and
1160 /// what we know on the client/adapter-side of its capabilities.
1161 pub fn adapter_server_capabilities(&self) -> AdapterServerCapabilities {
1162 AdapterServerCapabilities {
1163 server_capabilities: self.capabilities(),
1164 code_action_kinds: self.code_action_kinds(),
1165 }
1166 }
1167
1168 pub fn update_capabilities(&self, update: impl FnOnce(&mut ServerCapabilities)) {
1169 update(self.static_capabilities.write().deref_mut());
1170 }
1171
1172 pub fn configuration(&self) -> &Value {
1173 &self.configuration.settings
1174 }
1175
1176 /// Get the id of the running language server.
1177 pub fn server_id(&self) -> LanguageServerId {
1178 self.server_id
1179 }
1180
1181 /// Language server's binary information.
1182 pub fn binary(&self) -> &LanguageServerBinary {
1183 &self.binary
1184 }
1185
1186 /// Sends a RPC request to the language server.
1187 ///
1188 /// [LSP Specification](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#requestMessage)
1189 pub fn request<T: request::Request>(
1190 &self,
1191 params: T::Params,
1192 ) -> impl LspRequestFuture<T::Result> + use<T>
1193 where
1194 T::Result: 'static + Send,
1195 {
1196 Self::request_internal::<T>(
1197 &self.next_id,
1198 &self.response_handlers,
1199 &self.outbound_tx,
1200 &self.executor,
1201 params,
1202 )
1203 }
1204
1205 /// Sends a RPC request to the language server, with a custom timer, a future which when becoming
1206 /// ready causes the request to be timed out with the future's output message.
1207 ///
1208 /// [LSP Specification](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#requestMessage)
1209 pub fn request_with_timer<T: request::Request, U: Future<Output = String>>(
1210 &self,
1211 params: T::Params,
1212 timer: U,
1213 ) -> impl LspRequestFuture<T::Result> + use<T, U>
1214 where
1215 T::Result: 'static + Send,
1216 {
1217 Self::request_internal_with_timer::<T, U>(
1218 &self.next_id,
1219 &self.response_handlers,
1220 &self.outbound_tx,
1221 &self.executor,
1222 timer,
1223 params,
1224 )
1225 }
1226
1227 fn request_internal_with_timer<T, U>(
1228 next_id: &AtomicI32,
1229 response_handlers: &Mutex<Option<HashMap<RequestId, ResponseHandler>>>,
1230 outbound_tx: &channel::Sender<String>,
1231 executor: &BackgroundExecutor,
1232 timer: U,
1233 params: T::Params,
1234 ) -> impl LspRequestFuture<T::Result> + use<T, U>
1235 where
1236 T::Result: 'static + Send,
1237 T: request::Request,
1238 U: Future<Output = String>,
1239 {
1240 let id = next_id.fetch_add(1, SeqCst);
1241 let message = serde_json::to_string(&Request {
1242 jsonrpc: JSON_RPC_VERSION,
1243 id: RequestId::Int(id),
1244 method: T::METHOD,
1245 params,
1246 })
1247 .unwrap();
1248
1249 let (tx, rx) = oneshot::channel();
1250 let handle_response = response_handlers
1251 .lock()
1252 .as_mut()
1253 .context("server shut down")
1254 .map(|handlers| {
1255 let executor = executor.clone();
1256 handlers.insert(
1257 RequestId::Int(id),
1258 Box::new(move |result| {
1259 executor
1260 .spawn(async move {
1261 let response = match result {
1262 Ok(response) => match serde_json::from_str(&response) {
1263 Ok(deserialized) => Ok(deserialized),
1264 Err(error) => {
1265 log::error!("failed to deserialize response from language server: {}. response from language server: {:?}", error, response);
1266 Err(error).context("failed to deserialize response")
1267 }
1268 }
1269 Err(error) => Err(anyhow!("{}", error.message)),
1270 };
1271 _ = tx.send(response);
1272 })
1273 .detach();
1274 }),
1275 );
1276 });
1277
1278 let send = outbound_tx
1279 .try_send(message)
1280 .context("failed to write to language server's stdin");
1281
1282 let outbound_tx = outbound_tx.downgrade();
1283 let started = Instant::now();
1284 LspRequest::new(id, async move {
1285 if let Err(e) = handle_response {
1286 return ConnectionResult::Result(Err(e));
1287 }
1288 if let Err(e) = send {
1289 return ConnectionResult::Result(Err(e));
1290 }
1291
1292 let cancel_on_drop = util::defer(move || {
1293 if let Some(outbound_tx) = outbound_tx.upgrade() {
1294 Self::notify_internal::<notification::Cancel>(
1295 &outbound_tx,
1296 &CancelParams {
1297 id: NumberOrString::Number(id),
1298 },
1299 )
1300 .ok();
1301 }
1302 });
1303
1304 let method = T::METHOD;
1305 select! {
1306 response = rx.fuse() => {
1307 let elapsed = started.elapsed();
1308 log::trace!("Took {elapsed:?} to receive response to {method:?} id {id}");
1309 cancel_on_drop.abort();
1310 match response {
1311 Ok(response_result) => ConnectionResult::Result(response_result),
1312 Err(Canceled) => {
1313 log::error!("Server reset connection for a request {method:?} id {id}");
1314 ConnectionResult::ConnectionReset
1315 },
1316 }
1317 }
1318
1319 message = timer.fuse() => {
1320 log::error!("Cancelled LSP request task for {method:?} id {id} {message}");
1321 ConnectionResult::Timeout
1322 }
1323 }
1324 })
1325 }
1326
1327 fn request_internal<T>(
1328 next_id: &AtomicI32,
1329 response_handlers: &Mutex<Option<HashMap<RequestId, ResponseHandler>>>,
1330 outbound_tx: &channel::Sender<String>,
1331 executor: &BackgroundExecutor,
1332 params: T::Params,
1333 ) -> impl LspRequestFuture<T::Result> + use<T>
1334 where
1335 T::Result: 'static + Send,
1336 T: request::Request,
1337 {
1338 Self::request_internal_with_timer::<T, _>(
1339 next_id,
1340 response_handlers,
1341 outbound_tx,
1342 executor,
1343 Self::default_request_timer(executor.clone()),
1344 params,
1345 )
1346 }
1347
1348 pub fn default_request_timer(executor: BackgroundExecutor) -> impl Future<Output = String> {
1349 executor
1350 .timer(LSP_REQUEST_TIMEOUT)
1351 .map(|_| format!("which took over {LSP_REQUEST_TIMEOUT:?}"))
1352 }
1353
1354 /// Sends a RPC notification to the language server.
1355 ///
1356 /// [LSP Specification](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#notificationMessage)
1357 pub fn notify<T: notification::Notification>(&self, params: &T::Params) -> Result<()> {
1358 Self::notify_internal::<T>(&self.outbound_tx, params)
1359 }
1360
1361 fn notify_internal<T: notification::Notification>(
1362 outbound_tx: &channel::Sender<String>,
1363 params: &T::Params,
1364 ) -> Result<()> {
1365 let message = serde_json::to_string(&Notification {
1366 jsonrpc: JSON_RPC_VERSION,
1367 method: T::METHOD,
1368 params,
1369 })
1370 .unwrap();
1371 outbound_tx.try_send(message)?;
1372 Ok(())
1373 }
1374
1375 /// Add new workspace folder to the list.
1376 pub fn add_workspace_folder(&self, uri: Url) {
1377 if self
1378 .capabilities()
1379 .workspace
1380 .and_then(|ws| {
1381 ws.workspace_folders.and_then(|folders| {
1382 folders
1383 .change_notifications
1384 .map(|caps| matches!(caps, OneOf::Left(false)))
1385 })
1386 })
1387 .unwrap_or(true)
1388 {
1389 return;
1390 }
1391
1392 let Some(workspace_folders) = self.workspace_folders.as_ref() else {
1393 return;
1394 };
1395 let is_new_folder = workspace_folders.lock().insert(uri.clone());
1396 if is_new_folder {
1397 let params = DidChangeWorkspaceFoldersParams {
1398 event: WorkspaceFoldersChangeEvent {
1399 added: vec![WorkspaceFolder {
1400 uri,
1401 name: String::default(),
1402 }],
1403 removed: vec![],
1404 },
1405 };
1406 self.notify::<DidChangeWorkspaceFolders>(¶ms).ok();
1407 }
1408 }
1409 /// Add new workspace folder to the list.
1410 pub fn remove_workspace_folder(&self, uri: Url) {
1411 if self
1412 .capabilities()
1413 .workspace
1414 .and_then(|ws| {
1415 ws.workspace_folders.and_then(|folders| {
1416 folders
1417 .change_notifications
1418 .map(|caps| !matches!(caps, OneOf::Left(false)))
1419 })
1420 })
1421 .unwrap_or(true)
1422 {
1423 return;
1424 }
1425 let Some(workspace_folders) = self.workspace_folders.as_ref() else {
1426 return;
1427 };
1428 let was_removed = workspace_folders.lock().remove(&uri);
1429 if was_removed {
1430 let params = DidChangeWorkspaceFoldersParams {
1431 event: WorkspaceFoldersChangeEvent {
1432 added: vec![],
1433 removed: vec![WorkspaceFolder {
1434 uri,
1435 name: String::default(),
1436 }],
1437 },
1438 };
1439 self.notify::<DidChangeWorkspaceFolders>(¶ms).ok();
1440 }
1441 }
1442 pub fn set_workspace_folders(&self, folders: BTreeSet<Url>) {
1443 let Some(workspace_folders) = self.workspace_folders.as_ref() else {
1444 return;
1445 };
1446 let mut workspace_folders = workspace_folders.lock();
1447
1448 let old_workspace_folders = std::mem::take(&mut *workspace_folders);
1449 let added: Vec<_> = folders
1450 .difference(&old_workspace_folders)
1451 .map(|uri| WorkspaceFolder {
1452 uri: uri.clone(),
1453 name: String::default(),
1454 })
1455 .collect();
1456
1457 let removed: Vec<_> = old_workspace_folders
1458 .difference(&folders)
1459 .map(|uri| WorkspaceFolder {
1460 uri: uri.clone(),
1461 name: String::default(),
1462 })
1463 .collect();
1464 *workspace_folders = folders;
1465 let should_notify = !added.is_empty() || !removed.is_empty();
1466 if should_notify {
1467 drop(workspace_folders);
1468 let params = DidChangeWorkspaceFoldersParams {
1469 event: WorkspaceFoldersChangeEvent { added, removed },
1470 };
1471 self.notify::<DidChangeWorkspaceFolders>(¶ms).ok();
1472 }
1473 }
1474
1475 pub fn workspace_folders(&self) -> BTreeSet<Url> {
1476 self.workspace_folders.as_ref().map_or_else(
1477 || BTreeSet::from_iter([self.root_uri.clone()]),
1478 |folders| folders.lock().clone(),
1479 )
1480 }
1481
1482 pub fn register_buffer(
1483 &self,
1484 uri: Url,
1485 language_id: String,
1486 version: i32,
1487 initial_text: String,
1488 ) {
1489 self.notify::<notification::DidOpenTextDocument>(&DidOpenTextDocumentParams {
1490 text_document: TextDocumentItem::new(uri, language_id, version, initial_text),
1491 })
1492 .ok();
1493 }
1494
1495 pub fn unregister_buffer(&self, uri: Url) {
1496 self.notify::<notification::DidCloseTextDocument>(&DidCloseTextDocumentParams {
1497 text_document: TextDocumentIdentifier::new(uri),
1498 })
1499 .ok();
1500 }
1501}
1502
1503impl Drop for LanguageServer {
1504 fn drop(&mut self) {
1505 if let Some(shutdown) = self.shutdown() {
1506 self.executor.spawn(shutdown).detach();
1507 }
1508 }
1509}
1510
1511impl Subscription {
1512 /// Detaching a subscription handle prevents it from unsubscribing on drop.
1513 pub fn detach(&mut self) {
1514 match self {
1515 Subscription::Notification {
1516 notification_handlers,
1517 ..
1518 } => *notification_handlers = None,
1519 Subscription::Io { io_handlers, .. } => *io_handlers = None,
1520 }
1521 }
1522}
1523
1524impl fmt::Display for LanguageServerId {
1525 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1526 self.0.fmt(f)
1527 }
1528}
1529
1530impl fmt::Debug for LanguageServer {
1531 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1532 f.debug_struct("LanguageServer")
1533 .field("id", &self.server_id.0)
1534 .field("name", &self.name)
1535 .finish_non_exhaustive()
1536 }
1537}
1538
1539impl fmt::Debug for LanguageServerBinary {
1540 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1541 let mut debug = f.debug_struct("LanguageServerBinary");
1542 debug.field("path", &self.path);
1543 debug.field("arguments", &self.arguments);
1544
1545 if let Some(env) = &self.env {
1546 let redacted_env: BTreeMap<String, String> = env
1547 .iter()
1548 .map(|(key, value)| {
1549 let redacted_value = if redact::should_redact(key) {
1550 "REDACTED".to_string()
1551 } else {
1552 value.clone()
1553 };
1554 (key.clone(), redacted_value)
1555 })
1556 .collect();
1557 debug.field("env", &Some(redacted_env));
1558 } else {
1559 debug.field("env", &self.env);
1560 }
1561
1562 debug.finish()
1563 }
1564}
1565
1566impl Drop for Subscription {
1567 fn drop(&mut self) {
1568 match self {
1569 Subscription::Notification {
1570 method,
1571 notification_handlers,
1572 } => {
1573 if let Some(handlers) = notification_handlers {
1574 handlers.lock().remove(method);
1575 }
1576 }
1577 Subscription::Io { id, io_handlers } => {
1578 if let Some(io_handlers) = io_handlers.as_ref().and_then(|h| h.upgrade()) {
1579 io_handlers.lock().remove(id);
1580 }
1581 }
1582 }
1583 }
1584}
1585
1586/// Mock language server for use in tests.
1587#[cfg(any(test, feature = "test-support"))]
1588#[derive(Clone)]
1589pub struct FakeLanguageServer {
1590 pub binary: LanguageServerBinary,
1591 pub server: Arc<LanguageServer>,
1592 notifications_rx: channel::Receiver<(String, String)>,
1593}
1594
1595#[cfg(any(test, feature = "test-support"))]
1596impl FakeLanguageServer {
1597 /// Construct a fake language server.
1598 pub fn new(
1599 server_id: LanguageServerId,
1600 binary: LanguageServerBinary,
1601 name: String,
1602 capabilities: ServerCapabilities,
1603 cx: &mut AsyncApp,
1604 ) -> (LanguageServer, FakeLanguageServer) {
1605 let (stdin_writer, stdin_reader) = async_pipe::pipe();
1606 let (stdout_writer, stdout_reader) = async_pipe::pipe();
1607 let (notifications_tx, notifications_rx) = channel::unbounded();
1608
1609 let server_name = LanguageServerName(name.clone().into());
1610 let process_name = Arc::from(name.as_str());
1611 let root = Self::root_path();
1612 let workspace_folders: Arc<Mutex<BTreeSet<Url>>> = Default::default();
1613 let mut server = LanguageServer::new_internal(
1614 server_id,
1615 server_name.clone(),
1616 stdin_writer,
1617 stdout_reader,
1618 None::<async_pipe::PipeReader>,
1619 Arc::new(Mutex::new(None)),
1620 None,
1621 None,
1622 binary.clone(),
1623 root,
1624 Some(workspace_folders.clone()),
1625 cx,
1626 |_| false,
1627 );
1628 server.process_name = process_name;
1629 let fake = FakeLanguageServer {
1630 binary: binary.clone(),
1631 server: Arc::new({
1632 let mut server = LanguageServer::new_internal(
1633 server_id,
1634 server_name,
1635 stdout_writer,
1636 stdin_reader,
1637 None::<async_pipe::PipeReader>,
1638 Arc::new(Mutex::new(None)),
1639 None,
1640 None,
1641 binary,
1642 Self::root_path(),
1643 Some(workspace_folders),
1644 cx,
1645 move |msg| {
1646 notifications_tx
1647 .try_send((
1648 msg.method.to_string(),
1649 msg.params.as_ref().unwrap_or(&Value::Null).to_string(),
1650 ))
1651 .ok();
1652 true
1653 },
1654 );
1655 server.process_name = name.as_str().into();
1656 server
1657 }),
1658 notifications_rx,
1659 };
1660 fake.set_request_handler::<request::Initialize, _, _>({
1661 let capabilities = capabilities;
1662 move |_, _| {
1663 let capabilities = capabilities.clone();
1664 let name = name.clone();
1665 async move {
1666 Ok(InitializeResult {
1667 capabilities,
1668 server_info: Some(ServerInfo {
1669 name,
1670 ..Default::default()
1671 }),
1672 })
1673 }
1674 }
1675 });
1676
1677 fake.set_request_handler::<request::Shutdown, _, _>(|_, _| async move { Ok(()) });
1678
1679 (server, fake)
1680 }
1681 #[cfg(target_os = "windows")]
1682 fn root_path() -> Url {
1683 Url::from_file_path("C:/").unwrap()
1684 }
1685
1686 #[cfg(not(target_os = "windows"))]
1687 fn root_path() -> Url {
1688 Url::from_file_path("/").unwrap()
1689 }
1690}
1691
1692#[cfg(any(test, feature = "test-support"))]
1693impl LanguageServer {
1694 pub fn full_capabilities() -> ServerCapabilities {
1695 ServerCapabilities {
1696 document_highlight_provider: Some(OneOf::Left(true)),
1697 code_action_provider: Some(CodeActionProviderCapability::Simple(true)),
1698 document_formatting_provider: Some(OneOf::Left(true)),
1699 document_range_formatting_provider: Some(OneOf::Left(true)),
1700 definition_provider: Some(OneOf::Left(true)),
1701 workspace_symbol_provider: Some(OneOf::Left(true)),
1702 implementation_provider: Some(ImplementationProviderCapability::Simple(true)),
1703 type_definition_provider: Some(TypeDefinitionProviderCapability::Simple(true)),
1704 ..ServerCapabilities::default()
1705 }
1706 }
1707}
1708
1709#[cfg(any(test, feature = "test-support"))]
1710impl FakeLanguageServer {
1711 /// See [`LanguageServer::notify`].
1712 pub fn notify<T: notification::Notification>(&self, params: &T::Params) {
1713 self.server.notify::<T>(params).ok();
1714 }
1715
1716 /// See [`LanguageServer::request`].
1717 pub async fn request<T>(&self, params: T::Params) -> ConnectionResult<T::Result>
1718 where
1719 T: request::Request,
1720 T::Result: 'static + Send,
1721 {
1722 self.server.executor.start_waiting();
1723 self.server.request::<T>(params).await
1724 }
1725
1726 /// Attempts [`Self::try_receive_notification`], unwrapping if it has not received the specified type yet.
1727 pub async fn receive_notification<T: notification::Notification>(&mut self) -> T::Params {
1728 self.server.executor.start_waiting();
1729 self.try_receive_notification::<T>().await.unwrap()
1730 }
1731
1732 /// Consumes the notification channel until it finds a notification for the specified type.
1733 pub async fn try_receive_notification<T: notification::Notification>(
1734 &mut self,
1735 ) -> Option<T::Params> {
1736 loop {
1737 let (method, params) = self.notifications_rx.recv().await.ok()?;
1738 if method == T::METHOD {
1739 return Some(serde_json::from_str::<T::Params>(¶ms).unwrap());
1740 } else {
1741 log::info!("skipping message in fake language server {:?}", params);
1742 }
1743 }
1744 }
1745
1746 /// Registers a handler for a specific kind of request. Removes any existing handler for specified request type.
1747 pub fn set_request_handler<T, F, Fut>(
1748 &self,
1749 mut handler: F,
1750 ) -> futures::channel::mpsc::UnboundedReceiver<()>
1751 where
1752 T: 'static + request::Request,
1753 T::Params: 'static + Send,
1754 F: 'static + Send + FnMut(T::Params, gpui::AsyncApp) -> Fut,
1755 Fut: 'static + Future<Output = Result<T::Result>>,
1756 {
1757 let (responded_tx, responded_rx) = futures::channel::mpsc::unbounded();
1758 self.server.remove_request_handler::<T>();
1759 self.server
1760 .on_request::<T, _, _>(move |params, cx| {
1761 let result = handler(params, cx.clone());
1762 let responded_tx = responded_tx.clone();
1763 let executor = cx.background_executor().clone();
1764 async move {
1765 executor.simulate_random_delay().await;
1766 let result = result.await;
1767 responded_tx.unbounded_send(()).ok();
1768 result
1769 }
1770 })
1771 .detach();
1772 responded_rx
1773 }
1774
1775 /// Registers a handler for a specific kind of notification. Removes any existing handler for specified notification type.
1776 pub fn handle_notification<T, F>(
1777 &self,
1778 mut handler: F,
1779 ) -> futures::channel::mpsc::UnboundedReceiver<()>
1780 where
1781 T: 'static + notification::Notification,
1782 T::Params: 'static + Send,
1783 F: 'static + Send + FnMut(T::Params, gpui::AsyncApp),
1784 {
1785 let (handled_tx, handled_rx) = futures::channel::mpsc::unbounded();
1786 self.server.remove_notification_handler::<T>();
1787 self.server
1788 .on_notification::<T, _>(move |params, cx| {
1789 handler(params, cx.clone());
1790 handled_tx.unbounded_send(()).ok();
1791 })
1792 .detach();
1793 handled_rx
1794 }
1795
1796 /// Removes any existing handler for specified notification type.
1797 pub fn remove_request_handler<T>(&mut self)
1798 where
1799 T: 'static + request::Request,
1800 {
1801 self.server.remove_request_handler::<T>();
1802 }
1803
1804 /// Simulate that the server has started work and notifies about its progress with the specified token.
1805 pub async fn start_progress(&self, token: impl Into<String>) {
1806 self.start_progress_with(token, Default::default()).await
1807 }
1808
1809 pub async fn start_progress_with(
1810 &self,
1811 token: impl Into<String>,
1812 progress: WorkDoneProgressBegin,
1813 ) {
1814 let token = token.into();
1815 self.request::<request::WorkDoneProgressCreate>(WorkDoneProgressCreateParams {
1816 token: NumberOrString::String(token.clone()),
1817 })
1818 .await
1819 .into_response()
1820 .unwrap();
1821 self.notify::<notification::Progress>(&ProgressParams {
1822 token: NumberOrString::String(token),
1823 value: ProgressParamsValue::WorkDone(WorkDoneProgress::Begin(progress)),
1824 });
1825 }
1826
1827 /// Simulate that the server has completed work and notifies about that with the specified token.
1828 pub fn end_progress(&self, token: impl Into<String>) {
1829 self.notify::<notification::Progress>(&ProgressParams {
1830 token: NumberOrString::String(token.into()),
1831 value: ProgressParamsValue::WorkDone(WorkDoneProgress::End(Default::default())),
1832 });
1833 }
1834}
1835
1836#[cfg(test)]
1837mod tests {
1838 use super::*;
1839 use gpui::{SemanticVersion, TestAppContext};
1840 use std::str::FromStr;
1841
1842 #[ctor::ctor]
1843 fn init_logger() {
1844 zlog::init_test();
1845 }
1846
1847 #[gpui::test]
1848 async fn test_fake(cx: &mut TestAppContext) {
1849 cx.update(|cx| {
1850 release_channel::init(SemanticVersion::default(), cx);
1851 });
1852 let (server, mut fake) = FakeLanguageServer::new(
1853 LanguageServerId(0),
1854 LanguageServerBinary {
1855 path: "path/to/language-server".into(),
1856 arguments: vec![],
1857 env: None,
1858 },
1859 "the-lsp".to_string(),
1860 Default::default(),
1861 &mut cx.to_async(),
1862 );
1863
1864 let (message_tx, message_rx) = channel::unbounded();
1865 let (diagnostics_tx, diagnostics_rx) = channel::unbounded();
1866 server
1867 .on_notification::<notification::ShowMessage, _>(move |params, _| {
1868 message_tx.try_send(params).unwrap()
1869 })
1870 .detach();
1871 server
1872 .on_notification::<notification::PublishDiagnostics, _>(move |params, _| {
1873 diagnostics_tx.try_send(params).unwrap()
1874 })
1875 .detach();
1876
1877 let server = cx
1878 .update(|cx| {
1879 let params = server.default_initialize_params(false, cx);
1880 let configuration = DidChangeConfigurationParams {
1881 settings: Default::default(),
1882 };
1883 server.initialize(params, configuration.into(), cx)
1884 })
1885 .await
1886 .unwrap();
1887 server
1888 .notify::<notification::DidOpenTextDocument>(&DidOpenTextDocumentParams {
1889 text_document: TextDocumentItem::new(
1890 Url::from_str("file://a/b").unwrap(),
1891 "rust".to_string(),
1892 0,
1893 "".to_string(),
1894 ),
1895 })
1896 .unwrap();
1897 assert_eq!(
1898 fake.receive_notification::<notification::DidOpenTextDocument>()
1899 .await
1900 .text_document
1901 .uri
1902 .as_str(),
1903 "file://a/b"
1904 );
1905
1906 fake.notify::<notification::ShowMessage>(&ShowMessageParams {
1907 typ: MessageType::ERROR,
1908 message: "ok".to_string(),
1909 });
1910 fake.notify::<notification::PublishDiagnostics>(&PublishDiagnosticsParams {
1911 uri: Url::from_str("file://b/c").unwrap(),
1912 version: Some(5),
1913 diagnostics: vec![],
1914 });
1915 assert_eq!(message_rx.recv().await.unwrap().message, "ok");
1916 assert_eq!(
1917 diagnostics_rx.recv().await.unwrap().uri.as_str(),
1918 "file://b/c"
1919 );
1920
1921 fake.set_request_handler::<request::Shutdown, _, _>(|_, _| async move { Ok(()) });
1922
1923 drop(server);
1924 fake.receive_notification::<notification::Exit>().await;
1925 }
1926
1927 #[gpui::test]
1928 fn test_deserialize_string_digit_id() {
1929 let json = r#"{"jsonrpc":"2.0","id":"2","method":"workspace/configuration","params":{"items":[{"scopeUri":"file:///Users/mph/Devel/personal/hello-scala/","section":"metals"}]}}"#;
1930 let notification = serde_json::from_str::<NotificationOrRequest>(json)
1931 .expect("message with string id should be parsed");
1932 let expected_id = RequestId::Str("2".to_string());
1933 assert_eq!(notification.id, Some(expected_id));
1934 }
1935
1936 #[gpui::test]
1937 fn test_deserialize_string_id() {
1938 let json = r#"{"jsonrpc":"2.0","id":"anythingAtAll","method":"workspace/configuration","params":{"items":[{"scopeUri":"file:///Users/mph/Devel/personal/hello-scala/","section":"metals"}]}}"#;
1939 let notification = serde_json::from_str::<NotificationOrRequest>(json)
1940 .expect("message with string id should be parsed");
1941 let expected_id = RequestId::Str("anythingAtAll".to_string());
1942 assert_eq!(notification.id, Some(expected_id));
1943 }
1944
1945 #[gpui::test]
1946 fn test_deserialize_int_id() {
1947 let json = r#"{"jsonrpc":"2.0","id":2,"method":"workspace/configuration","params":{"items":[{"scopeUri":"file:///Users/mph/Devel/personal/hello-scala/","section":"metals"}]}}"#;
1948 let notification = serde_json::from_str::<NotificationOrRequest>(json)
1949 .expect("message with string id should be parsed");
1950 let expected_id = RequestId::Int(2);
1951 assert_eq!(notification.id, Some(expected_id));
1952 }
1953
1954 #[test]
1955 fn test_serialize_has_no_nulls() {
1956 // Ensure we're not setting both result and error variants. (ticket #10595)
1957 let no_tag = Response::<u32> {
1958 jsonrpc: "",
1959 id: RequestId::Int(0),
1960 value: LspResult::Ok(None),
1961 };
1962 assert_eq!(
1963 serde_json::to_string(&no_tag).unwrap(),
1964 "{\"jsonrpc\":\"\",\"id\":0,\"result\":null}"
1965 );
1966 let no_tag = Response::<u32> {
1967 jsonrpc: "",
1968 id: RequestId::Int(0),
1969 value: LspResult::Error(None),
1970 };
1971 assert_eq!(
1972 serde_json::to_string(&no_tag).unwrap(),
1973 "{\"jsonrpc\":\"\",\"id\":0,\"error\":null}"
1974 );
1975 }
1976}