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 "documentation".to_string(),
765 // NB: Do not have this resolved, otherwise Zed becomes slow to complete things
766 // "textEdit".to_string(),
767 ],
768 }),
769 deprecated_support: Some(true),
770 tag_support: Some(TagSupport {
771 value_set: vec![CompletionItemTag::DEPRECATED],
772 }),
773 insert_replace_support: Some(true),
774 label_details_support: Some(true),
775 insert_text_mode_support: Some(InsertTextModeSupport {
776 value_set: vec![
777 InsertTextMode::AS_IS,
778 InsertTextMode::ADJUST_INDENTATION,
779 ],
780 }),
781 documentation_format: Some(vec![
782 MarkupKind::Markdown,
783 MarkupKind::PlainText,
784 ]),
785 ..CompletionItemCapability::default()
786 }),
787 insert_text_mode: Some(InsertTextMode::ADJUST_INDENTATION),
788 completion_list: Some(CompletionListCapability {
789 item_defaults: Some(vec![
790 "commitCharacters".to_owned(),
791 "editRange".to_owned(),
792 "insertTextMode".to_owned(),
793 "insertTextFormat".to_owned(),
794 "data".to_owned(),
795 ]),
796 }),
797 context_support: Some(true),
798 dynamic_registration: Some(true),
799 ..CompletionClientCapabilities::default()
800 }),
801 rename: Some(RenameClientCapabilities {
802 prepare_support: Some(true),
803 prepare_support_default_behavior: Some(
804 PrepareSupportDefaultBehavior::IDENTIFIER,
805 ),
806 dynamic_registration: Some(true),
807 ..RenameClientCapabilities::default()
808 }),
809 hover: Some(HoverClientCapabilities {
810 content_format: Some(vec![MarkupKind::Markdown]),
811 dynamic_registration: Some(true),
812 }),
813 inlay_hint: Some(InlayHintClientCapabilities {
814 resolve_support: Some(InlayHintResolveClientCapabilities {
815 properties: vec![
816 "textEdits".to_string(),
817 "tooltip".to_string(),
818 "label.tooltip".to_string(),
819 "label.location".to_string(),
820 "label.command".to_string(),
821 ],
822 }),
823 dynamic_registration: Some(true),
824 }),
825 publish_diagnostics: Some(PublishDiagnosticsClientCapabilities {
826 related_information: Some(true),
827 version_support: Some(true),
828 data_support: Some(true),
829 tag_support: Some(TagSupport {
830 value_set: vec![DiagnosticTag::UNNECESSARY, DiagnosticTag::DEPRECATED],
831 }),
832 code_description_support: Some(true),
833 }),
834 formatting: Some(DynamicRegistrationClientCapabilities {
835 dynamic_registration: Some(true),
836 }),
837 range_formatting: Some(DynamicRegistrationClientCapabilities {
838 dynamic_registration: Some(true),
839 }),
840 on_type_formatting: Some(DynamicRegistrationClientCapabilities {
841 dynamic_registration: Some(true),
842 }),
843 signature_help: Some(SignatureHelpClientCapabilities {
844 signature_information: Some(SignatureInformationSettings {
845 documentation_format: Some(vec![
846 MarkupKind::Markdown,
847 MarkupKind::PlainText,
848 ]),
849 parameter_information: Some(ParameterInformationSettings {
850 label_offset_support: Some(true),
851 }),
852 active_parameter_support: Some(true),
853 }),
854 dynamic_registration: Some(true),
855 ..SignatureHelpClientCapabilities::default()
856 }),
857 synchronization: Some(TextDocumentSyncClientCapabilities {
858 did_save: Some(true),
859 dynamic_registration: Some(true),
860 ..TextDocumentSyncClientCapabilities::default()
861 }),
862 code_lens: Some(CodeLensClientCapabilities {
863 dynamic_registration: Some(true),
864 }),
865 document_symbol: Some(DocumentSymbolClientCapabilities {
866 hierarchical_document_symbol_support: Some(true),
867 dynamic_registration: Some(true),
868 ..DocumentSymbolClientCapabilities::default()
869 }),
870 diagnostic: Some(DiagnosticClientCapabilities {
871 dynamic_registration: Some(true),
872 related_document_support: Some(true),
873 })
874 .filter(|_| pull_diagnostics),
875 color_provider: Some(DocumentColorClientCapabilities {
876 dynamic_registration: Some(true),
877 }),
878 ..TextDocumentClientCapabilities::default()
879 }),
880 experimental: Some(json!({
881 "serverStatusNotification": true,
882 "localDocs": true,
883 })),
884 window: Some(WindowClientCapabilities {
885 work_done_progress: Some(true),
886 show_message: Some(ShowMessageRequestClientCapabilities {
887 message_action_item: Some(MessageActionItemCapabilities {
888 additional_properties_support: Some(true),
889 }),
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.version = info.version.map(SharedString::from);
931 self.process_name = info.name.into();
932 }
933 self.capabilities = RwLock::new(response.capabilities);
934 self.configuration = configuration;
935
936 self.notify::<notification::Initialized>(InitializedParams {})?;
937 Ok(Arc::new(self))
938 })
939 }
940
941 /// Sends a shutdown request to the language server process and prepares the [`LanguageServer`] to be dropped.
942 pub fn shutdown(&self) -> Option<impl 'static + Send + Future<Output = Option<()>> + use<>> {
943 if let Some(tasks) = self.io_tasks.lock().take() {
944 let response_handlers = self.response_handlers.clone();
945 let next_id = AtomicI32::new(self.next_id.load(SeqCst));
946 let outbound_tx = self.outbound_tx.clone();
947 let executor = self.executor.clone();
948 let notification_serializers = self.notification_tx.clone();
949 let mut output_done = self.output_done_rx.lock().take().unwrap();
950 let shutdown_request = Self::request_internal::<request::Shutdown>(
951 &next_id,
952 &response_handlers,
953 &outbound_tx,
954 ¬ification_serializers,
955 &executor,
956 (),
957 );
958
959 let server = self.server.clone();
960 let name = self.name.clone();
961 let server_id = self.server_id;
962 let mut timer = self.executor.timer(SERVER_SHUTDOWN_TIMEOUT).fuse();
963 Some(async move {
964 log::debug!("language server shutdown started");
965
966 select! {
967 request_result = shutdown_request.fuse() => {
968 match request_result {
969 ConnectionResult::Timeout => {
970 log::warn!("timeout waiting for language server {name} (id {server_id}) to shutdown");
971 },
972 ConnectionResult::ConnectionReset => {
973 log::warn!("language server {name} (id {server_id}) closed the shutdown request connection");
974 },
975 ConnectionResult::Result(Err(e)) => {
976 log::error!("Shutdown request failure, server {name} (id {server_id}): {e:#}");
977 },
978 ConnectionResult::Result(Ok(())) => {}
979 }
980 }
981
982 _ = timer => {
983 log::info!("timeout waiting for language server {name} (id {server_id}) to shutdown");
984 },
985 }
986
987 response_handlers.lock().take();
988 Self::notify_internal::<notification::Exit>(¬ification_serializers, ()).ok();
989 notification_serializers.close();
990 output_done.recv().await;
991 server.lock().take().map(|mut child| child.kill());
992 drop(tasks);
993 log::debug!("language server shutdown finished");
994 Some(())
995 })
996 } else {
997 None
998 }
999 }
1000
1001 /// Register a handler to handle incoming LSP notifications.
1002 ///
1003 /// [LSP Specification](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#notificationMessage)
1004 #[must_use]
1005 pub fn on_notification<T, F>(&self, f: F) -> Subscription
1006 where
1007 T: notification::Notification,
1008 F: 'static + Send + FnMut(T::Params, &mut AsyncApp),
1009 {
1010 self.on_custom_notification(T::METHOD, f)
1011 }
1012
1013 /// Register a handler to handle incoming LSP requests.
1014 ///
1015 /// [LSP Specification](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#requestMessage)
1016 #[must_use]
1017 pub fn on_request<T, F, Fut>(&self, f: F) -> Subscription
1018 where
1019 T: request::Request,
1020 T::Params: 'static + Send,
1021 F: 'static + FnMut(T::Params, &mut AsyncApp) -> Fut + Send,
1022 Fut: 'static + Future<Output = Result<T::Result>>,
1023 {
1024 self.on_custom_request(T::METHOD, f)
1025 }
1026
1027 /// Registers a handler to inspect all language server process stdio.
1028 #[must_use]
1029 pub fn on_io<F>(&self, f: F) -> Subscription
1030 where
1031 F: 'static + Send + FnMut(IoKind, &str),
1032 {
1033 let id = self.next_id.fetch_add(1, SeqCst);
1034 self.io_handlers.lock().insert(id, Box::new(f));
1035 Subscription::Io {
1036 id,
1037 io_handlers: Some(Arc::downgrade(&self.io_handlers)),
1038 }
1039 }
1040
1041 /// Removes a request handler registers via [`Self::on_request`].
1042 pub fn remove_request_handler<T: request::Request>(&self) {
1043 self.notification_handlers.lock().remove(T::METHOD);
1044 }
1045
1046 /// Removes a notification handler registers via [`Self::on_notification`].
1047 pub fn remove_notification_handler<T: notification::Notification>(&self) {
1048 self.notification_handlers.lock().remove(T::METHOD);
1049 }
1050
1051 /// Checks if a notification handler has been registered via [`Self::on_notification`].
1052 pub fn has_notification_handler<T: notification::Notification>(&self) -> bool {
1053 self.notification_handlers.lock().contains_key(T::METHOD)
1054 }
1055
1056 #[must_use]
1057 fn on_custom_notification<Params, F>(&self, method: &'static str, mut f: F) -> Subscription
1058 where
1059 F: 'static + FnMut(Params, &mut AsyncApp) + Send,
1060 Params: DeserializeOwned,
1061 {
1062 let prev_handler = self.notification_handlers.lock().insert(
1063 method,
1064 Box::new(move |_, params, cx| {
1065 if let Some(params) = serde_json::from_value(params).log_err() {
1066 f(params, cx);
1067 }
1068 }),
1069 );
1070 assert!(
1071 prev_handler.is_none(),
1072 "registered multiple handlers for the same LSP method"
1073 );
1074 Subscription::Notification {
1075 method,
1076 notification_handlers: Some(self.notification_handlers.clone()),
1077 }
1078 }
1079
1080 #[must_use]
1081 fn on_custom_request<Params, Res, Fut, F>(&self, method: &'static str, mut f: F) -> Subscription
1082 where
1083 F: 'static + FnMut(Params, &mut AsyncApp) -> Fut + Send,
1084 Fut: 'static + Future<Output = Result<Res>>,
1085 Params: DeserializeOwned + Send + 'static,
1086 Res: Serialize,
1087 {
1088 let outbound_tx = self.outbound_tx.clone();
1089 let prev_handler = self.notification_handlers.lock().insert(
1090 method,
1091 Box::new(move |id, params, cx| {
1092 if let Some(id) = id {
1093 match serde_json::from_value(params) {
1094 Ok(params) => {
1095 let response = f(params, cx);
1096 cx.foreground_executor()
1097 .spawn({
1098 let outbound_tx = outbound_tx.clone();
1099 async move {
1100 let response = match response.await {
1101 Ok(result) => Response {
1102 jsonrpc: JSON_RPC_VERSION,
1103 id,
1104 value: LspResult::Ok(Some(result)),
1105 },
1106 Err(error) => Response {
1107 jsonrpc: JSON_RPC_VERSION,
1108 id,
1109 value: LspResult::Error(Some(Error {
1110 code: lsp_types::error_codes::REQUEST_FAILED,
1111 message: error.to_string(),
1112 data: None,
1113 })),
1114 },
1115 };
1116 if let Some(response) =
1117 serde_json::to_string(&response).log_err()
1118 {
1119 outbound_tx.try_send(response).ok();
1120 }
1121 }
1122 })
1123 .detach();
1124 }
1125
1126 Err(error) => {
1127 log::error!("error deserializing {} request: {:?}", method, error);
1128 let response = AnyResponse {
1129 jsonrpc: JSON_RPC_VERSION,
1130 id,
1131 result: None,
1132 error: Some(Error {
1133 code: -32700, // Parse error
1134 message: error.to_string(),
1135 data: None,
1136 }),
1137 };
1138 if let Some(response) = serde_json::to_string(&response).log_err() {
1139 outbound_tx.try_send(response).ok();
1140 }
1141 }
1142 }
1143 }
1144 }),
1145 );
1146 assert!(
1147 prev_handler.is_none(),
1148 "registered multiple handlers for the same LSP method"
1149 );
1150 Subscription::Notification {
1151 method,
1152 notification_handlers: Some(self.notification_handlers.clone()),
1153 }
1154 }
1155
1156 /// Get the name of the running language server.
1157 pub fn name(&self) -> LanguageServerName {
1158 self.name.clone()
1159 }
1160
1161 /// Get the version of the running language server.
1162 pub fn version(&self) -> Option<SharedString> {
1163 self.version.clone()
1164 }
1165
1166 pub fn process_name(&self) -> &str {
1167 &self.process_name
1168 }
1169
1170 /// Get the reported capabilities of the running language server.
1171 pub fn capabilities(&self) -> ServerCapabilities {
1172 self.capabilities.read().clone()
1173 }
1174
1175 /// Get the reported capabilities of the running language server and
1176 /// what we know on the client/adapter-side of its capabilities.
1177 pub fn adapter_server_capabilities(&self) -> AdapterServerCapabilities {
1178 AdapterServerCapabilities {
1179 server_capabilities: self.capabilities(),
1180 code_action_kinds: self.code_action_kinds(),
1181 }
1182 }
1183
1184 pub fn update_capabilities(&self, update: impl FnOnce(&mut ServerCapabilities)) {
1185 update(self.capabilities.write().deref_mut());
1186 }
1187
1188 pub fn configuration(&self) -> &Value {
1189 &self.configuration.settings
1190 }
1191
1192 /// Get the id of the running language server.
1193 pub fn server_id(&self) -> LanguageServerId {
1194 self.server_id
1195 }
1196
1197 /// Language server's binary information.
1198 pub fn binary(&self) -> &LanguageServerBinary {
1199 &self.binary
1200 }
1201
1202 /// Sends a RPC request to the language server.
1203 ///
1204 /// [LSP Specification](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#requestMessage)
1205 pub fn request<T: request::Request>(
1206 &self,
1207 params: T::Params,
1208 ) -> impl LspRequestFuture<T::Result> + use<T>
1209 where
1210 T::Result: 'static + Send,
1211 {
1212 Self::request_internal::<T>(
1213 &self.next_id,
1214 &self.response_handlers,
1215 &self.outbound_tx,
1216 &self.notification_tx,
1217 &self.executor,
1218 params,
1219 )
1220 }
1221
1222 /// Sends a RPC request to the language server, with a custom timer, a future which when becoming
1223 /// ready causes the request to be timed out with the future's output message.
1224 ///
1225 /// [LSP Specification](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#requestMessage)
1226 pub fn request_with_timer<T: request::Request, U: Future<Output = String>>(
1227 &self,
1228 params: T::Params,
1229 timer: U,
1230 ) -> impl LspRequestFuture<T::Result> + use<T, U>
1231 where
1232 T::Result: 'static + Send,
1233 {
1234 Self::request_internal_with_timer::<T, U>(
1235 &self.next_id,
1236 &self.response_handlers,
1237 &self.outbound_tx,
1238 &self.notification_tx,
1239 &self.executor,
1240 timer,
1241 params,
1242 )
1243 }
1244
1245 fn request_internal_with_timer<T, U>(
1246 next_id: &AtomicI32,
1247 response_handlers: &Mutex<Option<HashMap<RequestId, ResponseHandler>>>,
1248 outbound_tx: &channel::Sender<String>,
1249 notification_serializers: &channel::Sender<NotificationSerializer>,
1250 executor: &BackgroundExecutor,
1251 timer: U,
1252 params: T::Params,
1253 ) -> impl LspRequestFuture<T::Result> + use<T, U>
1254 where
1255 T::Result: 'static + Send,
1256 T: request::Request,
1257 U: Future<Output = String>,
1258 {
1259 let id = next_id.fetch_add(1, SeqCst);
1260 let message = serde_json::to_string(&Request {
1261 jsonrpc: JSON_RPC_VERSION,
1262 id: RequestId::Int(id),
1263 method: T::METHOD,
1264 params,
1265 })
1266 .unwrap();
1267
1268 let (tx, rx) = oneshot::channel();
1269 let handle_response = response_handlers
1270 .lock()
1271 .as_mut()
1272 .context("server shut down")
1273 .map(|handlers| {
1274 let executor = executor.clone();
1275 handlers.insert(
1276 RequestId::Int(id),
1277 Box::new(move |result| {
1278 executor
1279 .spawn(async move {
1280 let response = match result {
1281 Ok(response) => match serde_json::from_str(&response) {
1282 Ok(deserialized) => Ok(deserialized),
1283 Err(error) => {
1284 log::error!("failed to deserialize response from language server: {}. response from language server: {:?}", error, response);
1285 Err(error).context("failed to deserialize response")
1286 }
1287 }
1288 Err(error) => Err(anyhow!("{}", error.message)),
1289 };
1290 _ = tx.send(response);
1291 })
1292 .detach();
1293 }),
1294 );
1295 });
1296
1297 let send = outbound_tx
1298 .try_send(message)
1299 .context("failed to write to language server's stdin");
1300
1301 let notification_serializers = notification_serializers.downgrade();
1302 let started = Instant::now();
1303 LspRequest::new(id, async move {
1304 if let Err(e) = handle_response {
1305 return ConnectionResult::Result(Err(e));
1306 }
1307 if let Err(e) = send {
1308 return ConnectionResult::Result(Err(e));
1309 }
1310
1311 let cancel_on_drop = util::defer(move || {
1312 if let Some(notification_serializers) = notification_serializers.upgrade() {
1313 Self::notify_internal::<notification::Cancel>(
1314 ¬ification_serializers,
1315 CancelParams {
1316 id: NumberOrString::Number(id),
1317 },
1318 )
1319 .ok();
1320 }
1321 });
1322
1323 let method = T::METHOD;
1324 select! {
1325 response = rx.fuse() => {
1326 let elapsed = started.elapsed();
1327 log::trace!("Took {elapsed:?} to receive response to {method:?} id {id}");
1328 cancel_on_drop.abort();
1329 match response {
1330 Ok(response_result) => ConnectionResult::Result(response_result),
1331 Err(Canceled) => {
1332 log::error!("Server reset connection for a request {method:?} id {id}");
1333 ConnectionResult::ConnectionReset
1334 },
1335 }
1336 }
1337
1338 message = timer.fuse() => {
1339 log::error!("Cancelled LSP request task for {method:?} id {id} {message}");
1340 ConnectionResult::Timeout
1341 }
1342 }
1343 })
1344 }
1345
1346 fn request_internal<T>(
1347 next_id: &AtomicI32,
1348 response_handlers: &Mutex<Option<HashMap<RequestId, ResponseHandler>>>,
1349 outbound_tx: &channel::Sender<String>,
1350 notification_serializers: &channel::Sender<NotificationSerializer>,
1351 executor: &BackgroundExecutor,
1352 params: T::Params,
1353 ) -> impl LspRequestFuture<T::Result> + use<T>
1354 where
1355 T::Result: 'static + Send,
1356 T: request::Request,
1357 {
1358 Self::request_internal_with_timer::<T, _>(
1359 next_id,
1360 response_handlers,
1361 outbound_tx,
1362 notification_serializers,
1363 executor,
1364 Self::default_request_timer(executor.clone()),
1365 params,
1366 )
1367 }
1368
1369 pub fn default_request_timer(executor: BackgroundExecutor) -> impl Future<Output = String> {
1370 executor
1371 .timer(LSP_REQUEST_TIMEOUT)
1372 .map(|_| format!("which took over {LSP_REQUEST_TIMEOUT:?}"))
1373 }
1374
1375 /// Sends a RPC notification to the language server.
1376 ///
1377 /// [LSP Specification](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#notificationMessage)
1378 pub fn notify<T: notification::Notification>(&self, params: T::Params) -> Result<()> {
1379 let outbound = self.notification_tx.clone();
1380 Self::notify_internal::<T>(&outbound, params)
1381 }
1382
1383 fn notify_internal<T: notification::Notification>(
1384 outbound_tx: &channel::Sender<NotificationSerializer>,
1385 params: T::Params,
1386 ) -> Result<()> {
1387 let serializer = NotificationSerializer(Box::new(move || {
1388 serde_json::to_string(&Notification {
1389 jsonrpc: JSON_RPC_VERSION,
1390 method: T::METHOD,
1391 params,
1392 })
1393 .unwrap()
1394 }));
1395
1396 outbound_tx.send_blocking(serializer)?;
1397 Ok(())
1398 }
1399
1400 /// Add new workspace folder to the list.
1401 pub fn add_workspace_folder(&self, uri: Uri) {
1402 if self
1403 .capabilities()
1404 .workspace
1405 .and_then(|ws| {
1406 ws.workspace_folders.and_then(|folders| {
1407 folders
1408 .change_notifications
1409 .map(|caps| matches!(caps, OneOf::Left(false)))
1410 })
1411 })
1412 .unwrap_or(true)
1413 {
1414 return;
1415 }
1416
1417 let Some(workspace_folders) = self.workspace_folders.as_ref() else {
1418 return;
1419 };
1420 let is_new_folder = workspace_folders.lock().insert(uri.clone());
1421 if is_new_folder {
1422 let params = DidChangeWorkspaceFoldersParams {
1423 event: WorkspaceFoldersChangeEvent {
1424 added: vec![WorkspaceFolder {
1425 uri,
1426 name: String::default(),
1427 }],
1428 removed: vec![],
1429 },
1430 };
1431 self.notify::<DidChangeWorkspaceFolders>(params).ok();
1432 }
1433 }
1434
1435 /// Remove existing workspace folder from the list.
1436 pub fn remove_workspace_folder(&self, uri: Uri) {
1437 if self
1438 .capabilities()
1439 .workspace
1440 .and_then(|ws| {
1441 ws.workspace_folders.and_then(|folders| {
1442 folders
1443 .change_notifications
1444 .map(|caps| !matches!(caps, OneOf::Left(false)))
1445 })
1446 })
1447 .unwrap_or(true)
1448 {
1449 return;
1450 }
1451 let Some(workspace_folders) = self.workspace_folders.as_ref() else {
1452 return;
1453 };
1454 let was_removed = workspace_folders.lock().remove(&uri);
1455 if was_removed {
1456 let params = DidChangeWorkspaceFoldersParams {
1457 event: WorkspaceFoldersChangeEvent {
1458 added: vec![],
1459 removed: vec![WorkspaceFolder {
1460 uri,
1461 name: String::default(),
1462 }],
1463 },
1464 };
1465 self.notify::<DidChangeWorkspaceFolders>(params).ok();
1466 }
1467 }
1468 pub fn set_workspace_folders(&self, folders: BTreeSet<Uri>) {
1469 let Some(workspace_folders) = self.workspace_folders.as_ref() else {
1470 return;
1471 };
1472 let mut workspace_folders = workspace_folders.lock();
1473
1474 let old_workspace_folders = std::mem::take(&mut *workspace_folders);
1475 let added: Vec<_> = folders
1476 .difference(&old_workspace_folders)
1477 .map(|uri| WorkspaceFolder {
1478 uri: uri.clone(),
1479 name: String::default(),
1480 })
1481 .collect();
1482
1483 let removed: Vec<_> = old_workspace_folders
1484 .difference(&folders)
1485 .map(|uri| WorkspaceFolder {
1486 uri: uri.clone(),
1487 name: String::default(),
1488 })
1489 .collect();
1490 *workspace_folders = folders;
1491 let should_notify = !added.is_empty() || !removed.is_empty();
1492 if should_notify {
1493 drop(workspace_folders);
1494 let params = DidChangeWorkspaceFoldersParams {
1495 event: WorkspaceFoldersChangeEvent { added, removed },
1496 };
1497 self.notify::<DidChangeWorkspaceFolders>(params).ok();
1498 }
1499 }
1500
1501 pub fn workspace_folders(&self) -> BTreeSet<Uri> {
1502 self.workspace_folders.as_ref().map_or_else(
1503 || BTreeSet::from_iter([self.root_uri.clone()]),
1504 |folders| folders.lock().clone(),
1505 )
1506 }
1507
1508 pub fn register_buffer(
1509 &self,
1510 uri: Uri,
1511 language_id: String,
1512 version: i32,
1513 initial_text: String,
1514 ) {
1515 self.notify::<notification::DidOpenTextDocument>(DidOpenTextDocumentParams {
1516 text_document: TextDocumentItem::new(uri, language_id, version, initial_text),
1517 })
1518 .ok();
1519 }
1520
1521 pub fn unregister_buffer(&self, uri: Uri) {
1522 self.notify::<notification::DidCloseTextDocument>(DidCloseTextDocumentParams {
1523 text_document: TextDocumentIdentifier::new(uri),
1524 })
1525 .ok();
1526 }
1527}
1528
1529impl Drop for LanguageServer {
1530 fn drop(&mut self) {
1531 if let Some(shutdown) = self.shutdown() {
1532 self.executor.spawn(shutdown).detach();
1533 }
1534 }
1535}
1536
1537impl Subscription {
1538 /// Detaching a subscription handle prevents it from unsubscribing on drop.
1539 pub fn detach(&mut self) {
1540 match self {
1541 Subscription::Notification {
1542 notification_handlers,
1543 ..
1544 } => *notification_handlers = None,
1545 Subscription::Io { io_handlers, .. } => *io_handlers = None,
1546 }
1547 }
1548}
1549
1550impl fmt::Display for LanguageServerId {
1551 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1552 self.0.fmt(f)
1553 }
1554}
1555
1556impl fmt::Debug for LanguageServer {
1557 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1558 f.debug_struct("LanguageServer")
1559 .field("id", &self.server_id.0)
1560 .field("name", &self.name)
1561 .finish_non_exhaustive()
1562 }
1563}
1564
1565impl fmt::Debug for LanguageServerBinary {
1566 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1567 let mut debug = f.debug_struct("LanguageServerBinary");
1568 debug.field("path", &self.path);
1569 debug.field("arguments", &self.arguments);
1570
1571 if let Some(env) = &self.env {
1572 let redacted_env: BTreeMap<String, String> = env
1573 .iter()
1574 .map(|(key, value)| {
1575 let redacted_value = if redact::should_redact(key) {
1576 "REDACTED".to_string()
1577 } else {
1578 value.clone()
1579 };
1580 (key.clone(), redacted_value)
1581 })
1582 .collect();
1583 debug.field("env", &Some(redacted_env));
1584 } else {
1585 debug.field("env", &self.env);
1586 }
1587
1588 debug.finish()
1589 }
1590}
1591
1592impl Drop for Subscription {
1593 fn drop(&mut self) {
1594 match self {
1595 Subscription::Notification {
1596 method,
1597 notification_handlers,
1598 } => {
1599 if let Some(handlers) = notification_handlers {
1600 handlers.lock().remove(method);
1601 }
1602 }
1603 Subscription::Io { id, io_handlers } => {
1604 if let Some(io_handlers) = io_handlers.as_ref().and_then(|h| h.upgrade()) {
1605 io_handlers.lock().remove(id);
1606 }
1607 }
1608 }
1609 }
1610}
1611
1612/// Mock language server for use in tests.
1613#[cfg(any(test, feature = "test-support"))]
1614#[derive(Clone)]
1615pub struct FakeLanguageServer {
1616 pub binary: LanguageServerBinary,
1617 pub server: Arc<LanguageServer>,
1618 notifications_rx: channel::Receiver<(String, String)>,
1619}
1620
1621#[cfg(any(test, feature = "test-support"))]
1622impl FakeLanguageServer {
1623 /// Construct a fake language server.
1624 pub fn new(
1625 server_id: LanguageServerId,
1626 binary: LanguageServerBinary,
1627 name: String,
1628 capabilities: ServerCapabilities,
1629 cx: &mut AsyncApp,
1630 ) -> (LanguageServer, FakeLanguageServer) {
1631 let (stdin_writer, stdin_reader) = async_pipe::pipe();
1632 let (stdout_writer, stdout_reader) = async_pipe::pipe();
1633 let (notifications_tx, notifications_rx) = channel::unbounded();
1634
1635 let server_name = LanguageServerName(name.clone().into());
1636 let process_name = Arc::from(name.as_str());
1637 let root = Self::root_path();
1638 let workspace_folders: Arc<Mutex<BTreeSet<Uri>>> = Default::default();
1639 let mut server = LanguageServer::new_internal(
1640 server_id,
1641 server_name.clone(),
1642 stdin_writer,
1643 stdout_reader,
1644 None::<async_pipe::PipeReader>,
1645 Arc::new(Mutex::new(None)),
1646 None,
1647 None,
1648 binary.clone(),
1649 root,
1650 Some(workspace_folders.clone()),
1651 cx,
1652 |_| false,
1653 );
1654 server.process_name = process_name;
1655 let fake = FakeLanguageServer {
1656 binary: binary.clone(),
1657 server: Arc::new({
1658 let mut server = LanguageServer::new_internal(
1659 server_id,
1660 server_name,
1661 stdout_writer,
1662 stdin_reader,
1663 None::<async_pipe::PipeReader>,
1664 Arc::new(Mutex::new(None)),
1665 None,
1666 None,
1667 binary,
1668 Self::root_path(),
1669 Some(workspace_folders),
1670 cx,
1671 move |msg| {
1672 notifications_tx
1673 .try_send((
1674 msg.method.to_string(),
1675 msg.params.as_ref().unwrap_or(&Value::Null).to_string(),
1676 ))
1677 .ok();
1678 true
1679 },
1680 );
1681 server.process_name = name.as_str().into();
1682 server
1683 }),
1684 notifications_rx,
1685 };
1686 fake.set_request_handler::<request::Initialize, _, _>({
1687 let capabilities = capabilities;
1688 move |_, _| {
1689 let capabilities = capabilities.clone();
1690 let name = name.clone();
1691 async move {
1692 Ok(InitializeResult {
1693 capabilities,
1694 server_info: Some(ServerInfo {
1695 name,
1696 ..Default::default()
1697 }),
1698 })
1699 }
1700 }
1701 });
1702
1703 fake.set_request_handler::<request::Shutdown, _, _>(|_, _| async move { Ok(()) });
1704
1705 (server, fake)
1706 }
1707 #[cfg(target_os = "windows")]
1708 fn root_path() -> Uri {
1709 Uri::from_file_path("C:/").unwrap()
1710 }
1711
1712 #[cfg(not(target_os = "windows"))]
1713 fn root_path() -> Uri {
1714 Uri::from_file_path("/").unwrap()
1715 }
1716}
1717
1718#[cfg(any(test, feature = "test-support"))]
1719impl LanguageServer {
1720 pub fn full_capabilities() -> ServerCapabilities {
1721 ServerCapabilities {
1722 document_highlight_provider: Some(OneOf::Left(true)),
1723 code_action_provider: Some(CodeActionProviderCapability::Simple(true)),
1724 document_formatting_provider: Some(OneOf::Left(true)),
1725 document_range_formatting_provider: Some(OneOf::Left(true)),
1726 definition_provider: Some(OneOf::Left(true)),
1727 workspace_symbol_provider: Some(OneOf::Left(true)),
1728 implementation_provider: Some(ImplementationProviderCapability::Simple(true)),
1729 type_definition_provider: Some(TypeDefinitionProviderCapability::Simple(true)),
1730 ..ServerCapabilities::default()
1731 }
1732 }
1733}
1734
1735#[cfg(any(test, feature = "test-support"))]
1736impl FakeLanguageServer {
1737 /// See [`LanguageServer::notify`].
1738 pub fn notify<T: notification::Notification>(&self, params: T::Params) {
1739 self.server.notify::<T>(params).ok();
1740 }
1741
1742 /// See [`LanguageServer::request`].
1743 pub async fn request<T>(&self, params: T::Params) -> ConnectionResult<T::Result>
1744 where
1745 T: request::Request,
1746 T::Result: 'static + Send,
1747 {
1748 self.server.executor.start_waiting();
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.server.executor.start_waiting();
1755 self.try_receive_notification::<T>().await.unwrap()
1756 }
1757
1758 /// Consumes the notification channel until it finds a notification for the specified type.
1759 pub async fn try_receive_notification<T: notification::Notification>(
1760 &mut self,
1761 ) -> Option<T::Params> {
1762 loop {
1763 let (method, params) = self.notifications_rx.recv().await.ok()?;
1764 if method == T::METHOD {
1765 return Some(serde_json::from_str::<T::Params>(¶ms).unwrap());
1766 } else {
1767 log::info!("skipping message in fake language server {:?}", params);
1768 }
1769 }
1770 }
1771
1772 /// Registers a handler for a specific kind of request. Removes any existing handler for specified request type.
1773 pub fn set_request_handler<T, F, Fut>(
1774 &self,
1775 mut handler: F,
1776 ) -> futures::channel::mpsc::UnboundedReceiver<()>
1777 where
1778 T: 'static + request::Request,
1779 T::Params: 'static + Send,
1780 F: 'static + Send + FnMut(T::Params, gpui::AsyncApp) -> Fut,
1781 Fut: 'static + Future<Output = Result<T::Result>>,
1782 {
1783 let (responded_tx, responded_rx) = futures::channel::mpsc::unbounded();
1784 self.server.remove_request_handler::<T>();
1785 self.server
1786 .on_request::<T, _, _>(move |params, cx| {
1787 let result = handler(params, cx.clone());
1788 let responded_tx = responded_tx.clone();
1789 let executor = cx.background_executor().clone();
1790 async move {
1791 executor.simulate_random_delay().await;
1792 let result = result.await;
1793 responded_tx.unbounded_send(()).ok();
1794 result
1795 }
1796 })
1797 .detach();
1798 responded_rx
1799 }
1800
1801 /// Registers a handler for a specific kind of notification. Removes any existing handler for specified notification type.
1802 pub fn handle_notification<T, F>(
1803 &self,
1804 mut handler: F,
1805 ) -> futures::channel::mpsc::UnboundedReceiver<()>
1806 where
1807 T: 'static + notification::Notification,
1808 T::Params: 'static + Send,
1809 F: 'static + Send + FnMut(T::Params, gpui::AsyncApp),
1810 {
1811 let (handled_tx, handled_rx) = futures::channel::mpsc::unbounded();
1812 self.server.remove_notification_handler::<T>();
1813 self.server
1814 .on_notification::<T, _>(move |params, cx| {
1815 handler(params, cx.clone());
1816 handled_tx.unbounded_send(()).ok();
1817 })
1818 .detach();
1819 handled_rx
1820 }
1821
1822 /// Removes any existing handler for specified notification type.
1823 pub fn remove_request_handler<T>(&mut self)
1824 where
1825 T: 'static + request::Request,
1826 {
1827 self.server.remove_request_handler::<T>();
1828 }
1829
1830 /// Simulate that the server has started work and notifies about its progress with the specified token.
1831 pub async fn start_progress(&self, token: impl Into<String>) {
1832 self.start_progress_with(token, Default::default()).await
1833 }
1834
1835 pub async fn start_progress_with(
1836 &self,
1837 token: impl Into<String>,
1838 progress: WorkDoneProgressBegin,
1839 ) {
1840 let token = token.into();
1841 self.request::<request::WorkDoneProgressCreate>(WorkDoneProgressCreateParams {
1842 token: NumberOrString::String(token.clone()),
1843 })
1844 .await
1845 .into_response()
1846 .unwrap();
1847 self.notify::<notification::Progress>(ProgressParams {
1848 token: NumberOrString::String(token),
1849 value: ProgressParamsValue::WorkDone(WorkDoneProgress::Begin(progress)),
1850 });
1851 }
1852
1853 /// Simulate that the server has completed work and notifies about that with the specified token.
1854 pub fn end_progress(&self, token: impl Into<String>) {
1855 self.notify::<notification::Progress>(ProgressParams {
1856 token: NumberOrString::String(token.into()),
1857 value: ProgressParamsValue::WorkDone(WorkDoneProgress::End(Default::default())),
1858 });
1859 }
1860}
1861
1862#[cfg(test)]
1863mod tests {
1864 use super::*;
1865 use gpui::TestAppContext;
1866 use std::str::FromStr;
1867
1868 #[ctor::ctor]
1869 fn init_logger() {
1870 zlog::init_test();
1871 }
1872
1873 #[gpui::test]
1874 async fn test_fake(cx: &mut TestAppContext) {
1875 cx.update(|cx| {
1876 release_channel::init(semver::Version::new(0, 0, 0), cx);
1877 });
1878 let (server, mut fake) = FakeLanguageServer::new(
1879 LanguageServerId(0),
1880 LanguageServerBinary {
1881 path: "path/to/language-server".into(),
1882 arguments: vec![],
1883 env: None,
1884 },
1885 "the-lsp".to_string(),
1886 Default::default(),
1887 &mut cx.to_async(),
1888 );
1889
1890 let (message_tx, message_rx) = channel::unbounded();
1891 let (diagnostics_tx, diagnostics_rx) = channel::unbounded();
1892 server
1893 .on_notification::<notification::ShowMessage, _>(move |params, _| {
1894 message_tx.try_send(params).unwrap()
1895 })
1896 .detach();
1897 server
1898 .on_notification::<notification::PublishDiagnostics, _>(move |params, _| {
1899 diagnostics_tx.try_send(params).unwrap()
1900 })
1901 .detach();
1902
1903 let server = cx
1904 .update(|cx| {
1905 let params = server.default_initialize_params(false, cx);
1906 let configuration = DidChangeConfigurationParams {
1907 settings: Default::default(),
1908 };
1909 server.initialize(params, configuration.into(), cx)
1910 })
1911 .await
1912 .unwrap();
1913 server
1914 .notify::<notification::DidOpenTextDocument>(DidOpenTextDocumentParams {
1915 text_document: TextDocumentItem::new(
1916 Uri::from_str("file://a/b").unwrap(),
1917 "rust".to_string(),
1918 0,
1919 "".to_string(),
1920 ),
1921 })
1922 .unwrap();
1923 assert_eq!(
1924 fake.receive_notification::<notification::DidOpenTextDocument>()
1925 .await
1926 .text_document
1927 .uri
1928 .as_str(),
1929 "file://a/b"
1930 );
1931
1932 fake.notify::<notification::ShowMessage>(ShowMessageParams {
1933 typ: MessageType::ERROR,
1934 message: "ok".to_string(),
1935 });
1936 fake.notify::<notification::PublishDiagnostics>(PublishDiagnosticsParams {
1937 uri: Uri::from_str("file://b/c").unwrap(),
1938 version: Some(5),
1939 diagnostics: vec![],
1940 });
1941 assert_eq!(message_rx.recv().await.unwrap().message, "ok");
1942 assert_eq!(
1943 diagnostics_rx.recv().await.unwrap().uri.as_str(),
1944 "file://b/c"
1945 );
1946
1947 fake.set_request_handler::<request::Shutdown, _, _>(|_, _| async move { Ok(()) });
1948
1949 drop(server);
1950 cx.run_until_parked();
1951 fake.receive_notification::<notification::Exit>().await;
1952 }
1953
1954 #[gpui::test]
1955 fn test_deserialize_string_digit_id() {
1956 let json = r#"{"jsonrpc":"2.0","id":"2","method":"workspace/configuration","params":{"items":[{"scopeUri":"file:///Users/mph/Devel/personal/hello-scala/","section":"metals"}]}}"#;
1957 let notification = serde_json::from_str::<NotificationOrRequest>(json)
1958 .expect("message with string id should be parsed");
1959 let expected_id = RequestId::Str("2".to_string());
1960 assert_eq!(notification.id, Some(expected_id));
1961 }
1962
1963 #[gpui::test]
1964 fn test_deserialize_string_id() {
1965 let json = r#"{"jsonrpc":"2.0","id":"anythingAtAll","method":"workspace/configuration","params":{"items":[{"scopeUri":"file:///Users/mph/Devel/personal/hello-scala/","section":"metals"}]}}"#;
1966 let notification = serde_json::from_str::<NotificationOrRequest>(json)
1967 .expect("message with string id should be parsed");
1968 let expected_id = RequestId::Str("anythingAtAll".to_string());
1969 assert_eq!(notification.id, Some(expected_id));
1970 }
1971
1972 #[gpui::test]
1973 fn test_deserialize_int_id() {
1974 let json = r#"{"jsonrpc":"2.0","id":2,"method":"workspace/configuration","params":{"items":[{"scopeUri":"file:///Users/mph/Devel/personal/hello-scala/","section":"metals"}]}}"#;
1975 let notification = serde_json::from_str::<NotificationOrRequest>(json)
1976 .expect("message with string id should be parsed");
1977 let expected_id = RequestId::Int(2);
1978 assert_eq!(notification.id, Some(expected_id));
1979 }
1980
1981 #[test]
1982 fn test_serialize_has_no_nulls() {
1983 // Ensure we're not setting both result and error variants. (ticket #10595)
1984 let no_tag = Response::<u32> {
1985 jsonrpc: "",
1986 id: RequestId::Int(0),
1987 value: LspResult::Ok(None),
1988 };
1989 assert_eq!(
1990 serde_json::to_string(&no_tag).unwrap(),
1991 "{\"jsonrpc\":\"\",\"id\":0,\"result\":null}"
1992 );
1993 let no_tag = Response::<u32> {
1994 jsonrpc: "",
1995 id: RequestId::Int(0),
1996 value: LspResult::Error(None),
1997 };
1998 assert_eq!(
1999 serde_json::to_string(&no_tag).unwrap(),
2000 "{\"jsonrpc\":\"\",\"id\":0,\"error\":null}"
2001 );
2002 }
2003}