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