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                    ..Default::default()
 683                }),
 684                text_document: Some(TextDocumentClientCapabilities {
 685                    definition: Some(GotoCapability {
 686                        link_support: Some(true),
 687                        dynamic_registration: None,
 688                    }),
 689                    code_action: Some(CodeActionClientCapabilities {
 690                        code_action_literal_support: Some(CodeActionLiteralSupport {
 691                            code_action_kind: CodeActionKindLiteralSupport {
 692                                value_set: vec![
 693                                    CodeActionKind::REFACTOR.as_str().into(),
 694                                    CodeActionKind::QUICKFIX.as_str().into(),
 695                                    CodeActionKind::SOURCE.as_str().into(),
 696                                ],
 697                            },
 698                        }),
 699                        data_support: Some(true),
 700                        resolve_support: Some(CodeActionCapabilityResolveSupport {
 701                            properties: vec![
 702                                "kind".to_string(),
 703                                "diagnostics".to_string(),
 704                                "isPreferred".to_string(),
 705                                "disabled".to_string(),
 706                                "edit".to_string(),
 707                                "command".to_string(),
 708                            ],
 709                        }),
 710                        ..Default::default()
 711                    }),
 712                    completion: Some(CompletionClientCapabilities {
 713                        completion_item: Some(CompletionItemCapability {
 714                            snippet_support: Some(true),
 715                            resolve_support: Some(CompletionItemCapabilityResolveSupport {
 716                                properties: vec![
 717                                    "additionalTextEdits".to_string(),
 718                                    "command".to_string(),
 719                                    "documentation".to_string(),
 720                                    // NB: Do not have this resolved, otherwise Zed becomes slow to complete things
 721                                    // "textEdit".to_string(),
 722                                ],
 723                            }),
 724                            insert_replace_support: Some(true),
 725                            label_details_support: Some(true),
 726                            ..Default::default()
 727                        }),
 728                        completion_list: Some(CompletionListCapability {
 729                            item_defaults: Some(vec![
 730                                "commitCharacters".to_owned(),
 731                                "editRange".to_owned(),
 732                                "insertTextMode".to_owned(),
 733                                "insertTextFormat".to_owned(),
 734                                "data".to_owned(),
 735                            ]),
 736                        }),
 737                        context_support: Some(true),
 738                        ..Default::default()
 739                    }),
 740                    rename: Some(RenameClientCapabilities {
 741                        prepare_support: Some(true),
 742                        prepare_support_default_behavior: Some(
 743                            PrepareSupportDefaultBehavior::IDENTIFIER,
 744                        ),
 745                        ..Default::default()
 746                    }),
 747                    hover: Some(HoverClientCapabilities {
 748                        content_format: Some(vec![MarkupKind::Markdown]),
 749                        dynamic_registration: None,
 750                    }),
 751                    inlay_hint: Some(InlayHintClientCapabilities {
 752                        resolve_support: Some(InlayHintResolveClientCapabilities {
 753                            properties: vec![
 754                                "textEdits".to_string(),
 755                                "tooltip".to_string(),
 756                                "label.tooltip".to_string(),
 757                                "label.location".to_string(),
 758                                "label.command".to_string(),
 759                            ],
 760                        }),
 761                        dynamic_registration: Some(false),
 762                    }),
 763                    publish_diagnostics: Some(PublishDiagnosticsClientCapabilities {
 764                        related_information: Some(true),
 765                        ..Default::default()
 766                    }),
 767                    formatting: Some(DynamicRegistrationClientCapabilities {
 768                        dynamic_registration: Some(true),
 769                    }),
 770                    range_formatting: Some(DynamicRegistrationClientCapabilities {
 771                        dynamic_registration: Some(true),
 772                    }),
 773                    on_type_formatting: Some(DynamicRegistrationClientCapabilities {
 774                        dynamic_registration: Some(true),
 775                    }),
 776                    signature_help: Some(SignatureHelpClientCapabilities {
 777                        signature_information: Some(SignatureInformationSettings {
 778                            documentation_format: Some(vec![
 779                                MarkupKind::Markdown,
 780                                MarkupKind::PlainText,
 781                            ]),
 782                            parameter_information: Some(ParameterInformationSettings {
 783                                label_offset_support: Some(true),
 784                            }),
 785                            active_parameter_support: Some(true),
 786                        }),
 787                        ..SignatureHelpClientCapabilities::default()
 788                    }),
 789                    synchronization: Some(TextDocumentSyncClientCapabilities {
 790                        did_save: Some(true),
 791                        ..TextDocumentSyncClientCapabilities::default()
 792                    }),
 793                    ..TextDocumentClientCapabilities::default()
 794                }),
 795                experimental: Some(json!({
 796                    "serverStatusNotification": true,
 797                    "localDocs": true,
 798                })),
 799                window: Some(WindowClientCapabilities {
 800                    work_done_progress: Some(true),
 801                    show_message: Some(ShowMessageRequestClientCapabilities {
 802                        message_action_item: None,
 803                    }),
 804                    ..Default::default()
 805                }),
 806            },
 807            trace: None,
 808            workspace_folders: Some(workspace_folders),
 809            client_info: release_channel::ReleaseChannel::try_global(cx).map(|release_channel| {
 810                ClientInfo {
 811                    name: release_channel.display_name().to_string(),
 812                    version: Some(release_channel::AppVersion::global(cx).to_string()),
 813                }
 814            }),
 815            locale: None,
 816
 817            ..Default::default()
 818        }
 819    }
 820
 821    /// Initializes a language server by sending the `Initialize` request.
 822    /// Note that `options` is used directly to construct [`InitializeParams`], which is why it is owned.
 823    ///
 824    /// [LSP Specification](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#initialize)
 825    pub fn initialize(
 826        mut self,
 827        params: InitializeParams,
 828        configuration: Arc<DidChangeConfigurationParams>,
 829        cx: &App,
 830    ) -> Task<Result<Arc<Self>>> {
 831        cx.spawn(|_| async move {
 832            let response = self.request::<request::Initialize>(params).await?;
 833            if let Some(info) = response.server_info {
 834                self.process_name = info.name.into();
 835            }
 836            self.capabilities = RwLock::new(response.capabilities);
 837            self.configuration = configuration;
 838
 839            self.notify::<notification::Initialized>(&InitializedParams {})?;
 840            Ok(Arc::new(self))
 841        })
 842    }
 843
 844    /// Sends a shutdown request to the language server process and prepares the [`LanguageServer`] to be dropped.
 845    pub fn shutdown(&self) -> Option<impl 'static + Send + Future<Output = Option<()>>> {
 846        if let Some(tasks) = self.io_tasks.lock().take() {
 847            let response_handlers = self.response_handlers.clone();
 848            let next_id = AtomicI32::new(self.next_id.load(SeqCst));
 849            let outbound_tx = self.outbound_tx.clone();
 850            let executor = self.executor.clone();
 851            let mut output_done = self.output_done_rx.lock().take().unwrap();
 852            let shutdown_request = Self::request_internal::<request::Shutdown>(
 853                &next_id,
 854                &response_handlers,
 855                &outbound_tx,
 856                &executor,
 857                (),
 858            );
 859            let exit = Self::notify_internal::<notification::Exit>(&outbound_tx, &());
 860            outbound_tx.close();
 861
 862            let server = self.server.clone();
 863            let name = self.name.clone();
 864            let mut timer = self.executor.timer(SERVER_SHUTDOWN_TIMEOUT).fuse();
 865            Some(
 866                async move {
 867                    log::debug!("language server shutdown started");
 868
 869                    select! {
 870                        request_result = shutdown_request.fuse() => {
 871                            request_result?;
 872                        }
 873
 874                        _ = timer => {
 875                            log::info!("timeout waiting for language server {name} to shutdown");
 876                        },
 877                    }
 878
 879                    response_handlers.lock().take();
 880                    exit?;
 881                    output_done.recv().await;
 882                    server.lock().take().map(|mut child| child.kill());
 883                    log::debug!("language server shutdown finished");
 884
 885                    drop(tasks);
 886                    anyhow::Ok(())
 887                }
 888                .log_err(),
 889            )
 890        } else {
 891            None
 892        }
 893    }
 894
 895    /// Register a handler to handle incoming LSP notifications.
 896    ///
 897    /// [LSP Specification](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#notificationMessage)
 898    #[must_use]
 899    pub fn on_notification<T, F>(&self, f: F) -> Subscription
 900    where
 901        T: notification::Notification,
 902        F: 'static + Send + FnMut(T::Params, AsyncApp),
 903    {
 904        self.on_custom_notification(T::METHOD, f)
 905    }
 906
 907    /// Register a handler to handle incoming LSP requests.
 908    ///
 909    /// [LSP Specification](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#requestMessage)
 910    #[must_use]
 911    pub fn on_request<T, F, Fut>(&self, f: F) -> Subscription
 912    where
 913        T: request::Request,
 914        T::Params: 'static + Send,
 915        F: 'static + FnMut(T::Params, AsyncApp) -> Fut + Send,
 916        Fut: 'static + Future<Output = Result<T::Result>>,
 917    {
 918        self.on_custom_request(T::METHOD, f)
 919    }
 920
 921    /// Registers a handler to inspect all language server process stdio.
 922    #[must_use]
 923    pub fn on_io<F>(&self, f: F) -> Subscription
 924    where
 925        F: 'static + Send + FnMut(IoKind, &str),
 926    {
 927        let id = self.next_id.fetch_add(1, SeqCst);
 928        self.io_handlers.lock().insert(id, Box::new(f));
 929        Subscription::Io {
 930            id,
 931            io_handlers: Some(Arc::downgrade(&self.io_handlers)),
 932        }
 933    }
 934
 935    /// Removes a request handler registers via [`Self::on_request`].
 936    pub fn remove_request_handler<T: request::Request>(&self) {
 937        self.notification_handlers.lock().remove(T::METHOD);
 938    }
 939
 940    /// Removes a notification handler registers via [`Self::on_notification`].
 941    pub fn remove_notification_handler<T: notification::Notification>(&self) {
 942        self.notification_handlers.lock().remove(T::METHOD);
 943    }
 944
 945    /// Checks if a notification handler has been registered via [`Self::on_notification`].
 946    pub fn has_notification_handler<T: notification::Notification>(&self) -> bool {
 947        self.notification_handlers.lock().contains_key(T::METHOD)
 948    }
 949
 950    #[must_use]
 951    fn on_custom_notification<Params, F>(&self, method: &'static str, mut f: F) -> Subscription
 952    where
 953        F: 'static + FnMut(Params, AsyncApp) + Send,
 954        Params: DeserializeOwned,
 955    {
 956        let prev_handler = self.notification_handlers.lock().insert(
 957            method,
 958            Box::new(move |_, params, cx| {
 959                if let Some(params) = serde_json::from_value(params).log_err() {
 960                    f(params, cx);
 961                }
 962            }),
 963        );
 964        assert!(
 965            prev_handler.is_none(),
 966            "registered multiple handlers for the same LSP method"
 967        );
 968        Subscription::Notification {
 969            method,
 970            notification_handlers: Some(self.notification_handlers.clone()),
 971        }
 972    }
 973
 974    #[must_use]
 975    fn on_custom_request<Params, Res, Fut, F>(&self, method: &'static str, mut f: F) -> Subscription
 976    where
 977        F: 'static + FnMut(Params, AsyncApp) -> Fut + Send,
 978        Fut: 'static + Future<Output = Result<Res>>,
 979        Params: DeserializeOwned + Send + 'static,
 980        Res: Serialize,
 981    {
 982        let outbound_tx = self.outbound_tx.clone();
 983        let prev_handler = self.notification_handlers.lock().insert(
 984            method,
 985            Box::new(move |id, params, cx| {
 986                if let Some(id) = id {
 987                    match serde_json::from_value(params) {
 988                        Ok(params) => {
 989                            let response = f(params, cx.clone());
 990                            cx.foreground_executor()
 991                                .spawn({
 992                                    let outbound_tx = outbound_tx.clone();
 993                                    async move {
 994                                        let response = match response.await {
 995                                            Ok(result) => Response {
 996                                                jsonrpc: JSON_RPC_VERSION,
 997                                                id,
 998                                                value: LspResult::Ok(Some(result)),
 999                                            },
1000                                            Err(error) => Response {
1001                                                jsonrpc: JSON_RPC_VERSION,
1002                                                id,
1003                                                value: LspResult::Error(Some(Error {
1004                                                    message: error.to_string(),
1005                                                })),
1006                                            },
1007                                        };
1008                                        if let Some(response) =
1009                                            serde_json::to_string(&response).log_err()
1010                                        {
1011                                            outbound_tx.try_send(response).ok();
1012                                        }
1013                                    }
1014                                })
1015                                .detach();
1016                        }
1017
1018                        Err(error) => {
1019                            log::error!("error deserializing {} request: {:?}", method, error);
1020                            let response = AnyResponse {
1021                                jsonrpc: JSON_RPC_VERSION,
1022                                id,
1023                                result: None,
1024                                error: Some(Error {
1025                                    message: error.to_string(),
1026                                }),
1027                            };
1028                            if let Some(response) = serde_json::to_string(&response).log_err() {
1029                                outbound_tx.try_send(response).ok();
1030                            }
1031                        }
1032                    }
1033                }
1034            }),
1035        );
1036        assert!(
1037            prev_handler.is_none(),
1038            "registered multiple handlers for the same LSP method"
1039        );
1040        Subscription::Notification {
1041            method,
1042            notification_handlers: Some(self.notification_handlers.clone()),
1043        }
1044    }
1045
1046    /// Get the name of the running language server.
1047    pub fn name(&self) -> LanguageServerName {
1048        self.name.clone()
1049    }
1050
1051    pub fn process_name(&self) -> &str {
1052        &self.process_name
1053    }
1054
1055    /// Get the reported capabilities of the running language server.
1056    pub fn capabilities(&self) -> ServerCapabilities {
1057        self.capabilities.read().clone()
1058    }
1059
1060    /// Get the reported capabilities of the running language server and
1061    /// what we know on the client/adapter-side of its capabilities.
1062    pub fn adapter_server_capabilities(&self) -> AdapterServerCapabilities {
1063        AdapterServerCapabilities {
1064            server_capabilities: self.capabilities(),
1065            code_action_kinds: self.code_action_kinds(),
1066        }
1067    }
1068
1069    pub fn update_capabilities(&self, update: impl FnOnce(&mut ServerCapabilities)) {
1070        update(self.capabilities.write().deref_mut());
1071    }
1072
1073    pub fn configuration(&self) -> &Value {
1074        &self.configuration.settings
1075    }
1076
1077    /// Get the id of the running language server.
1078    pub fn server_id(&self) -> LanguageServerId {
1079        self.server_id
1080    }
1081
1082    /// Language server's binary information.
1083    pub fn binary(&self) -> &LanguageServerBinary {
1084        &self.binary
1085    }
1086    /// Sends a RPC request to the language server.
1087    ///
1088    /// [LSP Specification](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#requestMessage)
1089    pub fn request<T: request::Request>(
1090        &self,
1091        params: T::Params,
1092    ) -> impl LspRequestFuture<Result<T::Result>>
1093    where
1094        T::Result: 'static + Send,
1095    {
1096        Self::request_internal::<T>(
1097            &self.next_id,
1098            &self.response_handlers,
1099            &self.outbound_tx,
1100            &self.executor,
1101            params,
1102        )
1103    }
1104
1105    fn request_internal<T: request::Request>(
1106        next_id: &AtomicI32,
1107        response_handlers: &Mutex<Option<HashMap<RequestId, ResponseHandler>>>,
1108        outbound_tx: &channel::Sender<String>,
1109        executor: &BackgroundExecutor,
1110        params: T::Params,
1111    ) -> impl LspRequestFuture<Result<T::Result>>
1112    where
1113        T::Result: 'static + Send,
1114    {
1115        let id = next_id.fetch_add(1, SeqCst);
1116        let message = serde_json::to_string(&Request {
1117            jsonrpc: JSON_RPC_VERSION,
1118            id: RequestId::Int(id),
1119            method: T::METHOD,
1120            params,
1121        })
1122        .unwrap();
1123
1124        let (tx, rx) = oneshot::channel();
1125        let handle_response = response_handlers
1126            .lock()
1127            .as_mut()
1128            .ok_or_else(|| anyhow!("server shut down"))
1129            .map(|handlers| {
1130                let executor = executor.clone();
1131                handlers.insert(
1132                    RequestId::Int(id),
1133                    Box::new(move |result| {
1134                        executor
1135                            .spawn(async move {
1136                                let response = match result {
1137                                    Ok(response) => match serde_json::from_str(&response) {
1138                                        Ok(deserialized) => Ok(deserialized),
1139                                        Err(error) => {
1140                                            log::error!("failed to deserialize response from language server: {}. response from language server: {:?}", error, response);
1141                                            Err(error).context("failed to deserialize response")
1142                                        }
1143                                    }
1144                                    Err(error) => Err(anyhow!("{}", error.message)),
1145                                };
1146                                _ = tx.send(response);
1147                            })
1148                            .detach();
1149                    }),
1150                );
1151            });
1152
1153        let send = outbound_tx
1154            .try_send(message)
1155            .context("failed to write to language server's stdin");
1156
1157        let outbound_tx = outbound_tx.downgrade();
1158        let mut timeout = executor.timer(LSP_REQUEST_TIMEOUT).fuse();
1159        let started = Instant::now();
1160        LspRequest::new(id, async move {
1161            handle_response?;
1162            send?;
1163
1164            let cancel_on_drop = util::defer(move || {
1165                if let Some(outbound_tx) = outbound_tx.upgrade() {
1166                    Self::notify_internal::<notification::Cancel>(
1167                        &outbound_tx,
1168                        &CancelParams {
1169                            id: NumberOrString::Number(id),
1170                        },
1171                    )
1172                    .log_err();
1173                }
1174            });
1175
1176            let method = T::METHOD;
1177            select! {
1178                response = rx.fuse() => {
1179                    let elapsed = started.elapsed();
1180                    log::trace!("Took {elapsed:?} to receive response to {method:?} id {id}");
1181                    cancel_on_drop.abort();
1182                    response?
1183                }
1184
1185                _ = timeout => {
1186                    log::error!("Cancelled LSP request task for {method:?} id {id} which took over {LSP_REQUEST_TIMEOUT:?}");
1187                    anyhow::bail!("LSP request timeout");
1188                }
1189            }
1190        })
1191    }
1192
1193    /// Sends a RPC notification to the language server.
1194    ///
1195    /// [LSP Specification](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#notificationMessage)
1196    pub fn notify<T: notification::Notification>(&self, params: &T::Params) -> Result<()> {
1197        Self::notify_internal::<T>(&self.outbound_tx, params)
1198    }
1199
1200    fn notify_internal<T: notification::Notification>(
1201        outbound_tx: &channel::Sender<String>,
1202        params: &T::Params,
1203    ) -> Result<()> {
1204        let message = serde_json::to_string(&Notification {
1205            jsonrpc: JSON_RPC_VERSION,
1206            method: T::METHOD,
1207            params,
1208        })
1209        .unwrap();
1210        outbound_tx.try_send(message)?;
1211        Ok(())
1212    }
1213
1214    /// Add new workspace folder to the list.
1215    pub fn add_workspace_folder(&self, uri: Url) {
1216        if self
1217            .capabilities()
1218            .workspace
1219            .and_then(|ws| {
1220                ws.workspace_folders.and_then(|folders| {
1221                    folders
1222                        .change_notifications
1223                        .map(|caps| matches!(caps, OneOf::Left(false)))
1224                })
1225            })
1226            .unwrap_or(true)
1227        {
1228            return;
1229        }
1230
1231        let is_new_folder = self.workspace_folders.lock().insert(uri.clone());
1232        if is_new_folder {
1233            let params = DidChangeWorkspaceFoldersParams {
1234                event: WorkspaceFoldersChangeEvent {
1235                    added: vec![WorkspaceFolder {
1236                        uri,
1237                        name: String::default(),
1238                    }],
1239                    removed: vec![],
1240                },
1241            };
1242            self.notify::<DidChangeWorkspaceFolders>(&params).log_err();
1243        }
1244    }
1245    /// Add new workspace folder to the list.
1246    pub fn remove_workspace_folder(&self, uri: Url) {
1247        if self
1248            .capabilities()
1249            .workspace
1250            .and_then(|ws| {
1251                ws.workspace_folders.and_then(|folders| {
1252                    folders
1253                        .change_notifications
1254                        .map(|caps| !matches!(caps, OneOf::Left(false)))
1255                })
1256            })
1257            .unwrap_or(true)
1258        {
1259            return;
1260        }
1261        let was_removed = self.workspace_folders.lock().remove(&uri);
1262        if was_removed {
1263            let params = DidChangeWorkspaceFoldersParams {
1264                event: WorkspaceFoldersChangeEvent {
1265                    added: vec![],
1266                    removed: vec![WorkspaceFolder {
1267                        uri,
1268                        name: String::default(),
1269                    }],
1270                },
1271            };
1272            self.notify::<DidChangeWorkspaceFolders>(&params).log_err();
1273        }
1274    }
1275    pub fn set_workspace_folders(&self, folders: BTreeSet<Url>) {
1276        let mut workspace_folders = self.workspace_folders.lock();
1277
1278        let old_workspace_folders = std::mem::take(&mut *workspace_folders);
1279        let added: Vec<_> = folders
1280            .difference(&old_workspace_folders)
1281            .map(|uri| WorkspaceFolder {
1282                uri: uri.clone(),
1283                name: String::default(),
1284            })
1285            .collect();
1286
1287        let removed: Vec<_> = old_workspace_folders
1288            .difference(&folders)
1289            .map(|uri| WorkspaceFolder {
1290                uri: uri.clone(),
1291                name: String::default(),
1292            })
1293            .collect();
1294        let should_notify = !added.is_empty() || !removed.is_empty();
1295        if should_notify {
1296            *workspace_folders = folders;
1297            drop(workspace_folders);
1298            let params = DidChangeWorkspaceFoldersParams {
1299                event: WorkspaceFoldersChangeEvent { added, removed },
1300            };
1301            self.notify::<DidChangeWorkspaceFolders>(&params).log_err();
1302        }
1303    }
1304
1305    pub fn workspace_folders(&self) -> impl Deref<Target = BTreeSet<Url>> + '_ {
1306        self.workspace_folders.lock()
1307    }
1308
1309    pub fn register_buffer(
1310        &self,
1311        uri: Url,
1312        language_id: String,
1313        version: i32,
1314        initial_text: String,
1315    ) {
1316        self.notify::<notification::DidOpenTextDocument>(&DidOpenTextDocumentParams {
1317            text_document: TextDocumentItem::new(uri, language_id, version, initial_text),
1318        })
1319        .log_err();
1320    }
1321
1322    pub fn unregister_buffer(&self, uri: Url) {
1323        self.notify::<notification::DidCloseTextDocument>(&DidCloseTextDocumentParams {
1324            text_document: TextDocumentIdentifier::new(uri),
1325        })
1326        .log_err();
1327    }
1328}
1329
1330impl Drop for LanguageServer {
1331    fn drop(&mut self) {
1332        if let Some(shutdown) = self.shutdown() {
1333            self.executor.spawn(shutdown).detach();
1334        }
1335    }
1336}
1337
1338impl Subscription {
1339    /// Detaching a subscription handle prevents it from unsubscribing on drop.
1340    pub fn detach(&mut self) {
1341        match self {
1342            Subscription::Notification {
1343                notification_handlers,
1344                ..
1345            } => *notification_handlers = None,
1346            Subscription::Io { io_handlers, .. } => *io_handlers = None,
1347        }
1348    }
1349}
1350
1351impl fmt::Display for LanguageServerId {
1352    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1353        self.0.fmt(f)
1354    }
1355}
1356
1357impl fmt::Debug for LanguageServer {
1358    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1359        f.debug_struct("LanguageServer")
1360            .field("id", &self.server_id.0)
1361            .field("name", &self.name)
1362            .finish_non_exhaustive()
1363    }
1364}
1365
1366impl Drop for Subscription {
1367    fn drop(&mut self) {
1368        match self {
1369            Subscription::Notification {
1370                method,
1371                notification_handlers,
1372            } => {
1373                if let Some(handlers) = notification_handlers {
1374                    handlers.lock().remove(method);
1375                }
1376            }
1377            Subscription::Io { id, io_handlers } => {
1378                if let Some(io_handlers) = io_handlers.as_ref().and_then(|h| h.upgrade()) {
1379                    io_handlers.lock().remove(id);
1380                }
1381            }
1382        }
1383    }
1384}
1385
1386/// Mock language server for use in tests.
1387#[cfg(any(test, feature = "test-support"))]
1388#[derive(Clone)]
1389pub struct FakeLanguageServer {
1390    pub binary: LanguageServerBinary,
1391    pub server: Arc<LanguageServer>,
1392    notifications_rx: channel::Receiver<(String, String)>,
1393}
1394
1395#[cfg(any(test, feature = "test-support"))]
1396impl FakeLanguageServer {
1397    /// Construct a fake language server.
1398    pub fn new(
1399        server_id: LanguageServerId,
1400        binary: LanguageServerBinary,
1401        name: String,
1402        capabilities: ServerCapabilities,
1403        cx: AsyncApp,
1404    ) -> (LanguageServer, FakeLanguageServer) {
1405        let (stdin_writer, stdin_reader) = async_pipe::pipe();
1406        let (stdout_writer, stdout_reader) = async_pipe::pipe();
1407        let (notifications_tx, notifications_rx) = channel::unbounded();
1408
1409        let server_name = LanguageServerName(name.clone().into());
1410        let process_name = Arc::from(name.as_str());
1411        let root = Self::root_path();
1412        let workspace_folders: Arc<Mutex<BTreeSet<Url>>> = Default::default();
1413        let mut server = LanguageServer::new_internal(
1414            server_id,
1415            server_name.clone(),
1416            stdin_writer,
1417            stdout_reader,
1418            None::<async_pipe::PipeReader>,
1419            Arc::new(Mutex::new(None)),
1420            None,
1421            None,
1422            binary.clone(),
1423            root,
1424            workspace_folders.clone(),
1425            cx.clone(),
1426            |_| {},
1427        );
1428        server.process_name = process_name;
1429        let fake = FakeLanguageServer {
1430            binary: binary.clone(),
1431            server: Arc::new({
1432                let mut server = LanguageServer::new_internal(
1433                    server_id,
1434                    server_name,
1435                    stdout_writer,
1436                    stdin_reader,
1437                    None::<async_pipe::PipeReader>,
1438                    Arc::new(Mutex::new(None)),
1439                    None,
1440                    None,
1441                    binary,
1442                    Self::root_path(),
1443                    workspace_folders,
1444                    cx.clone(),
1445                    move |msg| {
1446                        notifications_tx
1447                            .try_send((
1448                                msg.method.to_string(),
1449                                msg.params.unwrap_or(Value::Null).to_string(),
1450                            ))
1451                            .ok();
1452                    },
1453                );
1454                server.process_name = name.as_str().into();
1455                server
1456            }),
1457            notifications_rx,
1458        };
1459        fake.handle_request::<request::Initialize, _, _>({
1460            let capabilities = capabilities;
1461            move |_, _| {
1462                let capabilities = capabilities.clone();
1463                let name = name.clone();
1464                async move {
1465                    Ok(InitializeResult {
1466                        capabilities,
1467                        server_info: Some(ServerInfo {
1468                            name,
1469                            ..Default::default()
1470                        }),
1471                    })
1472                }
1473            }
1474        });
1475
1476        (server, fake)
1477    }
1478    #[cfg(target_os = "windows")]
1479    fn root_path() -> Url {
1480        Url::from_file_path("C:/").unwrap()
1481    }
1482
1483    #[cfg(not(target_os = "windows"))]
1484    fn root_path() -> Url {
1485        Url::from_file_path("/").unwrap()
1486    }
1487}
1488
1489#[cfg(any(test, feature = "test-support"))]
1490impl LanguageServer {
1491    pub fn full_capabilities() -> ServerCapabilities {
1492        ServerCapabilities {
1493            document_highlight_provider: Some(OneOf::Left(true)),
1494            code_action_provider: Some(CodeActionProviderCapability::Simple(true)),
1495            document_formatting_provider: Some(OneOf::Left(true)),
1496            document_range_formatting_provider: Some(OneOf::Left(true)),
1497            definition_provider: Some(OneOf::Left(true)),
1498            implementation_provider: Some(ImplementationProviderCapability::Simple(true)),
1499            type_definition_provider: Some(TypeDefinitionProviderCapability::Simple(true)),
1500            ..Default::default()
1501        }
1502    }
1503}
1504
1505#[cfg(any(test, feature = "test-support"))]
1506impl FakeLanguageServer {
1507    /// See [`LanguageServer::notify`].
1508    pub fn notify<T: notification::Notification>(&self, params: &T::Params) {
1509        self.server.notify::<T>(params).ok();
1510    }
1511
1512    /// See [`LanguageServer::request`].
1513    pub async fn request<T>(&self, params: T::Params) -> Result<T::Result>
1514    where
1515        T: request::Request,
1516        T::Result: 'static + Send,
1517    {
1518        self.server.executor.start_waiting();
1519        self.server.request::<T>(params).await
1520    }
1521
1522    /// Attempts [`Self::try_receive_notification`], unwrapping if it has not received the specified type yet.
1523    pub async fn receive_notification<T: notification::Notification>(&mut self) -> T::Params {
1524        self.server.executor.start_waiting();
1525        self.try_receive_notification::<T>().await.unwrap()
1526    }
1527
1528    /// Consumes the notification channel until it finds a notification for the specified type.
1529    pub async fn try_receive_notification<T: notification::Notification>(
1530        &mut self,
1531    ) -> Option<T::Params> {
1532        loop {
1533            let (method, params) = self.notifications_rx.recv().await.ok()?;
1534            if method == T::METHOD {
1535                return Some(serde_json::from_str::<T::Params>(&params).unwrap());
1536            } else {
1537                log::info!("skipping message in fake language server {:?}", params);
1538            }
1539        }
1540    }
1541
1542    /// Registers a handler for a specific kind of request. Removes any existing handler for specified request type.
1543    pub fn handle_request<T, F, Fut>(
1544        &self,
1545        mut handler: F,
1546    ) -> futures::channel::mpsc::UnboundedReceiver<()>
1547    where
1548        T: 'static + request::Request,
1549        T::Params: 'static + Send,
1550        F: 'static + Send + FnMut(T::Params, gpui::AsyncApp) -> Fut,
1551        Fut: 'static + Send + Future<Output = Result<T::Result>>,
1552    {
1553        let (responded_tx, responded_rx) = futures::channel::mpsc::unbounded();
1554        self.server.remove_request_handler::<T>();
1555        self.server
1556            .on_request::<T, _, _>(move |params, cx| {
1557                let result = handler(params, cx.clone());
1558                let responded_tx = responded_tx.clone();
1559                let executor = cx.background_executor().clone();
1560                async move {
1561                    executor.simulate_random_delay().await;
1562                    let result = result.await;
1563                    responded_tx.unbounded_send(()).ok();
1564                    result
1565                }
1566            })
1567            .detach();
1568        responded_rx
1569    }
1570
1571    /// Registers a handler for a specific kind of notification. Removes any existing handler for specified notification type.
1572    pub fn handle_notification<T, F>(
1573        &self,
1574        mut handler: F,
1575    ) -> futures::channel::mpsc::UnboundedReceiver<()>
1576    where
1577        T: 'static + notification::Notification,
1578        T::Params: 'static + Send,
1579        F: 'static + Send + FnMut(T::Params, gpui::AsyncApp),
1580    {
1581        let (handled_tx, handled_rx) = futures::channel::mpsc::unbounded();
1582        self.server.remove_notification_handler::<T>();
1583        self.server
1584            .on_notification::<T, _>(move |params, cx| {
1585                handler(params, cx.clone());
1586                handled_tx.unbounded_send(()).ok();
1587            })
1588            .detach();
1589        handled_rx
1590    }
1591
1592    /// Removes any existing handler for specified notification type.
1593    pub fn remove_request_handler<T>(&mut self)
1594    where
1595        T: 'static + request::Request,
1596    {
1597        self.server.remove_request_handler::<T>();
1598    }
1599
1600    /// Simulate that the server has started work and notifies about its progress with the specified token.
1601    pub async fn start_progress(&self, token: impl Into<String>) {
1602        self.start_progress_with(token, Default::default()).await
1603    }
1604
1605    pub async fn start_progress_with(
1606        &self,
1607        token: impl Into<String>,
1608        progress: WorkDoneProgressBegin,
1609    ) {
1610        let token = token.into();
1611        self.request::<request::WorkDoneProgressCreate>(WorkDoneProgressCreateParams {
1612            token: NumberOrString::String(token.clone()),
1613        })
1614        .await
1615        .unwrap();
1616        self.notify::<notification::Progress>(&ProgressParams {
1617            token: NumberOrString::String(token),
1618            value: ProgressParamsValue::WorkDone(WorkDoneProgress::Begin(progress)),
1619        });
1620    }
1621
1622    /// Simulate that the server has completed work and notifies about that with the specified token.
1623    pub fn end_progress(&self, token: impl Into<String>) {
1624        self.notify::<notification::Progress>(&ProgressParams {
1625            token: NumberOrString::String(token.into()),
1626            value: ProgressParamsValue::WorkDone(WorkDoneProgress::End(Default::default())),
1627        });
1628    }
1629}
1630
1631#[cfg(test)]
1632mod tests {
1633    use super::*;
1634    use gpui::{SemanticVersion, TestAppContext};
1635    use std::str::FromStr;
1636
1637    #[ctor::ctor]
1638    fn init_logger() {
1639        if std::env::var("RUST_LOG").is_ok() {
1640            env_logger::init();
1641        }
1642    }
1643
1644    #[gpui::test]
1645    async fn test_fake(cx: &mut TestAppContext) {
1646        cx.update(|cx| {
1647            release_channel::init(SemanticVersion::default(), cx);
1648        });
1649        let (server, mut fake) = FakeLanguageServer::new(
1650            LanguageServerId(0),
1651            LanguageServerBinary {
1652                path: "path/to/language-server".into(),
1653                arguments: vec![],
1654                env: None,
1655            },
1656            "the-lsp".to_string(),
1657            Default::default(),
1658            cx.to_async(),
1659        );
1660
1661        let (message_tx, message_rx) = channel::unbounded();
1662        let (diagnostics_tx, diagnostics_rx) = channel::unbounded();
1663        server
1664            .on_notification::<notification::ShowMessage, _>(move |params, _| {
1665                message_tx.try_send(params).unwrap()
1666            })
1667            .detach();
1668        server
1669            .on_notification::<notification::PublishDiagnostics, _>(move |params, _| {
1670                diagnostics_tx.try_send(params).unwrap()
1671            })
1672            .detach();
1673
1674        let server = cx
1675            .update(|cx| {
1676                let params = server.default_initialize_params(cx);
1677                let configuration = DidChangeConfigurationParams {
1678                    settings: Default::default(),
1679                };
1680                server.initialize(params, configuration.into(), cx)
1681            })
1682            .await
1683            .unwrap();
1684        server
1685            .notify::<notification::DidOpenTextDocument>(&DidOpenTextDocumentParams {
1686                text_document: TextDocumentItem::new(
1687                    Url::from_str("file://a/b").unwrap(),
1688                    "rust".to_string(),
1689                    0,
1690                    "".to_string(),
1691                ),
1692            })
1693            .unwrap();
1694        assert_eq!(
1695            fake.receive_notification::<notification::DidOpenTextDocument>()
1696                .await
1697                .text_document
1698                .uri
1699                .as_str(),
1700            "file://a/b"
1701        );
1702
1703        fake.notify::<notification::ShowMessage>(&ShowMessageParams {
1704            typ: MessageType::ERROR,
1705            message: "ok".to_string(),
1706        });
1707        fake.notify::<notification::PublishDiagnostics>(&PublishDiagnosticsParams {
1708            uri: Url::from_str("file://b/c").unwrap(),
1709            version: Some(5),
1710            diagnostics: vec![],
1711        });
1712        assert_eq!(message_rx.recv().await.unwrap().message, "ok");
1713        assert_eq!(
1714            diagnostics_rx.recv().await.unwrap().uri.as_str(),
1715            "file://b/c"
1716        );
1717
1718        fake.handle_request::<request::Shutdown, _, _>(|_, _| async move { Ok(()) });
1719
1720        drop(server);
1721        fake.receive_notification::<notification::Exit>().await;
1722    }
1723
1724    #[gpui::test]
1725    fn test_deserialize_string_digit_id() {
1726        let json = r#"{"jsonrpc":"2.0","id":"2","method":"workspace/configuration","params":{"items":[{"scopeUri":"file:///Users/mph/Devel/personal/hello-scala/","section":"metals"}]}}"#;
1727        let notification = serde_json::from_str::<AnyNotification>(json)
1728            .expect("message with string id should be parsed");
1729        let expected_id = RequestId::Str("2".to_string());
1730        assert_eq!(notification.id, Some(expected_id));
1731    }
1732
1733    #[gpui::test]
1734    fn test_deserialize_string_id() {
1735        let json = r#"{"jsonrpc":"2.0","id":"anythingAtAll","method":"workspace/configuration","params":{"items":[{"scopeUri":"file:///Users/mph/Devel/personal/hello-scala/","section":"metals"}]}}"#;
1736        let notification = serde_json::from_str::<AnyNotification>(json)
1737            .expect("message with string id should be parsed");
1738        let expected_id = RequestId::Str("anythingAtAll".to_string());
1739        assert_eq!(notification.id, Some(expected_id));
1740    }
1741
1742    #[gpui::test]
1743    fn test_deserialize_int_id() {
1744        let json = r#"{"jsonrpc":"2.0","id":2,"method":"workspace/configuration","params":{"items":[{"scopeUri":"file:///Users/mph/Devel/personal/hello-scala/","section":"metals"}]}}"#;
1745        let notification = serde_json::from_str::<AnyNotification>(json)
1746            .expect("message with string id should be parsed");
1747        let expected_id = RequestId::Int(2);
1748        assert_eq!(notification.id, Some(expected_id));
1749    }
1750
1751    #[test]
1752    fn test_serialize_has_no_nulls() {
1753        // Ensure we're not setting both result and error variants. (ticket #10595)
1754        let no_tag = Response::<u32> {
1755            jsonrpc: "",
1756            id: RequestId::Int(0),
1757            value: LspResult::Ok(None),
1758        };
1759        assert_eq!(
1760            serde_json::to_string(&no_tag).unwrap(),
1761            "{\"jsonrpc\":\"\",\"id\":0,\"result\":null}"
1762        );
1763        let no_tag = Response::<u32> {
1764            jsonrpc: "",
1765            id: RequestId::Int(0),
1766            value: LspResult::Error(None),
1767        };
1768        assert_eq!(
1769            serde_json::to_string(&no_tag).unwrap(),
1770            "{\"jsonrpc\":\"\",\"id\":0,\"error\":null}"
1771        );
1772    }
1773}