lsp.rs

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