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