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