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