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