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