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