lsp_command.rs

   1mod signature_help;
   2
   3use crate::{
   4    CodeAction, CompletionSource, CoreCompletion, CoreCompletionResponse, DocumentColor,
   5    DocumentHighlight, DocumentSymbol, Hover, HoverBlock, HoverBlockKind, InlayHint,
   6    InlayHintLabel, InlayHintLabelPart, InlayHintLabelPartTooltip, InlayHintTooltip, Location,
   7    LocationLink, LspAction, LspPullDiagnostics, MarkupContent, PrepareRenameResponse,
   8    ProjectTransaction, PulledDiagnostics, ResolveState,
   9    lsp_store::{LocalLspStore, LspStore},
  10};
  11use anyhow::{Context as _, Result};
  12use async_trait::async_trait;
  13use client::proto::{self, PeerId};
  14use clock::Global;
  15use collections::{HashMap, HashSet};
  16use futures::future;
  17use gpui::{App, AsyncApp, Entity, Task};
  18use language::{
  19    Anchor, Bias, Buffer, BufferSnapshot, CachedLspAdapter, CharKind, CharScopeContext,
  20    OffsetRangeExt, PointUtf16, ToOffset, ToPointUtf16, Transaction, Unclipped,
  21    language_settings::{InlayHintKind, LanguageSettings, language_settings},
  22    point_from_lsp, point_to_lsp,
  23    proto::{deserialize_anchor, deserialize_version, serialize_anchor, serialize_version},
  24    range_from_lsp, range_to_lsp,
  25};
  26use lsp::{
  27    AdapterServerCapabilities, CodeActionKind, CodeActionOptions, CodeDescription,
  28    CompletionContext, CompletionListItemDefaultsEditRange, CompletionTriggerKind,
  29    DiagnosticServerCapabilities, DocumentHighlightKind, LanguageServer, LanguageServerId,
  30    LinkedEditingRangeServerCapabilities, OneOf, RenameOptions, ServerCapabilities,
  31};
  32use serde::{Deserialize, Serialize};
  33use serde_json::Value;
  34use signature_help::{lsp_to_proto_signature, proto_to_lsp_signature};
  35use std::{
  36    cmp::Reverse, collections::hash_map, mem, ops::Range, path::Path, str::FromStr, sync::Arc,
  37};
  38use text::{BufferId, LineEnding};
  39use util::{ResultExt as _, debug_panic};
  40
  41pub use signature_help::SignatureHelp;
  42
  43pub fn lsp_formatting_options(settings: &LanguageSettings) -> lsp::FormattingOptions {
  44    lsp::FormattingOptions {
  45        tab_size: settings.tab_size.into(),
  46        insert_spaces: !settings.hard_tabs,
  47        trim_trailing_whitespace: Some(settings.remove_trailing_whitespace_on_save),
  48        trim_final_newlines: Some(settings.ensure_final_newline_on_save),
  49        insert_final_newline: Some(settings.ensure_final_newline_on_save),
  50        ..lsp::FormattingOptions::default()
  51    }
  52}
  53
  54pub fn file_path_to_lsp_url(path: &Path) -> Result<lsp::Uri> {
  55    match lsp::Uri::from_file_path(path) {
  56        Ok(url) => Ok(url),
  57        Err(()) => anyhow::bail!("Invalid file path provided to LSP request: {path:?}"),
  58    }
  59}
  60
  61pub(crate) fn make_text_document_identifier(path: &Path) -> Result<lsp::TextDocumentIdentifier> {
  62    Ok(lsp::TextDocumentIdentifier {
  63        uri: file_path_to_lsp_url(path)?,
  64    })
  65}
  66
  67pub(crate) fn make_lsp_text_document_position(
  68    path: &Path,
  69    position: PointUtf16,
  70) -> Result<lsp::TextDocumentPositionParams> {
  71    Ok(lsp::TextDocumentPositionParams {
  72        text_document: make_text_document_identifier(path)?,
  73        position: point_to_lsp(position),
  74    })
  75}
  76
  77#[async_trait(?Send)]
  78pub trait LspCommand: 'static + Sized + Send + std::fmt::Debug {
  79    type Response: 'static + Default + Send + std::fmt::Debug;
  80    type LspRequest: 'static + Send + lsp::request::Request;
  81    type ProtoRequest: 'static + Send + proto::RequestMessage;
  82
  83    fn display_name(&self) -> &str;
  84
  85    fn status(&self) -> Option<String> {
  86        None
  87    }
  88
  89    fn to_lsp_params_or_response(
  90        &self,
  91        path: &Path,
  92        buffer: &Buffer,
  93        language_server: &Arc<LanguageServer>,
  94        cx: &App,
  95    ) -> Result<
  96        LspParamsOrResponse<<Self::LspRequest as lsp::request::Request>::Params, Self::Response>,
  97    > {
  98        if self.check_capabilities(language_server.adapter_server_capabilities()) {
  99            Ok(LspParamsOrResponse::Params(self.to_lsp(
 100                path,
 101                buffer,
 102                language_server,
 103                cx,
 104            )?))
 105        } else {
 106            Ok(LspParamsOrResponse::Response(Default::default()))
 107        }
 108    }
 109
 110    /// When false, `to_lsp_params_or_response` default implementation will return the default response.
 111    fn check_capabilities(&self, _: AdapterServerCapabilities) -> bool;
 112
 113    fn to_lsp(
 114        &self,
 115        path: &Path,
 116        buffer: &Buffer,
 117        language_server: &Arc<LanguageServer>,
 118        cx: &App,
 119    ) -> Result<<Self::LspRequest as lsp::request::Request>::Params>;
 120
 121    async fn response_from_lsp(
 122        self,
 123        message: <Self::LspRequest as lsp::request::Request>::Result,
 124        lsp_store: Entity<LspStore>,
 125        buffer: Entity<Buffer>,
 126        server_id: LanguageServerId,
 127        cx: AsyncApp,
 128    ) -> Result<Self::Response>;
 129
 130    fn to_proto(&self, project_id: u64, buffer: &Buffer) -> Self::ProtoRequest;
 131
 132    async fn from_proto(
 133        message: Self::ProtoRequest,
 134        lsp_store: Entity<LspStore>,
 135        buffer: Entity<Buffer>,
 136        cx: AsyncApp,
 137    ) -> Result<Self>;
 138
 139    fn response_to_proto(
 140        response: Self::Response,
 141        lsp_store: &mut LspStore,
 142        peer_id: PeerId,
 143        buffer_version: &clock::Global,
 144        cx: &mut App,
 145    ) -> <Self::ProtoRequest as proto::RequestMessage>::Response;
 146
 147    async fn response_from_proto(
 148        self,
 149        message: <Self::ProtoRequest as proto::RequestMessage>::Response,
 150        lsp_store: Entity<LspStore>,
 151        buffer: Entity<Buffer>,
 152        cx: AsyncApp,
 153    ) -> Result<Self::Response>;
 154
 155    fn buffer_id_from_proto(message: &Self::ProtoRequest) -> Result<BufferId>;
 156}
 157
 158pub enum LspParamsOrResponse<P, R> {
 159    Params(P),
 160    Response(R),
 161}
 162
 163#[derive(Debug)]
 164pub(crate) struct PrepareRename {
 165    pub position: PointUtf16,
 166}
 167
 168#[derive(Debug)]
 169pub(crate) struct PerformRename {
 170    pub position: PointUtf16,
 171    pub new_name: String,
 172    pub push_to_history: bool,
 173}
 174
 175#[derive(Debug, Clone, Copy)]
 176pub struct GetDefinitions {
 177    pub position: PointUtf16,
 178}
 179
 180#[derive(Debug, Clone, Copy)]
 181pub(crate) struct GetDeclarations {
 182    pub position: PointUtf16,
 183}
 184
 185#[derive(Debug, Clone, Copy)]
 186pub(crate) struct GetTypeDefinitions {
 187    pub position: PointUtf16,
 188}
 189
 190#[derive(Debug, Clone, Copy)]
 191pub(crate) struct GetImplementations {
 192    pub position: PointUtf16,
 193}
 194
 195#[derive(Debug, Clone, Copy)]
 196pub(crate) struct GetReferences {
 197    pub position: PointUtf16,
 198}
 199
 200#[derive(Debug)]
 201pub(crate) struct GetDocumentHighlights {
 202    pub position: PointUtf16,
 203}
 204
 205#[derive(Debug, Copy, Clone)]
 206pub(crate) struct GetDocumentSymbols;
 207
 208#[derive(Clone, Debug)]
 209pub(crate) struct GetSignatureHelp {
 210    pub position: PointUtf16,
 211}
 212
 213#[derive(Clone, Debug)]
 214pub(crate) struct GetHover {
 215    pub position: PointUtf16,
 216}
 217
 218#[derive(Debug)]
 219pub(crate) struct GetCompletions {
 220    pub position: PointUtf16,
 221    pub context: CompletionContext,
 222}
 223
 224#[derive(Clone, Debug)]
 225pub(crate) struct GetCodeActions {
 226    pub range: Range<Anchor>,
 227    pub kinds: Option<Vec<lsp::CodeActionKind>>,
 228}
 229
 230#[derive(Debug)]
 231pub(crate) struct OnTypeFormatting {
 232    pub position: PointUtf16,
 233    pub trigger: String,
 234    pub options: lsp::FormattingOptions,
 235    pub push_to_history: bool,
 236}
 237
 238#[derive(Clone, Debug)]
 239pub(crate) struct InlayHints {
 240    pub range: Range<Anchor>,
 241}
 242
 243#[derive(Debug, Copy, Clone)]
 244pub(crate) struct GetCodeLens;
 245
 246#[derive(Debug, Copy, Clone)]
 247pub(crate) struct GetDocumentColor;
 248
 249impl GetCodeLens {
 250    pub(crate) fn can_resolve_lens(capabilities: &ServerCapabilities) -> bool {
 251        capabilities
 252            .code_lens_provider
 253            .as_ref()
 254            .and_then(|code_lens_options| code_lens_options.resolve_provider)
 255            .unwrap_or(false)
 256    }
 257}
 258
 259#[derive(Debug)]
 260pub(crate) struct LinkedEditingRange {
 261    pub position: Anchor,
 262}
 263
 264#[derive(Clone, Debug)]
 265pub(crate) struct GetDocumentDiagnostics {
 266    /// We cannot blindly rely on server's capabilities.diagnostic_provider, as they're a singular field, whereas
 267    /// a server can register multiple diagnostic providers post-mortem.
 268    pub dynamic_caps: DiagnosticServerCapabilities,
 269    pub previous_result_id: Option<String>,
 270}
 271
 272#[async_trait(?Send)]
 273impl LspCommand for PrepareRename {
 274    type Response = PrepareRenameResponse;
 275    type LspRequest = lsp::request::PrepareRenameRequest;
 276    type ProtoRequest = proto::PrepareRename;
 277
 278    fn display_name(&self) -> &str {
 279        "Prepare rename"
 280    }
 281
 282    fn check_capabilities(&self, capabilities: AdapterServerCapabilities) -> bool {
 283        capabilities
 284            .server_capabilities
 285            .rename_provider
 286            .is_some_and(|capability| match capability {
 287                OneOf::Left(enabled) => enabled,
 288                OneOf::Right(options) => options.prepare_provider.unwrap_or(false),
 289            })
 290    }
 291
 292    fn to_lsp_params_or_response(
 293        &self,
 294        path: &Path,
 295        buffer: &Buffer,
 296        language_server: &Arc<LanguageServer>,
 297        cx: &App,
 298    ) -> Result<LspParamsOrResponse<lsp::TextDocumentPositionParams, PrepareRenameResponse>> {
 299        let rename_provider = language_server
 300            .adapter_server_capabilities()
 301            .server_capabilities
 302            .rename_provider;
 303        match rename_provider {
 304            Some(lsp::OneOf::Right(RenameOptions {
 305                prepare_provider: Some(true),
 306                ..
 307            })) => Ok(LspParamsOrResponse::Params(self.to_lsp(
 308                path,
 309                buffer,
 310                language_server,
 311                cx,
 312            )?)),
 313            Some(lsp::OneOf::Right(_)) => Ok(LspParamsOrResponse::Response(
 314                PrepareRenameResponse::OnlyUnpreparedRenameSupported,
 315            )),
 316            Some(lsp::OneOf::Left(true)) => Ok(LspParamsOrResponse::Response(
 317                PrepareRenameResponse::OnlyUnpreparedRenameSupported,
 318            )),
 319            _ => anyhow::bail!("Rename not supported"),
 320        }
 321    }
 322
 323    fn to_lsp(
 324        &self,
 325        path: &Path,
 326        _: &Buffer,
 327        _: &Arc<LanguageServer>,
 328        _: &App,
 329    ) -> Result<lsp::TextDocumentPositionParams> {
 330        make_lsp_text_document_position(path, self.position)
 331    }
 332
 333    async fn response_from_lsp(
 334        self,
 335        message: Option<lsp::PrepareRenameResponse>,
 336        _: Entity<LspStore>,
 337        buffer: Entity<Buffer>,
 338        _: LanguageServerId,
 339        cx: AsyncApp,
 340    ) -> Result<PrepareRenameResponse> {
 341        buffer.read_with(&cx, |buffer, _| match message {
 342            Some(lsp::PrepareRenameResponse::Range(range))
 343            | Some(lsp::PrepareRenameResponse::RangeWithPlaceholder { range, .. }) => {
 344                let Range { start, end } = range_from_lsp(range);
 345                if buffer.clip_point_utf16(start, Bias::Left) == start.0
 346                    && buffer.clip_point_utf16(end, Bias::Left) == end.0
 347                {
 348                    Ok(PrepareRenameResponse::Success(
 349                        buffer.anchor_after(start)..buffer.anchor_before(end),
 350                    ))
 351                } else {
 352                    Ok(PrepareRenameResponse::InvalidPosition)
 353                }
 354            }
 355            Some(lsp::PrepareRenameResponse::DefaultBehavior { .. }) => {
 356                let snapshot = buffer.snapshot();
 357                let (range, _) = snapshot.surrounding_word(self.position, None);
 358                let range = snapshot.anchor_after(range.start)..snapshot.anchor_before(range.end);
 359                Ok(PrepareRenameResponse::Success(range))
 360            }
 361            None => Ok(PrepareRenameResponse::InvalidPosition),
 362        })?
 363    }
 364
 365    fn to_proto(&self, project_id: u64, buffer: &Buffer) -> proto::PrepareRename {
 366        proto::PrepareRename {
 367            project_id,
 368            buffer_id: buffer.remote_id().into(),
 369            position: Some(language::proto::serialize_anchor(
 370                &buffer.anchor_before(self.position),
 371            )),
 372            version: serialize_version(&buffer.version()),
 373        }
 374    }
 375
 376    async fn from_proto(
 377        message: proto::PrepareRename,
 378        _: Entity<LspStore>,
 379        buffer: Entity<Buffer>,
 380        mut cx: AsyncApp,
 381    ) -> Result<Self> {
 382        let position = message
 383            .position
 384            .and_then(deserialize_anchor)
 385            .context("invalid position")?;
 386        buffer
 387            .update(&mut cx, |buffer, _| {
 388                buffer.wait_for_version(deserialize_version(&message.version))
 389            })?
 390            .await?;
 391
 392        Ok(Self {
 393            position: buffer.read_with(&cx, |buffer, _| position.to_point_utf16(buffer))?,
 394        })
 395    }
 396
 397    fn response_to_proto(
 398        response: PrepareRenameResponse,
 399        _: &mut LspStore,
 400        _: PeerId,
 401        buffer_version: &clock::Global,
 402        _: &mut App,
 403    ) -> proto::PrepareRenameResponse {
 404        match response {
 405            PrepareRenameResponse::Success(range) => proto::PrepareRenameResponse {
 406                can_rename: true,
 407                only_unprepared_rename_supported: false,
 408                start: Some(language::proto::serialize_anchor(&range.start)),
 409                end: Some(language::proto::serialize_anchor(&range.end)),
 410                version: serialize_version(buffer_version),
 411            },
 412            PrepareRenameResponse::OnlyUnpreparedRenameSupported => proto::PrepareRenameResponse {
 413                can_rename: false,
 414                only_unprepared_rename_supported: true,
 415                start: None,
 416                end: None,
 417                version: vec![],
 418            },
 419            PrepareRenameResponse::InvalidPosition => proto::PrepareRenameResponse {
 420                can_rename: false,
 421                only_unprepared_rename_supported: false,
 422                start: None,
 423                end: None,
 424                version: vec![],
 425            },
 426        }
 427    }
 428
 429    async fn response_from_proto(
 430        self,
 431        message: proto::PrepareRenameResponse,
 432        _: Entity<LspStore>,
 433        buffer: Entity<Buffer>,
 434        mut cx: AsyncApp,
 435    ) -> Result<PrepareRenameResponse> {
 436        if message.can_rename {
 437            buffer
 438                .update(&mut cx, |buffer, _| {
 439                    buffer.wait_for_version(deserialize_version(&message.version))
 440                })?
 441                .await?;
 442            if let (Some(start), Some(end)) = (
 443                message.start.and_then(deserialize_anchor),
 444                message.end.and_then(deserialize_anchor),
 445            ) {
 446                Ok(PrepareRenameResponse::Success(start..end))
 447            } else {
 448                anyhow::bail!(
 449                    "Missing start or end position in remote project PrepareRenameResponse"
 450                );
 451            }
 452        } else if message.only_unprepared_rename_supported {
 453            Ok(PrepareRenameResponse::OnlyUnpreparedRenameSupported)
 454        } else {
 455            Ok(PrepareRenameResponse::InvalidPosition)
 456        }
 457    }
 458
 459    fn buffer_id_from_proto(message: &proto::PrepareRename) -> Result<BufferId> {
 460        BufferId::new(message.buffer_id)
 461    }
 462}
 463
 464#[async_trait(?Send)]
 465impl LspCommand for PerformRename {
 466    type Response = ProjectTransaction;
 467    type LspRequest = lsp::request::Rename;
 468    type ProtoRequest = proto::PerformRename;
 469
 470    fn display_name(&self) -> &str {
 471        "Rename"
 472    }
 473
 474    fn check_capabilities(&self, capabilities: AdapterServerCapabilities) -> bool {
 475        capabilities
 476            .server_capabilities
 477            .rename_provider
 478            .is_some_and(|capability| match capability {
 479                OneOf::Left(enabled) => enabled,
 480                OneOf::Right(_options) => true,
 481            })
 482    }
 483
 484    fn to_lsp(
 485        &self,
 486        path: &Path,
 487        _: &Buffer,
 488        _: &Arc<LanguageServer>,
 489        _: &App,
 490    ) -> Result<lsp::RenameParams> {
 491        Ok(lsp::RenameParams {
 492            text_document_position: make_lsp_text_document_position(path, self.position)?,
 493            new_name: self.new_name.clone(),
 494            work_done_progress_params: Default::default(),
 495        })
 496    }
 497
 498    async fn response_from_lsp(
 499        self,
 500        message: Option<lsp::WorkspaceEdit>,
 501        lsp_store: Entity<LspStore>,
 502        buffer: Entity<Buffer>,
 503        server_id: LanguageServerId,
 504        mut cx: AsyncApp,
 505    ) -> Result<ProjectTransaction> {
 506        if let Some(edit) = message {
 507            let (_, lsp_server) =
 508                language_server_for_buffer(&lsp_store, &buffer, server_id, &mut cx)?;
 509            LocalLspStore::deserialize_workspace_edit(
 510                lsp_store,
 511                edit,
 512                self.push_to_history,
 513                lsp_server,
 514                &mut cx,
 515            )
 516            .await
 517        } else {
 518            Ok(ProjectTransaction::default())
 519        }
 520    }
 521
 522    fn to_proto(&self, project_id: u64, buffer: &Buffer) -> proto::PerformRename {
 523        proto::PerformRename {
 524            project_id,
 525            buffer_id: buffer.remote_id().into(),
 526            position: Some(language::proto::serialize_anchor(
 527                &buffer.anchor_before(self.position),
 528            )),
 529            new_name: self.new_name.clone(),
 530            version: serialize_version(&buffer.version()),
 531        }
 532    }
 533
 534    async fn from_proto(
 535        message: proto::PerformRename,
 536        _: Entity<LspStore>,
 537        buffer: Entity<Buffer>,
 538        mut cx: AsyncApp,
 539    ) -> Result<Self> {
 540        let position = message
 541            .position
 542            .and_then(deserialize_anchor)
 543            .context("invalid position")?;
 544        buffer
 545            .update(&mut cx, |buffer, _| {
 546                buffer.wait_for_version(deserialize_version(&message.version))
 547            })?
 548            .await?;
 549        Ok(Self {
 550            position: buffer.read_with(&cx, |buffer, _| position.to_point_utf16(buffer))?,
 551            new_name: message.new_name,
 552            push_to_history: false,
 553        })
 554    }
 555
 556    fn response_to_proto(
 557        response: ProjectTransaction,
 558        lsp_store: &mut LspStore,
 559        peer_id: PeerId,
 560        _: &clock::Global,
 561        cx: &mut App,
 562    ) -> proto::PerformRenameResponse {
 563        let transaction = lsp_store.buffer_store().update(cx, |buffer_store, cx| {
 564            buffer_store.serialize_project_transaction_for_peer(response, peer_id, cx)
 565        });
 566        proto::PerformRenameResponse {
 567            transaction: Some(transaction),
 568        }
 569    }
 570
 571    async fn response_from_proto(
 572        self,
 573        message: proto::PerformRenameResponse,
 574        lsp_store: Entity<LspStore>,
 575        _: Entity<Buffer>,
 576        mut cx: AsyncApp,
 577    ) -> Result<ProjectTransaction> {
 578        let message = message.transaction.context("missing transaction")?;
 579        lsp_store
 580            .update(&mut cx, |lsp_store, cx| {
 581                lsp_store.buffer_store().update(cx, |buffer_store, cx| {
 582                    buffer_store.deserialize_project_transaction(message, self.push_to_history, cx)
 583                })
 584            })?
 585            .await
 586    }
 587
 588    fn buffer_id_from_proto(message: &proto::PerformRename) -> Result<BufferId> {
 589        BufferId::new(message.buffer_id)
 590    }
 591}
 592
 593#[async_trait(?Send)]
 594impl LspCommand for GetDefinitions {
 595    type Response = Vec<LocationLink>;
 596    type LspRequest = lsp::request::GotoDefinition;
 597    type ProtoRequest = proto::GetDefinition;
 598
 599    fn display_name(&self) -> &str {
 600        "Get definition"
 601    }
 602
 603    fn check_capabilities(&self, capabilities: AdapterServerCapabilities) -> bool {
 604        capabilities
 605            .server_capabilities
 606            .definition_provider
 607            .is_some_and(|capability| match capability {
 608                OneOf::Left(supported) => supported,
 609                OneOf::Right(_options) => true,
 610            })
 611    }
 612
 613    fn to_lsp(
 614        &self,
 615        path: &Path,
 616        _: &Buffer,
 617        _: &Arc<LanguageServer>,
 618        _: &App,
 619    ) -> Result<lsp::GotoDefinitionParams> {
 620        Ok(lsp::GotoDefinitionParams {
 621            text_document_position_params: make_lsp_text_document_position(path, self.position)?,
 622            work_done_progress_params: Default::default(),
 623            partial_result_params: Default::default(),
 624        })
 625    }
 626
 627    async fn response_from_lsp(
 628        self,
 629        message: Option<lsp::GotoDefinitionResponse>,
 630        lsp_store: Entity<LspStore>,
 631        buffer: Entity<Buffer>,
 632        server_id: LanguageServerId,
 633        cx: AsyncApp,
 634    ) -> Result<Vec<LocationLink>> {
 635        location_links_from_lsp(message, lsp_store, buffer, server_id, cx).await
 636    }
 637
 638    fn to_proto(&self, project_id: u64, buffer: &Buffer) -> proto::GetDefinition {
 639        proto::GetDefinition {
 640            project_id,
 641            buffer_id: buffer.remote_id().into(),
 642            position: Some(language::proto::serialize_anchor(
 643                &buffer.anchor_before(self.position),
 644            )),
 645            version: serialize_version(&buffer.version()),
 646        }
 647    }
 648
 649    async fn from_proto(
 650        message: proto::GetDefinition,
 651        _: Entity<LspStore>,
 652        buffer: Entity<Buffer>,
 653        mut cx: AsyncApp,
 654    ) -> Result<Self> {
 655        let position = message
 656            .position
 657            .and_then(deserialize_anchor)
 658            .context("invalid position")?;
 659        buffer
 660            .update(&mut cx, |buffer, _| {
 661                buffer.wait_for_version(deserialize_version(&message.version))
 662            })?
 663            .await?;
 664        Ok(Self {
 665            position: buffer.read_with(&cx, |buffer, _| position.to_point_utf16(buffer))?,
 666        })
 667    }
 668
 669    fn response_to_proto(
 670        response: Vec<LocationLink>,
 671        lsp_store: &mut LspStore,
 672        peer_id: PeerId,
 673        _: &clock::Global,
 674        cx: &mut App,
 675    ) -> proto::GetDefinitionResponse {
 676        let links = location_links_to_proto(response, lsp_store, peer_id, cx);
 677        proto::GetDefinitionResponse { links }
 678    }
 679
 680    async fn response_from_proto(
 681        self,
 682        message: proto::GetDefinitionResponse,
 683        lsp_store: Entity<LspStore>,
 684        _: Entity<Buffer>,
 685        cx: AsyncApp,
 686    ) -> Result<Vec<LocationLink>> {
 687        location_links_from_proto(message.links, lsp_store, cx).await
 688    }
 689
 690    fn buffer_id_from_proto(message: &proto::GetDefinition) -> Result<BufferId> {
 691        BufferId::new(message.buffer_id)
 692    }
 693}
 694
 695#[async_trait(?Send)]
 696impl LspCommand for GetDeclarations {
 697    type Response = Vec<LocationLink>;
 698    type LspRequest = lsp::request::GotoDeclaration;
 699    type ProtoRequest = proto::GetDeclaration;
 700
 701    fn display_name(&self) -> &str {
 702        "Get declaration"
 703    }
 704
 705    fn check_capabilities(&self, capabilities: AdapterServerCapabilities) -> bool {
 706        capabilities
 707            .server_capabilities
 708            .declaration_provider
 709            .is_some_and(|capability| match capability {
 710                lsp::DeclarationCapability::Simple(supported) => supported,
 711                lsp::DeclarationCapability::RegistrationOptions(..) => true,
 712                lsp::DeclarationCapability::Options(..) => true,
 713            })
 714    }
 715
 716    fn to_lsp(
 717        &self,
 718        path: &Path,
 719        _: &Buffer,
 720        _: &Arc<LanguageServer>,
 721        _: &App,
 722    ) -> Result<lsp::GotoDeclarationParams> {
 723        Ok(lsp::GotoDeclarationParams {
 724            text_document_position_params: make_lsp_text_document_position(path, self.position)?,
 725            work_done_progress_params: Default::default(),
 726            partial_result_params: Default::default(),
 727        })
 728    }
 729
 730    async fn response_from_lsp(
 731        self,
 732        message: Option<lsp::GotoDeclarationResponse>,
 733        lsp_store: Entity<LspStore>,
 734        buffer: Entity<Buffer>,
 735        server_id: LanguageServerId,
 736        cx: AsyncApp,
 737    ) -> Result<Vec<LocationLink>> {
 738        location_links_from_lsp(message, lsp_store, buffer, server_id, cx).await
 739    }
 740
 741    fn to_proto(&self, project_id: u64, buffer: &Buffer) -> proto::GetDeclaration {
 742        proto::GetDeclaration {
 743            project_id,
 744            buffer_id: buffer.remote_id().into(),
 745            position: Some(language::proto::serialize_anchor(
 746                &buffer.anchor_before(self.position),
 747            )),
 748            version: serialize_version(&buffer.version()),
 749        }
 750    }
 751
 752    async fn from_proto(
 753        message: proto::GetDeclaration,
 754        _: Entity<LspStore>,
 755        buffer: Entity<Buffer>,
 756        mut cx: AsyncApp,
 757    ) -> Result<Self> {
 758        let position = message
 759            .position
 760            .and_then(deserialize_anchor)
 761            .context("invalid position")?;
 762        buffer
 763            .update(&mut cx, |buffer, _| {
 764                buffer.wait_for_version(deserialize_version(&message.version))
 765            })?
 766            .await?;
 767        Ok(Self {
 768            position: buffer.read_with(&cx, |buffer, _| position.to_point_utf16(buffer))?,
 769        })
 770    }
 771
 772    fn response_to_proto(
 773        response: Vec<LocationLink>,
 774        lsp_store: &mut LspStore,
 775        peer_id: PeerId,
 776        _: &clock::Global,
 777        cx: &mut App,
 778    ) -> proto::GetDeclarationResponse {
 779        let links = location_links_to_proto(response, lsp_store, peer_id, cx);
 780        proto::GetDeclarationResponse { links }
 781    }
 782
 783    async fn response_from_proto(
 784        self,
 785        message: proto::GetDeclarationResponse,
 786        lsp_store: Entity<LspStore>,
 787        _: Entity<Buffer>,
 788        cx: AsyncApp,
 789    ) -> Result<Vec<LocationLink>> {
 790        location_links_from_proto(message.links, lsp_store, cx).await
 791    }
 792
 793    fn buffer_id_from_proto(message: &proto::GetDeclaration) -> Result<BufferId> {
 794        BufferId::new(message.buffer_id)
 795    }
 796}
 797
 798#[async_trait(?Send)]
 799impl LspCommand for GetImplementations {
 800    type Response = Vec<LocationLink>;
 801    type LspRequest = lsp::request::GotoImplementation;
 802    type ProtoRequest = proto::GetImplementation;
 803
 804    fn display_name(&self) -> &str {
 805        "Get implementation"
 806    }
 807
 808    fn check_capabilities(&self, capabilities: AdapterServerCapabilities) -> bool {
 809        capabilities
 810            .server_capabilities
 811            .implementation_provider
 812            .is_some_and(|capability| match capability {
 813                lsp::ImplementationProviderCapability::Simple(enabled) => enabled,
 814                lsp::ImplementationProviderCapability::Options(_options) => true,
 815            })
 816    }
 817
 818    fn to_lsp(
 819        &self,
 820        path: &Path,
 821        _: &Buffer,
 822        _: &Arc<LanguageServer>,
 823        _: &App,
 824    ) -> Result<lsp::GotoImplementationParams> {
 825        Ok(lsp::GotoImplementationParams {
 826            text_document_position_params: make_lsp_text_document_position(path, self.position)?,
 827            work_done_progress_params: Default::default(),
 828            partial_result_params: Default::default(),
 829        })
 830    }
 831
 832    async fn response_from_lsp(
 833        self,
 834        message: Option<lsp::GotoImplementationResponse>,
 835        lsp_store: Entity<LspStore>,
 836        buffer: Entity<Buffer>,
 837        server_id: LanguageServerId,
 838        cx: AsyncApp,
 839    ) -> Result<Vec<LocationLink>> {
 840        location_links_from_lsp(message, lsp_store, buffer, server_id, cx).await
 841    }
 842
 843    fn to_proto(&self, project_id: u64, buffer: &Buffer) -> proto::GetImplementation {
 844        proto::GetImplementation {
 845            project_id,
 846            buffer_id: buffer.remote_id().into(),
 847            position: Some(language::proto::serialize_anchor(
 848                &buffer.anchor_before(self.position),
 849            )),
 850            version: serialize_version(&buffer.version()),
 851        }
 852    }
 853
 854    async fn from_proto(
 855        message: proto::GetImplementation,
 856        _: Entity<LspStore>,
 857        buffer: Entity<Buffer>,
 858        mut cx: AsyncApp,
 859    ) -> Result<Self> {
 860        let position = message
 861            .position
 862            .and_then(deserialize_anchor)
 863            .context("invalid position")?;
 864        buffer
 865            .update(&mut cx, |buffer, _| {
 866                buffer.wait_for_version(deserialize_version(&message.version))
 867            })?
 868            .await?;
 869        Ok(Self {
 870            position: buffer.read_with(&cx, |buffer, _| position.to_point_utf16(buffer))?,
 871        })
 872    }
 873
 874    fn response_to_proto(
 875        response: Vec<LocationLink>,
 876        lsp_store: &mut LspStore,
 877        peer_id: PeerId,
 878        _: &clock::Global,
 879        cx: &mut App,
 880    ) -> proto::GetImplementationResponse {
 881        let links = location_links_to_proto(response, lsp_store, peer_id, cx);
 882        proto::GetImplementationResponse { links }
 883    }
 884
 885    async fn response_from_proto(
 886        self,
 887        message: proto::GetImplementationResponse,
 888        project: Entity<LspStore>,
 889        _: Entity<Buffer>,
 890        cx: AsyncApp,
 891    ) -> Result<Vec<LocationLink>> {
 892        location_links_from_proto(message.links, project, cx).await
 893    }
 894
 895    fn buffer_id_from_proto(message: &proto::GetImplementation) -> Result<BufferId> {
 896        BufferId::new(message.buffer_id)
 897    }
 898}
 899
 900#[async_trait(?Send)]
 901impl LspCommand for GetTypeDefinitions {
 902    type Response = Vec<LocationLink>;
 903    type LspRequest = lsp::request::GotoTypeDefinition;
 904    type ProtoRequest = proto::GetTypeDefinition;
 905
 906    fn display_name(&self) -> &str {
 907        "Get type definition"
 908    }
 909
 910    fn check_capabilities(&self, capabilities: AdapterServerCapabilities) -> bool {
 911        !matches!(
 912            &capabilities.server_capabilities.type_definition_provider,
 913            None | Some(lsp::TypeDefinitionProviderCapability::Simple(false))
 914        )
 915    }
 916
 917    fn to_lsp(
 918        &self,
 919        path: &Path,
 920        _: &Buffer,
 921        _: &Arc<LanguageServer>,
 922        _: &App,
 923    ) -> Result<lsp::GotoTypeDefinitionParams> {
 924        Ok(lsp::GotoTypeDefinitionParams {
 925            text_document_position_params: make_lsp_text_document_position(path, self.position)?,
 926            work_done_progress_params: Default::default(),
 927            partial_result_params: Default::default(),
 928        })
 929    }
 930
 931    async fn response_from_lsp(
 932        self,
 933        message: Option<lsp::GotoTypeDefinitionResponse>,
 934        project: Entity<LspStore>,
 935        buffer: Entity<Buffer>,
 936        server_id: LanguageServerId,
 937        cx: AsyncApp,
 938    ) -> Result<Vec<LocationLink>> {
 939        location_links_from_lsp(message, project, buffer, server_id, cx).await
 940    }
 941
 942    fn to_proto(&self, project_id: u64, buffer: &Buffer) -> proto::GetTypeDefinition {
 943        proto::GetTypeDefinition {
 944            project_id,
 945            buffer_id: buffer.remote_id().into(),
 946            position: Some(language::proto::serialize_anchor(
 947                &buffer.anchor_before(self.position),
 948            )),
 949            version: serialize_version(&buffer.version()),
 950        }
 951    }
 952
 953    async fn from_proto(
 954        message: proto::GetTypeDefinition,
 955        _: Entity<LspStore>,
 956        buffer: Entity<Buffer>,
 957        mut cx: AsyncApp,
 958    ) -> Result<Self> {
 959        let position = message
 960            .position
 961            .and_then(deserialize_anchor)
 962            .context("invalid position")?;
 963        buffer
 964            .update(&mut cx, |buffer, _| {
 965                buffer.wait_for_version(deserialize_version(&message.version))
 966            })?
 967            .await?;
 968        Ok(Self {
 969            position: buffer.read_with(&cx, |buffer, _| position.to_point_utf16(buffer))?,
 970        })
 971    }
 972
 973    fn response_to_proto(
 974        response: Vec<LocationLink>,
 975        lsp_store: &mut LspStore,
 976        peer_id: PeerId,
 977        _: &clock::Global,
 978        cx: &mut App,
 979    ) -> proto::GetTypeDefinitionResponse {
 980        let links = location_links_to_proto(response, lsp_store, peer_id, cx);
 981        proto::GetTypeDefinitionResponse { links }
 982    }
 983
 984    async fn response_from_proto(
 985        self,
 986        message: proto::GetTypeDefinitionResponse,
 987        project: Entity<LspStore>,
 988        _: Entity<Buffer>,
 989        cx: AsyncApp,
 990    ) -> Result<Vec<LocationLink>> {
 991        location_links_from_proto(message.links, project, cx).await
 992    }
 993
 994    fn buffer_id_from_proto(message: &proto::GetTypeDefinition) -> Result<BufferId> {
 995        BufferId::new(message.buffer_id)
 996    }
 997}
 998
 999fn language_server_for_buffer(
1000    lsp_store: &Entity<LspStore>,
1001    buffer: &Entity<Buffer>,
1002    server_id: LanguageServerId,
1003    cx: &mut AsyncApp,
1004) -> Result<(Arc<CachedLspAdapter>, Arc<LanguageServer>)> {
1005    lsp_store
1006        .update(cx, |lsp_store, cx| {
1007            buffer.update(cx, |buffer, cx| {
1008                lsp_store
1009                    .language_server_for_local_buffer(buffer, server_id, cx)
1010                    .map(|(adapter, server)| (adapter.clone(), server.clone()))
1011            })
1012        })?
1013        .context("no language server found for buffer")
1014}
1015
1016pub async fn location_links_from_proto(
1017    proto_links: Vec<proto::LocationLink>,
1018    lsp_store: Entity<LspStore>,
1019    mut cx: AsyncApp,
1020) -> Result<Vec<LocationLink>> {
1021    let mut links = Vec::new();
1022
1023    for link in proto_links {
1024        links.push(location_link_from_proto(link, lsp_store.clone(), &mut cx).await?)
1025    }
1026
1027    Ok(links)
1028}
1029
1030pub fn location_link_from_proto(
1031    link: proto::LocationLink,
1032    lsp_store: Entity<LspStore>,
1033    cx: &mut AsyncApp,
1034) -> Task<Result<LocationLink>> {
1035    cx.spawn(async move |cx| {
1036        let origin = match link.origin {
1037            Some(origin) => {
1038                let buffer_id = BufferId::new(origin.buffer_id)?;
1039                let buffer = lsp_store
1040                    .update(cx, |lsp_store, cx| {
1041                        lsp_store.wait_for_remote_buffer(buffer_id, cx)
1042                    })?
1043                    .await?;
1044                let start = origin
1045                    .start
1046                    .and_then(deserialize_anchor)
1047                    .context("missing origin start")?;
1048                let end = origin
1049                    .end
1050                    .and_then(deserialize_anchor)
1051                    .context("missing origin end")?;
1052                buffer
1053                    .update(cx, |buffer, _| buffer.wait_for_anchors([start, end]))?
1054                    .await?;
1055                Some(Location {
1056                    buffer,
1057                    range: start..end,
1058                })
1059            }
1060            None => None,
1061        };
1062
1063        let target = link.target.context("missing target")?;
1064        let buffer_id = BufferId::new(target.buffer_id)?;
1065        let buffer = lsp_store
1066            .update(cx, |lsp_store, cx| {
1067                lsp_store.wait_for_remote_buffer(buffer_id, cx)
1068            })?
1069            .await?;
1070        let start = target
1071            .start
1072            .and_then(deserialize_anchor)
1073            .context("missing target start")?;
1074        let end = target
1075            .end
1076            .and_then(deserialize_anchor)
1077            .context("missing target end")?;
1078        buffer
1079            .update(cx, |buffer, _| buffer.wait_for_anchors([start, end]))?
1080            .await?;
1081        let target = Location {
1082            buffer,
1083            range: start..end,
1084        };
1085        Ok(LocationLink { origin, target })
1086    })
1087}
1088
1089pub async fn location_links_from_lsp(
1090    message: Option<lsp::GotoDefinitionResponse>,
1091    lsp_store: Entity<LspStore>,
1092    buffer: Entity<Buffer>,
1093    server_id: LanguageServerId,
1094    mut cx: AsyncApp,
1095) -> Result<Vec<LocationLink>> {
1096    let message = match message {
1097        Some(message) => message,
1098        None => return Ok(Vec::new()),
1099    };
1100
1101    let mut unresolved_links = Vec::new();
1102    match message {
1103        lsp::GotoDefinitionResponse::Scalar(loc) => {
1104            unresolved_links.push((None, loc.uri, loc.range));
1105        }
1106
1107        lsp::GotoDefinitionResponse::Array(locs) => {
1108            unresolved_links.extend(locs.into_iter().map(|l| (None, l.uri, l.range)));
1109        }
1110
1111        lsp::GotoDefinitionResponse::Link(links) => {
1112            unresolved_links.extend(links.into_iter().map(|l| {
1113                (
1114                    l.origin_selection_range,
1115                    l.target_uri,
1116                    l.target_selection_range,
1117                )
1118            }));
1119        }
1120    }
1121
1122    let (_, language_server) = language_server_for_buffer(&lsp_store, &buffer, server_id, &mut cx)?;
1123    let mut definitions = Vec::new();
1124    for (origin_range, target_uri, target_range) in unresolved_links {
1125        let target_buffer_handle = lsp_store
1126            .update(&mut cx, |this, cx| {
1127                this.open_local_buffer_via_lsp(target_uri, language_server.server_id(), cx)
1128            })?
1129            .await?;
1130
1131        cx.update(|cx| {
1132            let origin_location = origin_range.map(|origin_range| {
1133                let origin_buffer = buffer.read(cx);
1134                let origin_start =
1135                    origin_buffer.clip_point_utf16(point_from_lsp(origin_range.start), Bias::Left);
1136                let origin_end =
1137                    origin_buffer.clip_point_utf16(point_from_lsp(origin_range.end), Bias::Left);
1138                Location {
1139                    buffer: buffer.clone(),
1140                    range: origin_buffer.anchor_after(origin_start)
1141                        ..origin_buffer.anchor_before(origin_end),
1142                }
1143            });
1144
1145            let target_buffer = target_buffer_handle.read(cx);
1146            let target_start =
1147                target_buffer.clip_point_utf16(point_from_lsp(target_range.start), Bias::Left);
1148            let target_end =
1149                target_buffer.clip_point_utf16(point_from_lsp(target_range.end), Bias::Left);
1150            let target_location = Location {
1151                buffer: target_buffer_handle,
1152                range: target_buffer.anchor_after(target_start)
1153                    ..target_buffer.anchor_before(target_end),
1154            };
1155
1156            definitions.push(LocationLink {
1157                origin: origin_location,
1158                target: target_location,
1159            })
1160        })?;
1161    }
1162    Ok(definitions)
1163}
1164
1165pub async fn location_link_from_lsp(
1166    link: lsp::LocationLink,
1167    lsp_store: &Entity<LspStore>,
1168    buffer: &Entity<Buffer>,
1169    server_id: LanguageServerId,
1170    cx: &mut AsyncApp,
1171) -> Result<LocationLink> {
1172    let (_, language_server) = language_server_for_buffer(lsp_store, buffer, server_id, cx)?;
1173
1174    let (origin_range, target_uri, target_range) = (
1175        link.origin_selection_range,
1176        link.target_uri,
1177        link.target_selection_range,
1178    );
1179
1180    let target_buffer_handle = lsp_store
1181        .update(cx, |lsp_store, cx| {
1182            lsp_store.open_local_buffer_via_lsp(target_uri, language_server.server_id(), cx)
1183        })?
1184        .await?;
1185
1186    cx.update(|cx| {
1187        let origin_location = origin_range.map(|origin_range| {
1188            let origin_buffer = buffer.read(cx);
1189            let origin_start =
1190                origin_buffer.clip_point_utf16(point_from_lsp(origin_range.start), Bias::Left);
1191            let origin_end =
1192                origin_buffer.clip_point_utf16(point_from_lsp(origin_range.end), Bias::Left);
1193            Location {
1194                buffer: buffer.clone(),
1195                range: origin_buffer.anchor_after(origin_start)
1196                    ..origin_buffer.anchor_before(origin_end),
1197            }
1198        });
1199
1200        let target_buffer = target_buffer_handle.read(cx);
1201        let target_start =
1202            target_buffer.clip_point_utf16(point_from_lsp(target_range.start), Bias::Left);
1203        let target_end =
1204            target_buffer.clip_point_utf16(point_from_lsp(target_range.end), Bias::Left);
1205        let target_location = Location {
1206            buffer: target_buffer_handle,
1207            range: target_buffer.anchor_after(target_start)
1208                ..target_buffer.anchor_before(target_end),
1209        };
1210
1211        LocationLink {
1212            origin: origin_location,
1213            target: target_location,
1214        }
1215    })
1216}
1217
1218pub fn location_links_to_proto(
1219    links: Vec<LocationLink>,
1220    lsp_store: &mut LspStore,
1221    peer_id: PeerId,
1222    cx: &mut App,
1223) -> Vec<proto::LocationLink> {
1224    links
1225        .into_iter()
1226        .map(|definition| location_link_to_proto(definition, lsp_store, peer_id, cx))
1227        .collect()
1228}
1229
1230pub fn location_link_to_proto(
1231    location: LocationLink,
1232    lsp_store: &mut LspStore,
1233    peer_id: PeerId,
1234    cx: &mut App,
1235) -> proto::LocationLink {
1236    let origin = location.origin.map(|origin| {
1237        lsp_store
1238            .buffer_store()
1239            .update(cx, |buffer_store, cx| {
1240                buffer_store.create_buffer_for_peer(&origin.buffer, peer_id, cx)
1241            })
1242            .detach_and_log_err(cx);
1243
1244        let buffer_id = origin.buffer.read(cx).remote_id().into();
1245        proto::Location {
1246            start: Some(serialize_anchor(&origin.range.start)),
1247            end: Some(serialize_anchor(&origin.range.end)),
1248            buffer_id,
1249        }
1250    });
1251
1252    lsp_store
1253        .buffer_store()
1254        .update(cx, |buffer_store, cx| {
1255            buffer_store.create_buffer_for_peer(&location.target.buffer, peer_id, cx)
1256        })
1257        .detach_and_log_err(cx);
1258
1259    let buffer_id = location.target.buffer.read(cx).remote_id().into();
1260    let target = proto::Location {
1261        start: Some(serialize_anchor(&location.target.range.start)),
1262        end: Some(serialize_anchor(&location.target.range.end)),
1263        buffer_id,
1264    };
1265
1266    proto::LocationLink {
1267        origin,
1268        target: Some(target),
1269    }
1270}
1271
1272#[async_trait(?Send)]
1273impl LspCommand for GetReferences {
1274    type Response = Vec<Location>;
1275    type LspRequest = lsp::request::References;
1276    type ProtoRequest = proto::GetReferences;
1277
1278    fn display_name(&self) -> &str {
1279        "Find all references"
1280    }
1281
1282    fn status(&self) -> Option<String> {
1283        Some("Finding references...".to_owned())
1284    }
1285
1286    fn check_capabilities(&self, capabilities: AdapterServerCapabilities) -> bool {
1287        match &capabilities.server_capabilities.references_provider {
1288            Some(OneOf::Left(has_support)) => *has_support,
1289            Some(OneOf::Right(_)) => true,
1290            None => false,
1291        }
1292    }
1293
1294    fn to_lsp(
1295        &self,
1296        path: &Path,
1297        _: &Buffer,
1298        _: &Arc<LanguageServer>,
1299        _: &App,
1300    ) -> Result<lsp::ReferenceParams> {
1301        Ok(lsp::ReferenceParams {
1302            text_document_position: make_lsp_text_document_position(path, self.position)?,
1303            work_done_progress_params: Default::default(),
1304            partial_result_params: Default::default(),
1305            context: lsp::ReferenceContext {
1306                include_declaration: true,
1307            },
1308        })
1309    }
1310
1311    async fn response_from_lsp(
1312        self,
1313        locations: Option<Vec<lsp::Location>>,
1314        lsp_store: Entity<LspStore>,
1315        buffer: Entity<Buffer>,
1316        server_id: LanguageServerId,
1317        mut cx: AsyncApp,
1318    ) -> Result<Vec<Location>> {
1319        let mut references = Vec::new();
1320        let (_, language_server) =
1321            language_server_for_buffer(&lsp_store, &buffer, server_id, &mut cx)?;
1322
1323        if let Some(locations) = locations {
1324            for lsp_location in locations {
1325                let target_buffer_handle = lsp_store
1326                    .update(&mut cx, |lsp_store, cx| {
1327                        lsp_store.open_local_buffer_via_lsp(
1328                            lsp_location.uri,
1329                            language_server.server_id(),
1330                            cx,
1331                        )
1332                    })?
1333                    .await?;
1334
1335                target_buffer_handle
1336                    .clone()
1337                    .read_with(&cx, |target_buffer, _| {
1338                        let target_start = target_buffer
1339                            .clip_point_utf16(point_from_lsp(lsp_location.range.start), Bias::Left);
1340                        let target_end = target_buffer
1341                            .clip_point_utf16(point_from_lsp(lsp_location.range.end), Bias::Left);
1342                        references.push(Location {
1343                            buffer: target_buffer_handle,
1344                            range: target_buffer.anchor_after(target_start)
1345                                ..target_buffer.anchor_before(target_end),
1346                        });
1347                    })?;
1348            }
1349        }
1350
1351        Ok(references)
1352    }
1353
1354    fn to_proto(&self, project_id: u64, buffer: &Buffer) -> proto::GetReferences {
1355        proto::GetReferences {
1356            project_id,
1357            buffer_id: buffer.remote_id().into(),
1358            position: Some(language::proto::serialize_anchor(
1359                &buffer.anchor_before(self.position),
1360            )),
1361            version: serialize_version(&buffer.version()),
1362        }
1363    }
1364
1365    async fn from_proto(
1366        message: proto::GetReferences,
1367        _: Entity<LspStore>,
1368        buffer: Entity<Buffer>,
1369        mut cx: AsyncApp,
1370    ) -> Result<Self> {
1371        let position = message
1372            .position
1373            .and_then(deserialize_anchor)
1374            .context("invalid position")?;
1375        buffer
1376            .update(&mut cx, |buffer, _| {
1377                buffer.wait_for_version(deserialize_version(&message.version))
1378            })?
1379            .await?;
1380        Ok(Self {
1381            position: buffer.read_with(&cx, |buffer, _| position.to_point_utf16(buffer))?,
1382        })
1383    }
1384
1385    fn response_to_proto(
1386        response: Vec<Location>,
1387        lsp_store: &mut LspStore,
1388        peer_id: PeerId,
1389        _: &clock::Global,
1390        cx: &mut App,
1391    ) -> proto::GetReferencesResponse {
1392        let locations = response
1393            .into_iter()
1394            .map(|definition| {
1395                lsp_store
1396                    .buffer_store()
1397                    .update(cx, |buffer_store, cx| {
1398                        buffer_store.create_buffer_for_peer(&definition.buffer, peer_id, cx)
1399                    })
1400                    .detach_and_log_err(cx);
1401                let buffer_id = definition.buffer.read(cx).remote_id();
1402                proto::Location {
1403                    start: Some(serialize_anchor(&definition.range.start)),
1404                    end: Some(serialize_anchor(&definition.range.end)),
1405                    buffer_id: buffer_id.into(),
1406                }
1407            })
1408            .collect();
1409        proto::GetReferencesResponse { locations }
1410    }
1411
1412    async fn response_from_proto(
1413        self,
1414        message: proto::GetReferencesResponse,
1415        project: Entity<LspStore>,
1416        _: Entity<Buffer>,
1417        mut cx: AsyncApp,
1418    ) -> Result<Vec<Location>> {
1419        let mut locations = Vec::new();
1420        for location in message.locations {
1421            let buffer_id = BufferId::new(location.buffer_id)?;
1422            let target_buffer = project
1423                .update(&mut cx, |this, cx| {
1424                    this.wait_for_remote_buffer(buffer_id, cx)
1425                })?
1426                .await?;
1427            let start = location
1428                .start
1429                .and_then(deserialize_anchor)
1430                .context("missing target start")?;
1431            let end = location
1432                .end
1433                .and_then(deserialize_anchor)
1434                .context("missing target end")?;
1435            target_buffer
1436                .update(&mut cx, |buffer, _| buffer.wait_for_anchors([start, end]))?
1437                .await?;
1438            locations.push(Location {
1439                buffer: target_buffer,
1440                range: start..end,
1441            })
1442        }
1443        Ok(locations)
1444    }
1445
1446    fn buffer_id_from_proto(message: &proto::GetReferences) -> Result<BufferId> {
1447        BufferId::new(message.buffer_id)
1448    }
1449}
1450
1451#[async_trait(?Send)]
1452impl LspCommand for GetDocumentHighlights {
1453    type Response = Vec<DocumentHighlight>;
1454    type LspRequest = lsp::request::DocumentHighlightRequest;
1455    type ProtoRequest = proto::GetDocumentHighlights;
1456
1457    fn display_name(&self) -> &str {
1458        "Get document highlights"
1459    }
1460
1461    fn check_capabilities(&self, capabilities: AdapterServerCapabilities) -> bool {
1462        capabilities
1463            .server_capabilities
1464            .document_highlight_provider
1465            .is_some_and(|capability| match capability {
1466                OneOf::Left(supported) => supported,
1467                OneOf::Right(_options) => true,
1468            })
1469    }
1470
1471    fn to_lsp(
1472        &self,
1473        path: &Path,
1474        _: &Buffer,
1475        _: &Arc<LanguageServer>,
1476        _: &App,
1477    ) -> Result<lsp::DocumentHighlightParams> {
1478        Ok(lsp::DocumentHighlightParams {
1479            text_document_position_params: make_lsp_text_document_position(path, self.position)?,
1480            work_done_progress_params: Default::default(),
1481            partial_result_params: Default::default(),
1482        })
1483    }
1484
1485    async fn response_from_lsp(
1486        self,
1487        lsp_highlights: Option<Vec<lsp::DocumentHighlight>>,
1488        _: Entity<LspStore>,
1489        buffer: Entity<Buffer>,
1490        _: LanguageServerId,
1491        cx: AsyncApp,
1492    ) -> Result<Vec<DocumentHighlight>> {
1493        buffer.read_with(&cx, |buffer, _| {
1494            let mut lsp_highlights = lsp_highlights.unwrap_or_default();
1495            lsp_highlights.sort_unstable_by_key(|h| (h.range.start, Reverse(h.range.end)));
1496            lsp_highlights
1497                .into_iter()
1498                .map(|lsp_highlight| {
1499                    let start = buffer
1500                        .clip_point_utf16(point_from_lsp(lsp_highlight.range.start), Bias::Left);
1501                    let end = buffer
1502                        .clip_point_utf16(point_from_lsp(lsp_highlight.range.end), Bias::Left);
1503                    DocumentHighlight {
1504                        range: buffer.anchor_after(start)..buffer.anchor_before(end),
1505                        kind: lsp_highlight
1506                            .kind
1507                            .unwrap_or(lsp::DocumentHighlightKind::READ),
1508                    }
1509                })
1510                .collect()
1511        })
1512    }
1513
1514    fn to_proto(&self, project_id: u64, buffer: &Buffer) -> proto::GetDocumentHighlights {
1515        proto::GetDocumentHighlights {
1516            project_id,
1517            buffer_id: buffer.remote_id().into(),
1518            position: Some(language::proto::serialize_anchor(
1519                &buffer.anchor_before(self.position),
1520            )),
1521            version: serialize_version(&buffer.version()),
1522        }
1523    }
1524
1525    async fn from_proto(
1526        message: proto::GetDocumentHighlights,
1527        _: Entity<LspStore>,
1528        buffer: Entity<Buffer>,
1529        mut cx: AsyncApp,
1530    ) -> Result<Self> {
1531        let position = message
1532            .position
1533            .and_then(deserialize_anchor)
1534            .context("invalid position")?;
1535        buffer
1536            .update(&mut cx, |buffer, _| {
1537                buffer.wait_for_version(deserialize_version(&message.version))
1538            })?
1539            .await?;
1540        Ok(Self {
1541            position: buffer.read_with(&cx, |buffer, _| position.to_point_utf16(buffer))?,
1542        })
1543    }
1544
1545    fn response_to_proto(
1546        response: Vec<DocumentHighlight>,
1547        _: &mut LspStore,
1548        _: PeerId,
1549        _: &clock::Global,
1550        _: &mut App,
1551    ) -> proto::GetDocumentHighlightsResponse {
1552        let highlights = response
1553            .into_iter()
1554            .map(|highlight| proto::DocumentHighlight {
1555                start: Some(serialize_anchor(&highlight.range.start)),
1556                end: Some(serialize_anchor(&highlight.range.end)),
1557                kind: match highlight.kind {
1558                    DocumentHighlightKind::TEXT => proto::document_highlight::Kind::Text.into(),
1559                    DocumentHighlightKind::WRITE => proto::document_highlight::Kind::Write.into(),
1560                    DocumentHighlightKind::READ => proto::document_highlight::Kind::Read.into(),
1561                    _ => proto::document_highlight::Kind::Text.into(),
1562                },
1563            })
1564            .collect();
1565        proto::GetDocumentHighlightsResponse { highlights }
1566    }
1567
1568    async fn response_from_proto(
1569        self,
1570        message: proto::GetDocumentHighlightsResponse,
1571        _: Entity<LspStore>,
1572        buffer: Entity<Buffer>,
1573        mut cx: AsyncApp,
1574    ) -> Result<Vec<DocumentHighlight>> {
1575        let mut highlights = Vec::new();
1576        for highlight in message.highlights {
1577            let start = highlight
1578                .start
1579                .and_then(deserialize_anchor)
1580                .context("missing target start")?;
1581            let end = highlight
1582                .end
1583                .and_then(deserialize_anchor)
1584                .context("missing target end")?;
1585            buffer
1586                .update(&mut cx, |buffer, _| buffer.wait_for_anchors([start, end]))?
1587                .await?;
1588            let kind = match proto::document_highlight::Kind::from_i32(highlight.kind) {
1589                Some(proto::document_highlight::Kind::Text) => DocumentHighlightKind::TEXT,
1590                Some(proto::document_highlight::Kind::Read) => DocumentHighlightKind::READ,
1591                Some(proto::document_highlight::Kind::Write) => DocumentHighlightKind::WRITE,
1592                None => DocumentHighlightKind::TEXT,
1593            };
1594            highlights.push(DocumentHighlight {
1595                range: start..end,
1596                kind,
1597            });
1598        }
1599        Ok(highlights)
1600    }
1601
1602    fn buffer_id_from_proto(message: &proto::GetDocumentHighlights) -> Result<BufferId> {
1603        BufferId::new(message.buffer_id)
1604    }
1605}
1606
1607#[async_trait(?Send)]
1608impl LspCommand for GetDocumentSymbols {
1609    type Response = Vec<DocumentSymbol>;
1610    type LspRequest = lsp::request::DocumentSymbolRequest;
1611    type ProtoRequest = proto::GetDocumentSymbols;
1612
1613    fn display_name(&self) -> &str {
1614        "Get document symbols"
1615    }
1616
1617    fn check_capabilities(&self, capabilities: AdapterServerCapabilities) -> bool {
1618        capabilities
1619            .server_capabilities
1620            .document_symbol_provider
1621            .is_some_and(|capability| match capability {
1622                OneOf::Left(supported) => supported,
1623                OneOf::Right(_options) => true,
1624            })
1625    }
1626
1627    fn to_lsp(
1628        &self,
1629        path: &Path,
1630        _: &Buffer,
1631        _: &Arc<LanguageServer>,
1632        _: &App,
1633    ) -> Result<lsp::DocumentSymbolParams> {
1634        Ok(lsp::DocumentSymbolParams {
1635            text_document: make_text_document_identifier(path)?,
1636            work_done_progress_params: Default::default(),
1637            partial_result_params: Default::default(),
1638        })
1639    }
1640
1641    async fn response_from_lsp(
1642        self,
1643        lsp_symbols: Option<lsp::DocumentSymbolResponse>,
1644        _: Entity<LspStore>,
1645        _: Entity<Buffer>,
1646        _: LanguageServerId,
1647        _: AsyncApp,
1648    ) -> Result<Vec<DocumentSymbol>> {
1649        let Some(lsp_symbols) = lsp_symbols else {
1650            return Ok(Vec::new());
1651        };
1652
1653        let symbols: Vec<_> = match lsp_symbols {
1654            lsp::DocumentSymbolResponse::Flat(symbol_information) => symbol_information
1655                .into_iter()
1656                .map(|lsp_symbol| DocumentSymbol {
1657                    name: lsp_symbol.name,
1658                    kind: lsp_symbol.kind,
1659                    range: range_from_lsp(lsp_symbol.location.range),
1660                    selection_range: range_from_lsp(lsp_symbol.location.range),
1661                    children: Vec::new(),
1662                })
1663                .collect(),
1664            lsp::DocumentSymbolResponse::Nested(nested_responses) => {
1665                fn convert_symbol(lsp_symbol: lsp::DocumentSymbol) -> DocumentSymbol {
1666                    DocumentSymbol {
1667                        name: lsp_symbol.name,
1668                        kind: lsp_symbol.kind,
1669                        range: range_from_lsp(lsp_symbol.range),
1670                        selection_range: range_from_lsp(lsp_symbol.selection_range),
1671                        children: lsp_symbol
1672                            .children
1673                            .map(|children| {
1674                                children.into_iter().map(convert_symbol).collect::<Vec<_>>()
1675                            })
1676                            .unwrap_or_default(),
1677                    }
1678                }
1679                nested_responses.into_iter().map(convert_symbol).collect()
1680            }
1681        };
1682        Ok(symbols)
1683    }
1684
1685    fn to_proto(&self, project_id: u64, buffer: &Buffer) -> proto::GetDocumentSymbols {
1686        proto::GetDocumentSymbols {
1687            project_id,
1688            buffer_id: buffer.remote_id().into(),
1689            version: serialize_version(&buffer.version()),
1690        }
1691    }
1692
1693    async fn from_proto(
1694        message: proto::GetDocumentSymbols,
1695        _: Entity<LspStore>,
1696        buffer: Entity<Buffer>,
1697        mut cx: AsyncApp,
1698    ) -> Result<Self> {
1699        buffer
1700            .update(&mut cx, |buffer, _| {
1701                buffer.wait_for_version(deserialize_version(&message.version))
1702            })?
1703            .await?;
1704        Ok(Self)
1705    }
1706
1707    fn response_to_proto(
1708        response: Vec<DocumentSymbol>,
1709        _: &mut LspStore,
1710        _: PeerId,
1711        _: &clock::Global,
1712        _: &mut App,
1713    ) -> proto::GetDocumentSymbolsResponse {
1714        let symbols = response
1715            .into_iter()
1716            .map(|symbol| {
1717                fn convert_symbol_to_proto(symbol: DocumentSymbol) -> proto::DocumentSymbol {
1718                    proto::DocumentSymbol {
1719                        name: symbol.name.clone(),
1720                        kind: unsafe { mem::transmute::<lsp::SymbolKind, i32>(symbol.kind) },
1721                        start: Some(proto::PointUtf16 {
1722                            row: symbol.range.start.0.row,
1723                            column: symbol.range.start.0.column,
1724                        }),
1725                        end: Some(proto::PointUtf16 {
1726                            row: symbol.range.end.0.row,
1727                            column: symbol.range.end.0.column,
1728                        }),
1729                        selection_start: Some(proto::PointUtf16 {
1730                            row: symbol.selection_range.start.0.row,
1731                            column: symbol.selection_range.start.0.column,
1732                        }),
1733                        selection_end: Some(proto::PointUtf16 {
1734                            row: symbol.selection_range.end.0.row,
1735                            column: symbol.selection_range.end.0.column,
1736                        }),
1737                        children: symbol
1738                            .children
1739                            .into_iter()
1740                            .map(convert_symbol_to_proto)
1741                            .collect(),
1742                    }
1743                }
1744                convert_symbol_to_proto(symbol)
1745            })
1746            .collect::<Vec<_>>();
1747
1748        proto::GetDocumentSymbolsResponse { symbols }
1749    }
1750
1751    async fn response_from_proto(
1752        self,
1753        message: proto::GetDocumentSymbolsResponse,
1754        _: Entity<LspStore>,
1755        _: Entity<Buffer>,
1756        _: AsyncApp,
1757    ) -> Result<Vec<DocumentSymbol>> {
1758        let mut symbols = Vec::with_capacity(message.symbols.len());
1759        for serialized_symbol in message.symbols {
1760            fn deserialize_symbol_with_children(
1761                serialized_symbol: proto::DocumentSymbol,
1762            ) -> Result<DocumentSymbol> {
1763                let kind =
1764                    unsafe { mem::transmute::<i32, lsp::SymbolKind>(serialized_symbol.kind) };
1765
1766                let start = serialized_symbol.start.context("invalid start")?;
1767                let end = serialized_symbol.end.context("invalid end")?;
1768
1769                let selection_start = serialized_symbol
1770                    .selection_start
1771                    .context("invalid selection start")?;
1772                let selection_end = serialized_symbol
1773                    .selection_end
1774                    .context("invalid selection end")?;
1775
1776                Ok(DocumentSymbol {
1777                    name: serialized_symbol.name,
1778                    kind,
1779                    range: Unclipped(PointUtf16::new(start.row, start.column))
1780                        ..Unclipped(PointUtf16::new(end.row, end.column)),
1781                    selection_range: Unclipped(PointUtf16::new(
1782                        selection_start.row,
1783                        selection_start.column,
1784                    ))
1785                        ..Unclipped(PointUtf16::new(selection_end.row, selection_end.column)),
1786                    children: serialized_symbol
1787                        .children
1788                        .into_iter()
1789                        .filter_map(|symbol| deserialize_symbol_with_children(symbol).ok())
1790                        .collect::<Vec<_>>(),
1791                })
1792            }
1793
1794            symbols.push(deserialize_symbol_with_children(serialized_symbol)?);
1795        }
1796
1797        Ok(symbols)
1798    }
1799
1800    fn buffer_id_from_proto(message: &proto::GetDocumentSymbols) -> Result<BufferId> {
1801        BufferId::new(message.buffer_id)
1802    }
1803}
1804
1805#[async_trait(?Send)]
1806impl LspCommand for GetSignatureHelp {
1807    type Response = Option<SignatureHelp>;
1808    type LspRequest = lsp::SignatureHelpRequest;
1809    type ProtoRequest = proto::GetSignatureHelp;
1810
1811    fn display_name(&self) -> &str {
1812        "Get signature help"
1813    }
1814
1815    fn check_capabilities(&self, capabilities: AdapterServerCapabilities) -> bool {
1816        capabilities
1817            .server_capabilities
1818            .signature_help_provider
1819            .is_some()
1820    }
1821
1822    fn to_lsp(
1823        &self,
1824        path: &Path,
1825        _: &Buffer,
1826        _: &Arc<LanguageServer>,
1827        _cx: &App,
1828    ) -> Result<lsp::SignatureHelpParams> {
1829        Ok(lsp::SignatureHelpParams {
1830            text_document_position_params: make_lsp_text_document_position(path, self.position)?,
1831            context: None,
1832            work_done_progress_params: Default::default(),
1833        })
1834    }
1835
1836    async fn response_from_lsp(
1837        self,
1838        message: Option<lsp::SignatureHelp>,
1839        lsp_store: Entity<LspStore>,
1840        _: Entity<Buffer>,
1841        id: LanguageServerId,
1842        cx: AsyncApp,
1843    ) -> Result<Self::Response> {
1844        let Some(message) = message else {
1845            return Ok(None);
1846        };
1847        cx.update(|cx| {
1848            SignatureHelp::new(
1849                message,
1850                Some(lsp_store.read(cx).languages.clone()),
1851                Some(id),
1852                cx,
1853            )
1854        })
1855    }
1856
1857    fn to_proto(&self, project_id: u64, buffer: &Buffer) -> Self::ProtoRequest {
1858        let offset = buffer.point_utf16_to_offset(self.position);
1859        proto::GetSignatureHelp {
1860            project_id,
1861            buffer_id: buffer.remote_id().to_proto(),
1862            position: Some(serialize_anchor(&buffer.anchor_after(offset))),
1863            version: serialize_version(&buffer.version()),
1864        }
1865    }
1866
1867    async fn from_proto(
1868        payload: Self::ProtoRequest,
1869        _: Entity<LspStore>,
1870        buffer: Entity<Buffer>,
1871        mut cx: AsyncApp,
1872    ) -> Result<Self> {
1873        buffer
1874            .update(&mut cx, |buffer, _| {
1875                buffer.wait_for_version(deserialize_version(&payload.version))
1876            })?
1877            .await
1878            .with_context(|| format!("waiting for version for buffer {}", buffer.entity_id()))?;
1879        let buffer_snapshot = buffer.read_with(&cx, |buffer, _| buffer.snapshot())?;
1880        Ok(Self {
1881            position: payload
1882                .position
1883                .and_then(deserialize_anchor)
1884                .context("invalid position")?
1885                .to_point_utf16(&buffer_snapshot),
1886        })
1887    }
1888
1889    fn response_to_proto(
1890        response: Self::Response,
1891        _: &mut LspStore,
1892        _: PeerId,
1893        _: &Global,
1894        _: &mut App,
1895    ) -> proto::GetSignatureHelpResponse {
1896        proto::GetSignatureHelpResponse {
1897            signature_help: response
1898                .map(|signature_help| lsp_to_proto_signature(signature_help.original_data)),
1899        }
1900    }
1901
1902    async fn response_from_proto(
1903        self,
1904        response: proto::GetSignatureHelpResponse,
1905        lsp_store: Entity<LspStore>,
1906        _: Entity<Buffer>,
1907        cx: AsyncApp,
1908    ) -> Result<Self::Response> {
1909        cx.update(|cx| {
1910            response
1911                .signature_help
1912                .map(proto_to_lsp_signature)
1913                .and_then(|signature| {
1914                    SignatureHelp::new(
1915                        signature,
1916                        Some(lsp_store.read(cx).languages.clone()),
1917                        None,
1918                        cx,
1919                    )
1920                })
1921        })
1922    }
1923
1924    fn buffer_id_from_proto(message: &Self::ProtoRequest) -> Result<BufferId> {
1925        BufferId::new(message.buffer_id)
1926    }
1927}
1928
1929pub struct HoverRequest(lsp::HoverRequest);
1930
1931impl lsp::request::Request for HoverRequest {
1932    type Params = lsp::HoverParams;
1933    type Result = Option<Hover2>;
1934    const METHOD: &'static str = lsp::HoverRequest::METHOD;
1935}
1936
1937#[derive(Debug, Serialize, Deserialize)]
1938pub struct Hover2 {
1939    #[serde(flatten)]
1940    lsp_hover: lsp::Hover,
1941    #[serde(skip_serializing_if = "Option::is_none")]
1942    actions: Option<Vec<lsp::Command>>,
1943}
1944
1945#[async_trait(?Send)]
1946impl LspCommand for GetHover {
1947    type Response = Option<Hover>;
1948    type LspRequest = HoverRequest;
1949    type ProtoRequest = proto::GetHover;
1950
1951    fn display_name(&self) -> &str {
1952        "Get hover"
1953    }
1954
1955    fn check_capabilities(&self, capabilities: AdapterServerCapabilities) -> bool {
1956        match capabilities.server_capabilities.hover_provider {
1957            Some(lsp::HoverProviderCapability::Simple(enabled)) => enabled,
1958            Some(lsp::HoverProviderCapability::Options(_)) => true,
1959            None => false,
1960        }
1961    }
1962
1963    fn to_lsp(
1964        &self,
1965        path: &Path,
1966        _: &Buffer,
1967        _: &Arc<LanguageServer>,
1968        _: &App,
1969    ) -> Result<lsp::HoverParams> {
1970        Ok(lsp::HoverParams {
1971            text_document_position_params: make_lsp_text_document_position(path, self.position)?,
1972            work_done_progress_params: Default::default(),
1973        })
1974    }
1975
1976    async fn response_from_lsp(
1977        self,
1978        message: Option<Hover2>,
1979        _: Entity<LspStore>,
1980        buffer: Entity<Buffer>,
1981        _: LanguageServerId,
1982        cx: AsyncApp,
1983    ) -> Result<Self::Response> {
1984        let Some(hover) = message else {
1985            return Ok(None);
1986        };
1987
1988        let lsp_hover = hover.lsp_hover;
1989        dbg!(hover.actions);
1990
1991        let (language, range) = buffer.read_with(&cx, |buffer, _| {
1992            (
1993                buffer.language().cloned(),
1994                lsp_hover.range.map(|range| {
1995                    let token_start =
1996                        buffer.clip_point_utf16(point_from_lsp(range.start), Bias::Left);
1997                    let token_end = buffer.clip_point_utf16(point_from_lsp(range.end), Bias::Left);
1998                    buffer.anchor_after(token_start)..buffer.anchor_before(token_end)
1999                }),
2000            )
2001        })?;
2002
2003        fn hover_blocks_from_marked_string(marked_string: lsp::MarkedString) -> Option<HoverBlock> {
2004            let block = match marked_string {
2005                lsp::MarkedString::String(content) => HoverBlock {
2006                    text: content,
2007                    kind: HoverBlockKind::Markdown,
2008                },
2009                lsp::MarkedString::LanguageString(lsp::LanguageString { language, value }) => {
2010                    HoverBlock {
2011                        text: value,
2012                        kind: HoverBlockKind::Code { language },
2013                    }
2014                }
2015            };
2016            if block.text.is_empty() {
2017                None
2018            } else {
2019                Some(block)
2020            }
2021        }
2022
2023        let contents = match lsp_hover.contents {
2024            lsp::HoverContents::Scalar(marked_string) => {
2025                hover_blocks_from_marked_string(marked_string)
2026                    .into_iter()
2027                    .collect()
2028            }
2029            lsp::HoverContents::Array(marked_strings) => marked_strings
2030                .into_iter()
2031                .filter_map(hover_blocks_from_marked_string)
2032                .collect(),
2033            lsp::HoverContents::Markup(markup_content) => vec![HoverBlock {
2034                text: markup_content.value,
2035                kind: if markup_content.kind == lsp::MarkupKind::Markdown {
2036                    HoverBlockKind::Markdown
2037                } else {
2038                    HoverBlockKind::PlainText
2039                },
2040            }],
2041        };
2042
2043        Ok(Some(Hover {
2044            contents,
2045            range,
2046            language,
2047        }))
2048    }
2049
2050    fn to_proto(&self, project_id: u64, buffer: &Buffer) -> Self::ProtoRequest {
2051        proto::GetHover {
2052            project_id,
2053            buffer_id: buffer.remote_id().into(),
2054            position: Some(language::proto::serialize_anchor(
2055                &buffer.anchor_before(self.position),
2056            )),
2057            version: serialize_version(&buffer.version),
2058        }
2059    }
2060
2061    async fn from_proto(
2062        message: Self::ProtoRequest,
2063        _: Entity<LspStore>,
2064        buffer: Entity<Buffer>,
2065        mut cx: AsyncApp,
2066    ) -> Result<Self> {
2067        let position = message
2068            .position
2069            .and_then(deserialize_anchor)
2070            .context("invalid position")?;
2071        buffer
2072            .update(&mut cx, |buffer, _| {
2073                buffer.wait_for_version(deserialize_version(&message.version))
2074            })?
2075            .await?;
2076        Ok(Self {
2077            position: buffer.read_with(&cx, |buffer, _| position.to_point_utf16(buffer))?,
2078        })
2079    }
2080
2081    fn response_to_proto(
2082        response: Self::Response,
2083        _: &mut LspStore,
2084        _: PeerId,
2085        _: &clock::Global,
2086        _: &mut App,
2087    ) -> proto::GetHoverResponse {
2088        if let Some(response) = response {
2089            let (start, end) = if let Some(range) = response.range {
2090                (
2091                    Some(language::proto::serialize_anchor(&range.start)),
2092                    Some(language::proto::serialize_anchor(&range.end)),
2093                )
2094            } else {
2095                (None, None)
2096            };
2097
2098            let contents = response
2099                .contents
2100                .into_iter()
2101                .map(|block| proto::HoverBlock {
2102                    text: block.text,
2103                    is_markdown: block.kind == HoverBlockKind::Markdown,
2104                    language: if let HoverBlockKind::Code { language } = block.kind {
2105                        Some(language)
2106                    } else {
2107                        None
2108                    },
2109                })
2110                .collect();
2111
2112            proto::GetHoverResponse {
2113                start,
2114                end,
2115                contents,
2116            }
2117        } else {
2118            proto::GetHoverResponse {
2119                start: None,
2120                end: None,
2121                contents: Vec::new(),
2122            }
2123        }
2124    }
2125
2126    async fn response_from_proto(
2127        self,
2128        message: proto::GetHoverResponse,
2129        _: Entity<LspStore>,
2130        buffer: Entity<Buffer>,
2131        mut cx: AsyncApp,
2132    ) -> Result<Self::Response> {
2133        let contents: Vec<_> = message
2134            .contents
2135            .into_iter()
2136            .map(|block| HoverBlock {
2137                text: block.text,
2138                kind: if let Some(language) = block.language {
2139                    HoverBlockKind::Code { language }
2140                } else if block.is_markdown {
2141                    HoverBlockKind::Markdown
2142                } else {
2143                    HoverBlockKind::PlainText
2144                },
2145            })
2146            .collect();
2147        if contents.is_empty() {
2148            return Ok(None);
2149        }
2150
2151        let language = buffer.read_with(&cx, |buffer, _| buffer.language().cloned())?;
2152        let range = if let (Some(start), Some(end)) = (message.start, message.end) {
2153            language::proto::deserialize_anchor(start)
2154                .and_then(|start| language::proto::deserialize_anchor(end).map(|end| start..end))
2155        } else {
2156            None
2157        };
2158        if let Some(range) = range.as_ref() {
2159            buffer
2160                .update(&mut cx, |buffer, _| {
2161                    buffer.wait_for_anchors([range.start, range.end])
2162                })?
2163                .await?;
2164        }
2165
2166        Ok(Some(Hover {
2167            contents,
2168            range,
2169            language,
2170        }))
2171    }
2172
2173    fn buffer_id_from_proto(message: &Self::ProtoRequest) -> Result<BufferId> {
2174        BufferId::new(message.buffer_id)
2175    }
2176}
2177
2178impl GetCompletions {
2179    pub fn can_resolve_completions(capabilities: &lsp::ServerCapabilities) -> bool {
2180        capabilities
2181            .completion_provider
2182            .as_ref()
2183            .and_then(|options| options.resolve_provider)
2184            .unwrap_or(false)
2185    }
2186}
2187
2188#[async_trait(?Send)]
2189impl LspCommand for GetCompletions {
2190    type Response = CoreCompletionResponse;
2191    type LspRequest = lsp::request::Completion;
2192    type ProtoRequest = proto::GetCompletions;
2193
2194    fn display_name(&self) -> &str {
2195        "Get completion"
2196    }
2197
2198    fn check_capabilities(&self, capabilities: AdapterServerCapabilities) -> bool {
2199        capabilities
2200            .server_capabilities
2201            .completion_provider
2202            .is_some()
2203    }
2204
2205    fn to_lsp(
2206        &self,
2207        path: &Path,
2208        _: &Buffer,
2209        _: &Arc<LanguageServer>,
2210        _: &App,
2211    ) -> Result<lsp::CompletionParams> {
2212        Ok(lsp::CompletionParams {
2213            text_document_position: make_lsp_text_document_position(path, self.position)?,
2214            context: Some(self.context.clone()),
2215            work_done_progress_params: Default::default(),
2216            partial_result_params: Default::default(),
2217        })
2218    }
2219
2220    async fn response_from_lsp(
2221        self,
2222        completions: Option<lsp::CompletionResponse>,
2223        lsp_store: Entity<LspStore>,
2224        buffer: Entity<Buffer>,
2225        server_id: LanguageServerId,
2226        mut cx: AsyncApp,
2227    ) -> Result<Self::Response> {
2228        let mut response_list = None;
2229        let (mut completions, mut is_incomplete) = if let Some(completions) = completions {
2230            match completions {
2231                lsp::CompletionResponse::Array(completions) => (completions, false),
2232                lsp::CompletionResponse::List(mut list) => {
2233                    let is_incomplete = list.is_incomplete;
2234                    let items = std::mem::take(&mut list.items);
2235                    response_list = Some(list);
2236                    (items, is_incomplete)
2237                }
2238            }
2239        } else {
2240            (Vec::new(), false)
2241        };
2242
2243        let unfiltered_completions_count = completions.len();
2244
2245        let language_server_adapter = lsp_store
2246            .read_with(&cx, |lsp_store, _| {
2247                lsp_store.language_server_adapter_for_id(server_id)
2248            })?
2249            .with_context(|| format!("no language server with id {server_id}"))?;
2250
2251        let lsp_defaults = response_list
2252            .as_ref()
2253            .and_then(|list| list.item_defaults.clone())
2254            .map(Arc::new);
2255
2256        let mut completion_edits = Vec::new();
2257        buffer.update(&mut cx, |buffer, _cx| {
2258            let snapshot = buffer.snapshot();
2259            let clipped_position = buffer.clip_point_utf16(Unclipped(self.position), Bias::Left);
2260
2261            let mut range_for_token = None;
2262            completions.retain(|lsp_completion| {
2263                let lsp_edit = lsp_completion.text_edit.clone().or_else(|| {
2264                    let default_text_edit = lsp_defaults.as_deref()?.edit_range.as_ref()?;
2265                    let new_text = lsp_completion
2266                        .text_edit_text
2267                        .as_ref()
2268                        .unwrap_or(&lsp_completion.label)
2269                        .clone();
2270                    match default_text_edit {
2271                        CompletionListItemDefaultsEditRange::Range(range) => {
2272                            Some(lsp::CompletionTextEdit::Edit(lsp::TextEdit {
2273                                range: *range,
2274                                new_text,
2275                            }))
2276                        }
2277                        CompletionListItemDefaultsEditRange::InsertAndReplace {
2278                            insert,
2279                            replace,
2280                        } => Some(lsp::CompletionTextEdit::InsertAndReplace(
2281                            lsp::InsertReplaceEdit {
2282                                new_text,
2283                                insert: *insert,
2284                                replace: *replace,
2285                            },
2286                        )),
2287                    }
2288                });
2289
2290                let edit = match lsp_edit {
2291                    // If the language server provides a range to overwrite, then
2292                    // check that the range is valid.
2293                    Some(completion_text_edit) => {
2294                        match parse_completion_text_edit(&completion_text_edit, &snapshot) {
2295                            Some(edit) => edit,
2296                            None => return false,
2297                        }
2298                    }
2299                    // If the language server does not provide a range, then infer
2300                    // the range based on the syntax tree.
2301                    None => {
2302                        if self.position != clipped_position {
2303                            log::info!("completion out of expected range ");
2304                            return false;
2305                        }
2306
2307                        let default_edit_range = lsp_defaults.as_ref().and_then(|lsp_defaults| {
2308                            lsp_defaults
2309                                .edit_range
2310                                .as_ref()
2311                                .and_then(|range| match range {
2312                                    CompletionListItemDefaultsEditRange::Range(r) => Some(r),
2313                                    _ => None,
2314                                })
2315                        });
2316
2317                        let range = if let Some(range) = default_edit_range {
2318                            let range = range_from_lsp(*range);
2319                            let start = snapshot.clip_point_utf16(range.start, Bias::Left);
2320                            let end = snapshot.clip_point_utf16(range.end, Bias::Left);
2321                            if start != range.start.0 || end != range.end.0 {
2322                                log::info!("completion out of expected range");
2323                                return false;
2324                            }
2325
2326                            snapshot.anchor_before(start)..snapshot.anchor_after(end)
2327                        } else {
2328                            range_for_token
2329                                .get_or_insert_with(|| {
2330                                    let offset = self.position.to_offset(&snapshot);
2331                                    let (range, kind) = snapshot.surrounding_word(
2332                                        offset,
2333                                        Some(CharScopeContext::Completion),
2334                                    );
2335                                    let range = if kind == Some(CharKind::Word) {
2336                                        range
2337                                    } else {
2338                                        offset..offset
2339                                    };
2340
2341                                    snapshot.anchor_before(range.start)
2342                                        ..snapshot.anchor_after(range.end)
2343                                })
2344                                .clone()
2345                        };
2346
2347                        // We already know text_edit is None here
2348                        let text = lsp_completion
2349                            .insert_text
2350                            .as_ref()
2351                            .unwrap_or(&lsp_completion.label)
2352                            .clone();
2353
2354                        ParsedCompletionEdit {
2355                            replace_range: range,
2356                            insert_range: None,
2357                            new_text: text,
2358                        }
2359                    }
2360                };
2361
2362                completion_edits.push(edit);
2363                true
2364            });
2365        })?;
2366
2367        // If completions were filtered out due to errors that may be transient, mark the result
2368        // incomplete so that it is re-queried.
2369        if unfiltered_completions_count != completions.len() {
2370            is_incomplete = true;
2371        }
2372
2373        language_server_adapter
2374            .process_completions(&mut completions)
2375            .await;
2376
2377        let completions = completions
2378            .into_iter()
2379            .zip(completion_edits)
2380            .map(|(mut lsp_completion, mut edit)| {
2381                LineEnding::normalize(&mut edit.new_text);
2382                if lsp_completion.data.is_none()
2383                    && let Some(default_data) = lsp_defaults
2384                        .as_ref()
2385                        .and_then(|item_defaults| item_defaults.data.clone())
2386                {
2387                    // Servers (e.g. JDTLS) prefer unchanged completions, when resolving the items later,
2388                    // so we do not insert the defaults here, but `data` is needed for resolving, so this is an exception.
2389                    lsp_completion.data = Some(default_data);
2390                }
2391                CoreCompletion {
2392                    replace_range: edit.replace_range,
2393                    new_text: edit.new_text,
2394                    source: CompletionSource::Lsp {
2395                        insert_range: edit.insert_range,
2396                        server_id,
2397                        lsp_completion: Box::new(lsp_completion),
2398                        lsp_defaults: lsp_defaults.clone(),
2399                        resolved: false,
2400                    },
2401                }
2402            })
2403            .collect();
2404
2405        Ok(CoreCompletionResponse {
2406            completions,
2407            is_incomplete,
2408        })
2409    }
2410
2411    fn to_proto(&self, project_id: u64, buffer: &Buffer) -> proto::GetCompletions {
2412        let anchor = buffer.anchor_after(self.position);
2413        proto::GetCompletions {
2414            project_id,
2415            buffer_id: buffer.remote_id().into(),
2416            position: Some(language::proto::serialize_anchor(&anchor)),
2417            version: serialize_version(&buffer.version()),
2418        }
2419    }
2420
2421    async fn from_proto(
2422        message: proto::GetCompletions,
2423        _: Entity<LspStore>,
2424        buffer: Entity<Buffer>,
2425        mut cx: AsyncApp,
2426    ) -> Result<Self> {
2427        let version = deserialize_version(&message.version);
2428        buffer
2429            .update(&mut cx, |buffer, _| buffer.wait_for_version(version))?
2430            .await?;
2431        let position = message
2432            .position
2433            .and_then(language::proto::deserialize_anchor)
2434            .map(|p| {
2435                buffer.read_with(&cx, |buffer, _| {
2436                    buffer.clip_point_utf16(Unclipped(p.to_point_utf16(buffer)), Bias::Left)
2437                })
2438            })
2439            .context("invalid position")??;
2440        Ok(Self {
2441            position,
2442            context: CompletionContext {
2443                trigger_kind: CompletionTriggerKind::INVOKED,
2444                trigger_character: None,
2445            },
2446        })
2447    }
2448
2449    fn response_to_proto(
2450        response: CoreCompletionResponse,
2451        _: &mut LspStore,
2452        _: PeerId,
2453        buffer_version: &clock::Global,
2454        _: &mut App,
2455    ) -> proto::GetCompletionsResponse {
2456        proto::GetCompletionsResponse {
2457            completions: response
2458                .completions
2459                .iter()
2460                .map(LspStore::serialize_completion)
2461                .collect(),
2462            version: serialize_version(buffer_version),
2463            can_reuse: !response.is_incomplete,
2464        }
2465    }
2466
2467    async fn response_from_proto(
2468        self,
2469        message: proto::GetCompletionsResponse,
2470        _project: Entity<LspStore>,
2471        buffer: Entity<Buffer>,
2472        mut cx: AsyncApp,
2473    ) -> Result<Self::Response> {
2474        buffer
2475            .update(&mut cx, |buffer, _| {
2476                buffer.wait_for_version(deserialize_version(&message.version))
2477            })?
2478            .await?;
2479
2480        let completions = message
2481            .completions
2482            .into_iter()
2483            .map(LspStore::deserialize_completion)
2484            .collect::<Result<Vec<_>>>()?;
2485
2486        Ok(CoreCompletionResponse {
2487            completions,
2488            is_incomplete: !message.can_reuse,
2489        })
2490    }
2491
2492    fn buffer_id_from_proto(message: &proto::GetCompletions) -> Result<BufferId> {
2493        BufferId::new(message.buffer_id)
2494    }
2495}
2496
2497pub struct ParsedCompletionEdit {
2498    pub replace_range: Range<Anchor>,
2499    pub insert_range: Option<Range<Anchor>>,
2500    pub new_text: String,
2501}
2502
2503pub(crate) fn parse_completion_text_edit(
2504    edit: &lsp::CompletionTextEdit,
2505    snapshot: &BufferSnapshot,
2506) -> Option<ParsedCompletionEdit> {
2507    let (replace_range, insert_range, new_text) = match edit {
2508        lsp::CompletionTextEdit::Edit(edit) => (edit.range, None, &edit.new_text),
2509        lsp::CompletionTextEdit::InsertAndReplace(edit) => {
2510            (edit.replace, Some(edit.insert), &edit.new_text)
2511        }
2512    };
2513
2514    let replace_range = {
2515        let range = range_from_lsp(replace_range);
2516        let start = snapshot.clip_point_utf16(range.start, Bias::Left);
2517        let end = snapshot.clip_point_utf16(range.end, Bias::Left);
2518        if start != range.start.0 || end != range.end.0 {
2519            log::info!(
2520                "completion out of expected range, start: {start:?}, end: {end:?}, range: {range:?}"
2521            );
2522            return None;
2523        }
2524        snapshot.anchor_before(start)..snapshot.anchor_after(end)
2525    };
2526
2527    let insert_range = match insert_range {
2528        None => None,
2529        Some(insert_range) => {
2530            let range = range_from_lsp(insert_range);
2531            let start = snapshot.clip_point_utf16(range.start, Bias::Left);
2532            let end = snapshot.clip_point_utf16(range.end, Bias::Left);
2533            if start != range.start.0 || end != range.end.0 {
2534                log::info!("completion (insert) out of expected range");
2535                return None;
2536            }
2537            Some(snapshot.anchor_before(start)..snapshot.anchor_after(end))
2538        }
2539    };
2540
2541    Some(ParsedCompletionEdit {
2542        insert_range,
2543        replace_range,
2544        new_text: new_text.clone(),
2545    })
2546}
2547
2548#[async_trait(?Send)]
2549impl LspCommand for GetCodeActions {
2550    type Response = Vec<CodeAction>;
2551    type LspRequest = lsp::request::CodeActionRequest;
2552    type ProtoRequest = proto::GetCodeActions;
2553
2554    fn display_name(&self) -> &str {
2555        "Get code actions"
2556    }
2557
2558    fn check_capabilities(&self, capabilities: AdapterServerCapabilities) -> bool {
2559        match &capabilities.server_capabilities.code_action_provider {
2560            None => false,
2561            Some(lsp::CodeActionProviderCapability::Simple(false)) => false,
2562            _ => {
2563                // If we do know that we want specific code actions AND we know that
2564                // the server only supports specific code actions, then we want to filter
2565                // down to the ones that are supported.
2566                if let Some((requested, supported)) = self
2567                    .kinds
2568                    .as_ref()
2569                    .zip(Self::supported_code_action_kinds(capabilities))
2570                {
2571                    let server_supported = supported.into_iter().collect::<HashSet<_>>();
2572                    requested.iter().any(|kind| server_supported.contains(kind))
2573                } else {
2574                    true
2575                }
2576            }
2577        }
2578    }
2579
2580    fn to_lsp(
2581        &self,
2582        path: &Path,
2583        buffer: &Buffer,
2584        language_server: &Arc<LanguageServer>,
2585        _: &App,
2586    ) -> Result<lsp::CodeActionParams> {
2587        let mut relevant_diagnostics = Vec::new();
2588        for entry in buffer
2589            .snapshot()
2590            .diagnostics_in_range::<_, language::PointUtf16>(self.range.clone(), false)
2591        {
2592            relevant_diagnostics.push(entry.to_lsp_diagnostic_stub()?);
2593        }
2594
2595        let supported =
2596            Self::supported_code_action_kinds(language_server.adapter_server_capabilities());
2597
2598        let only = if let Some(requested) = &self.kinds {
2599            if let Some(supported_kinds) = supported {
2600                let server_supported = supported_kinds.into_iter().collect::<HashSet<_>>();
2601
2602                let filtered = requested
2603                    .iter()
2604                    .filter(|kind| server_supported.contains(kind))
2605                    .cloned()
2606                    .collect();
2607                Some(filtered)
2608            } else {
2609                Some(requested.clone())
2610            }
2611        } else {
2612            supported
2613        };
2614
2615        Ok(lsp::CodeActionParams {
2616            text_document: make_text_document_identifier(path)?,
2617            range: range_to_lsp(self.range.to_point_utf16(buffer))?,
2618            work_done_progress_params: Default::default(),
2619            partial_result_params: Default::default(),
2620            context: lsp::CodeActionContext {
2621                diagnostics: relevant_diagnostics,
2622                only,
2623                ..lsp::CodeActionContext::default()
2624            },
2625        })
2626    }
2627
2628    async fn response_from_lsp(
2629        self,
2630        actions: Option<lsp::CodeActionResponse>,
2631        lsp_store: Entity<LspStore>,
2632        _: Entity<Buffer>,
2633        server_id: LanguageServerId,
2634        cx: AsyncApp,
2635    ) -> Result<Vec<CodeAction>> {
2636        let requested_kinds_set = self
2637            .kinds
2638            .map(|kinds| kinds.into_iter().collect::<HashSet<_>>());
2639
2640        let language_server = cx.update(|cx| {
2641            lsp_store
2642                .read(cx)
2643                .language_server_for_id(server_id)
2644                .with_context(|| {
2645                    format!("Missing the language server that just returned a response {server_id}")
2646                })
2647        })??;
2648
2649        let server_capabilities = language_server.capabilities();
2650        let available_commands = server_capabilities
2651            .execute_command_provider
2652            .as_ref()
2653            .map(|options| options.commands.as_slice())
2654            .unwrap_or_default();
2655        Ok(actions
2656            .unwrap_or_default()
2657            .into_iter()
2658            .filter_map(|entry| {
2659                let (lsp_action, resolved) = match entry {
2660                    lsp::CodeActionOrCommand::CodeAction(lsp_action) => {
2661                        if let Some(command) = lsp_action.command.as_ref()
2662                            && !available_commands.contains(&command.command)
2663                        {
2664                            return None;
2665                        }
2666                        (LspAction::Action(Box::new(lsp_action)), false)
2667                    }
2668                    lsp::CodeActionOrCommand::Command(command) => {
2669                        if available_commands.contains(&command.command) {
2670                            (LspAction::Command(command), true)
2671                        } else {
2672                            return None;
2673                        }
2674                    }
2675                };
2676
2677                if let Some((requested_kinds, kind)) =
2678                    requested_kinds_set.as_ref().zip(lsp_action.action_kind())
2679                    && !requested_kinds.contains(&kind)
2680                {
2681                    return None;
2682                }
2683
2684                Some(CodeAction {
2685                    server_id,
2686                    range: self.range.clone(),
2687                    lsp_action,
2688                    resolved,
2689                })
2690            })
2691            .collect())
2692    }
2693
2694    fn to_proto(&self, project_id: u64, buffer: &Buffer) -> proto::GetCodeActions {
2695        proto::GetCodeActions {
2696            project_id,
2697            buffer_id: buffer.remote_id().into(),
2698            start: Some(language::proto::serialize_anchor(&self.range.start)),
2699            end: Some(language::proto::serialize_anchor(&self.range.end)),
2700            version: serialize_version(&buffer.version()),
2701        }
2702    }
2703
2704    async fn from_proto(
2705        message: proto::GetCodeActions,
2706        _: Entity<LspStore>,
2707        buffer: Entity<Buffer>,
2708        mut cx: AsyncApp,
2709    ) -> Result<Self> {
2710        let start = message
2711            .start
2712            .and_then(language::proto::deserialize_anchor)
2713            .context("invalid start")?;
2714        let end = message
2715            .end
2716            .and_then(language::proto::deserialize_anchor)
2717            .context("invalid end")?;
2718        buffer
2719            .update(&mut cx, |buffer, _| {
2720                buffer.wait_for_version(deserialize_version(&message.version))
2721            })?
2722            .await?;
2723
2724        Ok(Self {
2725            range: start..end,
2726            kinds: None,
2727        })
2728    }
2729
2730    fn response_to_proto(
2731        code_actions: Vec<CodeAction>,
2732        _: &mut LspStore,
2733        _: PeerId,
2734        buffer_version: &clock::Global,
2735        _: &mut App,
2736    ) -> proto::GetCodeActionsResponse {
2737        proto::GetCodeActionsResponse {
2738            actions: code_actions
2739                .iter()
2740                .map(LspStore::serialize_code_action)
2741                .collect(),
2742            version: serialize_version(buffer_version),
2743        }
2744    }
2745
2746    async fn response_from_proto(
2747        self,
2748        message: proto::GetCodeActionsResponse,
2749        _: Entity<LspStore>,
2750        buffer: Entity<Buffer>,
2751        mut cx: AsyncApp,
2752    ) -> Result<Vec<CodeAction>> {
2753        buffer
2754            .update(&mut cx, |buffer, _| {
2755                buffer.wait_for_version(deserialize_version(&message.version))
2756            })?
2757            .await?;
2758        message
2759            .actions
2760            .into_iter()
2761            .map(LspStore::deserialize_code_action)
2762            .collect()
2763    }
2764
2765    fn buffer_id_from_proto(message: &proto::GetCodeActions) -> Result<BufferId> {
2766        BufferId::new(message.buffer_id)
2767    }
2768}
2769
2770impl GetCodeActions {
2771    fn supported_code_action_kinds(
2772        capabilities: AdapterServerCapabilities,
2773    ) -> Option<Vec<CodeActionKind>> {
2774        match capabilities.server_capabilities.code_action_provider {
2775            Some(lsp::CodeActionProviderCapability::Options(CodeActionOptions {
2776                code_action_kinds: Some(supported_action_kinds),
2777                ..
2778            })) => Some(supported_action_kinds),
2779            _ => capabilities.code_action_kinds,
2780        }
2781    }
2782
2783    pub fn can_resolve_actions(capabilities: &ServerCapabilities) -> bool {
2784        capabilities
2785            .code_action_provider
2786            .as_ref()
2787            .and_then(|options| match options {
2788                lsp::CodeActionProviderCapability::Simple(_is_supported) => None,
2789                lsp::CodeActionProviderCapability::Options(options) => options.resolve_provider,
2790            })
2791            .unwrap_or(false)
2792    }
2793}
2794
2795impl OnTypeFormatting {
2796    pub fn supports_on_type_formatting(trigger: &str, capabilities: &ServerCapabilities) -> bool {
2797        let Some(on_type_formatting_options) = &capabilities.document_on_type_formatting_provider
2798        else {
2799            return false;
2800        };
2801        on_type_formatting_options
2802            .first_trigger_character
2803            .contains(trigger)
2804            || on_type_formatting_options
2805                .more_trigger_character
2806                .iter()
2807                .flatten()
2808                .any(|chars| chars.contains(trigger))
2809    }
2810}
2811
2812#[async_trait(?Send)]
2813impl LspCommand for OnTypeFormatting {
2814    type Response = Option<Transaction>;
2815    type LspRequest = lsp::request::OnTypeFormatting;
2816    type ProtoRequest = proto::OnTypeFormatting;
2817
2818    fn display_name(&self) -> &str {
2819        "Formatting on typing"
2820    }
2821
2822    fn check_capabilities(&self, capabilities: AdapterServerCapabilities) -> bool {
2823        Self::supports_on_type_formatting(&self.trigger, &capabilities.server_capabilities)
2824    }
2825
2826    fn to_lsp(
2827        &self,
2828        path: &Path,
2829        _: &Buffer,
2830        _: &Arc<LanguageServer>,
2831        _: &App,
2832    ) -> Result<lsp::DocumentOnTypeFormattingParams> {
2833        Ok(lsp::DocumentOnTypeFormattingParams {
2834            text_document_position: make_lsp_text_document_position(path, self.position)?,
2835            ch: self.trigger.clone(),
2836            options: self.options.clone(),
2837        })
2838    }
2839
2840    async fn response_from_lsp(
2841        self,
2842        message: Option<Vec<lsp::TextEdit>>,
2843        lsp_store: Entity<LspStore>,
2844        buffer: Entity<Buffer>,
2845        server_id: LanguageServerId,
2846        mut cx: AsyncApp,
2847    ) -> Result<Option<Transaction>> {
2848        if let Some(edits) = message {
2849            let (lsp_adapter, lsp_server) =
2850                language_server_for_buffer(&lsp_store, &buffer, server_id, &mut cx)?;
2851            LocalLspStore::deserialize_text_edits(
2852                lsp_store,
2853                buffer,
2854                edits,
2855                self.push_to_history,
2856                lsp_adapter,
2857                lsp_server,
2858                &mut cx,
2859            )
2860            .await
2861        } else {
2862            Ok(None)
2863        }
2864    }
2865
2866    fn to_proto(&self, project_id: u64, buffer: &Buffer) -> proto::OnTypeFormatting {
2867        proto::OnTypeFormatting {
2868            project_id,
2869            buffer_id: buffer.remote_id().into(),
2870            position: Some(language::proto::serialize_anchor(
2871                &buffer.anchor_before(self.position),
2872            )),
2873            trigger: self.trigger.clone(),
2874            version: serialize_version(&buffer.version()),
2875        }
2876    }
2877
2878    async fn from_proto(
2879        message: proto::OnTypeFormatting,
2880        _: Entity<LspStore>,
2881        buffer: Entity<Buffer>,
2882        mut cx: AsyncApp,
2883    ) -> Result<Self> {
2884        let position = message
2885            .position
2886            .and_then(deserialize_anchor)
2887            .context("invalid position")?;
2888        buffer
2889            .update(&mut cx, |buffer, _| {
2890                buffer.wait_for_version(deserialize_version(&message.version))
2891            })?
2892            .await?;
2893
2894        let options = buffer.update(&mut cx, |buffer, cx| {
2895            lsp_formatting_options(
2896                language_settings(buffer.language().map(|l| l.name()), buffer.file(), cx).as_ref(),
2897            )
2898        })?;
2899
2900        Ok(Self {
2901            position: buffer.read_with(&cx, |buffer, _| position.to_point_utf16(buffer))?,
2902            trigger: message.trigger.clone(),
2903            options,
2904            push_to_history: false,
2905        })
2906    }
2907
2908    fn response_to_proto(
2909        response: Option<Transaction>,
2910        _: &mut LspStore,
2911        _: PeerId,
2912        _: &clock::Global,
2913        _: &mut App,
2914    ) -> proto::OnTypeFormattingResponse {
2915        proto::OnTypeFormattingResponse {
2916            transaction: response
2917                .map(|transaction| language::proto::serialize_transaction(&transaction)),
2918        }
2919    }
2920
2921    async fn response_from_proto(
2922        self,
2923        message: proto::OnTypeFormattingResponse,
2924        _: Entity<LspStore>,
2925        _: Entity<Buffer>,
2926        _: AsyncApp,
2927    ) -> Result<Option<Transaction>> {
2928        let Some(transaction) = message.transaction else {
2929            return Ok(None);
2930        };
2931        Ok(Some(language::proto::deserialize_transaction(transaction)?))
2932    }
2933
2934    fn buffer_id_from_proto(message: &proto::OnTypeFormatting) -> Result<BufferId> {
2935        BufferId::new(message.buffer_id)
2936    }
2937}
2938
2939impl InlayHints {
2940    pub async fn lsp_to_project_hint(
2941        lsp_hint: lsp::InlayHint,
2942        buffer_handle: &Entity<Buffer>,
2943        server_id: LanguageServerId,
2944        resolve_state: ResolveState,
2945        force_no_type_left_padding: bool,
2946        cx: &mut AsyncApp,
2947    ) -> anyhow::Result<InlayHint> {
2948        let kind = lsp_hint.kind.and_then(|kind| match kind {
2949            lsp::InlayHintKind::TYPE => Some(InlayHintKind::Type),
2950            lsp::InlayHintKind::PARAMETER => Some(InlayHintKind::Parameter),
2951            _ => None,
2952        });
2953
2954        let position = buffer_handle.read_with(cx, |buffer, _| {
2955            let position = buffer.clip_point_utf16(point_from_lsp(lsp_hint.position), Bias::Left);
2956            if kind == Some(InlayHintKind::Parameter) {
2957                buffer.anchor_before(position)
2958            } else {
2959                buffer.anchor_after(position)
2960            }
2961        })?;
2962        let label = Self::lsp_inlay_label_to_project(lsp_hint.label, server_id)
2963            .await
2964            .context("lsp to project inlay hint conversion")?;
2965        let padding_left = if force_no_type_left_padding && kind == Some(InlayHintKind::Type) {
2966            false
2967        } else {
2968            lsp_hint.padding_left.unwrap_or(false)
2969        };
2970
2971        Ok(InlayHint {
2972            position,
2973            padding_left,
2974            padding_right: lsp_hint.padding_right.unwrap_or(false),
2975            label,
2976            kind,
2977            tooltip: lsp_hint.tooltip.map(|tooltip| match tooltip {
2978                lsp::InlayHintTooltip::String(s) => InlayHintTooltip::String(s),
2979                lsp::InlayHintTooltip::MarkupContent(markup_content) => {
2980                    InlayHintTooltip::MarkupContent(MarkupContent {
2981                        kind: match markup_content.kind {
2982                            lsp::MarkupKind::PlainText => HoverBlockKind::PlainText,
2983                            lsp::MarkupKind::Markdown => HoverBlockKind::Markdown,
2984                        },
2985                        value: markup_content.value,
2986                    })
2987                }
2988            }),
2989            resolve_state,
2990        })
2991    }
2992
2993    async fn lsp_inlay_label_to_project(
2994        lsp_label: lsp::InlayHintLabel,
2995        server_id: LanguageServerId,
2996    ) -> anyhow::Result<InlayHintLabel> {
2997        let label = match lsp_label {
2998            lsp::InlayHintLabel::String(s) => InlayHintLabel::String(s),
2999            lsp::InlayHintLabel::LabelParts(lsp_parts) => {
3000                let mut parts = Vec::with_capacity(lsp_parts.len());
3001                for lsp_part in lsp_parts {
3002                    parts.push(InlayHintLabelPart {
3003                        value: lsp_part.value,
3004                        tooltip: lsp_part.tooltip.map(|tooltip| match tooltip {
3005                            lsp::InlayHintLabelPartTooltip::String(s) => {
3006                                InlayHintLabelPartTooltip::String(s)
3007                            }
3008                            lsp::InlayHintLabelPartTooltip::MarkupContent(markup_content) => {
3009                                InlayHintLabelPartTooltip::MarkupContent(MarkupContent {
3010                                    kind: match markup_content.kind {
3011                                        lsp::MarkupKind::PlainText => HoverBlockKind::PlainText,
3012                                        lsp::MarkupKind::Markdown => HoverBlockKind::Markdown,
3013                                    },
3014                                    value: markup_content.value,
3015                                })
3016                            }
3017                        }),
3018                        location: Some(server_id).zip(lsp_part.location),
3019                    });
3020                }
3021                InlayHintLabel::LabelParts(parts)
3022            }
3023        };
3024
3025        Ok(label)
3026    }
3027
3028    pub fn project_to_proto_hint(response_hint: InlayHint) -> proto::InlayHint {
3029        let (state, lsp_resolve_state) = match response_hint.resolve_state {
3030            ResolveState::Resolved => (0, None),
3031            ResolveState::CanResolve(server_id, resolve_data) => (
3032                1,
3033                Some(proto::resolve_state::LspResolveState {
3034                    server_id: server_id.0 as u64,
3035                    value: resolve_data.map(|json_data| {
3036                        serde_json::to_string(&json_data)
3037                            .expect("failed to serialize resolve json data")
3038                    }),
3039                }),
3040            ),
3041            ResolveState::Resolving => (2, None),
3042        };
3043        let resolve_state = Some(proto::ResolveState {
3044            state,
3045            lsp_resolve_state,
3046        });
3047        proto::InlayHint {
3048            position: Some(language::proto::serialize_anchor(&response_hint.position)),
3049            padding_left: response_hint.padding_left,
3050            padding_right: response_hint.padding_right,
3051            label: Some(proto::InlayHintLabel {
3052                label: Some(match response_hint.label {
3053                    InlayHintLabel::String(s) => proto::inlay_hint_label::Label::Value(s),
3054                    InlayHintLabel::LabelParts(label_parts) => {
3055                        proto::inlay_hint_label::Label::LabelParts(proto::InlayHintLabelParts {
3056                            parts: label_parts.into_iter().map(|label_part| {
3057                                let location_url = label_part.location.as_ref().map(|(_, location)| location.uri.to_string());
3058                                let location_range_start = label_part.location.as_ref().map(|(_, location)| point_from_lsp(location.range.start).0).map(|point| proto::PointUtf16 { row: point.row, column: point.column });
3059                                let location_range_end = label_part.location.as_ref().map(|(_, location)| point_from_lsp(location.range.end).0).map(|point| proto::PointUtf16 { row: point.row, column: point.column });
3060                                proto::InlayHintLabelPart {
3061                                value: label_part.value,
3062                                tooltip: label_part.tooltip.map(|tooltip| {
3063                                    let proto_tooltip = match tooltip {
3064                                        InlayHintLabelPartTooltip::String(s) => proto::inlay_hint_label_part_tooltip::Content::Value(s),
3065                                        InlayHintLabelPartTooltip::MarkupContent(markup_content) => proto::inlay_hint_label_part_tooltip::Content::MarkupContent(proto::MarkupContent {
3066                                            is_markdown: markup_content.kind == HoverBlockKind::Markdown,
3067                                            value: markup_content.value,
3068                                        }),
3069                                    };
3070                                    proto::InlayHintLabelPartTooltip {content: Some(proto_tooltip)}
3071                                }),
3072                                location_url,
3073                                location_range_start,
3074                                location_range_end,
3075                                language_server_id: label_part.location.as_ref().map(|(server_id, _)| server_id.0 as u64),
3076                            }}).collect()
3077                        })
3078                    }
3079                }),
3080            }),
3081            kind: response_hint.kind.map(|kind| kind.name().to_string()),
3082            tooltip: response_hint.tooltip.map(|response_tooltip| {
3083                let proto_tooltip = match response_tooltip {
3084                    InlayHintTooltip::String(s) => proto::inlay_hint_tooltip::Content::Value(s),
3085                    InlayHintTooltip::MarkupContent(markup_content) => {
3086                        proto::inlay_hint_tooltip::Content::MarkupContent(proto::MarkupContent {
3087                            is_markdown: markup_content.kind == HoverBlockKind::Markdown,
3088                            value: markup_content.value,
3089                        })
3090                    }
3091                };
3092                proto::InlayHintTooltip {
3093                    content: Some(proto_tooltip),
3094                }
3095            }),
3096            resolve_state,
3097        }
3098    }
3099
3100    pub fn proto_to_project_hint(message_hint: proto::InlayHint) -> anyhow::Result<InlayHint> {
3101        let resolve_state = message_hint.resolve_state.as_ref().unwrap_or_else(|| {
3102            panic!("incorrect proto inlay hint message: no resolve state in hint {message_hint:?}",)
3103        });
3104        let resolve_state_data = resolve_state
3105            .lsp_resolve_state.as_ref()
3106            .map(|lsp_resolve_state| {
3107                let value = lsp_resolve_state.value.as_deref().map(|value| {
3108                    serde_json::from_str::<Option<lsp::LSPAny>>(value)
3109                        .with_context(|| format!("incorrect proto inlay hint message: non-json resolve state {lsp_resolve_state:?}"))
3110                }).transpose()?.flatten();
3111                anyhow::Ok((LanguageServerId(lsp_resolve_state.server_id as usize), value))
3112            })
3113            .transpose()?;
3114        let resolve_state = match resolve_state.state {
3115            0 => ResolveState::Resolved,
3116            1 => {
3117                let (server_id, lsp_resolve_state) = resolve_state_data.with_context(|| {
3118                    format!(
3119                        "No lsp resolve data for the hint that can be resolved: {message_hint:?}"
3120                    )
3121                })?;
3122                ResolveState::CanResolve(server_id, lsp_resolve_state)
3123            }
3124            2 => ResolveState::Resolving,
3125            invalid => {
3126                anyhow::bail!("Unexpected resolve state {invalid} for hint {message_hint:?}")
3127            }
3128        };
3129        Ok(InlayHint {
3130            position: message_hint
3131                .position
3132                .and_then(language::proto::deserialize_anchor)
3133                .context("invalid position")?,
3134            label: match message_hint
3135                .label
3136                .and_then(|label| label.label)
3137                .context("missing label")?
3138            {
3139                proto::inlay_hint_label::Label::Value(s) => InlayHintLabel::String(s),
3140                proto::inlay_hint_label::Label::LabelParts(parts) => {
3141                    let mut label_parts = Vec::new();
3142                    for part in parts.parts {
3143                        label_parts.push(InlayHintLabelPart {
3144                            value: part.value,
3145                            tooltip: part.tooltip.map(|tooltip| match tooltip.content {
3146                                Some(proto::inlay_hint_label_part_tooltip::Content::Value(s)) => {
3147                                    InlayHintLabelPartTooltip::String(s)
3148                                }
3149                                Some(
3150                                    proto::inlay_hint_label_part_tooltip::Content::MarkupContent(
3151                                        markup_content,
3152                                    ),
3153                                ) => InlayHintLabelPartTooltip::MarkupContent(MarkupContent {
3154                                    kind: if markup_content.is_markdown {
3155                                        HoverBlockKind::Markdown
3156                                    } else {
3157                                        HoverBlockKind::PlainText
3158                                    },
3159                                    value: markup_content.value,
3160                                }),
3161                                None => InlayHintLabelPartTooltip::String(String::new()),
3162                            }),
3163                            location: {
3164                                match part
3165                                    .location_url
3166                                    .zip(
3167                                        part.location_range_start.and_then(|start| {
3168                                            Some(start..part.location_range_end?)
3169                                        }),
3170                                    )
3171                                    .zip(part.language_server_id)
3172                                {
3173                                    Some(((uri, range), server_id)) => Some((
3174                                        LanguageServerId(server_id as usize),
3175                                        lsp::Location {
3176                                            uri: lsp::Uri::from_str(&uri)
3177                                                .context("invalid uri in hint part {part:?}")?,
3178                                            range: lsp::Range::new(
3179                                                point_to_lsp(PointUtf16::new(
3180                                                    range.start.row,
3181                                                    range.start.column,
3182                                                )),
3183                                                point_to_lsp(PointUtf16::new(
3184                                                    range.end.row,
3185                                                    range.end.column,
3186                                                )),
3187                                            ),
3188                                        },
3189                                    )),
3190                                    None => None,
3191                                }
3192                            },
3193                        });
3194                    }
3195
3196                    InlayHintLabel::LabelParts(label_parts)
3197                }
3198            },
3199            padding_left: message_hint.padding_left,
3200            padding_right: message_hint.padding_right,
3201            kind: message_hint
3202                .kind
3203                .as_deref()
3204                .and_then(InlayHintKind::from_name),
3205            tooltip: message_hint.tooltip.and_then(|tooltip| {
3206                Some(match tooltip.content? {
3207                    proto::inlay_hint_tooltip::Content::Value(s) => InlayHintTooltip::String(s),
3208                    proto::inlay_hint_tooltip::Content::MarkupContent(markup_content) => {
3209                        InlayHintTooltip::MarkupContent(MarkupContent {
3210                            kind: if markup_content.is_markdown {
3211                                HoverBlockKind::Markdown
3212                            } else {
3213                                HoverBlockKind::PlainText
3214                            },
3215                            value: markup_content.value,
3216                        })
3217                    }
3218                })
3219            }),
3220            resolve_state,
3221        })
3222    }
3223
3224    pub fn project_to_lsp_hint(hint: InlayHint, snapshot: &BufferSnapshot) -> lsp::InlayHint {
3225        lsp::InlayHint {
3226            position: point_to_lsp(hint.position.to_point_utf16(snapshot)),
3227            kind: hint.kind.map(|kind| match kind {
3228                InlayHintKind::Type => lsp::InlayHintKind::TYPE,
3229                InlayHintKind::Parameter => lsp::InlayHintKind::PARAMETER,
3230            }),
3231            text_edits: None,
3232            tooltip: hint.tooltip.and_then(|tooltip| {
3233                Some(match tooltip {
3234                    InlayHintTooltip::String(s) => lsp::InlayHintTooltip::String(s),
3235                    InlayHintTooltip::MarkupContent(markup_content) => {
3236                        lsp::InlayHintTooltip::MarkupContent(lsp::MarkupContent {
3237                            kind: match markup_content.kind {
3238                                HoverBlockKind::PlainText => lsp::MarkupKind::PlainText,
3239                                HoverBlockKind::Markdown => lsp::MarkupKind::Markdown,
3240                                HoverBlockKind::Code { .. } => return None,
3241                            },
3242                            value: markup_content.value,
3243                        })
3244                    }
3245                })
3246            }),
3247            label: match hint.label {
3248                InlayHintLabel::String(s) => lsp::InlayHintLabel::String(s),
3249                InlayHintLabel::LabelParts(label_parts) => lsp::InlayHintLabel::LabelParts(
3250                    label_parts
3251                        .into_iter()
3252                        .map(|part| lsp::InlayHintLabelPart {
3253                            value: part.value,
3254                            tooltip: part.tooltip.and_then(|tooltip| {
3255                                Some(match tooltip {
3256                                    InlayHintLabelPartTooltip::String(s) => {
3257                                        lsp::InlayHintLabelPartTooltip::String(s)
3258                                    }
3259                                    InlayHintLabelPartTooltip::MarkupContent(markup_content) => {
3260                                        lsp::InlayHintLabelPartTooltip::MarkupContent(
3261                                            lsp::MarkupContent {
3262                                                kind: match markup_content.kind {
3263                                                    HoverBlockKind::PlainText => {
3264                                                        lsp::MarkupKind::PlainText
3265                                                    }
3266                                                    HoverBlockKind::Markdown => {
3267                                                        lsp::MarkupKind::Markdown
3268                                                    }
3269                                                    HoverBlockKind::Code { .. } => return None,
3270                                                },
3271                                                value: markup_content.value,
3272                                            },
3273                                        )
3274                                    }
3275                                })
3276                            }),
3277                            location: part.location.map(|(_, location)| location),
3278                            command: None,
3279                        })
3280                        .collect(),
3281                ),
3282            },
3283            padding_left: Some(hint.padding_left),
3284            padding_right: Some(hint.padding_right),
3285            data: match hint.resolve_state {
3286                ResolveState::CanResolve(_, data) => data,
3287                ResolveState::Resolving | ResolveState::Resolved => None,
3288            },
3289        }
3290    }
3291
3292    pub fn can_resolve_inlays(capabilities: &ServerCapabilities) -> bool {
3293        capabilities
3294            .inlay_hint_provider
3295            .as_ref()
3296            .and_then(|options| match options {
3297                OneOf::Left(_is_supported) => None,
3298                OneOf::Right(capabilities) => match capabilities {
3299                    lsp::InlayHintServerCapabilities::Options(o) => o.resolve_provider,
3300                    lsp::InlayHintServerCapabilities::RegistrationOptions(o) => {
3301                        o.inlay_hint_options.resolve_provider
3302                    }
3303                },
3304            })
3305            .unwrap_or(false)
3306    }
3307
3308    pub fn check_capabilities(capabilities: &ServerCapabilities) -> bool {
3309        capabilities
3310            .inlay_hint_provider
3311            .as_ref()
3312            .is_some_and(|inlay_hint_provider| match inlay_hint_provider {
3313                lsp::OneOf::Left(enabled) => *enabled,
3314                lsp::OneOf::Right(_) => true,
3315            })
3316    }
3317}
3318
3319#[async_trait(?Send)]
3320impl LspCommand for InlayHints {
3321    type Response = Vec<InlayHint>;
3322    type LspRequest = lsp::InlayHintRequest;
3323    type ProtoRequest = proto::InlayHints;
3324
3325    fn display_name(&self) -> &str {
3326        "Inlay hints"
3327    }
3328
3329    fn check_capabilities(&self, capabilities: AdapterServerCapabilities) -> bool {
3330        Self::check_capabilities(&capabilities.server_capabilities)
3331    }
3332
3333    fn to_lsp(
3334        &self,
3335        path: &Path,
3336        buffer: &Buffer,
3337        _: &Arc<LanguageServer>,
3338        _: &App,
3339    ) -> Result<lsp::InlayHintParams> {
3340        Ok(lsp::InlayHintParams {
3341            text_document: lsp::TextDocumentIdentifier {
3342                uri: file_path_to_lsp_url(path)?,
3343            },
3344            range: range_to_lsp(self.range.to_point_utf16(buffer))?,
3345            work_done_progress_params: Default::default(),
3346        })
3347    }
3348
3349    async fn response_from_lsp(
3350        self,
3351        message: Option<Vec<lsp::InlayHint>>,
3352        lsp_store: Entity<LspStore>,
3353        buffer: Entity<Buffer>,
3354        server_id: LanguageServerId,
3355        mut cx: AsyncApp,
3356    ) -> anyhow::Result<Vec<InlayHint>> {
3357        let (lsp_adapter, lsp_server) =
3358            language_server_for_buffer(&lsp_store, &buffer, server_id, &mut cx)?;
3359        // `typescript-language-server` adds padding to the left for type hints, turning
3360        // `const foo: boolean` into `const foo : boolean` which looks odd.
3361        // `rust-analyzer` does not have the padding for this case, and we have to accommodate both.
3362        //
3363        // We could trim the whole string, but being pessimistic on par with the situation above,
3364        // there might be a hint with multiple whitespaces at the end(s) which we need to display properly.
3365        // Hence let's use a heuristic first to handle the most awkward case and look for more.
3366        let force_no_type_left_padding =
3367            lsp_adapter.name.0.as_ref() == "typescript-language-server";
3368
3369        let hints = message.unwrap_or_default().into_iter().map(|lsp_hint| {
3370            let resolve_state = if InlayHints::can_resolve_inlays(&lsp_server.capabilities()) {
3371                ResolveState::CanResolve(lsp_server.server_id(), lsp_hint.data.clone())
3372            } else {
3373                ResolveState::Resolved
3374            };
3375
3376            let buffer = buffer.clone();
3377            cx.spawn(async move |cx| {
3378                InlayHints::lsp_to_project_hint(
3379                    lsp_hint,
3380                    &buffer,
3381                    server_id,
3382                    resolve_state,
3383                    force_no_type_left_padding,
3384                    cx,
3385                )
3386                .await
3387            })
3388        });
3389        future::join_all(hints)
3390            .await
3391            .into_iter()
3392            .collect::<anyhow::Result<_>>()
3393            .context("lsp to project inlay hints conversion")
3394    }
3395
3396    fn to_proto(&self, project_id: u64, buffer: &Buffer) -> proto::InlayHints {
3397        proto::InlayHints {
3398            project_id,
3399            buffer_id: buffer.remote_id().into(),
3400            start: Some(language::proto::serialize_anchor(&self.range.start)),
3401            end: Some(language::proto::serialize_anchor(&self.range.end)),
3402            version: serialize_version(&buffer.version()),
3403        }
3404    }
3405
3406    async fn from_proto(
3407        message: proto::InlayHints,
3408        _: Entity<LspStore>,
3409        buffer: Entity<Buffer>,
3410        mut cx: AsyncApp,
3411    ) -> Result<Self> {
3412        let start = message
3413            .start
3414            .and_then(language::proto::deserialize_anchor)
3415            .context("invalid start")?;
3416        let end = message
3417            .end
3418            .and_then(language::proto::deserialize_anchor)
3419            .context("invalid end")?;
3420        buffer
3421            .update(&mut cx, |buffer, _| {
3422                buffer.wait_for_version(deserialize_version(&message.version))
3423            })?
3424            .await?;
3425
3426        Ok(Self { range: start..end })
3427    }
3428
3429    fn response_to_proto(
3430        response: Vec<InlayHint>,
3431        _: &mut LspStore,
3432        _: PeerId,
3433        buffer_version: &clock::Global,
3434        _: &mut App,
3435    ) -> proto::InlayHintsResponse {
3436        proto::InlayHintsResponse {
3437            hints: response
3438                .into_iter()
3439                .map(InlayHints::project_to_proto_hint)
3440                .collect(),
3441            version: serialize_version(buffer_version),
3442        }
3443    }
3444
3445    async fn response_from_proto(
3446        self,
3447        message: proto::InlayHintsResponse,
3448        _: Entity<LspStore>,
3449        buffer: Entity<Buffer>,
3450        mut cx: AsyncApp,
3451    ) -> anyhow::Result<Vec<InlayHint>> {
3452        buffer
3453            .update(&mut cx, |buffer, _| {
3454                buffer.wait_for_version(deserialize_version(&message.version))
3455            })?
3456            .await?;
3457
3458        let mut hints = Vec::new();
3459        for message_hint in message.hints {
3460            hints.push(InlayHints::proto_to_project_hint(message_hint)?);
3461        }
3462
3463        Ok(hints)
3464    }
3465
3466    fn buffer_id_from_proto(message: &proto::InlayHints) -> Result<BufferId> {
3467        BufferId::new(message.buffer_id)
3468    }
3469}
3470
3471#[async_trait(?Send)]
3472impl LspCommand for GetCodeLens {
3473    type Response = Vec<CodeAction>;
3474    type LspRequest = lsp::CodeLensRequest;
3475    type ProtoRequest = proto::GetCodeLens;
3476
3477    fn display_name(&self) -> &str {
3478        "Code Lens"
3479    }
3480
3481    fn check_capabilities(&self, capabilities: AdapterServerCapabilities) -> bool {
3482        capabilities
3483            .server_capabilities
3484            .code_lens_provider
3485            .is_some()
3486    }
3487
3488    fn to_lsp(
3489        &self,
3490        path: &Path,
3491        _: &Buffer,
3492        _: &Arc<LanguageServer>,
3493        _: &App,
3494    ) -> Result<lsp::CodeLensParams> {
3495        Ok(lsp::CodeLensParams {
3496            text_document: lsp::TextDocumentIdentifier {
3497                uri: file_path_to_lsp_url(path)?,
3498            },
3499            work_done_progress_params: lsp::WorkDoneProgressParams::default(),
3500            partial_result_params: lsp::PartialResultParams::default(),
3501        })
3502    }
3503
3504    async fn response_from_lsp(
3505        self,
3506        message: Option<Vec<lsp::CodeLens>>,
3507        lsp_store: Entity<LspStore>,
3508        buffer: Entity<Buffer>,
3509        server_id: LanguageServerId,
3510        cx: AsyncApp,
3511    ) -> anyhow::Result<Vec<CodeAction>> {
3512        let snapshot = buffer.read_with(&cx, |buffer, _| buffer.snapshot())?;
3513        let language_server = cx.update(|cx| {
3514            lsp_store
3515                .read(cx)
3516                .language_server_for_id(server_id)
3517                .with_context(|| {
3518                    format!("Missing the language server that just returned a response {server_id}")
3519                })
3520        })??;
3521        let server_capabilities = language_server.capabilities();
3522        let available_commands = server_capabilities
3523            .execute_command_provider
3524            .as_ref()
3525            .map(|options| options.commands.as_slice())
3526            .unwrap_or_default();
3527        Ok(message
3528            .unwrap_or_default()
3529            .into_iter()
3530            .filter(|code_lens| {
3531                code_lens
3532                    .command
3533                    .as_ref()
3534                    .is_none_or(|command| available_commands.contains(&command.command))
3535            })
3536            .map(|code_lens| {
3537                let code_lens_range = range_from_lsp(code_lens.range);
3538                let start = snapshot.clip_point_utf16(code_lens_range.start, Bias::Left);
3539                let end = snapshot.clip_point_utf16(code_lens_range.end, Bias::Right);
3540                let range = snapshot.anchor_before(start)..snapshot.anchor_after(end);
3541                CodeAction {
3542                    server_id,
3543                    range,
3544                    lsp_action: LspAction::CodeLens(code_lens),
3545                    resolved: false,
3546                }
3547            })
3548            .collect())
3549    }
3550
3551    fn to_proto(&self, project_id: u64, buffer: &Buffer) -> proto::GetCodeLens {
3552        proto::GetCodeLens {
3553            project_id,
3554            buffer_id: buffer.remote_id().into(),
3555            version: serialize_version(&buffer.version()),
3556        }
3557    }
3558
3559    async fn from_proto(
3560        message: proto::GetCodeLens,
3561        _: Entity<LspStore>,
3562        buffer: Entity<Buffer>,
3563        mut cx: AsyncApp,
3564    ) -> Result<Self> {
3565        buffer
3566            .update(&mut cx, |buffer, _| {
3567                buffer.wait_for_version(deserialize_version(&message.version))
3568            })?
3569            .await?;
3570        Ok(Self)
3571    }
3572
3573    fn response_to_proto(
3574        response: Vec<CodeAction>,
3575        _: &mut LspStore,
3576        _: PeerId,
3577        buffer_version: &clock::Global,
3578        _: &mut App,
3579    ) -> proto::GetCodeLensResponse {
3580        proto::GetCodeLensResponse {
3581            lens_actions: response
3582                .iter()
3583                .map(LspStore::serialize_code_action)
3584                .collect(),
3585            version: serialize_version(buffer_version),
3586        }
3587    }
3588
3589    async fn response_from_proto(
3590        self,
3591        message: proto::GetCodeLensResponse,
3592        _: Entity<LspStore>,
3593        buffer: Entity<Buffer>,
3594        mut cx: AsyncApp,
3595    ) -> anyhow::Result<Vec<CodeAction>> {
3596        buffer
3597            .update(&mut cx, |buffer, _| {
3598                buffer.wait_for_version(deserialize_version(&message.version))
3599            })?
3600            .await?;
3601        message
3602            .lens_actions
3603            .into_iter()
3604            .map(LspStore::deserialize_code_action)
3605            .collect::<Result<Vec<_>>>()
3606            .context("deserializing proto code lens response")
3607    }
3608
3609    fn buffer_id_from_proto(message: &proto::GetCodeLens) -> Result<BufferId> {
3610        BufferId::new(message.buffer_id)
3611    }
3612}
3613
3614impl LinkedEditingRange {
3615    pub fn check_server_capabilities(capabilities: ServerCapabilities) -> bool {
3616        let Some(linked_editing_options) = capabilities.linked_editing_range_provider else {
3617            return false;
3618        };
3619        if let LinkedEditingRangeServerCapabilities::Simple(false) = linked_editing_options {
3620            return false;
3621        }
3622        true
3623    }
3624}
3625
3626#[async_trait(?Send)]
3627impl LspCommand for LinkedEditingRange {
3628    type Response = Vec<Range<Anchor>>;
3629    type LspRequest = lsp::request::LinkedEditingRange;
3630    type ProtoRequest = proto::LinkedEditingRange;
3631
3632    fn display_name(&self) -> &str {
3633        "Linked editing range"
3634    }
3635
3636    fn check_capabilities(&self, capabilities: AdapterServerCapabilities) -> bool {
3637        Self::check_server_capabilities(capabilities.server_capabilities)
3638    }
3639
3640    fn to_lsp(
3641        &self,
3642        path: &Path,
3643        buffer: &Buffer,
3644        _server: &Arc<LanguageServer>,
3645        _: &App,
3646    ) -> Result<lsp::LinkedEditingRangeParams> {
3647        let position = self.position.to_point_utf16(&buffer.snapshot());
3648        Ok(lsp::LinkedEditingRangeParams {
3649            text_document_position_params: make_lsp_text_document_position(path, position)?,
3650            work_done_progress_params: Default::default(),
3651        })
3652    }
3653
3654    async fn response_from_lsp(
3655        self,
3656        message: Option<lsp::LinkedEditingRanges>,
3657        _: Entity<LspStore>,
3658        buffer: Entity<Buffer>,
3659        _server_id: LanguageServerId,
3660        cx: AsyncApp,
3661    ) -> Result<Vec<Range<Anchor>>> {
3662        if let Some(lsp::LinkedEditingRanges { mut ranges, .. }) = message {
3663            ranges.sort_by_key(|range| range.start);
3664
3665            buffer.read_with(&cx, |buffer, _| {
3666                ranges
3667                    .into_iter()
3668                    .map(|range| {
3669                        let start =
3670                            buffer.clip_point_utf16(point_from_lsp(range.start), Bias::Left);
3671                        let end = buffer.clip_point_utf16(point_from_lsp(range.end), Bias::Left);
3672                        buffer.anchor_before(start)..buffer.anchor_after(end)
3673                    })
3674                    .collect()
3675            })
3676        } else {
3677            Ok(vec![])
3678        }
3679    }
3680
3681    fn to_proto(&self, project_id: u64, buffer: &Buffer) -> proto::LinkedEditingRange {
3682        proto::LinkedEditingRange {
3683            project_id,
3684            buffer_id: buffer.remote_id().to_proto(),
3685            position: Some(serialize_anchor(&self.position)),
3686            version: serialize_version(&buffer.version()),
3687        }
3688    }
3689
3690    async fn from_proto(
3691        message: proto::LinkedEditingRange,
3692        _: Entity<LspStore>,
3693        buffer: Entity<Buffer>,
3694        mut cx: AsyncApp,
3695    ) -> Result<Self> {
3696        let position = message.position.context("invalid position")?;
3697        buffer
3698            .update(&mut cx, |buffer, _| {
3699                buffer.wait_for_version(deserialize_version(&message.version))
3700            })?
3701            .await?;
3702        let position = deserialize_anchor(position).context("invalid position")?;
3703        buffer
3704            .update(&mut cx, |buffer, _| buffer.wait_for_anchors([position]))?
3705            .await?;
3706        Ok(Self { position })
3707    }
3708
3709    fn response_to_proto(
3710        response: Vec<Range<Anchor>>,
3711        _: &mut LspStore,
3712        _: PeerId,
3713        buffer_version: &clock::Global,
3714        _: &mut App,
3715    ) -> proto::LinkedEditingRangeResponse {
3716        proto::LinkedEditingRangeResponse {
3717            items: response
3718                .into_iter()
3719                .map(|range| proto::AnchorRange {
3720                    start: Some(serialize_anchor(&range.start)),
3721                    end: Some(serialize_anchor(&range.end)),
3722                })
3723                .collect(),
3724            version: serialize_version(buffer_version),
3725        }
3726    }
3727
3728    async fn response_from_proto(
3729        self,
3730        message: proto::LinkedEditingRangeResponse,
3731        _: Entity<LspStore>,
3732        buffer: Entity<Buffer>,
3733        mut cx: AsyncApp,
3734    ) -> Result<Vec<Range<Anchor>>> {
3735        buffer
3736            .update(&mut cx, |buffer, _| {
3737                buffer.wait_for_version(deserialize_version(&message.version))
3738            })?
3739            .await?;
3740        let items: Vec<Range<Anchor>> = message
3741            .items
3742            .into_iter()
3743            .filter_map(|range| {
3744                let start = deserialize_anchor(range.start?)?;
3745                let end = deserialize_anchor(range.end?)?;
3746                Some(start..end)
3747            })
3748            .collect();
3749        for range in &items {
3750            buffer
3751                .update(&mut cx, |buffer, _| {
3752                    buffer.wait_for_anchors([range.start, range.end])
3753                })?
3754                .await?;
3755        }
3756        Ok(items)
3757    }
3758
3759    fn buffer_id_from_proto(message: &proto::LinkedEditingRange) -> Result<BufferId> {
3760        BufferId::new(message.buffer_id)
3761    }
3762}
3763
3764impl GetDocumentDiagnostics {
3765    pub fn diagnostics_from_proto(
3766        response: proto::GetDocumentDiagnosticsResponse,
3767    ) -> Vec<LspPullDiagnostics> {
3768        response
3769            .pulled_diagnostics
3770            .into_iter()
3771            .filter_map(|diagnostics| {
3772                Some(LspPullDiagnostics::Response {
3773                    server_id: LanguageServerId::from_proto(diagnostics.server_id),
3774                    uri: lsp::Uri::from_str(diagnostics.uri.as_str()).log_err()?,
3775                    diagnostics: if diagnostics.changed {
3776                        PulledDiagnostics::Unchanged {
3777                            result_id: diagnostics.result_id?,
3778                        }
3779                    } else {
3780                        PulledDiagnostics::Changed {
3781                            result_id: diagnostics.result_id,
3782                            diagnostics: diagnostics
3783                                .diagnostics
3784                                .into_iter()
3785                                .filter_map(|diagnostic| {
3786                                    GetDocumentDiagnostics::deserialize_lsp_diagnostic(diagnostic)
3787                                        .context("deserializing diagnostics")
3788                                        .log_err()
3789                                })
3790                                .collect(),
3791                        }
3792                    },
3793                })
3794            })
3795            .collect()
3796    }
3797
3798    fn deserialize_lsp_diagnostic(diagnostic: proto::LspDiagnostic) -> Result<lsp::Diagnostic> {
3799        let start = diagnostic.start.context("invalid start range")?;
3800        let end = diagnostic.end.context("invalid end range")?;
3801
3802        let range = Range::<PointUtf16> {
3803            start: PointUtf16 {
3804                row: start.row,
3805                column: start.column,
3806            },
3807            end: PointUtf16 {
3808                row: end.row,
3809                column: end.column,
3810            },
3811        };
3812
3813        let data = diagnostic.data.and_then(|data| Value::from_str(&data).ok());
3814        let code = diagnostic.code.map(lsp::NumberOrString::String);
3815
3816        let related_information = diagnostic
3817            .related_information
3818            .into_iter()
3819            .map(|info| {
3820                let start = info.location_range_start.unwrap();
3821                let end = info.location_range_end.unwrap();
3822
3823                lsp::DiagnosticRelatedInformation {
3824                    location: lsp::Location {
3825                        range: lsp::Range {
3826                            start: point_to_lsp(PointUtf16::new(start.row, start.column)),
3827                            end: point_to_lsp(PointUtf16::new(end.row, end.column)),
3828                        },
3829                        uri: lsp::Uri::from_str(&info.location_url.unwrap()).unwrap(),
3830                    },
3831                    message: info.message,
3832                }
3833            })
3834            .collect::<Vec<_>>();
3835
3836        let tags = diagnostic
3837            .tags
3838            .into_iter()
3839            .filter_map(|tag| match proto::LspDiagnosticTag::from_i32(tag) {
3840                Some(proto::LspDiagnosticTag::Unnecessary) => Some(lsp::DiagnosticTag::UNNECESSARY),
3841                Some(proto::LspDiagnosticTag::Deprecated) => Some(lsp::DiagnosticTag::DEPRECATED),
3842                _ => None,
3843            })
3844            .collect::<Vec<_>>();
3845
3846        Ok(lsp::Diagnostic {
3847            range: language::range_to_lsp(range)?,
3848            severity: match proto::lsp_diagnostic::Severity::from_i32(diagnostic.severity).unwrap()
3849            {
3850                proto::lsp_diagnostic::Severity::Error => Some(lsp::DiagnosticSeverity::ERROR),
3851                proto::lsp_diagnostic::Severity::Warning => Some(lsp::DiagnosticSeverity::WARNING),
3852                proto::lsp_diagnostic::Severity::Information => {
3853                    Some(lsp::DiagnosticSeverity::INFORMATION)
3854                }
3855                proto::lsp_diagnostic::Severity::Hint => Some(lsp::DiagnosticSeverity::HINT),
3856                _ => None,
3857            },
3858            code,
3859            code_description: diagnostic
3860                .code_description
3861                .map(|code_description| CodeDescription {
3862                    href: Some(lsp::Uri::from_str(&code_description).unwrap()),
3863                }),
3864            related_information: Some(related_information),
3865            tags: Some(tags),
3866            source: diagnostic.source.clone(),
3867            message: diagnostic.message,
3868            data,
3869        })
3870    }
3871
3872    fn serialize_lsp_diagnostic(diagnostic: lsp::Diagnostic) -> Result<proto::LspDiagnostic> {
3873        let range = language::range_from_lsp(diagnostic.range);
3874        let related_information = diagnostic
3875            .related_information
3876            .unwrap_or_default()
3877            .into_iter()
3878            .map(|related_information| {
3879                let location_range_start =
3880                    point_from_lsp(related_information.location.range.start).0;
3881                let location_range_end = point_from_lsp(related_information.location.range.end).0;
3882
3883                Ok(proto::LspDiagnosticRelatedInformation {
3884                    location_url: Some(related_information.location.uri.to_string()),
3885                    location_range_start: Some(proto::PointUtf16 {
3886                        row: location_range_start.row,
3887                        column: location_range_start.column,
3888                    }),
3889                    location_range_end: Some(proto::PointUtf16 {
3890                        row: location_range_end.row,
3891                        column: location_range_end.column,
3892                    }),
3893                    message: related_information.message,
3894                })
3895            })
3896            .collect::<Result<Vec<_>>>()?;
3897
3898        let tags = diagnostic
3899            .tags
3900            .unwrap_or_default()
3901            .into_iter()
3902            .map(|tag| match tag {
3903                lsp::DiagnosticTag::UNNECESSARY => proto::LspDiagnosticTag::Unnecessary,
3904                lsp::DiagnosticTag::DEPRECATED => proto::LspDiagnosticTag::Deprecated,
3905                _ => proto::LspDiagnosticTag::None,
3906            } as i32)
3907            .collect();
3908
3909        Ok(proto::LspDiagnostic {
3910            start: Some(proto::PointUtf16 {
3911                row: range.start.0.row,
3912                column: range.start.0.column,
3913            }),
3914            end: Some(proto::PointUtf16 {
3915                row: range.end.0.row,
3916                column: range.end.0.column,
3917            }),
3918            severity: match diagnostic.severity {
3919                Some(lsp::DiagnosticSeverity::ERROR) => proto::lsp_diagnostic::Severity::Error,
3920                Some(lsp::DiagnosticSeverity::WARNING) => proto::lsp_diagnostic::Severity::Warning,
3921                Some(lsp::DiagnosticSeverity::INFORMATION) => {
3922                    proto::lsp_diagnostic::Severity::Information
3923                }
3924                Some(lsp::DiagnosticSeverity::HINT) => proto::lsp_diagnostic::Severity::Hint,
3925                _ => proto::lsp_diagnostic::Severity::None,
3926            } as i32,
3927            code: diagnostic.code.as_ref().map(|code| match code {
3928                lsp::NumberOrString::Number(code) => code.to_string(),
3929                lsp::NumberOrString::String(code) => code.clone(),
3930            }),
3931            source: diagnostic.source.clone(),
3932            related_information,
3933            tags,
3934            code_description: diagnostic
3935                .code_description
3936                .and_then(|desc| desc.href.map(|url| url.to_string())),
3937            message: diagnostic.message,
3938            data: diagnostic.data.as_ref().map(|data| data.to_string()),
3939        })
3940    }
3941
3942    pub fn deserialize_workspace_diagnostics_report(
3943        report: lsp::WorkspaceDiagnosticReportResult,
3944        server_id: LanguageServerId,
3945    ) -> Vec<WorkspaceLspPullDiagnostics> {
3946        let mut pulled_diagnostics = HashMap::default();
3947        match report {
3948            lsp::WorkspaceDiagnosticReportResult::Report(workspace_diagnostic_report) => {
3949                for report in workspace_diagnostic_report.items {
3950                    match report {
3951                        lsp::WorkspaceDocumentDiagnosticReport::Full(report) => {
3952                            process_full_workspace_diagnostics_report(
3953                                &mut pulled_diagnostics,
3954                                server_id,
3955                                report,
3956                            )
3957                        }
3958                        lsp::WorkspaceDocumentDiagnosticReport::Unchanged(report) => {
3959                            process_unchanged_workspace_diagnostics_report(
3960                                &mut pulled_diagnostics,
3961                                server_id,
3962                                report,
3963                            )
3964                        }
3965                    }
3966                }
3967            }
3968            lsp::WorkspaceDiagnosticReportResult::Partial(
3969                workspace_diagnostic_report_partial_result,
3970            ) => {
3971                for report in workspace_diagnostic_report_partial_result.items {
3972                    match report {
3973                        lsp::WorkspaceDocumentDiagnosticReport::Full(report) => {
3974                            process_full_workspace_diagnostics_report(
3975                                &mut pulled_diagnostics,
3976                                server_id,
3977                                report,
3978                            )
3979                        }
3980                        lsp::WorkspaceDocumentDiagnosticReport::Unchanged(report) => {
3981                            process_unchanged_workspace_diagnostics_report(
3982                                &mut pulled_diagnostics,
3983                                server_id,
3984                                report,
3985                            )
3986                        }
3987                    }
3988                }
3989            }
3990        }
3991        pulled_diagnostics.into_values().collect()
3992    }
3993}
3994
3995#[derive(Debug)]
3996pub struct WorkspaceLspPullDiagnostics {
3997    pub version: Option<i32>,
3998    pub diagnostics: LspPullDiagnostics,
3999}
4000
4001fn process_full_workspace_diagnostics_report(
4002    diagnostics: &mut HashMap<lsp::Uri, WorkspaceLspPullDiagnostics>,
4003    server_id: LanguageServerId,
4004    report: lsp::WorkspaceFullDocumentDiagnosticReport,
4005) {
4006    let mut new_diagnostics = HashMap::default();
4007    process_full_diagnostics_report(
4008        &mut new_diagnostics,
4009        server_id,
4010        report.uri,
4011        report.full_document_diagnostic_report,
4012    );
4013    diagnostics.extend(new_diagnostics.into_iter().map(|(uri, diagnostics)| {
4014        (
4015            uri,
4016            WorkspaceLspPullDiagnostics {
4017                version: report.version.map(|v| v as i32),
4018                diagnostics,
4019            },
4020        )
4021    }));
4022}
4023
4024fn process_unchanged_workspace_diagnostics_report(
4025    diagnostics: &mut HashMap<lsp::Uri, WorkspaceLspPullDiagnostics>,
4026    server_id: LanguageServerId,
4027    report: lsp::WorkspaceUnchangedDocumentDiagnosticReport,
4028) {
4029    let mut new_diagnostics = HashMap::default();
4030    process_unchanged_diagnostics_report(
4031        &mut new_diagnostics,
4032        server_id,
4033        report.uri,
4034        report.unchanged_document_diagnostic_report,
4035    );
4036    diagnostics.extend(new_diagnostics.into_iter().map(|(uri, diagnostics)| {
4037        (
4038            uri,
4039            WorkspaceLspPullDiagnostics {
4040                version: report.version.map(|v| v as i32),
4041                diagnostics,
4042            },
4043        )
4044    }));
4045}
4046
4047#[async_trait(?Send)]
4048impl LspCommand for GetDocumentDiagnostics {
4049    type Response = Vec<LspPullDiagnostics>;
4050    type LspRequest = lsp::request::DocumentDiagnosticRequest;
4051    type ProtoRequest = proto::GetDocumentDiagnostics;
4052
4053    fn display_name(&self) -> &str {
4054        "Get diagnostics"
4055    }
4056
4057    fn check_capabilities(&self, _: AdapterServerCapabilities) -> bool {
4058        true
4059    }
4060
4061    fn to_lsp(
4062        &self,
4063        path: &Path,
4064        _: &Buffer,
4065        _: &Arc<LanguageServer>,
4066        _: &App,
4067    ) -> Result<lsp::DocumentDiagnosticParams> {
4068        let identifier = match &self.dynamic_caps {
4069            lsp::DiagnosticServerCapabilities::Options(options) => options.identifier.clone(),
4070            lsp::DiagnosticServerCapabilities::RegistrationOptions(options) => {
4071                options.diagnostic_options.identifier.clone()
4072            }
4073        };
4074
4075        Ok(lsp::DocumentDiagnosticParams {
4076            text_document: lsp::TextDocumentIdentifier {
4077                uri: file_path_to_lsp_url(path)?,
4078            },
4079            identifier,
4080            previous_result_id: self.previous_result_id.clone(),
4081            partial_result_params: Default::default(),
4082            work_done_progress_params: Default::default(),
4083        })
4084    }
4085
4086    async fn response_from_lsp(
4087        self,
4088        message: lsp::DocumentDiagnosticReportResult,
4089        _: Entity<LspStore>,
4090        buffer: Entity<Buffer>,
4091        server_id: LanguageServerId,
4092        cx: AsyncApp,
4093    ) -> Result<Self::Response> {
4094        let url = buffer.read_with(&cx, |buffer, cx| {
4095            buffer
4096                .file()
4097                .and_then(|file| file.as_local())
4098                .map(|file| {
4099                    let abs_path = file.abs_path(cx);
4100                    file_path_to_lsp_url(&abs_path)
4101                })
4102                .transpose()?
4103                .with_context(|| format!("missing url on buffer {}", buffer.remote_id()))
4104        })??;
4105
4106        let mut pulled_diagnostics = HashMap::default();
4107        match message {
4108            lsp::DocumentDiagnosticReportResult::Report(report) => match report {
4109                lsp::DocumentDiagnosticReport::Full(report) => {
4110                    if let Some(related_documents) = report.related_documents {
4111                        process_related_documents(
4112                            &mut pulled_diagnostics,
4113                            server_id,
4114                            related_documents,
4115                        );
4116                    }
4117                    process_full_diagnostics_report(
4118                        &mut pulled_diagnostics,
4119                        server_id,
4120                        url,
4121                        report.full_document_diagnostic_report,
4122                    );
4123                }
4124                lsp::DocumentDiagnosticReport::Unchanged(report) => {
4125                    if let Some(related_documents) = report.related_documents {
4126                        process_related_documents(
4127                            &mut pulled_diagnostics,
4128                            server_id,
4129                            related_documents,
4130                        );
4131                    }
4132                    process_unchanged_diagnostics_report(
4133                        &mut pulled_diagnostics,
4134                        server_id,
4135                        url,
4136                        report.unchanged_document_diagnostic_report,
4137                    );
4138                }
4139            },
4140            lsp::DocumentDiagnosticReportResult::Partial(report) => {
4141                if let Some(related_documents) = report.related_documents {
4142                    process_related_documents(
4143                        &mut pulled_diagnostics,
4144                        server_id,
4145                        related_documents,
4146                    );
4147                }
4148            }
4149        }
4150
4151        Ok(pulled_diagnostics.into_values().collect())
4152    }
4153
4154    fn to_proto(&self, project_id: u64, buffer: &Buffer) -> proto::GetDocumentDiagnostics {
4155        proto::GetDocumentDiagnostics {
4156            project_id,
4157            buffer_id: buffer.remote_id().into(),
4158            version: serialize_version(&buffer.version()),
4159        }
4160    }
4161
4162    async fn from_proto(
4163        _: proto::GetDocumentDiagnostics,
4164        _: Entity<LspStore>,
4165        _: Entity<Buffer>,
4166        _: AsyncApp,
4167    ) -> Result<Self> {
4168        anyhow::bail!(
4169            "proto::GetDocumentDiagnostics is not expected to be converted from proto directly, as it needs `previous_result_id` fetched first"
4170        )
4171    }
4172
4173    fn response_to_proto(
4174        response: Self::Response,
4175        _: &mut LspStore,
4176        _: PeerId,
4177        _: &clock::Global,
4178        _: &mut App,
4179    ) -> proto::GetDocumentDiagnosticsResponse {
4180        let pulled_diagnostics = response
4181            .into_iter()
4182            .filter_map(|diagnostics| match diagnostics {
4183                LspPullDiagnostics::Default => None,
4184                LspPullDiagnostics::Response {
4185                    server_id,
4186                    uri,
4187                    diagnostics,
4188                } => {
4189                    let mut changed = false;
4190                    let (diagnostics, result_id) = match diagnostics {
4191                        PulledDiagnostics::Unchanged { result_id } => (Vec::new(), Some(result_id)),
4192                        PulledDiagnostics::Changed {
4193                            result_id,
4194                            diagnostics,
4195                        } => {
4196                            changed = true;
4197                            (diagnostics, result_id)
4198                        }
4199                    };
4200                    Some(proto::PulledDiagnostics {
4201                        changed,
4202                        result_id,
4203                        uri: uri.to_string(),
4204                        server_id: server_id.to_proto(),
4205                        diagnostics: diagnostics
4206                            .into_iter()
4207                            .filter_map(|diagnostic| {
4208                                GetDocumentDiagnostics::serialize_lsp_diagnostic(diagnostic)
4209                                    .context("serializing diagnostics")
4210                                    .log_err()
4211                            })
4212                            .collect(),
4213                    })
4214                }
4215            })
4216            .collect();
4217
4218        proto::GetDocumentDiagnosticsResponse { pulled_diagnostics }
4219    }
4220
4221    async fn response_from_proto(
4222        self,
4223        response: proto::GetDocumentDiagnosticsResponse,
4224        _: Entity<LspStore>,
4225        _: Entity<Buffer>,
4226        _: AsyncApp,
4227    ) -> Result<Self::Response> {
4228        Ok(Self::diagnostics_from_proto(response))
4229    }
4230
4231    fn buffer_id_from_proto(message: &proto::GetDocumentDiagnostics) -> Result<BufferId> {
4232        BufferId::new(message.buffer_id)
4233    }
4234}
4235
4236#[async_trait(?Send)]
4237impl LspCommand for GetDocumentColor {
4238    type Response = Vec<DocumentColor>;
4239    type LspRequest = lsp::request::DocumentColor;
4240    type ProtoRequest = proto::GetDocumentColor;
4241
4242    fn display_name(&self) -> &str {
4243        "Document color"
4244    }
4245
4246    fn check_capabilities(&self, server_capabilities: AdapterServerCapabilities) -> bool {
4247        server_capabilities
4248            .server_capabilities
4249            .color_provider
4250            .as_ref()
4251            .is_some_and(|capability| match capability {
4252                lsp::ColorProviderCapability::Simple(supported) => *supported,
4253                lsp::ColorProviderCapability::ColorProvider(..) => true,
4254                lsp::ColorProviderCapability::Options(..) => true,
4255            })
4256    }
4257
4258    fn to_lsp(
4259        &self,
4260        path: &Path,
4261        _: &Buffer,
4262        _: &Arc<LanguageServer>,
4263        _: &App,
4264    ) -> Result<lsp::DocumentColorParams> {
4265        Ok(lsp::DocumentColorParams {
4266            text_document: make_text_document_identifier(path)?,
4267            work_done_progress_params: Default::default(),
4268            partial_result_params: Default::default(),
4269        })
4270    }
4271
4272    async fn response_from_lsp(
4273        self,
4274        message: Vec<lsp::ColorInformation>,
4275        _: Entity<LspStore>,
4276        _: Entity<Buffer>,
4277        _: LanguageServerId,
4278        _: AsyncApp,
4279    ) -> Result<Self::Response> {
4280        Ok(message
4281            .into_iter()
4282            .map(|color| DocumentColor {
4283                lsp_range: color.range,
4284                color: color.color,
4285                resolved: false,
4286                color_presentations: Vec::new(),
4287            })
4288            .collect())
4289    }
4290
4291    fn to_proto(&self, project_id: u64, buffer: &Buffer) -> Self::ProtoRequest {
4292        proto::GetDocumentColor {
4293            project_id,
4294            buffer_id: buffer.remote_id().to_proto(),
4295            version: serialize_version(&buffer.version()),
4296        }
4297    }
4298
4299    async fn from_proto(
4300        _: Self::ProtoRequest,
4301        _: Entity<LspStore>,
4302        _: Entity<Buffer>,
4303        _: AsyncApp,
4304    ) -> Result<Self> {
4305        Ok(Self {})
4306    }
4307
4308    fn response_to_proto(
4309        response: Self::Response,
4310        _: &mut LspStore,
4311        _: PeerId,
4312        buffer_version: &clock::Global,
4313        _: &mut App,
4314    ) -> proto::GetDocumentColorResponse {
4315        proto::GetDocumentColorResponse {
4316            colors: response
4317                .into_iter()
4318                .map(|color| {
4319                    let start = point_from_lsp(color.lsp_range.start).0;
4320                    let end = point_from_lsp(color.lsp_range.end).0;
4321                    proto::ColorInformation {
4322                        red: color.color.red,
4323                        green: color.color.green,
4324                        blue: color.color.blue,
4325                        alpha: color.color.alpha,
4326                        lsp_range_start: Some(proto::PointUtf16 {
4327                            row: start.row,
4328                            column: start.column,
4329                        }),
4330                        lsp_range_end: Some(proto::PointUtf16 {
4331                            row: end.row,
4332                            column: end.column,
4333                        }),
4334                    }
4335                })
4336                .collect(),
4337            version: serialize_version(buffer_version),
4338        }
4339    }
4340
4341    async fn response_from_proto(
4342        self,
4343        message: proto::GetDocumentColorResponse,
4344        _: Entity<LspStore>,
4345        _: Entity<Buffer>,
4346        _: AsyncApp,
4347    ) -> Result<Self::Response> {
4348        Ok(message
4349            .colors
4350            .into_iter()
4351            .filter_map(|color| {
4352                let start = color.lsp_range_start?;
4353                let start = PointUtf16::new(start.row, start.column);
4354                let end = color.lsp_range_end?;
4355                let end = PointUtf16::new(end.row, end.column);
4356                Some(DocumentColor {
4357                    resolved: false,
4358                    color_presentations: Vec::new(),
4359                    lsp_range: lsp::Range {
4360                        start: point_to_lsp(start),
4361                        end: point_to_lsp(end),
4362                    },
4363                    color: lsp::Color {
4364                        red: color.red,
4365                        green: color.green,
4366                        blue: color.blue,
4367                        alpha: color.alpha,
4368                    },
4369                })
4370            })
4371            .collect())
4372    }
4373
4374    fn buffer_id_from_proto(message: &Self::ProtoRequest) -> Result<BufferId> {
4375        BufferId::new(message.buffer_id)
4376    }
4377}
4378
4379fn process_related_documents(
4380    diagnostics: &mut HashMap<lsp::Uri, LspPullDiagnostics>,
4381    server_id: LanguageServerId,
4382    documents: impl IntoIterator<Item = (lsp::Uri, lsp::DocumentDiagnosticReportKind)>,
4383) {
4384    for (url, report_kind) in documents {
4385        match report_kind {
4386            lsp::DocumentDiagnosticReportKind::Full(report) => {
4387                process_full_diagnostics_report(diagnostics, server_id, url, report)
4388            }
4389            lsp::DocumentDiagnosticReportKind::Unchanged(report) => {
4390                process_unchanged_diagnostics_report(diagnostics, server_id, url, report)
4391            }
4392        }
4393    }
4394}
4395
4396fn process_unchanged_diagnostics_report(
4397    diagnostics: &mut HashMap<lsp::Uri, LspPullDiagnostics>,
4398    server_id: LanguageServerId,
4399    uri: lsp::Uri,
4400    report: lsp::UnchangedDocumentDiagnosticReport,
4401) {
4402    let result_id = report.result_id;
4403    match diagnostics.entry(uri.clone()) {
4404        hash_map::Entry::Occupied(mut o) => match o.get_mut() {
4405            LspPullDiagnostics::Default => {
4406                o.insert(LspPullDiagnostics::Response {
4407                    server_id,
4408                    uri,
4409                    diagnostics: PulledDiagnostics::Unchanged { result_id },
4410                });
4411            }
4412            LspPullDiagnostics::Response {
4413                server_id: existing_server_id,
4414                uri: existing_uri,
4415                diagnostics: existing_diagnostics,
4416            } => {
4417                if server_id != *existing_server_id || &uri != existing_uri {
4418                    debug_panic!(
4419                        "Unexpected state: file {uri} has two different sets of diagnostics reported"
4420                    );
4421                }
4422                match existing_diagnostics {
4423                    PulledDiagnostics::Unchanged { .. } => {
4424                        *existing_diagnostics = PulledDiagnostics::Unchanged { result_id };
4425                    }
4426                    PulledDiagnostics::Changed { .. } => {}
4427                }
4428            }
4429        },
4430        hash_map::Entry::Vacant(v) => {
4431            v.insert(LspPullDiagnostics::Response {
4432                server_id,
4433                uri,
4434                diagnostics: PulledDiagnostics::Unchanged { result_id },
4435            });
4436        }
4437    }
4438}
4439
4440fn process_full_diagnostics_report(
4441    diagnostics: &mut HashMap<lsp::Uri, LspPullDiagnostics>,
4442    server_id: LanguageServerId,
4443    uri: lsp::Uri,
4444    report: lsp::FullDocumentDiagnosticReport,
4445) {
4446    let result_id = report.result_id;
4447    match diagnostics.entry(uri.clone()) {
4448        hash_map::Entry::Occupied(mut o) => match o.get_mut() {
4449            LspPullDiagnostics::Default => {
4450                o.insert(LspPullDiagnostics::Response {
4451                    server_id,
4452                    uri,
4453                    diagnostics: PulledDiagnostics::Changed {
4454                        result_id,
4455                        diagnostics: report.items,
4456                    },
4457                });
4458            }
4459            LspPullDiagnostics::Response {
4460                server_id: existing_server_id,
4461                uri: existing_uri,
4462                diagnostics: existing_diagnostics,
4463            } => {
4464                if server_id != *existing_server_id || &uri != existing_uri {
4465                    debug_panic!(
4466                        "Unexpected state: file {uri} has two different sets of diagnostics reported"
4467                    );
4468                }
4469                match existing_diagnostics {
4470                    PulledDiagnostics::Unchanged { .. } => {
4471                        *existing_diagnostics = PulledDiagnostics::Changed {
4472                            result_id,
4473                            diagnostics: report.items,
4474                        };
4475                    }
4476                    PulledDiagnostics::Changed {
4477                        result_id: existing_result_id,
4478                        diagnostics: existing_diagnostics,
4479                    } => {
4480                        if result_id.is_some() {
4481                            *existing_result_id = result_id;
4482                        }
4483                        existing_diagnostics.extend(report.items);
4484                    }
4485                }
4486            }
4487        },
4488        hash_map::Entry::Vacant(v) => {
4489            v.insert(LspPullDiagnostics::Response {
4490                server_id,
4491                uri,
4492                diagnostics: PulledDiagnostics::Changed {
4493                    result_id,
4494                    diagnostics: report.items,
4495                },
4496            });
4497        }
4498    }
4499}
4500
4501#[cfg(test)]
4502mod tests {
4503    use super::*;
4504    use lsp::{DiagnosticSeverity, DiagnosticTag};
4505    use serde_json::json;
4506
4507    #[test]
4508    fn test_serialize_lsp_diagnostic() {
4509        let lsp_diagnostic = lsp::Diagnostic {
4510            range: lsp::Range {
4511                start: lsp::Position::new(0, 1),
4512                end: lsp::Position::new(2, 3),
4513            },
4514            severity: Some(DiagnosticSeverity::ERROR),
4515            code: Some(lsp::NumberOrString::String("E001".to_string())),
4516            source: Some("test-source".to_string()),
4517            message: "Test error message".to_string(),
4518            related_information: None,
4519            tags: Some(vec![DiagnosticTag::DEPRECATED]),
4520            code_description: None,
4521            data: Some(json!({"detail": "test detail"})),
4522        };
4523
4524        let proto_diagnostic = GetDocumentDiagnostics::serialize_lsp_diagnostic(lsp_diagnostic)
4525            .expect("Failed to serialize diagnostic");
4526
4527        let start = proto_diagnostic.start.unwrap();
4528        let end = proto_diagnostic.end.unwrap();
4529        assert_eq!(start.row, 0);
4530        assert_eq!(start.column, 1);
4531        assert_eq!(end.row, 2);
4532        assert_eq!(end.column, 3);
4533        assert_eq!(
4534            proto_diagnostic.severity,
4535            proto::lsp_diagnostic::Severity::Error as i32
4536        );
4537        assert_eq!(proto_diagnostic.code, Some("E001".to_string()));
4538        assert_eq!(proto_diagnostic.source, Some("test-source".to_string()));
4539        assert_eq!(proto_diagnostic.message, "Test error message");
4540    }
4541
4542    #[test]
4543    fn test_deserialize_lsp_diagnostic() {
4544        let proto_diagnostic = proto::LspDiagnostic {
4545            start: Some(proto::PointUtf16 { row: 0, column: 1 }),
4546            end: Some(proto::PointUtf16 { row: 2, column: 3 }),
4547            severity: proto::lsp_diagnostic::Severity::Warning as i32,
4548            code: Some("ERR".to_string()),
4549            source: Some("Prism".to_string()),
4550            message: "assigned but unused variable - a".to_string(),
4551            related_information: vec![],
4552            tags: vec![],
4553            code_description: None,
4554            data: None,
4555        };
4556
4557        let lsp_diagnostic = GetDocumentDiagnostics::deserialize_lsp_diagnostic(proto_diagnostic)
4558            .expect("Failed to deserialize diagnostic");
4559
4560        assert_eq!(lsp_diagnostic.range.start.line, 0);
4561        assert_eq!(lsp_diagnostic.range.start.character, 1);
4562        assert_eq!(lsp_diagnostic.range.end.line, 2);
4563        assert_eq!(lsp_diagnostic.range.end.character, 3);
4564        assert_eq!(lsp_diagnostic.severity, Some(DiagnosticSeverity::WARNING));
4565        assert_eq!(
4566            lsp_diagnostic.code,
4567            Some(lsp::NumberOrString::String("ERR".to_string()))
4568        );
4569        assert_eq!(lsp_diagnostic.source, Some("Prism".to_string()));
4570        assert_eq!(lsp_diagnostic.message, "assigned but unused variable - a");
4571    }
4572
4573    #[test]
4574    fn test_related_information() {
4575        let related_info = lsp::DiagnosticRelatedInformation {
4576            location: lsp::Location {
4577                uri: lsp::Uri::from_str("file:///test.rs").unwrap(),
4578                range: lsp::Range {
4579                    start: lsp::Position::new(1, 1),
4580                    end: lsp::Position::new(1, 5),
4581                },
4582            },
4583            message: "Related info message".to_string(),
4584        };
4585
4586        let lsp_diagnostic = lsp::Diagnostic {
4587            range: lsp::Range {
4588                start: lsp::Position::new(0, 0),
4589                end: lsp::Position::new(0, 1),
4590            },
4591            severity: Some(DiagnosticSeverity::INFORMATION),
4592            code: None,
4593            source: Some("Prism".to_string()),
4594            message: "assigned but unused variable - a".to_string(),
4595            related_information: Some(vec![related_info]),
4596            tags: None,
4597            code_description: None,
4598            data: None,
4599        };
4600
4601        let proto_diagnostic = GetDocumentDiagnostics::serialize_lsp_diagnostic(lsp_diagnostic)
4602            .expect("Failed to serialize diagnostic");
4603
4604        assert_eq!(proto_diagnostic.related_information.len(), 1);
4605        let related = &proto_diagnostic.related_information[0];
4606        assert_eq!(related.location_url, Some("file:///test.rs".to_string()));
4607        assert_eq!(related.message, "Related info message");
4608    }
4609
4610    #[test]
4611    fn test_invalid_ranges() {
4612        let proto_diagnostic = proto::LspDiagnostic {
4613            start: None,
4614            end: Some(proto::PointUtf16 { row: 2, column: 3 }),
4615            severity: proto::lsp_diagnostic::Severity::Error as i32,
4616            code: None,
4617            source: None,
4618            message: "Test message".to_string(),
4619            related_information: vec![],
4620            tags: vec![],
4621            code_description: None,
4622            data: None,
4623        };
4624
4625        let result = GetDocumentDiagnostics::deserialize_lsp_diagnostic(proto_diagnostic);
4626        assert!(result.is_err());
4627    }
4628}