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