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