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