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