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