1mod input_handler;
2
3pub use lsp_types::request::*;
4pub use lsp_types::*;
5
6use anyhow::{anyhow, Context, Result};
7use collections::HashMap;
8use futures::{channel::oneshot, io::BufWriter, select, AsyncRead, AsyncWrite, Future, FutureExt};
9use gpui::{AppContext, AsyncAppContext, BackgroundExecutor, Task};
10use parking_lot::{Mutex, RwLock};
11use postage::{barrier, prelude::Stream};
12use serde::{de::DeserializeOwned, Deserialize, Serialize};
13use serde_json::{json, value::RawValue, Value};
14use smol::{
15 channel,
16 io::{AsyncBufReadExt, AsyncWriteExt, BufReader},
17 process::{self, Child},
18};
19
20#[cfg(target_os = "windows")]
21use smol::process::windows::CommandExt;
22
23use std::{
24 ffi::OsString,
25 fmt,
26 io::Write,
27 ops::DerefMut,
28 path::PathBuf,
29 pin::Pin,
30 sync::{
31 atomic::{AtomicI32, Ordering::SeqCst},
32 Arc, Weak,
33 },
34 task::Poll,
35 time::{Duration, Instant},
36};
37use std::{path::Path, process::Stdio};
38use util::{ResultExt, TryFutureExt};
39
40const JSON_RPC_VERSION: &str = "2.0";
41const CONTENT_LEN_HEADER: &str = "Content-Length: ";
42
43const LSP_REQUEST_TIMEOUT: Duration = Duration::from_secs(60 * 2);
44const SERVER_SHUTDOWN_TIMEOUT: Duration = Duration::from_secs(5);
45
46type NotificationHandler = Box<dyn Send + FnMut(Option<RequestId>, Value, AsyncAppContext)>;
47type ResponseHandler = Box<dyn Send + FnOnce(Result<String, Error>)>;
48type IoHandler = Box<dyn Send + FnMut(IoKind, &str)>;
49
50/// Kind of language server stdio given to an IO handler.
51#[derive(Debug, Clone, Copy)]
52pub enum IoKind {
53 StdOut,
54 StdIn,
55 StdErr,
56}
57
58/// Represents a launchable language server. This can either be a standalone binary or the path
59/// to a runtime with arguments to instruct it to launch the actual language server file.
60#[derive(Debug, Clone, Deserialize)]
61pub struct LanguageServerBinary {
62 pub path: PathBuf,
63 pub arguments: Vec<OsString>,
64 pub env: Option<HashMap<String, String>>,
65}
66
67/// Configures the search (and installation) of language servers.
68#[derive(Debug, Clone, Deserialize)]
69pub struct LanguageServerBinaryOptions {
70 /// Whether the adapter should look at the users system
71 pub allow_path_lookup: bool,
72 /// Whether the adapter should download its own version
73 pub allow_binary_download: bool,
74}
75
76/// A running language server process.
77pub struct LanguageServer {
78 server_id: LanguageServerId,
79 next_id: AtomicI32,
80 outbound_tx: channel::Sender<String>,
81 name: Arc<str>,
82 capabilities: RwLock<ServerCapabilities>,
83 code_action_kinds: Option<Vec<CodeActionKind>>,
84 notification_handlers: Arc<Mutex<HashMap<&'static str, NotificationHandler>>>,
85 response_handlers: Arc<Mutex<Option<HashMap<RequestId, ResponseHandler>>>>,
86 io_handlers: Arc<Mutex<HashMap<i32, IoHandler>>>,
87 executor: BackgroundExecutor,
88 #[allow(clippy::type_complexity)]
89 io_tasks: Mutex<Option<(Task<Option<()>>, Task<Option<()>>)>>,
90 output_done_rx: Mutex<Option<barrier::Receiver>>,
91 root_path: PathBuf,
92 working_dir: PathBuf,
93 server: Arc<Mutex<Option<Child>>>,
94}
95
96/// Identifies a running language server.
97#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
98#[repr(transparent)]
99pub struct LanguageServerId(pub usize);
100
101impl LanguageServerId {
102 pub fn from_proto(id: u64) -> Self {
103 Self(id as usize)
104 }
105
106 pub fn to_proto(self) -> u64 {
107 self.0 as u64
108 }
109}
110
111/// Handle to a language server RPC activity subscription.
112pub enum Subscription {
113 Notification {
114 method: &'static str,
115 notification_handlers: Option<Arc<Mutex<HashMap<&'static str, NotificationHandler>>>>,
116 },
117 Io {
118 id: i32,
119 io_handlers: Option<Weak<Mutex<HashMap<i32, IoHandler>>>>,
120 },
121}
122
123/// Language server protocol RPC request message ID.
124///
125/// [LSP Specification](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#requestMessage)
126#[derive(Debug, Clone, Eq, PartialEq, Hash, Serialize, Deserialize)]
127#[serde(untagged)]
128pub enum RequestId {
129 Int(i32),
130 Str(String),
131}
132
133/// Language server protocol RPC request message.
134///
135/// [LSP Specification](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#requestMessage)
136#[derive(Serialize, Deserialize)]
137pub struct Request<'a, T> {
138 jsonrpc: &'static str,
139 id: RequestId,
140 method: &'a str,
141 params: T,
142}
143
144/// Language server protocol RPC request response message before it is deserialized into a concrete type.
145#[derive(Serialize, Deserialize)]
146struct AnyResponse<'a> {
147 jsonrpc: &'a str,
148 id: RequestId,
149 #[serde(default)]
150 error: Option<Error>,
151 #[serde(borrow)]
152 result: Option<&'a RawValue>,
153}
154
155/// Language server protocol RPC request response message.
156///
157/// [LSP Specification](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#responseMessage)
158#[derive(Serialize)]
159struct Response<T> {
160 jsonrpc: &'static str,
161 id: RequestId,
162 #[serde(flatten)]
163 value: LspResult<T>,
164}
165
166#[derive(Serialize)]
167#[serde(rename_all = "snake_case")]
168enum LspResult<T> {
169 #[serde(rename = "result")]
170 Ok(Option<T>),
171 Error(Option<Error>),
172}
173
174/// Language server protocol RPC notification message.
175///
176/// [LSP Specification](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#notificationMessage)
177#[derive(Serialize, Deserialize)]
178struct Notification<'a, T> {
179 jsonrpc: &'static str,
180 #[serde(borrow)]
181 method: &'a str,
182 params: T,
183}
184
185/// Language server RPC notification message before it is deserialized into a concrete type.
186#[derive(Debug, Clone, Deserialize)]
187struct AnyNotification {
188 #[serde(default)]
189 id: Option<RequestId>,
190 method: String,
191 #[serde(default)]
192 params: Option<Value>,
193}
194
195#[derive(Debug, Serialize, Deserialize)]
196struct Error {
197 message: String,
198}
199
200pub trait LspRequestFuture<O>: Future<Output = O> {
201 fn id(&self) -> i32;
202}
203
204struct LspRequest<F> {
205 id: i32,
206 request: F,
207}
208
209impl<F> LspRequest<F> {
210 pub fn new(id: i32, request: F) -> Self {
211 Self { id, request }
212 }
213}
214
215impl<F: Future> Future for LspRequest<F> {
216 type Output = F::Output;
217
218 fn poll(self: Pin<&mut Self>, cx: &mut std::task::Context<'_>) -> Poll<Self::Output> {
219 // SAFETY: This is standard pin projection, we're pinned so our fields must be pinned.
220 let inner = unsafe { Pin::new_unchecked(&mut self.get_unchecked_mut().request) };
221 inner.poll(cx)
222 }
223}
224
225impl<F: Future> LspRequestFuture<F::Output> for LspRequest<F> {
226 fn id(&self) -> i32 {
227 self.id
228 }
229}
230
231/// Combined capabilities of the server and the adapter.
232pub struct AdapterServerCapabilities {
233 // Reported capabilities by the server
234 pub server_capabilities: ServerCapabilities,
235 // List of code actions supported by the LspAdapter matching the server
236 pub code_action_kinds: Option<Vec<CodeActionKind>>,
237}
238
239/// Experimental: Informs the end user about the state of the server
240///
241/// [Rust Analyzer Specification](https://github.com/rust-lang/rust-analyzer/blob/master/docs/dev/lsp-extensions.md#server-status)
242#[derive(Debug)]
243pub enum ServerStatus {}
244
245/// Other(String) variant to handle unknown values due to this still being experimental
246#[derive(Debug, PartialEq, Deserialize, Serialize, Clone)]
247#[serde(rename_all = "camelCase")]
248pub enum ServerHealthStatus {
249 Ok,
250 Warning,
251 Error,
252 Other(String),
253}
254
255#[derive(Debug, PartialEq, Deserialize, Serialize, Clone)]
256#[serde(rename_all = "camelCase")]
257pub struct ServerStatusParams {
258 pub health: ServerHealthStatus,
259 pub message: Option<String>,
260}
261
262impl lsp_types::notification::Notification for ServerStatus {
263 type Params = ServerStatusParams;
264 const METHOD: &'static str = "experimental/serverStatus";
265}
266
267impl LanguageServer {
268 /// Starts a language server process.
269 pub fn new(
270 stderr_capture: Arc<Mutex<Option<String>>>,
271 server_id: LanguageServerId,
272 binary: LanguageServerBinary,
273 root_path: &Path,
274 code_action_kinds: Option<Vec<CodeActionKind>>,
275 cx: AsyncAppContext,
276 ) -> Result<Self> {
277 let working_dir = if root_path.is_dir() {
278 root_path
279 } else {
280 root_path.parent().unwrap_or_else(|| Path::new("/"))
281 };
282
283 log::info!(
284 "starting language server process. binary path: {:?}, working directory: {:?}, args: {:?}",
285 binary.path,
286 working_dir,
287 &binary.arguments
288 );
289
290 let mut command = process::Command::new(&binary.path);
291 command
292 .current_dir(working_dir)
293 .args(&binary.arguments)
294 .envs(binary.env.unwrap_or_default())
295 .stdin(Stdio::piped())
296 .stdout(Stdio::piped())
297 .stderr(Stdio::piped())
298 .kill_on_drop(true);
299 #[cfg(windows)]
300 command.creation_flags(windows::Win32::System::Threading::CREATE_NO_WINDOW.0);
301 let mut server = command.spawn().with_context(|| {
302 format!(
303 "failed to spawn command. path: {:?}, working directory: {:?}, args: {:?}",
304 binary.path, working_dir, &binary.arguments
305 )
306 })?;
307
308 let stdin = server.stdin.take().unwrap();
309 let stdout = server.stdout.take().unwrap();
310 let stderr = server.stderr.take().unwrap();
311 let mut server = Self::new_internal(
312 server_id,
313 stdin,
314 stdout,
315 Some(stderr),
316 stderr_capture,
317 Some(server),
318 root_path,
319 working_dir,
320 code_action_kinds,
321 cx,
322 move |notification| {
323 log::info!(
324 "Language server with id {} sent unhandled notification {}:\n{}",
325 server_id,
326 notification.method,
327 serde_json::to_string_pretty(¬ification.params).unwrap(),
328 );
329 },
330 );
331
332 if let Some(name) = binary.path.file_name() {
333 server.name = name.to_string_lossy().into();
334 }
335
336 Ok(server)
337 }
338
339 #[allow(clippy::too_many_arguments)]
340 fn new_internal<Stdin, Stdout, Stderr, F>(
341 server_id: LanguageServerId,
342 stdin: Stdin,
343 stdout: Stdout,
344 stderr: Option<Stderr>,
345 stderr_capture: Arc<Mutex<Option<String>>>,
346 server: Option<Child>,
347 root_path: &Path,
348 working_dir: &Path,
349 code_action_kinds: Option<Vec<CodeActionKind>>,
350 cx: AsyncAppContext,
351 on_unhandled_notification: F,
352 ) -> Self
353 where
354 Stdin: AsyncWrite + Unpin + Send + 'static,
355 Stdout: AsyncRead + Unpin + Send + 'static,
356 Stderr: AsyncRead + Unpin + Send + 'static,
357 F: FnMut(AnyNotification) + 'static + Send + Sync + Clone,
358 {
359 let (outbound_tx, outbound_rx) = channel::unbounded::<String>();
360 let (output_done_tx, output_done_rx) = barrier::channel();
361 let notification_handlers =
362 Arc::new(Mutex::new(HashMap::<_, NotificationHandler>::default()));
363 let response_handlers =
364 Arc::new(Mutex::new(Some(HashMap::<_, ResponseHandler>::default())));
365 let io_handlers = Arc::new(Mutex::new(HashMap::default()));
366
367 let stdout_input_task = cx.spawn({
368 let on_unhandled_notification = on_unhandled_notification.clone();
369 let notification_handlers = notification_handlers.clone();
370 let response_handlers = response_handlers.clone();
371 let io_handlers = io_handlers.clone();
372 move |cx| {
373 Self::handle_input(
374 stdout,
375 on_unhandled_notification,
376 notification_handlers,
377 response_handlers,
378 io_handlers,
379 cx,
380 )
381 .log_err()
382 }
383 });
384 let stderr_input_task = stderr
385 .map(|stderr| {
386 let io_handlers = io_handlers.clone();
387 let stderr_captures = stderr_capture.clone();
388 cx.spawn(|_| Self::handle_stderr(stderr, io_handlers, stderr_captures).log_err())
389 })
390 .unwrap_or_else(|| Task::Ready(Some(None)));
391 let input_task = cx.spawn(|_| async move {
392 let (stdout, stderr) = futures::join!(stdout_input_task, stderr_input_task);
393 stdout.or(stderr)
394 });
395 let output_task = cx.background_executor().spawn({
396 Self::handle_output(
397 stdin,
398 outbound_rx,
399 output_done_tx,
400 response_handlers.clone(),
401 io_handlers.clone(),
402 )
403 .log_err()
404 });
405
406 Self {
407 server_id,
408 notification_handlers,
409 response_handlers,
410 io_handlers,
411 name: Arc::default(),
412 capabilities: Default::default(),
413 code_action_kinds,
414 next_id: Default::default(),
415 outbound_tx,
416 executor: cx.background_executor().clone(),
417 io_tasks: Mutex::new(Some((input_task, output_task))),
418 output_done_rx: Mutex::new(Some(output_done_rx)),
419 root_path: root_path.to_path_buf(),
420 working_dir: working_dir.to_path_buf(),
421 server: Arc::new(Mutex::new(server)),
422 }
423 }
424
425 /// List of code action kinds this language server reports being able to emit.
426 pub fn code_action_kinds(&self) -> Option<Vec<CodeActionKind>> {
427 self.code_action_kinds.clone()
428 }
429
430 async fn handle_input<Stdout, F>(
431 stdout: Stdout,
432 mut on_unhandled_notification: F,
433 notification_handlers: Arc<Mutex<HashMap<&'static str, NotificationHandler>>>,
434 response_handlers: Arc<Mutex<Option<HashMap<RequestId, ResponseHandler>>>>,
435 io_handlers: Arc<Mutex<HashMap<i32, IoHandler>>>,
436 cx: AsyncAppContext,
437 ) -> anyhow::Result<()>
438 where
439 Stdout: AsyncRead + Unpin + Send + 'static,
440 F: FnMut(AnyNotification) + 'static + Send,
441 {
442 use smol::stream::StreamExt;
443 let stdout = BufReader::new(stdout);
444 let _clear_response_handlers = util::defer({
445 let response_handlers = response_handlers.clone();
446 move || {
447 response_handlers.lock().take();
448 }
449 });
450 let mut input_handler = input_handler::LspStdoutHandler::new(
451 stdout,
452 response_handlers,
453 io_handlers,
454 cx.background_executor().clone(),
455 );
456
457 while let Some(msg) = input_handler.notifications_channel.next().await {
458 {
459 let mut notification_handlers = notification_handlers.lock();
460 if let Some(handler) = notification_handlers.get_mut(msg.method.as_str()) {
461 handler(msg.id, msg.params.unwrap_or(Value::Null), cx.clone());
462 } else {
463 drop(notification_handlers);
464 on_unhandled_notification(msg);
465 }
466 }
467
468 // Don't starve the main thread when receiving lots of notifications at once.
469 smol::future::yield_now().await;
470 }
471 input_handler.loop_handle.await
472 }
473
474 async fn handle_stderr<Stderr>(
475 stderr: Stderr,
476 io_handlers: Arc<Mutex<HashMap<i32, IoHandler>>>,
477 stderr_capture: Arc<Mutex<Option<String>>>,
478 ) -> anyhow::Result<()>
479 where
480 Stderr: AsyncRead + Unpin + Send + 'static,
481 {
482 let mut stderr = BufReader::new(stderr);
483 let mut buffer = Vec::new();
484
485 loop {
486 buffer.clear();
487
488 let bytes_read = stderr.read_until(b'\n', &mut buffer).await?;
489 if bytes_read == 0 {
490 return Ok(());
491 }
492
493 if let Ok(message) = std::str::from_utf8(&buffer) {
494 log::trace!("incoming stderr message:{message}");
495 for handler in io_handlers.lock().values_mut() {
496 handler(IoKind::StdErr, message);
497 }
498
499 if let Some(stderr) = stderr_capture.lock().as_mut() {
500 stderr.push_str(message);
501 }
502 }
503
504 // Don't starve the main thread when receiving lots of messages at once.
505 smol::future::yield_now().await;
506 }
507 }
508
509 async fn handle_output<Stdin>(
510 stdin: Stdin,
511 outbound_rx: channel::Receiver<String>,
512 output_done_tx: barrier::Sender,
513 response_handlers: Arc<Mutex<Option<HashMap<RequestId, ResponseHandler>>>>,
514 io_handlers: Arc<Mutex<HashMap<i32, IoHandler>>>,
515 ) -> anyhow::Result<()>
516 where
517 Stdin: AsyncWrite + Unpin + Send + 'static,
518 {
519 let mut stdin = BufWriter::new(stdin);
520 let _clear_response_handlers = util::defer({
521 let response_handlers = response_handlers.clone();
522 move || {
523 response_handlers.lock().take();
524 }
525 });
526 let mut content_len_buffer = Vec::new();
527 while let Ok(message) = outbound_rx.recv().await {
528 log::trace!("outgoing message:{}", message);
529 for handler in io_handlers.lock().values_mut() {
530 handler(IoKind::StdIn, &message);
531 }
532
533 content_len_buffer.clear();
534 write!(content_len_buffer, "{}", message.len()).unwrap();
535 stdin.write_all(CONTENT_LEN_HEADER.as_bytes()).await?;
536 stdin.write_all(&content_len_buffer).await?;
537 stdin.write_all("\r\n\r\n".as_bytes()).await?;
538 stdin.write_all(message.as_bytes()).await?;
539 stdin.flush().await?;
540 }
541 drop(output_done_tx);
542 Ok(())
543 }
544
545 /// Initializes a language server by sending the `Initialize` request.
546 /// Note that `options` is used directly to construct [`InitializeParams`], which is why it is owned.
547 ///
548 /// [LSP Specification](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#initialize)
549 pub fn initialize(
550 mut self,
551 options: Option<Value>,
552 cx: &AppContext,
553 ) -> Task<Result<Arc<Self>>> {
554 let root_uri = Url::from_file_path(&self.working_dir).unwrap();
555 #[allow(deprecated)]
556 let params = InitializeParams {
557 process_id: None,
558 root_path: None,
559 root_uri: Some(root_uri.clone()),
560 initialization_options: options,
561 capabilities: ClientCapabilities {
562 workspace: Some(WorkspaceClientCapabilities {
563 configuration: Some(true),
564 did_change_watched_files: Some(DidChangeWatchedFilesClientCapabilities {
565 dynamic_registration: Some(true),
566 relative_pattern_support: Some(true),
567 }),
568 did_change_configuration: Some(DynamicRegistrationClientCapabilities {
569 dynamic_registration: Some(true),
570 }),
571 workspace_folders: Some(true),
572 symbol: Some(WorkspaceSymbolClientCapabilities {
573 resolve_support: None,
574 ..WorkspaceSymbolClientCapabilities::default()
575 }),
576 inlay_hint: Some(InlayHintWorkspaceClientCapabilities {
577 refresh_support: Some(true),
578 }),
579 diagnostic: Some(DiagnosticWorkspaceClientCapabilities {
580 refresh_support: None,
581 }),
582 workspace_edit: Some(WorkspaceEditClientCapabilities {
583 resource_operations: Some(vec![
584 ResourceOperationKind::Create,
585 ResourceOperationKind::Rename,
586 ResourceOperationKind::Delete,
587 ]),
588 document_changes: Some(true),
589 snippet_edit_support: Some(true),
590 ..WorkspaceEditClientCapabilities::default()
591 }),
592 ..Default::default()
593 }),
594 text_document: Some(TextDocumentClientCapabilities {
595 definition: Some(GotoCapability {
596 link_support: Some(true),
597 dynamic_registration: None,
598 }),
599 code_action: Some(CodeActionClientCapabilities {
600 code_action_literal_support: Some(CodeActionLiteralSupport {
601 code_action_kind: CodeActionKindLiteralSupport {
602 value_set: vec![
603 CodeActionKind::REFACTOR.as_str().into(),
604 CodeActionKind::QUICKFIX.as_str().into(),
605 CodeActionKind::SOURCE.as_str().into(),
606 ],
607 },
608 }),
609 data_support: Some(true),
610 resolve_support: Some(CodeActionCapabilityResolveSupport {
611 properties: vec![
612 "kind".to_string(),
613 "diagnostics".to_string(),
614 "isPreferred".to_string(),
615 "disabled".to_string(),
616 "edit".to_string(),
617 "command".to_string(),
618 ],
619 }),
620 ..Default::default()
621 }),
622 completion: Some(CompletionClientCapabilities {
623 completion_item: Some(CompletionItemCapability {
624 snippet_support: Some(true),
625 resolve_support: Some(CompletionItemCapabilityResolveSupport {
626 properties: vec![
627 "additionalTextEdits".to_string(),
628 "command".to_string(),
629 "detail".to_string(),
630 "documentation".to_string(),
631 "filterText".to_string(),
632 "labelDetails".to_string(),
633 "tags".to_string(),
634 "textEdit".to_string(),
635 ],
636 }),
637 insert_replace_support: Some(true),
638 label_details_support: Some(true),
639 ..Default::default()
640 }),
641 completion_list: Some(CompletionListCapability {
642 item_defaults: Some(vec![
643 "commitCharacters".to_owned(),
644 "editRange".to_owned(),
645 "insertTextMode".to_owned(),
646 "data".to_owned(),
647 ]),
648 }),
649 context_support: Some(true),
650 ..Default::default()
651 }),
652 rename: Some(RenameClientCapabilities {
653 prepare_support: Some(true),
654 ..Default::default()
655 }),
656 hover: Some(HoverClientCapabilities {
657 content_format: Some(vec![MarkupKind::Markdown]),
658 dynamic_registration: None,
659 }),
660 inlay_hint: Some(InlayHintClientCapabilities {
661 resolve_support: Some(InlayHintResolveClientCapabilities {
662 properties: vec![
663 "textEdits".to_string(),
664 "tooltip".to_string(),
665 "label.tooltip".to_string(),
666 "label.location".to_string(),
667 "label.command".to_string(),
668 ],
669 }),
670 dynamic_registration: Some(false),
671 }),
672 publish_diagnostics: Some(PublishDiagnosticsClientCapabilities {
673 related_information: Some(true),
674 ..Default::default()
675 }),
676 formatting: Some(DynamicRegistrationClientCapabilities {
677 dynamic_registration: Some(true),
678 }),
679 range_formatting: Some(DynamicRegistrationClientCapabilities {
680 dynamic_registration: Some(true),
681 }),
682 on_type_formatting: Some(DynamicRegistrationClientCapabilities {
683 dynamic_registration: Some(true),
684 }),
685 signature_help: Some(SignatureHelpClientCapabilities {
686 signature_information: Some(SignatureInformationSettings {
687 documentation_format: Some(vec![
688 MarkupKind::Markdown,
689 MarkupKind::PlainText,
690 ]),
691 parameter_information: Some(ParameterInformationSettings {
692 label_offset_support: Some(true),
693 }),
694 active_parameter_support: Some(true),
695 }),
696 ..SignatureHelpClientCapabilities::default()
697 }),
698 synchronization: Some(TextDocumentSyncClientCapabilities {
699 did_save: Some(true),
700 ..TextDocumentSyncClientCapabilities::default()
701 }),
702 ..TextDocumentClientCapabilities::default()
703 }),
704 experimental: Some(json!({
705 "serverStatusNotification": true,
706 })),
707 window: Some(WindowClientCapabilities {
708 work_done_progress: Some(true),
709 ..Default::default()
710 }),
711 general: None,
712 },
713 trace: None,
714 workspace_folders: Some(vec![WorkspaceFolder {
715 uri: root_uri,
716 name: Default::default(),
717 }]),
718 client_info: release_channel::ReleaseChannel::try_global(cx).map(|release_channel| {
719 ClientInfo {
720 name: release_channel.display_name().to_string(),
721 version: Some(release_channel::AppVersion::global(cx).to_string()),
722 }
723 }),
724 locale: None,
725 ..Default::default()
726 };
727
728 cx.spawn(|_| async move {
729 let response = self.request::<request::Initialize>(params).await?;
730 if let Some(info) = response.server_info {
731 self.name = info.name.into();
732 }
733 self.capabilities = RwLock::new(response.capabilities);
734
735 self.notify::<notification::Initialized>(InitializedParams {})?;
736 Ok(Arc::new(self))
737 })
738 }
739
740 /// Sends a shutdown request to the language server process and prepares the [`LanguageServer`] to be dropped.
741 pub fn shutdown(&self) -> Option<impl 'static + Send + Future<Output = Option<()>>> {
742 if let Some(tasks) = self.io_tasks.lock().take() {
743 let response_handlers = self.response_handlers.clone();
744 let next_id = AtomicI32::new(self.next_id.load(SeqCst));
745 let outbound_tx = self.outbound_tx.clone();
746 let executor = self.executor.clone();
747 let mut output_done = self.output_done_rx.lock().take().unwrap();
748 let shutdown_request = Self::request_internal::<request::Shutdown>(
749 &next_id,
750 &response_handlers,
751 &outbound_tx,
752 &executor,
753 (),
754 );
755 let exit = Self::notify_internal::<notification::Exit>(&outbound_tx, ());
756 outbound_tx.close();
757
758 let server = self.server.clone();
759 let name = self.name.clone();
760 let mut timer = self.executor.timer(SERVER_SHUTDOWN_TIMEOUT).fuse();
761 Some(
762 async move {
763 log::debug!("language server shutdown started");
764
765 select! {
766 request_result = shutdown_request.fuse() => {
767 request_result?;
768 }
769
770 _ = timer => {
771 log::info!("timeout waiting for language server {name} to shutdown");
772 },
773 }
774
775 response_handlers.lock().take();
776 exit?;
777 output_done.recv().await;
778 server.lock().take().map(|mut child| child.kill());
779 log::debug!("language server shutdown finished");
780
781 drop(tasks);
782 anyhow::Ok(())
783 }
784 .log_err(),
785 )
786 } else {
787 None
788 }
789 }
790
791 /// Register a handler to handle incoming LSP notifications.
792 ///
793 /// [LSP Specification](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#notificationMessage)
794 #[must_use]
795 pub fn on_notification<T, F>(&self, f: F) -> Subscription
796 where
797 T: notification::Notification,
798 F: 'static + Send + FnMut(T::Params, AsyncAppContext),
799 {
800 self.on_custom_notification(T::METHOD, f)
801 }
802
803 /// Register a handler to handle incoming LSP requests.
804 ///
805 /// [LSP Specification](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#requestMessage)
806 #[must_use]
807 pub fn on_request<T, F, Fut>(&self, f: F) -> Subscription
808 where
809 T: request::Request,
810 T::Params: 'static + Send,
811 F: 'static + FnMut(T::Params, AsyncAppContext) -> Fut + Send,
812 Fut: 'static + Future<Output = Result<T::Result>>,
813 {
814 self.on_custom_request(T::METHOD, f)
815 }
816
817 /// Registers a handler to inspect all language server process stdio.
818 #[must_use]
819 pub fn on_io<F>(&self, f: F) -> Subscription
820 where
821 F: 'static + Send + FnMut(IoKind, &str),
822 {
823 let id = self.next_id.fetch_add(1, SeqCst);
824 self.io_handlers.lock().insert(id, Box::new(f));
825 Subscription::Io {
826 id,
827 io_handlers: Some(Arc::downgrade(&self.io_handlers)),
828 }
829 }
830
831 /// Removes a request handler registers via [`Self::on_request`].
832 pub fn remove_request_handler<T: request::Request>(&self) {
833 self.notification_handlers.lock().remove(T::METHOD);
834 }
835
836 /// Removes a notification handler registers via [`Self::on_notification`].
837 pub fn remove_notification_handler<T: notification::Notification>(&self) {
838 self.notification_handlers.lock().remove(T::METHOD);
839 }
840
841 /// Checks if a notification handler has been registered via [`Self::on_notification`].
842 pub fn has_notification_handler<T: notification::Notification>(&self) -> bool {
843 self.notification_handlers.lock().contains_key(T::METHOD)
844 }
845
846 #[must_use]
847 fn on_custom_notification<Params, F>(&self, method: &'static str, mut f: F) -> Subscription
848 where
849 F: 'static + FnMut(Params, AsyncAppContext) + Send,
850 Params: DeserializeOwned,
851 {
852 let prev_handler = self.notification_handlers.lock().insert(
853 method,
854 Box::new(move |_, params, cx| {
855 if let Some(params) = serde_json::from_value(params).log_err() {
856 f(params, cx);
857 }
858 }),
859 );
860 assert!(
861 prev_handler.is_none(),
862 "registered multiple handlers for the same LSP method"
863 );
864 Subscription::Notification {
865 method,
866 notification_handlers: Some(self.notification_handlers.clone()),
867 }
868 }
869
870 #[must_use]
871 fn on_custom_request<Params, Res, Fut, F>(&self, method: &'static str, mut f: F) -> Subscription
872 where
873 F: 'static + FnMut(Params, AsyncAppContext) -> Fut + Send,
874 Fut: 'static + Future<Output = Result<Res>>,
875 Params: DeserializeOwned + Send + 'static,
876 Res: Serialize,
877 {
878 let outbound_tx = self.outbound_tx.clone();
879 let prev_handler = self.notification_handlers.lock().insert(
880 method,
881 Box::new(move |id, params, cx| {
882 if let Some(id) = id {
883 match serde_json::from_value(params) {
884 Ok(params) => {
885 let response = f(params, cx.clone());
886 cx.foreground_executor()
887 .spawn({
888 let outbound_tx = outbound_tx.clone();
889 async move {
890 let response = match response.await {
891 Ok(result) => Response {
892 jsonrpc: JSON_RPC_VERSION,
893 id,
894 value: LspResult::Ok(Some(result)),
895 },
896 Err(error) => Response {
897 jsonrpc: JSON_RPC_VERSION,
898 id,
899 value: LspResult::Error(Some(Error {
900 message: error.to_string(),
901 })),
902 },
903 };
904 if let Some(response) =
905 serde_json::to_string(&response).log_err()
906 {
907 outbound_tx.try_send(response).ok();
908 }
909 }
910 })
911 .detach();
912 }
913
914 Err(error) => {
915 log::error!("error deserializing {} request: {:?}", method, error);
916 let response = AnyResponse {
917 jsonrpc: JSON_RPC_VERSION,
918 id,
919 result: None,
920 error: Some(Error {
921 message: error.to_string(),
922 }),
923 };
924 if let Some(response) = serde_json::to_string(&response).log_err() {
925 outbound_tx.try_send(response).ok();
926 }
927 }
928 }
929 }
930 }),
931 );
932 assert!(
933 prev_handler.is_none(),
934 "registered multiple handlers for the same LSP method"
935 );
936 Subscription::Notification {
937 method,
938 notification_handlers: Some(self.notification_handlers.clone()),
939 }
940 }
941
942 /// Get the name of the running language server.
943 pub fn name(&self) -> &str {
944 &self.name
945 }
946
947 /// Get the reported capabilities of the running language server.
948 pub fn capabilities(&self) -> ServerCapabilities {
949 self.capabilities.read().clone()
950 }
951
952 /// Get the reported capabilities of the running language server and
953 /// what we know on the client/adapter-side of its capabilities.
954 pub fn adapter_server_capabilities(&self) -> AdapterServerCapabilities {
955 AdapterServerCapabilities {
956 server_capabilities: self.capabilities(),
957 code_action_kinds: self.code_action_kinds(),
958 }
959 }
960
961 pub fn update_capabilities(&self, update: impl FnOnce(&mut ServerCapabilities)) {
962 update(self.capabilities.write().deref_mut());
963 }
964
965 /// Get the id of the running language server.
966 pub fn server_id(&self) -> LanguageServerId {
967 self.server_id
968 }
969
970 /// Get the root path of the project the language server is running against.
971 pub fn root_path(&self) -> &PathBuf {
972 &self.root_path
973 }
974
975 /// Sends a RPC request to the language server.
976 ///
977 /// [LSP Specification](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#requestMessage)
978 pub fn request<T: request::Request>(
979 &self,
980 params: T::Params,
981 ) -> impl LspRequestFuture<Result<T::Result>>
982 where
983 T::Result: 'static + Send,
984 {
985 Self::request_internal::<T>(
986 &self.next_id,
987 &self.response_handlers,
988 &self.outbound_tx,
989 &self.executor,
990 params,
991 )
992 }
993
994 fn request_internal<T: request::Request>(
995 next_id: &AtomicI32,
996 response_handlers: &Mutex<Option<HashMap<RequestId, ResponseHandler>>>,
997 outbound_tx: &channel::Sender<String>,
998 executor: &BackgroundExecutor,
999 params: T::Params,
1000 ) -> impl LspRequestFuture<Result<T::Result>>
1001 where
1002 T::Result: 'static + Send,
1003 {
1004 let id = next_id.fetch_add(1, SeqCst);
1005 let message = serde_json::to_string(&Request {
1006 jsonrpc: JSON_RPC_VERSION,
1007 id: RequestId::Int(id),
1008 method: T::METHOD,
1009 params,
1010 })
1011 .unwrap();
1012
1013 let (tx, rx) = oneshot::channel();
1014 let handle_response = response_handlers
1015 .lock()
1016 .as_mut()
1017 .ok_or_else(|| anyhow!("server shut down"))
1018 .map(|handlers| {
1019 let executor = executor.clone();
1020 handlers.insert(
1021 RequestId::Int(id),
1022 Box::new(move |result| {
1023 executor
1024 .spawn(async move {
1025 let response = match result {
1026 Ok(response) => match serde_json::from_str(&response) {
1027 Ok(deserialized) => Ok(deserialized),
1028 Err(error) => {
1029 log::error!("failed to deserialize response from language server: {}. response from language server: {:?}", error, response);
1030 Err(error).context("failed to deserialize response")
1031 }
1032 }
1033 Err(error) => Err(anyhow!("{}", error.message)),
1034 };
1035 _ = tx.send(response);
1036 })
1037 .detach();
1038 }),
1039 );
1040 });
1041
1042 let send = outbound_tx
1043 .try_send(message)
1044 .context("failed to write to language server's stdin");
1045
1046 let outbound_tx = outbound_tx.downgrade();
1047 let mut timeout = executor.timer(LSP_REQUEST_TIMEOUT).fuse();
1048 let started = Instant::now();
1049 LspRequest::new(id, async move {
1050 handle_response?;
1051 send?;
1052
1053 let cancel_on_drop = util::defer(move || {
1054 if let Some(outbound_tx) = outbound_tx.upgrade() {
1055 Self::notify_internal::<notification::Cancel>(
1056 &outbound_tx,
1057 CancelParams {
1058 id: NumberOrString::Number(id),
1059 },
1060 )
1061 .log_err();
1062 }
1063 });
1064
1065 let method = T::METHOD;
1066 select! {
1067 response = rx.fuse() => {
1068 let elapsed = started.elapsed();
1069 log::trace!("Took {elapsed:?} to receive response to {method:?} id {id}");
1070 cancel_on_drop.abort();
1071 response?
1072 }
1073
1074 _ = timeout => {
1075 log::error!("Cancelled LSP request task for {method:?} id {id} which took over {LSP_REQUEST_TIMEOUT:?}");
1076 anyhow::bail!("LSP request timeout");
1077 }
1078 }
1079 })
1080 }
1081
1082 /// Sends a RPC notification to the language server.
1083 ///
1084 /// [LSP Specification](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#notificationMessage)
1085 pub fn notify<T: notification::Notification>(&self, params: T::Params) -> Result<()> {
1086 Self::notify_internal::<T>(&self.outbound_tx, params)
1087 }
1088
1089 fn notify_internal<T: notification::Notification>(
1090 outbound_tx: &channel::Sender<String>,
1091 params: T::Params,
1092 ) -> Result<()> {
1093 let message = serde_json::to_string(&Notification {
1094 jsonrpc: JSON_RPC_VERSION,
1095 method: T::METHOD,
1096 params,
1097 })
1098 .unwrap();
1099 outbound_tx.try_send(message)?;
1100 Ok(())
1101 }
1102}
1103
1104impl Drop for LanguageServer {
1105 fn drop(&mut self) {
1106 if let Some(shutdown) = self.shutdown() {
1107 self.executor.spawn(shutdown).detach();
1108 }
1109 }
1110}
1111
1112impl Subscription {
1113 /// Detaching a subscription handle prevents it from unsubscribing on drop.
1114 pub fn detach(&mut self) {
1115 match self {
1116 Subscription::Notification {
1117 notification_handlers,
1118 ..
1119 } => *notification_handlers = None,
1120 Subscription::Io { io_handlers, .. } => *io_handlers = None,
1121 }
1122 }
1123}
1124
1125impl fmt::Display for LanguageServerId {
1126 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1127 self.0.fmt(f)
1128 }
1129}
1130
1131impl fmt::Debug for LanguageServer {
1132 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1133 f.debug_struct("LanguageServer")
1134 .field("id", &self.server_id.0)
1135 .field("name", &self.name)
1136 .finish_non_exhaustive()
1137 }
1138}
1139
1140impl Drop for Subscription {
1141 fn drop(&mut self) {
1142 match self {
1143 Subscription::Notification {
1144 method,
1145 notification_handlers,
1146 } => {
1147 if let Some(handlers) = notification_handlers {
1148 handlers.lock().remove(method);
1149 }
1150 }
1151 Subscription::Io { id, io_handlers } => {
1152 if let Some(io_handlers) = io_handlers.as_ref().and_then(|h| h.upgrade()) {
1153 io_handlers.lock().remove(id);
1154 }
1155 }
1156 }
1157 }
1158}
1159
1160/// Mock language server for use in tests.
1161#[cfg(any(test, feature = "test-support"))]
1162#[derive(Clone)]
1163pub struct FakeLanguageServer {
1164 pub binary: LanguageServerBinary,
1165 pub server: Arc<LanguageServer>,
1166 notifications_rx: channel::Receiver<(String, String)>,
1167}
1168
1169#[cfg(any(test, feature = "test-support"))]
1170impl FakeLanguageServer {
1171 /// Construct a fake language server.
1172 pub fn new(
1173 server_id: LanguageServerId,
1174 binary: LanguageServerBinary,
1175 name: String,
1176 capabilities: ServerCapabilities,
1177 cx: AsyncAppContext,
1178 ) -> (LanguageServer, FakeLanguageServer) {
1179 let (stdin_writer, stdin_reader) = async_pipe::pipe();
1180 let (stdout_writer, stdout_reader) = async_pipe::pipe();
1181 let (notifications_tx, notifications_rx) = channel::unbounded();
1182
1183 let mut server = LanguageServer::new_internal(
1184 server_id,
1185 stdin_writer,
1186 stdout_reader,
1187 None::<async_pipe::PipeReader>,
1188 Arc::new(Mutex::new(None)),
1189 None,
1190 Path::new("/"),
1191 Path::new("/"),
1192 None,
1193 cx.clone(),
1194 |_| {},
1195 );
1196 server.name = name.as_str().into();
1197 let fake = FakeLanguageServer {
1198 binary,
1199 server: Arc::new({
1200 let mut server = LanguageServer::new_internal(
1201 server_id,
1202 stdout_writer,
1203 stdin_reader,
1204 None::<async_pipe::PipeReader>,
1205 Arc::new(Mutex::new(None)),
1206 None,
1207 Path::new("/"),
1208 Path::new("/"),
1209 None,
1210 cx,
1211 move |msg| {
1212 notifications_tx
1213 .try_send((
1214 msg.method.to_string(),
1215 msg.params.unwrap_or(Value::Null).to_string(),
1216 ))
1217 .ok();
1218 },
1219 );
1220 server.name = name.as_str().into();
1221 server
1222 }),
1223 notifications_rx,
1224 };
1225 fake.handle_request::<request::Initialize, _, _>({
1226 let capabilities = capabilities;
1227 move |_, _| {
1228 let capabilities = capabilities.clone();
1229 let name = name.clone();
1230 async move {
1231 Ok(InitializeResult {
1232 capabilities,
1233 server_info: Some(ServerInfo {
1234 name,
1235 ..Default::default()
1236 }),
1237 })
1238 }
1239 }
1240 });
1241
1242 (server, fake)
1243 }
1244}
1245
1246#[cfg(any(test, feature = "test-support"))]
1247impl LanguageServer {
1248 pub fn full_capabilities() -> ServerCapabilities {
1249 ServerCapabilities {
1250 document_highlight_provider: Some(OneOf::Left(true)),
1251 code_action_provider: Some(CodeActionProviderCapability::Simple(true)),
1252 document_formatting_provider: Some(OneOf::Left(true)),
1253 document_range_formatting_provider: Some(OneOf::Left(true)),
1254 definition_provider: Some(OneOf::Left(true)),
1255 implementation_provider: Some(ImplementationProviderCapability::Simple(true)),
1256 type_definition_provider: Some(TypeDefinitionProviderCapability::Simple(true)),
1257 ..Default::default()
1258 }
1259 }
1260}
1261
1262#[cfg(any(test, feature = "test-support"))]
1263impl FakeLanguageServer {
1264 /// See [`LanguageServer::notify`].
1265 pub fn notify<T: notification::Notification>(&self, params: T::Params) {
1266 self.server.notify::<T>(params).ok();
1267 }
1268
1269 /// See [`LanguageServer::request`].
1270 pub async fn request<T>(&self, params: T::Params) -> Result<T::Result>
1271 where
1272 T: request::Request,
1273 T::Result: 'static + Send,
1274 {
1275 self.server.executor.start_waiting();
1276 self.server.request::<T>(params).await
1277 }
1278
1279 /// Attempts [`Self::try_receive_notification`], unwrapping if it has not received the specified type yet.
1280 pub async fn receive_notification<T: notification::Notification>(&mut self) -> T::Params {
1281 self.server.executor.start_waiting();
1282 self.try_receive_notification::<T>().await.unwrap()
1283 }
1284
1285 /// Consumes the notification channel until it finds a notification for the specified type.
1286 pub async fn try_receive_notification<T: notification::Notification>(
1287 &mut self,
1288 ) -> Option<T::Params> {
1289 use futures::StreamExt as _;
1290
1291 loop {
1292 let (method, params) = self.notifications_rx.next().await?;
1293 if method == T::METHOD {
1294 return Some(serde_json::from_str::<T::Params>(¶ms).unwrap());
1295 } else {
1296 log::info!("skipping message in fake language server {:?}", params);
1297 }
1298 }
1299 }
1300
1301 /// Registers a handler for a specific kind of request. Removes any existing handler for specified request type.
1302 pub fn handle_request<T, F, Fut>(
1303 &self,
1304 mut handler: F,
1305 ) -> futures::channel::mpsc::UnboundedReceiver<()>
1306 where
1307 T: 'static + request::Request,
1308 T::Params: 'static + Send,
1309 F: 'static + Send + FnMut(T::Params, gpui::AsyncAppContext) -> Fut,
1310 Fut: 'static + Send + Future<Output = Result<T::Result>>,
1311 {
1312 let (responded_tx, responded_rx) = futures::channel::mpsc::unbounded();
1313 self.server.remove_request_handler::<T>();
1314 self.server
1315 .on_request::<T, _, _>(move |params, cx| {
1316 let result = handler(params, cx.clone());
1317 let responded_tx = responded_tx.clone();
1318 let executor = cx.background_executor().clone();
1319 async move {
1320 executor.simulate_random_delay().await;
1321 let result = result.await;
1322 responded_tx.unbounded_send(()).ok();
1323 result
1324 }
1325 })
1326 .detach();
1327 responded_rx
1328 }
1329
1330 /// Registers a handler for a specific kind of notification. Removes any existing handler for specified notification type.
1331 pub fn handle_notification<T, F>(
1332 &self,
1333 mut handler: F,
1334 ) -> futures::channel::mpsc::UnboundedReceiver<()>
1335 where
1336 T: 'static + notification::Notification,
1337 T::Params: 'static + Send,
1338 F: 'static + Send + FnMut(T::Params, gpui::AsyncAppContext),
1339 {
1340 let (handled_tx, handled_rx) = futures::channel::mpsc::unbounded();
1341 self.server.remove_notification_handler::<T>();
1342 self.server
1343 .on_notification::<T, _>(move |params, cx| {
1344 handler(params, cx.clone());
1345 handled_tx.unbounded_send(()).ok();
1346 })
1347 .detach();
1348 handled_rx
1349 }
1350
1351 /// Removes any existing handler for specified notification type.
1352 pub fn remove_request_handler<T>(&mut self)
1353 where
1354 T: 'static + request::Request,
1355 {
1356 self.server.remove_request_handler::<T>();
1357 }
1358
1359 /// Simulate that the server has started work and notifies about its progress with the specified token.
1360 pub async fn start_progress(&self, token: impl Into<String>) {
1361 self.start_progress_with(token, Default::default()).await
1362 }
1363
1364 pub async fn start_progress_with(
1365 &self,
1366 token: impl Into<String>,
1367 progress: WorkDoneProgressBegin,
1368 ) {
1369 let token = token.into();
1370 self.request::<request::WorkDoneProgressCreate>(WorkDoneProgressCreateParams {
1371 token: NumberOrString::String(token.clone()),
1372 })
1373 .await
1374 .unwrap();
1375 self.notify::<notification::Progress>(ProgressParams {
1376 token: NumberOrString::String(token),
1377 value: ProgressParamsValue::WorkDone(WorkDoneProgress::Begin(progress)),
1378 });
1379 }
1380
1381 /// Simulate that the server has completed work and notifies about that with the specified token.
1382 pub fn end_progress(&self, token: impl Into<String>) {
1383 self.notify::<notification::Progress>(ProgressParams {
1384 token: NumberOrString::String(token.into()),
1385 value: ProgressParamsValue::WorkDone(WorkDoneProgress::End(Default::default())),
1386 });
1387 }
1388}
1389
1390#[cfg(test)]
1391mod tests {
1392 use super::*;
1393 use gpui::{SemanticVersion, TestAppContext};
1394 use std::str::FromStr;
1395
1396 #[ctor::ctor]
1397 fn init_logger() {
1398 if std::env::var("RUST_LOG").is_ok() {
1399 env_logger::init();
1400 }
1401 }
1402
1403 #[gpui::test]
1404 async fn test_fake(cx: &mut TestAppContext) {
1405 cx.update(|cx| {
1406 release_channel::init(SemanticVersion::default(), cx);
1407 });
1408 let (server, mut fake) = FakeLanguageServer::new(
1409 LanguageServerId(0),
1410 LanguageServerBinary {
1411 path: "path/to/language-server".into(),
1412 arguments: vec![],
1413 env: None,
1414 },
1415 "the-lsp".to_string(),
1416 Default::default(),
1417 cx.to_async(),
1418 );
1419
1420 let (message_tx, message_rx) = channel::unbounded();
1421 let (diagnostics_tx, diagnostics_rx) = channel::unbounded();
1422 server
1423 .on_notification::<notification::ShowMessage, _>(move |params, _| {
1424 message_tx.try_send(params).unwrap()
1425 })
1426 .detach();
1427 server
1428 .on_notification::<notification::PublishDiagnostics, _>(move |params, _| {
1429 diagnostics_tx.try_send(params).unwrap()
1430 })
1431 .detach();
1432
1433 let server = cx.update(|cx| server.initialize(None, cx)).await.unwrap();
1434 server
1435 .notify::<notification::DidOpenTextDocument>(DidOpenTextDocumentParams {
1436 text_document: TextDocumentItem::new(
1437 Url::from_str("file://a/b").unwrap(),
1438 "rust".to_string(),
1439 0,
1440 "".to_string(),
1441 ),
1442 })
1443 .unwrap();
1444 assert_eq!(
1445 fake.receive_notification::<notification::DidOpenTextDocument>()
1446 .await
1447 .text_document
1448 .uri
1449 .as_str(),
1450 "file://a/b"
1451 );
1452
1453 fake.notify::<notification::ShowMessage>(ShowMessageParams {
1454 typ: MessageType::ERROR,
1455 message: "ok".to_string(),
1456 });
1457 fake.notify::<notification::PublishDiagnostics>(PublishDiagnosticsParams {
1458 uri: Url::from_str("file://b/c").unwrap(),
1459 version: Some(5),
1460 diagnostics: vec![],
1461 });
1462 assert_eq!(message_rx.recv().await.unwrap().message, "ok");
1463 assert_eq!(
1464 diagnostics_rx.recv().await.unwrap().uri.as_str(),
1465 "file://b/c"
1466 );
1467
1468 fake.handle_request::<request::Shutdown, _, _>(|_, _| async move { Ok(()) });
1469
1470 drop(server);
1471 fake.receive_notification::<notification::Exit>().await;
1472 }
1473
1474 #[gpui::test]
1475 fn test_deserialize_string_digit_id() {
1476 let json = r#"{"jsonrpc":"2.0","id":"2","method":"workspace/configuration","params":{"items":[{"scopeUri":"file:///Users/mph/Devel/personal/hello-scala/","section":"metals"}]}}"#;
1477 let notification = serde_json::from_str::<AnyNotification>(json)
1478 .expect("message with string id should be parsed");
1479 let expected_id = RequestId::Str("2".to_string());
1480 assert_eq!(notification.id, Some(expected_id));
1481 }
1482
1483 #[gpui::test]
1484 fn test_deserialize_string_id() {
1485 let json = r#"{"jsonrpc":"2.0","id":"anythingAtAll","method":"workspace/configuration","params":{"items":[{"scopeUri":"file:///Users/mph/Devel/personal/hello-scala/","section":"metals"}]}}"#;
1486 let notification = serde_json::from_str::<AnyNotification>(json)
1487 .expect("message with string id should be parsed");
1488 let expected_id = RequestId::Str("anythingAtAll".to_string());
1489 assert_eq!(notification.id, Some(expected_id));
1490 }
1491
1492 #[gpui::test]
1493 fn test_deserialize_int_id() {
1494 let json = r#"{"jsonrpc":"2.0","id":2,"method":"workspace/configuration","params":{"items":[{"scopeUri":"file:///Users/mph/Devel/personal/hello-scala/","section":"metals"}]}}"#;
1495 let notification = serde_json::from_str::<AnyNotification>(json)
1496 .expect("message with string id should be parsed");
1497 let expected_id = RequestId::Int(2);
1498 assert_eq!(notification.id, Some(expected_id));
1499 }
1500
1501 #[test]
1502 fn test_serialize_has_no_nulls() {
1503 // Ensure we're not setting both result and error variants. (ticket #10595)
1504 let no_tag = Response::<u32> {
1505 jsonrpc: "",
1506 id: RequestId::Int(0),
1507 value: LspResult::Ok(None),
1508 };
1509 assert_eq!(
1510 serde_json::to_string(&no_tag).unwrap(),
1511 "{\"jsonrpc\":\"\",\"id\":0,\"result\":null}"
1512 );
1513 let no_tag = Response::<u32> {
1514 jsonrpc: "",
1515 id: RequestId::Int(0),
1516 value: LspResult::Error(None),
1517 };
1518 assert_eq!(
1519 serde_json::to_string(&no_tag).unwrap(),
1520 "{\"jsonrpc\":\"\",\"id\":0,\"error\":null}"
1521 );
1522 }
1523}