lsp_command.rs

   1mod signature_help;
   2
   3use crate::{
   4    CodeAction, CompletionSource, CoreCompletion, CoreCompletionResponse, DocumentColor,
   5    DocumentHighlight, DocumentSymbol, Hover, HoverBlock, HoverBlockKind, InlayHint,
   6    InlayHintLabel, InlayHintLabelPart, InlayHintLabelPartTooltip, InlayHintTooltip, Location,
   7    LocationLink, LspAction, LspPullDiagnostics, MarkupContent, PrepareRenameResponse,
   8    ProjectTransaction, PulledDiagnostics, ResolveState,
   9    lsp_store::{LocalLspStore, LspStore},
  10};
  11use anyhow::{Context as _, Result};
  12use async_trait::async_trait;
  13use client::proto::{self, PeerId};
  14use clock::Global;
  15use collections::{HashMap, HashSet};
  16use futures::future;
  17use gpui::{App, AsyncApp, Entity, Task};
  18use language::{
  19    Anchor, Bias, Buffer, BufferSnapshot, CachedLspAdapter, CharKind, CharScopeContext,
  20    OffsetRangeExt, PointUtf16, ToOffset, ToPointUtf16, Transaction, Unclipped,
  21    language_settings::{InlayHintKind, LanguageSettings, language_settings},
  22    point_from_lsp, point_to_lsp,
  23    proto::{deserialize_anchor, deserialize_version, serialize_anchor, serialize_version},
  24    range_from_lsp, range_to_lsp,
  25};
  26use lsp::{
  27    AdapterServerCapabilities, CodeActionKind, CodeActionOptions, CodeDescription,
  28    CompletionContext, CompletionListItemDefaultsEditRange, CompletionTriggerKind,
  29    DiagnosticServerCapabilities, DocumentHighlightKind, LanguageServer, LanguageServerId,
  30    LinkedEditingRangeServerCapabilities, OneOf, RenameOptions, ServerCapabilities,
  31};
  32use serde_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(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        _: LanguageServerId,
1841        cx: AsyncApp,
1842    ) -> Result<Self::Response> {
1843        let Some(message) = message else {
1844            return Ok(None);
1845        };
1846        cx.update(|cx| SignatureHelp::new(message, Some(lsp_store.read(cx).languages.clone()), cx))
1847    }
1848
1849    fn to_proto(&self, project_id: u64, buffer: &Buffer) -> Self::ProtoRequest {
1850        let offset = buffer.point_utf16_to_offset(self.position);
1851        proto::GetSignatureHelp {
1852            project_id,
1853            buffer_id: buffer.remote_id().to_proto(),
1854            position: Some(serialize_anchor(&buffer.anchor_after(offset))),
1855            version: serialize_version(&buffer.version()),
1856        }
1857    }
1858
1859    async fn from_proto(
1860        payload: Self::ProtoRequest,
1861        _: Entity<LspStore>,
1862        buffer: Entity<Buffer>,
1863        mut cx: AsyncApp,
1864    ) -> Result<Self> {
1865        buffer
1866            .update(&mut cx, |buffer, _| {
1867                buffer.wait_for_version(deserialize_version(&payload.version))
1868            })?
1869            .await
1870            .with_context(|| format!("waiting for version for buffer {}", buffer.entity_id()))?;
1871        let buffer_snapshot = buffer.read_with(&cx, |buffer, _| buffer.snapshot())?;
1872        Ok(Self {
1873            position: payload
1874                .position
1875                .and_then(deserialize_anchor)
1876                .context("invalid position")?
1877                .to_point_utf16(&buffer_snapshot),
1878        })
1879    }
1880
1881    fn response_to_proto(
1882        response: Self::Response,
1883        _: &mut LspStore,
1884        _: PeerId,
1885        _: &Global,
1886        _: &mut App,
1887    ) -> proto::GetSignatureHelpResponse {
1888        proto::GetSignatureHelpResponse {
1889            signature_help: response
1890                .map(|signature_help| lsp_to_proto_signature(signature_help.original_data)),
1891        }
1892    }
1893
1894    async fn response_from_proto(
1895        self,
1896        response: proto::GetSignatureHelpResponse,
1897        lsp_store: Entity<LspStore>,
1898        _: Entity<Buffer>,
1899        cx: AsyncApp,
1900    ) -> Result<Self::Response> {
1901        cx.update(|cx| {
1902            response
1903                .signature_help
1904                .map(proto_to_lsp_signature)
1905                .and_then(|signature| {
1906                    SignatureHelp::new(signature, Some(lsp_store.read(cx).languages.clone()), cx)
1907                })
1908        })
1909    }
1910
1911    fn buffer_id_from_proto(message: &Self::ProtoRequest) -> Result<BufferId> {
1912        BufferId::new(message.buffer_id)
1913    }
1914}
1915
1916#[async_trait(?Send)]
1917impl LspCommand for GetHover {
1918    type Response = Option<Hover>;
1919    type LspRequest = lsp::request::HoverRequest;
1920    type ProtoRequest = proto::GetHover;
1921
1922    fn display_name(&self) -> &str {
1923        "Get hover"
1924    }
1925
1926    fn check_capabilities(&self, capabilities: AdapterServerCapabilities) -> bool {
1927        match capabilities.server_capabilities.hover_provider {
1928            Some(lsp::HoverProviderCapability::Simple(enabled)) => enabled,
1929            Some(lsp::HoverProviderCapability::Options(_)) => true,
1930            None => false,
1931        }
1932    }
1933
1934    fn to_lsp(
1935        &self,
1936        path: &Path,
1937        _: &Buffer,
1938        _: &Arc<LanguageServer>,
1939        _: &App,
1940    ) -> Result<lsp::HoverParams> {
1941        Ok(lsp::HoverParams {
1942            text_document_position_params: make_lsp_text_document_position(path, self.position)?,
1943            work_done_progress_params: Default::default(),
1944        })
1945    }
1946
1947    async fn response_from_lsp(
1948        self,
1949        message: Option<lsp::Hover>,
1950        _: Entity<LspStore>,
1951        buffer: Entity<Buffer>,
1952        _: LanguageServerId,
1953        cx: AsyncApp,
1954    ) -> Result<Self::Response> {
1955        let Some(hover) = message else {
1956            return Ok(None);
1957        };
1958
1959        let (language, range) = buffer.read_with(&cx, |buffer, _| {
1960            (
1961                buffer.language().cloned(),
1962                hover.range.map(|range| {
1963                    let token_start =
1964                        buffer.clip_point_utf16(point_from_lsp(range.start), Bias::Left);
1965                    let token_end = buffer.clip_point_utf16(point_from_lsp(range.end), Bias::Left);
1966                    buffer.anchor_after(token_start)..buffer.anchor_before(token_end)
1967                }),
1968            )
1969        })?;
1970
1971        fn hover_blocks_from_marked_string(marked_string: lsp::MarkedString) -> Option<HoverBlock> {
1972            let block = match marked_string {
1973                lsp::MarkedString::String(content) => HoverBlock {
1974                    text: content,
1975                    kind: HoverBlockKind::Markdown,
1976                },
1977                lsp::MarkedString::LanguageString(lsp::LanguageString { language, value }) => {
1978                    HoverBlock {
1979                        text: value,
1980                        kind: HoverBlockKind::Code { language },
1981                    }
1982                }
1983            };
1984            if block.text.is_empty() {
1985                None
1986            } else {
1987                Some(block)
1988            }
1989        }
1990
1991        let contents = match hover.contents {
1992            lsp::HoverContents::Scalar(marked_string) => {
1993                hover_blocks_from_marked_string(marked_string)
1994                    .into_iter()
1995                    .collect()
1996            }
1997            lsp::HoverContents::Array(marked_strings) => marked_strings
1998                .into_iter()
1999                .filter_map(hover_blocks_from_marked_string)
2000                .collect(),
2001            lsp::HoverContents::Markup(markup_content) => vec![HoverBlock {
2002                text: markup_content.value,
2003                kind: if markup_content.kind == lsp::MarkupKind::Markdown {
2004                    HoverBlockKind::Markdown
2005                } else {
2006                    HoverBlockKind::PlainText
2007                },
2008            }],
2009        };
2010
2011        Ok(Some(Hover {
2012            contents,
2013            range,
2014            language,
2015        }))
2016    }
2017
2018    fn to_proto(&self, project_id: u64, buffer: &Buffer) -> Self::ProtoRequest {
2019        proto::GetHover {
2020            project_id,
2021            buffer_id: buffer.remote_id().into(),
2022            position: Some(language::proto::serialize_anchor(
2023                &buffer.anchor_before(self.position),
2024            )),
2025            version: serialize_version(&buffer.version),
2026        }
2027    }
2028
2029    async fn from_proto(
2030        message: Self::ProtoRequest,
2031        _: Entity<LspStore>,
2032        buffer: Entity<Buffer>,
2033        mut cx: AsyncApp,
2034    ) -> Result<Self> {
2035        let position = message
2036            .position
2037            .and_then(deserialize_anchor)
2038            .context("invalid position")?;
2039        buffer
2040            .update(&mut cx, |buffer, _| {
2041                buffer.wait_for_version(deserialize_version(&message.version))
2042            })?
2043            .await?;
2044        Ok(Self {
2045            position: buffer.read_with(&cx, |buffer, _| position.to_point_utf16(buffer))?,
2046        })
2047    }
2048
2049    fn response_to_proto(
2050        response: Self::Response,
2051        _: &mut LspStore,
2052        _: PeerId,
2053        _: &clock::Global,
2054        _: &mut App,
2055    ) -> proto::GetHoverResponse {
2056        if let Some(response) = response {
2057            let (start, end) = if let Some(range) = response.range {
2058                (
2059                    Some(language::proto::serialize_anchor(&range.start)),
2060                    Some(language::proto::serialize_anchor(&range.end)),
2061                )
2062            } else {
2063                (None, None)
2064            };
2065
2066            let contents = response
2067                .contents
2068                .into_iter()
2069                .map(|block| proto::HoverBlock {
2070                    text: block.text,
2071                    is_markdown: block.kind == HoverBlockKind::Markdown,
2072                    language: if let HoverBlockKind::Code { language } = block.kind {
2073                        Some(language)
2074                    } else {
2075                        None
2076                    },
2077                })
2078                .collect();
2079
2080            proto::GetHoverResponse {
2081                start,
2082                end,
2083                contents,
2084            }
2085        } else {
2086            proto::GetHoverResponse {
2087                start: None,
2088                end: None,
2089                contents: Vec::new(),
2090            }
2091        }
2092    }
2093
2094    async fn response_from_proto(
2095        self,
2096        message: proto::GetHoverResponse,
2097        _: Entity<LspStore>,
2098        buffer: Entity<Buffer>,
2099        mut cx: AsyncApp,
2100    ) -> Result<Self::Response> {
2101        let contents: Vec<_> = message
2102            .contents
2103            .into_iter()
2104            .map(|block| HoverBlock {
2105                text: block.text,
2106                kind: if let Some(language) = block.language {
2107                    HoverBlockKind::Code { language }
2108                } else if block.is_markdown {
2109                    HoverBlockKind::Markdown
2110                } else {
2111                    HoverBlockKind::PlainText
2112                },
2113            })
2114            .collect();
2115        if contents.is_empty() {
2116            return Ok(None);
2117        }
2118
2119        let language = buffer.read_with(&cx, |buffer, _| buffer.language().cloned())?;
2120        let range = if let (Some(start), Some(end)) = (message.start, message.end) {
2121            language::proto::deserialize_anchor(start)
2122                .and_then(|start| language::proto::deserialize_anchor(end).map(|end| start..end))
2123        } else {
2124            None
2125        };
2126        if let Some(range) = range.as_ref() {
2127            buffer
2128                .update(&mut cx, |buffer, _| {
2129                    buffer.wait_for_anchors([range.start, range.end])
2130                })?
2131                .await?;
2132        }
2133
2134        Ok(Some(Hover {
2135            contents,
2136            range,
2137            language,
2138        }))
2139    }
2140
2141    fn buffer_id_from_proto(message: &Self::ProtoRequest) -> Result<BufferId> {
2142        BufferId::new(message.buffer_id)
2143    }
2144}
2145
2146impl GetCompletions {
2147    pub fn can_resolve_completions(capabilities: &lsp::ServerCapabilities) -> bool {
2148        capabilities
2149            .completion_provider
2150            .as_ref()
2151            .and_then(|options| options.resolve_provider)
2152            .unwrap_or(false)
2153    }
2154}
2155
2156#[async_trait(?Send)]
2157impl LspCommand for GetCompletions {
2158    type Response = CoreCompletionResponse;
2159    type LspRequest = lsp::request::Completion;
2160    type ProtoRequest = proto::GetCompletions;
2161
2162    fn display_name(&self) -> &str {
2163        "Get completion"
2164    }
2165
2166    fn check_capabilities(&self, capabilities: AdapterServerCapabilities) -> bool {
2167        capabilities
2168            .server_capabilities
2169            .completion_provider
2170            .is_some()
2171    }
2172
2173    fn to_lsp(
2174        &self,
2175        path: &Path,
2176        _: &Buffer,
2177        _: &Arc<LanguageServer>,
2178        _: &App,
2179    ) -> Result<lsp::CompletionParams> {
2180        Ok(lsp::CompletionParams {
2181            text_document_position: make_lsp_text_document_position(path, self.position)?,
2182            context: Some(self.context.clone()),
2183            work_done_progress_params: Default::default(),
2184            partial_result_params: Default::default(),
2185        })
2186    }
2187
2188    async fn response_from_lsp(
2189        self,
2190        completions: Option<lsp::CompletionResponse>,
2191        lsp_store: Entity<LspStore>,
2192        buffer: Entity<Buffer>,
2193        server_id: LanguageServerId,
2194        mut cx: AsyncApp,
2195    ) -> Result<Self::Response> {
2196        let mut response_list = None;
2197        let (mut completions, mut is_incomplete) = if let Some(completions) = completions {
2198            match completions {
2199                lsp::CompletionResponse::Array(completions) => (completions, false),
2200                lsp::CompletionResponse::List(mut list) => {
2201                    let is_incomplete = list.is_incomplete;
2202                    let items = std::mem::take(&mut list.items);
2203                    response_list = Some(list);
2204                    (items, is_incomplete)
2205                }
2206            }
2207        } else {
2208            (Vec::new(), false)
2209        };
2210
2211        let unfiltered_completions_count = completions.len();
2212
2213        let language_server_adapter = lsp_store
2214            .read_with(&cx, |lsp_store, _| {
2215                lsp_store.language_server_adapter_for_id(server_id)
2216            })?
2217            .with_context(|| format!("no language server with id {server_id}"))?;
2218
2219        let lsp_defaults = response_list
2220            .as_ref()
2221            .and_then(|list| list.item_defaults.clone())
2222            .map(Arc::new);
2223
2224        let mut completion_edits = Vec::new();
2225        buffer.update(&mut cx, |buffer, _cx| {
2226            let snapshot = buffer.snapshot();
2227            let clipped_position = buffer.clip_point_utf16(Unclipped(self.position), Bias::Left);
2228
2229            let mut range_for_token = None;
2230            completions.retain(|lsp_completion| {
2231                let lsp_edit = lsp_completion.text_edit.clone().or_else(|| {
2232                    let default_text_edit = lsp_defaults.as_deref()?.edit_range.as_ref()?;
2233                    let new_text = lsp_completion
2234                        .insert_text
2235                        .as_ref()
2236                        .unwrap_or(&lsp_completion.label)
2237                        .clone();
2238                    match default_text_edit {
2239                        CompletionListItemDefaultsEditRange::Range(range) => {
2240                            Some(lsp::CompletionTextEdit::Edit(lsp::TextEdit {
2241                                range: *range,
2242                                new_text,
2243                            }))
2244                        }
2245                        CompletionListItemDefaultsEditRange::InsertAndReplace {
2246                            insert,
2247                            replace,
2248                        } => Some(lsp::CompletionTextEdit::InsertAndReplace(
2249                            lsp::InsertReplaceEdit {
2250                                new_text,
2251                                insert: *insert,
2252                                replace: *replace,
2253                            },
2254                        )),
2255                    }
2256                });
2257
2258                let edit = match lsp_edit {
2259                    // If the language server provides a range to overwrite, then
2260                    // check that the range is valid.
2261                    Some(completion_text_edit) => {
2262                        match parse_completion_text_edit(&completion_text_edit, &snapshot) {
2263                            Some(edit) => edit,
2264                            None => return false,
2265                        }
2266                    }
2267                    // If the language server does not provide a range, then infer
2268                    // the range based on the syntax tree.
2269                    None => {
2270                        if self.position != clipped_position {
2271                            log::info!("completion out of expected range ");
2272                            return false;
2273                        }
2274
2275                        let default_edit_range = lsp_defaults.as_ref().and_then(|lsp_defaults| {
2276                            lsp_defaults
2277                                .edit_range
2278                                .as_ref()
2279                                .and_then(|range| match range {
2280                                    CompletionListItemDefaultsEditRange::Range(r) => Some(r),
2281                                    _ => None,
2282                                })
2283                        });
2284
2285                        let range = if let Some(range) = default_edit_range {
2286                            let range = range_from_lsp(*range);
2287                            let start = snapshot.clip_point_utf16(range.start, Bias::Left);
2288                            let end = snapshot.clip_point_utf16(range.end, Bias::Left);
2289                            if start != range.start.0 || end != range.end.0 {
2290                                log::info!("completion out of expected range");
2291                                return false;
2292                            }
2293
2294                            snapshot.anchor_before(start)..snapshot.anchor_after(end)
2295                        } else {
2296                            range_for_token
2297                                .get_or_insert_with(|| {
2298                                    let offset = self.position.to_offset(&snapshot);
2299                                    let (range, kind) = snapshot.surrounding_word(
2300                                        offset,
2301                                        Some(CharScopeContext::Completion),
2302                                    );
2303                                    let range = if kind == Some(CharKind::Word) {
2304                                        range
2305                                    } else {
2306                                        offset..offset
2307                                    };
2308
2309                                    snapshot.anchor_before(range.start)
2310                                        ..snapshot.anchor_after(range.end)
2311                                })
2312                                .clone()
2313                        };
2314
2315                        // We already know text_edit is None here
2316                        let text = lsp_completion
2317                            .insert_text
2318                            .as_ref()
2319                            .unwrap_or(&lsp_completion.label)
2320                            .clone();
2321
2322                        ParsedCompletionEdit {
2323                            replace_range: range,
2324                            insert_range: None,
2325                            new_text: text,
2326                        }
2327                    }
2328                };
2329
2330                completion_edits.push(edit);
2331                true
2332            });
2333        })?;
2334
2335        // If completions were filtered out due to errors that may be transient, mark the result
2336        // incomplete so that it is re-queried.
2337        if unfiltered_completions_count != completions.len() {
2338            is_incomplete = true;
2339        }
2340
2341        language_server_adapter
2342            .process_completions(&mut completions)
2343            .await;
2344
2345        let completions = completions
2346            .into_iter()
2347            .zip(completion_edits)
2348            .map(|(mut lsp_completion, mut edit)| {
2349                LineEnding::normalize(&mut edit.new_text);
2350                if lsp_completion.data.is_none()
2351                    && let Some(default_data) = lsp_defaults
2352                        .as_ref()
2353                        .and_then(|item_defaults| item_defaults.data.clone())
2354                {
2355                    // Servers (e.g. JDTLS) prefer unchanged completions, when resolving the items later,
2356                    // so we do not insert the defaults here, but `data` is needed for resolving, so this is an exception.
2357                    lsp_completion.data = Some(default_data);
2358                }
2359                CoreCompletion {
2360                    replace_range: edit.replace_range,
2361                    new_text: edit.new_text,
2362                    source: CompletionSource::Lsp {
2363                        insert_range: edit.insert_range,
2364                        server_id,
2365                        lsp_completion: Box::new(lsp_completion),
2366                        lsp_defaults: lsp_defaults.clone(),
2367                        resolved: false,
2368                    },
2369                }
2370            })
2371            .collect();
2372
2373        Ok(CoreCompletionResponse {
2374            completions,
2375            is_incomplete,
2376        })
2377    }
2378
2379    fn to_proto(&self, project_id: u64, buffer: &Buffer) -> proto::GetCompletions {
2380        let anchor = buffer.anchor_after(self.position);
2381        proto::GetCompletions {
2382            project_id,
2383            buffer_id: buffer.remote_id().into(),
2384            position: Some(language::proto::serialize_anchor(&anchor)),
2385            version: serialize_version(&buffer.version()),
2386        }
2387    }
2388
2389    async fn from_proto(
2390        message: proto::GetCompletions,
2391        _: Entity<LspStore>,
2392        buffer: Entity<Buffer>,
2393        mut cx: AsyncApp,
2394    ) -> Result<Self> {
2395        let version = deserialize_version(&message.version);
2396        buffer
2397            .update(&mut cx, |buffer, _| buffer.wait_for_version(version))?
2398            .await?;
2399        let position = message
2400            .position
2401            .and_then(language::proto::deserialize_anchor)
2402            .map(|p| {
2403                buffer.read_with(&cx, |buffer, _| {
2404                    buffer.clip_point_utf16(Unclipped(p.to_point_utf16(buffer)), Bias::Left)
2405                })
2406            })
2407            .context("invalid position")??;
2408        Ok(Self {
2409            position,
2410            context: CompletionContext {
2411                trigger_kind: CompletionTriggerKind::INVOKED,
2412                trigger_character: None,
2413            },
2414        })
2415    }
2416
2417    fn response_to_proto(
2418        response: CoreCompletionResponse,
2419        _: &mut LspStore,
2420        _: PeerId,
2421        buffer_version: &clock::Global,
2422        _: &mut App,
2423    ) -> proto::GetCompletionsResponse {
2424        proto::GetCompletionsResponse {
2425            completions: response
2426                .completions
2427                .iter()
2428                .map(LspStore::serialize_completion)
2429                .collect(),
2430            version: serialize_version(buffer_version),
2431            can_reuse: !response.is_incomplete,
2432        }
2433    }
2434
2435    async fn response_from_proto(
2436        self,
2437        message: proto::GetCompletionsResponse,
2438        _project: Entity<LspStore>,
2439        buffer: Entity<Buffer>,
2440        mut cx: AsyncApp,
2441    ) -> Result<Self::Response> {
2442        buffer
2443            .update(&mut cx, |buffer, _| {
2444                buffer.wait_for_version(deserialize_version(&message.version))
2445            })?
2446            .await?;
2447
2448        let completions = message
2449            .completions
2450            .into_iter()
2451            .map(LspStore::deserialize_completion)
2452            .collect::<Result<Vec<_>>>()?;
2453
2454        Ok(CoreCompletionResponse {
2455            completions,
2456            is_incomplete: !message.can_reuse,
2457        })
2458    }
2459
2460    fn buffer_id_from_proto(message: &proto::GetCompletions) -> Result<BufferId> {
2461        BufferId::new(message.buffer_id)
2462    }
2463}
2464
2465pub struct ParsedCompletionEdit {
2466    pub replace_range: Range<Anchor>,
2467    pub insert_range: Option<Range<Anchor>>,
2468    pub new_text: String,
2469}
2470
2471pub(crate) fn parse_completion_text_edit(
2472    edit: &lsp::CompletionTextEdit,
2473    snapshot: &BufferSnapshot,
2474) -> Option<ParsedCompletionEdit> {
2475    let (replace_range, insert_range, new_text) = match edit {
2476        lsp::CompletionTextEdit::Edit(edit) => (edit.range, None, &edit.new_text),
2477        lsp::CompletionTextEdit::InsertAndReplace(edit) => {
2478            (edit.replace, Some(edit.insert), &edit.new_text)
2479        }
2480    };
2481
2482    let replace_range = {
2483        let range = range_from_lsp(replace_range);
2484        let start = snapshot.clip_point_utf16(range.start, Bias::Left);
2485        let end = snapshot.clip_point_utf16(range.end, Bias::Left);
2486        if start != range.start.0 || end != range.end.0 {
2487            log::info!(
2488                "completion out of expected range, start: {start:?}, end: {end:?}, range: {range:?}"
2489            );
2490            return None;
2491        }
2492        snapshot.anchor_before(start)..snapshot.anchor_after(end)
2493    };
2494
2495    let insert_range = match insert_range {
2496        None => None,
2497        Some(insert_range) => {
2498            let range = range_from_lsp(insert_range);
2499            let start = snapshot.clip_point_utf16(range.start, Bias::Left);
2500            let end = snapshot.clip_point_utf16(range.end, Bias::Left);
2501            if start != range.start.0 || end != range.end.0 {
2502                log::info!("completion (insert) out of expected range");
2503                return None;
2504            }
2505            Some(snapshot.anchor_before(start)..snapshot.anchor_after(end))
2506        }
2507    };
2508
2509    Some(ParsedCompletionEdit {
2510        insert_range,
2511        replace_range,
2512        new_text: new_text.clone(),
2513    })
2514}
2515
2516#[async_trait(?Send)]
2517impl LspCommand for GetCodeActions {
2518    type Response = Vec<CodeAction>;
2519    type LspRequest = lsp::request::CodeActionRequest;
2520    type ProtoRequest = proto::GetCodeActions;
2521
2522    fn display_name(&self) -> &str {
2523        "Get code actions"
2524    }
2525
2526    fn check_capabilities(&self, capabilities: AdapterServerCapabilities) -> bool {
2527        match &capabilities.server_capabilities.code_action_provider {
2528            None => false,
2529            Some(lsp::CodeActionProviderCapability::Simple(false)) => false,
2530            _ => {
2531                // If we do know that we want specific code actions AND we know that
2532                // the server only supports specific code actions, then we want to filter
2533                // down to the ones that are supported.
2534                if let Some((requested, supported)) = self
2535                    .kinds
2536                    .as_ref()
2537                    .zip(Self::supported_code_action_kinds(capabilities))
2538                {
2539                    let server_supported = supported.into_iter().collect::<HashSet<_>>();
2540                    requested.iter().any(|kind| server_supported.contains(kind))
2541                } else {
2542                    true
2543                }
2544            }
2545        }
2546    }
2547
2548    fn to_lsp(
2549        &self,
2550        path: &Path,
2551        buffer: &Buffer,
2552        language_server: &Arc<LanguageServer>,
2553        _: &App,
2554    ) -> Result<lsp::CodeActionParams> {
2555        let mut relevant_diagnostics = Vec::new();
2556        for entry in buffer
2557            .snapshot()
2558            .diagnostics_in_range::<_, language::PointUtf16>(self.range.clone(), false)
2559        {
2560            relevant_diagnostics.push(entry.to_lsp_diagnostic_stub()?);
2561        }
2562
2563        let supported =
2564            Self::supported_code_action_kinds(language_server.adapter_server_capabilities());
2565
2566        let only = if let Some(requested) = &self.kinds {
2567            if let Some(supported_kinds) = supported {
2568                let server_supported = supported_kinds.into_iter().collect::<HashSet<_>>();
2569
2570                let filtered = requested
2571                    .iter()
2572                    .filter(|kind| server_supported.contains(kind))
2573                    .cloned()
2574                    .collect();
2575                Some(filtered)
2576            } else {
2577                Some(requested.clone())
2578            }
2579        } else {
2580            supported
2581        };
2582
2583        Ok(lsp::CodeActionParams {
2584            text_document: make_text_document_identifier(path)?,
2585            range: range_to_lsp(self.range.to_point_utf16(buffer))?,
2586            work_done_progress_params: Default::default(),
2587            partial_result_params: Default::default(),
2588            context: lsp::CodeActionContext {
2589                diagnostics: relevant_diagnostics,
2590                only,
2591                ..lsp::CodeActionContext::default()
2592            },
2593        })
2594    }
2595
2596    async fn response_from_lsp(
2597        self,
2598        actions: Option<lsp::CodeActionResponse>,
2599        lsp_store: Entity<LspStore>,
2600        _: Entity<Buffer>,
2601        server_id: LanguageServerId,
2602        cx: AsyncApp,
2603    ) -> Result<Vec<CodeAction>> {
2604        let requested_kinds_set = self
2605            .kinds
2606            .map(|kinds| kinds.into_iter().collect::<HashSet<_>>());
2607
2608        let language_server = cx.update(|cx| {
2609            lsp_store
2610                .read(cx)
2611                .language_server_for_id(server_id)
2612                .with_context(|| {
2613                    format!("Missing the language server that just returned a response {server_id}")
2614                })
2615        })??;
2616
2617        let server_capabilities = language_server.capabilities();
2618        let available_commands = server_capabilities
2619            .execute_command_provider
2620            .as_ref()
2621            .map(|options| options.commands.as_slice())
2622            .unwrap_or_default();
2623        Ok(actions
2624            .unwrap_or_default()
2625            .into_iter()
2626            .filter_map(|entry| {
2627                let (lsp_action, resolved) = match entry {
2628                    lsp::CodeActionOrCommand::CodeAction(lsp_action) => {
2629                        if let Some(command) = lsp_action.command.as_ref()
2630                            && !available_commands.contains(&command.command)
2631                        {
2632                            return None;
2633                        }
2634                        (LspAction::Action(Box::new(lsp_action)), false)
2635                    }
2636                    lsp::CodeActionOrCommand::Command(command) => {
2637                        if available_commands.contains(&command.command) {
2638                            (LspAction::Command(command), true)
2639                        } else {
2640                            return None;
2641                        }
2642                    }
2643                };
2644
2645                if let Some((requested_kinds, kind)) =
2646                    requested_kinds_set.as_ref().zip(lsp_action.action_kind())
2647                    && !requested_kinds.contains(&kind)
2648                {
2649                    return None;
2650                }
2651
2652                Some(CodeAction {
2653                    server_id,
2654                    range: self.range.clone(),
2655                    lsp_action,
2656                    resolved,
2657                })
2658            })
2659            .collect())
2660    }
2661
2662    fn to_proto(&self, project_id: u64, buffer: &Buffer) -> proto::GetCodeActions {
2663        proto::GetCodeActions {
2664            project_id,
2665            buffer_id: buffer.remote_id().into(),
2666            start: Some(language::proto::serialize_anchor(&self.range.start)),
2667            end: Some(language::proto::serialize_anchor(&self.range.end)),
2668            version: serialize_version(&buffer.version()),
2669        }
2670    }
2671
2672    async fn from_proto(
2673        message: proto::GetCodeActions,
2674        _: Entity<LspStore>,
2675        buffer: Entity<Buffer>,
2676        mut cx: AsyncApp,
2677    ) -> Result<Self> {
2678        let start = message
2679            .start
2680            .and_then(language::proto::deserialize_anchor)
2681            .context("invalid start")?;
2682        let end = message
2683            .end
2684            .and_then(language::proto::deserialize_anchor)
2685            .context("invalid end")?;
2686        buffer
2687            .update(&mut cx, |buffer, _| {
2688                buffer.wait_for_version(deserialize_version(&message.version))
2689            })?
2690            .await?;
2691
2692        Ok(Self {
2693            range: start..end,
2694            kinds: None,
2695        })
2696    }
2697
2698    fn response_to_proto(
2699        code_actions: Vec<CodeAction>,
2700        _: &mut LspStore,
2701        _: PeerId,
2702        buffer_version: &clock::Global,
2703        _: &mut App,
2704    ) -> proto::GetCodeActionsResponse {
2705        proto::GetCodeActionsResponse {
2706            actions: code_actions
2707                .iter()
2708                .map(LspStore::serialize_code_action)
2709                .collect(),
2710            version: serialize_version(buffer_version),
2711        }
2712    }
2713
2714    async fn response_from_proto(
2715        self,
2716        message: proto::GetCodeActionsResponse,
2717        _: Entity<LspStore>,
2718        buffer: Entity<Buffer>,
2719        mut cx: AsyncApp,
2720    ) -> Result<Vec<CodeAction>> {
2721        buffer
2722            .update(&mut cx, |buffer, _| {
2723                buffer.wait_for_version(deserialize_version(&message.version))
2724            })?
2725            .await?;
2726        message
2727            .actions
2728            .into_iter()
2729            .map(LspStore::deserialize_code_action)
2730            .collect()
2731    }
2732
2733    fn buffer_id_from_proto(message: &proto::GetCodeActions) -> Result<BufferId> {
2734        BufferId::new(message.buffer_id)
2735    }
2736}
2737
2738impl GetCodeActions {
2739    fn supported_code_action_kinds(
2740        capabilities: AdapterServerCapabilities,
2741    ) -> Option<Vec<CodeActionKind>> {
2742        match capabilities.server_capabilities.code_action_provider {
2743            Some(lsp::CodeActionProviderCapability::Options(CodeActionOptions {
2744                code_action_kinds: Some(supported_action_kinds),
2745                ..
2746            })) => Some(supported_action_kinds),
2747            _ => capabilities.code_action_kinds,
2748        }
2749    }
2750
2751    pub fn can_resolve_actions(capabilities: &ServerCapabilities) -> bool {
2752        capabilities
2753            .code_action_provider
2754            .as_ref()
2755            .and_then(|options| match options {
2756                lsp::CodeActionProviderCapability::Simple(_is_supported) => None,
2757                lsp::CodeActionProviderCapability::Options(options) => options.resolve_provider,
2758            })
2759            .unwrap_or(false)
2760    }
2761}
2762
2763impl OnTypeFormatting {
2764    pub fn supports_on_type_formatting(trigger: &str, capabilities: &ServerCapabilities) -> bool {
2765        let Some(on_type_formatting_options) = &capabilities.document_on_type_formatting_provider
2766        else {
2767            return false;
2768        };
2769        on_type_formatting_options
2770            .first_trigger_character
2771            .contains(trigger)
2772            || on_type_formatting_options
2773                .more_trigger_character
2774                .iter()
2775                .flatten()
2776                .any(|chars| chars.contains(trigger))
2777    }
2778}
2779
2780#[async_trait(?Send)]
2781impl LspCommand for OnTypeFormatting {
2782    type Response = Option<Transaction>;
2783    type LspRequest = lsp::request::OnTypeFormatting;
2784    type ProtoRequest = proto::OnTypeFormatting;
2785
2786    fn display_name(&self) -> &str {
2787        "Formatting on typing"
2788    }
2789
2790    fn check_capabilities(&self, capabilities: AdapterServerCapabilities) -> bool {
2791        Self::supports_on_type_formatting(&self.trigger, &capabilities.server_capabilities)
2792    }
2793
2794    fn to_lsp(
2795        &self,
2796        path: &Path,
2797        _: &Buffer,
2798        _: &Arc<LanguageServer>,
2799        _: &App,
2800    ) -> Result<lsp::DocumentOnTypeFormattingParams> {
2801        Ok(lsp::DocumentOnTypeFormattingParams {
2802            text_document_position: make_lsp_text_document_position(path, self.position)?,
2803            ch: self.trigger.clone(),
2804            options: self.options.clone(),
2805        })
2806    }
2807
2808    async fn response_from_lsp(
2809        self,
2810        message: Option<Vec<lsp::TextEdit>>,
2811        lsp_store: Entity<LspStore>,
2812        buffer: Entity<Buffer>,
2813        server_id: LanguageServerId,
2814        mut cx: AsyncApp,
2815    ) -> Result<Option<Transaction>> {
2816        if let Some(edits) = message {
2817            let (lsp_adapter, lsp_server) =
2818                language_server_for_buffer(&lsp_store, &buffer, server_id, &mut cx)?;
2819            LocalLspStore::deserialize_text_edits(
2820                lsp_store,
2821                buffer,
2822                edits,
2823                self.push_to_history,
2824                lsp_adapter,
2825                lsp_server,
2826                &mut cx,
2827            )
2828            .await
2829        } else {
2830            Ok(None)
2831        }
2832    }
2833
2834    fn to_proto(&self, project_id: u64, buffer: &Buffer) -> proto::OnTypeFormatting {
2835        proto::OnTypeFormatting {
2836            project_id,
2837            buffer_id: buffer.remote_id().into(),
2838            position: Some(language::proto::serialize_anchor(
2839                &buffer.anchor_before(self.position),
2840            )),
2841            trigger: self.trigger.clone(),
2842            version: serialize_version(&buffer.version()),
2843        }
2844    }
2845
2846    async fn from_proto(
2847        message: proto::OnTypeFormatting,
2848        _: Entity<LspStore>,
2849        buffer: Entity<Buffer>,
2850        mut cx: AsyncApp,
2851    ) -> Result<Self> {
2852        let position = message
2853            .position
2854            .and_then(deserialize_anchor)
2855            .context("invalid position")?;
2856        buffer
2857            .update(&mut cx, |buffer, _| {
2858                buffer.wait_for_version(deserialize_version(&message.version))
2859            })?
2860            .await?;
2861
2862        let options = buffer.update(&mut cx, |buffer, cx| {
2863            lsp_formatting_options(
2864                language_settings(buffer.language().map(|l| l.name()), buffer.file(), cx).as_ref(),
2865            )
2866        })?;
2867
2868        Ok(Self {
2869            position: buffer.read_with(&cx, |buffer, _| position.to_point_utf16(buffer))?,
2870            trigger: message.trigger.clone(),
2871            options,
2872            push_to_history: false,
2873        })
2874    }
2875
2876    fn response_to_proto(
2877        response: Option<Transaction>,
2878        _: &mut LspStore,
2879        _: PeerId,
2880        _: &clock::Global,
2881        _: &mut App,
2882    ) -> proto::OnTypeFormattingResponse {
2883        proto::OnTypeFormattingResponse {
2884            transaction: response
2885                .map(|transaction| language::proto::serialize_transaction(&transaction)),
2886        }
2887    }
2888
2889    async fn response_from_proto(
2890        self,
2891        message: proto::OnTypeFormattingResponse,
2892        _: Entity<LspStore>,
2893        _: Entity<Buffer>,
2894        _: AsyncApp,
2895    ) -> Result<Option<Transaction>> {
2896        let Some(transaction) = message.transaction else {
2897            return Ok(None);
2898        };
2899        Ok(Some(language::proto::deserialize_transaction(transaction)?))
2900    }
2901
2902    fn buffer_id_from_proto(message: &proto::OnTypeFormatting) -> Result<BufferId> {
2903        BufferId::new(message.buffer_id)
2904    }
2905}
2906
2907impl InlayHints {
2908    pub async fn lsp_to_project_hint(
2909        lsp_hint: lsp::InlayHint,
2910        buffer_handle: &Entity<Buffer>,
2911        server_id: LanguageServerId,
2912        resolve_state: ResolveState,
2913        force_no_type_left_padding: bool,
2914        cx: &mut AsyncApp,
2915    ) -> anyhow::Result<InlayHint> {
2916        let kind = lsp_hint.kind.and_then(|kind| match kind {
2917            lsp::InlayHintKind::TYPE => Some(InlayHintKind::Type),
2918            lsp::InlayHintKind::PARAMETER => Some(InlayHintKind::Parameter),
2919            _ => None,
2920        });
2921
2922        let position = buffer_handle.read_with(cx, |buffer, _| {
2923            let position = buffer.clip_point_utf16(point_from_lsp(lsp_hint.position), Bias::Left);
2924            if kind == Some(InlayHintKind::Parameter) {
2925                buffer.anchor_before(position)
2926            } else {
2927                buffer.anchor_after(position)
2928            }
2929        })?;
2930        let label = Self::lsp_inlay_label_to_project(lsp_hint.label, server_id)
2931            .await
2932            .context("lsp to project inlay hint conversion")?;
2933        let padding_left = if force_no_type_left_padding && kind == Some(InlayHintKind::Type) {
2934            false
2935        } else {
2936            lsp_hint.padding_left.unwrap_or(false)
2937        };
2938
2939        Ok(InlayHint {
2940            position,
2941            padding_left,
2942            padding_right: lsp_hint.padding_right.unwrap_or(false),
2943            label,
2944            kind,
2945            tooltip: lsp_hint.tooltip.map(|tooltip| match tooltip {
2946                lsp::InlayHintTooltip::String(s) => InlayHintTooltip::String(s),
2947                lsp::InlayHintTooltip::MarkupContent(markup_content) => {
2948                    InlayHintTooltip::MarkupContent(MarkupContent {
2949                        kind: match markup_content.kind {
2950                            lsp::MarkupKind::PlainText => HoverBlockKind::PlainText,
2951                            lsp::MarkupKind::Markdown => HoverBlockKind::Markdown,
2952                        },
2953                        value: markup_content.value,
2954                    })
2955                }
2956            }),
2957            resolve_state,
2958        })
2959    }
2960
2961    async fn lsp_inlay_label_to_project(
2962        lsp_label: lsp::InlayHintLabel,
2963        server_id: LanguageServerId,
2964    ) -> anyhow::Result<InlayHintLabel> {
2965        let label = match lsp_label {
2966            lsp::InlayHintLabel::String(s) => InlayHintLabel::String(s),
2967            lsp::InlayHintLabel::LabelParts(lsp_parts) => {
2968                let mut parts = Vec::with_capacity(lsp_parts.len());
2969                for lsp_part in lsp_parts {
2970                    parts.push(InlayHintLabelPart {
2971                        value: lsp_part.value,
2972                        tooltip: lsp_part.tooltip.map(|tooltip| match tooltip {
2973                            lsp::InlayHintLabelPartTooltip::String(s) => {
2974                                InlayHintLabelPartTooltip::String(s)
2975                            }
2976                            lsp::InlayHintLabelPartTooltip::MarkupContent(markup_content) => {
2977                                InlayHintLabelPartTooltip::MarkupContent(MarkupContent {
2978                                    kind: match markup_content.kind {
2979                                        lsp::MarkupKind::PlainText => HoverBlockKind::PlainText,
2980                                        lsp::MarkupKind::Markdown => HoverBlockKind::Markdown,
2981                                    },
2982                                    value: markup_content.value,
2983                                })
2984                            }
2985                        }),
2986                        location: Some(server_id).zip(lsp_part.location),
2987                    });
2988                }
2989                InlayHintLabel::LabelParts(parts)
2990            }
2991        };
2992
2993        Ok(label)
2994    }
2995
2996    pub fn project_to_proto_hint(response_hint: InlayHint) -> proto::InlayHint {
2997        let (state, lsp_resolve_state) = match response_hint.resolve_state {
2998            ResolveState::Resolved => (0, None),
2999            ResolveState::CanResolve(server_id, resolve_data) => (
3000                1,
3001                Some(proto::resolve_state::LspResolveState {
3002                    server_id: server_id.0 as u64,
3003                    value: resolve_data.map(|json_data| {
3004                        serde_json::to_string(&json_data)
3005                            .expect("failed to serialize resolve json data")
3006                    }),
3007                }),
3008            ),
3009            ResolveState::Resolving => (2, None),
3010        };
3011        let resolve_state = Some(proto::ResolveState {
3012            state,
3013            lsp_resolve_state,
3014        });
3015        proto::InlayHint {
3016            position: Some(language::proto::serialize_anchor(&response_hint.position)),
3017            padding_left: response_hint.padding_left,
3018            padding_right: response_hint.padding_right,
3019            label: Some(proto::InlayHintLabel {
3020                label: Some(match response_hint.label {
3021                    InlayHintLabel::String(s) => proto::inlay_hint_label::Label::Value(s),
3022                    InlayHintLabel::LabelParts(label_parts) => {
3023                        proto::inlay_hint_label::Label::LabelParts(proto::InlayHintLabelParts {
3024                            parts: label_parts.into_iter().map(|label_part| {
3025                                let location_url = label_part.location.as_ref().map(|(_, location)| location.uri.to_string());
3026                                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 });
3027                                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 });
3028                                proto::InlayHintLabelPart {
3029                                value: label_part.value,
3030                                tooltip: label_part.tooltip.map(|tooltip| {
3031                                    let proto_tooltip = match tooltip {
3032                                        InlayHintLabelPartTooltip::String(s) => proto::inlay_hint_label_part_tooltip::Content::Value(s),
3033                                        InlayHintLabelPartTooltip::MarkupContent(markup_content) => proto::inlay_hint_label_part_tooltip::Content::MarkupContent(proto::MarkupContent {
3034                                            is_markdown: markup_content.kind == HoverBlockKind::Markdown,
3035                                            value: markup_content.value,
3036                                        }),
3037                                    };
3038                                    proto::InlayHintLabelPartTooltip {content: Some(proto_tooltip)}
3039                                }),
3040                                location_url,
3041                                location_range_start,
3042                                location_range_end,
3043                                language_server_id: label_part.location.as_ref().map(|(server_id, _)| server_id.0 as u64),
3044                            }}).collect()
3045                        })
3046                    }
3047                }),
3048            }),
3049            kind: response_hint.kind.map(|kind| kind.name().to_string()),
3050            tooltip: response_hint.tooltip.map(|response_tooltip| {
3051                let proto_tooltip = match response_tooltip {
3052                    InlayHintTooltip::String(s) => proto::inlay_hint_tooltip::Content::Value(s),
3053                    InlayHintTooltip::MarkupContent(markup_content) => {
3054                        proto::inlay_hint_tooltip::Content::MarkupContent(proto::MarkupContent {
3055                            is_markdown: markup_content.kind == HoverBlockKind::Markdown,
3056                            value: markup_content.value,
3057                        })
3058                    }
3059                };
3060                proto::InlayHintTooltip {
3061                    content: Some(proto_tooltip),
3062                }
3063            }),
3064            resolve_state,
3065        }
3066    }
3067
3068    pub fn proto_to_project_hint(message_hint: proto::InlayHint) -> anyhow::Result<InlayHint> {
3069        let resolve_state = message_hint.resolve_state.as_ref().unwrap_or_else(|| {
3070            panic!("incorrect proto inlay hint message: no resolve state in hint {message_hint:?}",)
3071        });
3072        let resolve_state_data = resolve_state
3073            .lsp_resolve_state.as_ref()
3074            .map(|lsp_resolve_state| {
3075                let value = lsp_resolve_state.value.as_deref().map(|value| {
3076                    serde_json::from_str::<Option<lsp::LSPAny>>(value)
3077                        .with_context(|| format!("incorrect proto inlay hint message: non-json resolve state {lsp_resolve_state:?}"))
3078                }).transpose()?.flatten();
3079                anyhow::Ok((LanguageServerId(lsp_resolve_state.server_id as usize), value))
3080            })
3081            .transpose()?;
3082        let resolve_state = match resolve_state.state {
3083            0 => ResolveState::Resolved,
3084            1 => {
3085                let (server_id, lsp_resolve_state) = resolve_state_data.with_context(|| {
3086                    format!(
3087                        "No lsp resolve data for the hint that can be resolved: {message_hint:?}"
3088                    )
3089                })?;
3090                ResolveState::CanResolve(server_id, lsp_resolve_state)
3091            }
3092            2 => ResolveState::Resolving,
3093            invalid => {
3094                anyhow::bail!("Unexpected resolve state {invalid} for hint {message_hint:?}")
3095            }
3096        };
3097        Ok(InlayHint {
3098            position: message_hint
3099                .position
3100                .and_then(language::proto::deserialize_anchor)
3101                .context("invalid position")?,
3102            label: match message_hint
3103                .label
3104                .and_then(|label| label.label)
3105                .context("missing label")?
3106            {
3107                proto::inlay_hint_label::Label::Value(s) => InlayHintLabel::String(s),
3108                proto::inlay_hint_label::Label::LabelParts(parts) => {
3109                    let mut label_parts = Vec::new();
3110                    for part in parts.parts {
3111                        label_parts.push(InlayHintLabelPart {
3112                            value: part.value,
3113                            tooltip: part.tooltip.map(|tooltip| match tooltip.content {
3114                                Some(proto::inlay_hint_label_part_tooltip::Content::Value(s)) => {
3115                                    InlayHintLabelPartTooltip::String(s)
3116                                }
3117                                Some(
3118                                    proto::inlay_hint_label_part_tooltip::Content::MarkupContent(
3119                                        markup_content,
3120                                    ),
3121                                ) => InlayHintLabelPartTooltip::MarkupContent(MarkupContent {
3122                                    kind: if markup_content.is_markdown {
3123                                        HoverBlockKind::Markdown
3124                                    } else {
3125                                        HoverBlockKind::PlainText
3126                                    },
3127                                    value: markup_content.value,
3128                                }),
3129                                None => InlayHintLabelPartTooltip::String(String::new()),
3130                            }),
3131                            location: {
3132                                match part
3133                                    .location_url
3134                                    .zip(
3135                                        part.location_range_start.and_then(|start| {
3136                                            Some(start..part.location_range_end?)
3137                                        }),
3138                                    )
3139                                    .zip(part.language_server_id)
3140                                {
3141                                    Some(((uri, range), server_id)) => Some((
3142                                        LanguageServerId(server_id as usize),
3143                                        lsp::Location {
3144                                            uri: lsp::Uri::from_str(&uri)
3145                                                .context("invalid uri in hint part {part:?}")?,
3146                                            range: lsp::Range::new(
3147                                                point_to_lsp(PointUtf16::new(
3148                                                    range.start.row,
3149                                                    range.start.column,
3150                                                )),
3151                                                point_to_lsp(PointUtf16::new(
3152                                                    range.end.row,
3153                                                    range.end.column,
3154                                                )),
3155                                            ),
3156                                        },
3157                                    )),
3158                                    None => None,
3159                                }
3160                            },
3161                        });
3162                    }
3163
3164                    InlayHintLabel::LabelParts(label_parts)
3165                }
3166            },
3167            padding_left: message_hint.padding_left,
3168            padding_right: message_hint.padding_right,
3169            kind: message_hint
3170                .kind
3171                .as_deref()
3172                .and_then(InlayHintKind::from_name),
3173            tooltip: message_hint.tooltip.and_then(|tooltip| {
3174                Some(match tooltip.content? {
3175                    proto::inlay_hint_tooltip::Content::Value(s) => InlayHintTooltip::String(s),
3176                    proto::inlay_hint_tooltip::Content::MarkupContent(markup_content) => {
3177                        InlayHintTooltip::MarkupContent(MarkupContent {
3178                            kind: if markup_content.is_markdown {
3179                                HoverBlockKind::Markdown
3180                            } else {
3181                                HoverBlockKind::PlainText
3182                            },
3183                            value: markup_content.value,
3184                        })
3185                    }
3186                })
3187            }),
3188            resolve_state,
3189        })
3190    }
3191
3192    pub fn project_to_lsp_hint(hint: InlayHint, snapshot: &BufferSnapshot) -> lsp::InlayHint {
3193        lsp::InlayHint {
3194            position: point_to_lsp(hint.position.to_point_utf16(snapshot)),
3195            kind: hint.kind.map(|kind| match kind {
3196                InlayHintKind::Type => lsp::InlayHintKind::TYPE,
3197                InlayHintKind::Parameter => lsp::InlayHintKind::PARAMETER,
3198            }),
3199            text_edits: None,
3200            tooltip: hint.tooltip.and_then(|tooltip| {
3201                Some(match tooltip {
3202                    InlayHintTooltip::String(s) => lsp::InlayHintTooltip::String(s),
3203                    InlayHintTooltip::MarkupContent(markup_content) => {
3204                        lsp::InlayHintTooltip::MarkupContent(lsp::MarkupContent {
3205                            kind: match markup_content.kind {
3206                                HoverBlockKind::PlainText => lsp::MarkupKind::PlainText,
3207                                HoverBlockKind::Markdown => lsp::MarkupKind::Markdown,
3208                                HoverBlockKind::Code { .. } => return None,
3209                            },
3210                            value: markup_content.value,
3211                        })
3212                    }
3213                })
3214            }),
3215            label: match hint.label {
3216                InlayHintLabel::String(s) => lsp::InlayHintLabel::String(s),
3217                InlayHintLabel::LabelParts(label_parts) => lsp::InlayHintLabel::LabelParts(
3218                    label_parts
3219                        .into_iter()
3220                        .map(|part| lsp::InlayHintLabelPart {
3221                            value: part.value,
3222                            tooltip: part.tooltip.and_then(|tooltip| {
3223                                Some(match tooltip {
3224                                    InlayHintLabelPartTooltip::String(s) => {
3225                                        lsp::InlayHintLabelPartTooltip::String(s)
3226                                    }
3227                                    InlayHintLabelPartTooltip::MarkupContent(markup_content) => {
3228                                        lsp::InlayHintLabelPartTooltip::MarkupContent(
3229                                            lsp::MarkupContent {
3230                                                kind: match markup_content.kind {
3231                                                    HoverBlockKind::PlainText => {
3232                                                        lsp::MarkupKind::PlainText
3233                                                    }
3234                                                    HoverBlockKind::Markdown => {
3235                                                        lsp::MarkupKind::Markdown
3236                                                    }
3237                                                    HoverBlockKind::Code { .. } => return None,
3238                                                },
3239                                                value: markup_content.value,
3240                                            },
3241                                        )
3242                                    }
3243                                })
3244                            }),
3245                            location: part.location.map(|(_, location)| location),
3246                            command: None,
3247                        })
3248                        .collect(),
3249                ),
3250            },
3251            padding_left: Some(hint.padding_left),
3252            padding_right: Some(hint.padding_right),
3253            data: match hint.resolve_state {
3254                ResolveState::CanResolve(_, data) => data,
3255                ResolveState::Resolving | ResolveState::Resolved => None,
3256            },
3257        }
3258    }
3259
3260    pub fn can_resolve_inlays(capabilities: &ServerCapabilities) -> bool {
3261        capabilities
3262            .inlay_hint_provider
3263            .as_ref()
3264            .and_then(|options| match options {
3265                OneOf::Left(_is_supported) => None,
3266                OneOf::Right(capabilities) => match capabilities {
3267                    lsp::InlayHintServerCapabilities::Options(o) => o.resolve_provider,
3268                    lsp::InlayHintServerCapabilities::RegistrationOptions(o) => {
3269                        o.inlay_hint_options.resolve_provider
3270                    }
3271                },
3272            })
3273            .unwrap_or(false)
3274    }
3275
3276    pub fn check_capabilities(capabilities: &ServerCapabilities) -> bool {
3277        capabilities
3278            .inlay_hint_provider
3279            .as_ref()
3280            .is_some_and(|inlay_hint_provider| match inlay_hint_provider {
3281                lsp::OneOf::Left(enabled) => *enabled,
3282                lsp::OneOf::Right(_) => true,
3283            })
3284    }
3285}
3286
3287#[async_trait(?Send)]
3288impl LspCommand for InlayHints {
3289    type Response = Vec<InlayHint>;
3290    type LspRequest = lsp::InlayHintRequest;
3291    type ProtoRequest = proto::InlayHints;
3292
3293    fn display_name(&self) -> &str {
3294        "Inlay hints"
3295    }
3296
3297    fn check_capabilities(&self, capabilities: AdapterServerCapabilities) -> bool {
3298        Self::check_capabilities(&capabilities.server_capabilities)
3299    }
3300
3301    fn to_lsp(
3302        &self,
3303        path: &Path,
3304        buffer: &Buffer,
3305        _: &Arc<LanguageServer>,
3306        _: &App,
3307    ) -> Result<lsp::InlayHintParams> {
3308        Ok(lsp::InlayHintParams {
3309            text_document: lsp::TextDocumentIdentifier {
3310                uri: file_path_to_lsp_url(path)?,
3311            },
3312            range: range_to_lsp(self.range.to_point_utf16(buffer))?,
3313            work_done_progress_params: Default::default(),
3314        })
3315    }
3316
3317    async fn response_from_lsp(
3318        self,
3319        message: Option<Vec<lsp::InlayHint>>,
3320        lsp_store: Entity<LspStore>,
3321        buffer: Entity<Buffer>,
3322        server_id: LanguageServerId,
3323        mut cx: AsyncApp,
3324    ) -> anyhow::Result<Vec<InlayHint>> {
3325        let (lsp_adapter, lsp_server) =
3326            language_server_for_buffer(&lsp_store, &buffer, server_id, &mut cx)?;
3327        // `typescript-language-server` adds padding to the left for type hints, turning
3328        // `const foo: boolean` into `const foo : boolean` which looks odd.
3329        // `rust-analyzer` does not have the padding for this case, and we have to accommodate both.
3330        //
3331        // We could trim the whole string, but being pessimistic on par with the situation above,
3332        // there might be a hint with multiple whitespaces at the end(s) which we need to display properly.
3333        // Hence let's use a heuristic first to handle the most awkward case and look for more.
3334        let force_no_type_left_padding =
3335            lsp_adapter.name.0.as_ref() == "typescript-language-server";
3336
3337        let hints = message.unwrap_or_default().into_iter().map(|lsp_hint| {
3338            let resolve_state = if InlayHints::can_resolve_inlays(&lsp_server.capabilities()) {
3339                ResolveState::CanResolve(lsp_server.server_id(), lsp_hint.data.clone())
3340            } else {
3341                ResolveState::Resolved
3342            };
3343
3344            let buffer = buffer.clone();
3345            cx.spawn(async move |cx| {
3346                InlayHints::lsp_to_project_hint(
3347                    lsp_hint,
3348                    &buffer,
3349                    server_id,
3350                    resolve_state,
3351                    force_no_type_left_padding,
3352                    cx,
3353                )
3354                .await
3355            })
3356        });
3357        future::join_all(hints)
3358            .await
3359            .into_iter()
3360            .collect::<anyhow::Result<_>>()
3361            .context("lsp to project inlay hints conversion")
3362    }
3363
3364    fn to_proto(&self, project_id: u64, buffer: &Buffer) -> proto::InlayHints {
3365        proto::InlayHints {
3366            project_id,
3367            buffer_id: buffer.remote_id().into(),
3368            start: Some(language::proto::serialize_anchor(&self.range.start)),
3369            end: Some(language::proto::serialize_anchor(&self.range.end)),
3370            version: serialize_version(&buffer.version()),
3371        }
3372    }
3373
3374    async fn from_proto(
3375        message: proto::InlayHints,
3376        _: Entity<LspStore>,
3377        buffer: Entity<Buffer>,
3378        mut cx: AsyncApp,
3379    ) -> Result<Self> {
3380        let start = message
3381            .start
3382            .and_then(language::proto::deserialize_anchor)
3383            .context("invalid start")?;
3384        let end = message
3385            .end
3386            .and_then(language::proto::deserialize_anchor)
3387            .context("invalid end")?;
3388        buffer
3389            .update(&mut cx, |buffer, _| {
3390                buffer.wait_for_version(deserialize_version(&message.version))
3391            })?
3392            .await?;
3393
3394        Ok(Self { range: start..end })
3395    }
3396
3397    fn response_to_proto(
3398        response: Vec<InlayHint>,
3399        _: &mut LspStore,
3400        _: PeerId,
3401        buffer_version: &clock::Global,
3402        _: &mut App,
3403    ) -> proto::InlayHintsResponse {
3404        proto::InlayHintsResponse {
3405            hints: response
3406                .into_iter()
3407                .map(InlayHints::project_to_proto_hint)
3408                .collect(),
3409            version: serialize_version(buffer_version),
3410        }
3411    }
3412
3413    async fn response_from_proto(
3414        self,
3415        message: proto::InlayHintsResponse,
3416        _: Entity<LspStore>,
3417        buffer: Entity<Buffer>,
3418        mut cx: AsyncApp,
3419    ) -> anyhow::Result<Vec<InlayHint>> {
3420        buffer
3421            .update(&mut cx, |buffer, _| {
3422                buffer.wait_for_version(deserialize_version(&message.version))
3423            })?
3424            .await?;
3425
3426        let mut hints = Vec::new();
3427        for message_hint in message.hints {
3428            hints.push(InlayHints::proto_to_project_hint(message_hint)?);
3429        }
3430
3431        Ok(hints)
3432    }
3433
3434    fn buffer_id_from_proto(message: &proto::InlayHints) -> Result<BufferId> {
3435        BufferId::new(message.buffer_id)
3436    }
3437}
3438
3439#[async_trait(?Send)]
3440impl LspCommand for GetCodeLens {
3441    type Response = Vec<CodeAction>;
3442    type LspRequest = lsp::CodeLensRequest;
3443    type ProtoRequest = proto::GetCodeLens;
3444
3445    fn display_name(&self) -> &str {
3446        "Code Lens"
3447    }
3448
3449    fn check_capabilities(&self, capabilities: AdapterServerCapabilities) -> bool {
3450        capabilities
3451            .server_capabilities
3452            .code_lens_provider
3453            .is_some()
3454    }
3455
3456    fn to_lsp(
3457        &self,
3458        path: &Path,
3459        _: &Buffer,
3460        _: &Arc<LanguageServer>,
3461        _: &App,
3462    ) -> Result<lsp::CodeLensParams> {
3463        Ok(lsp::CodeLensParams {
3464            text_document: lsp::TextDocumentIdentifier {
3465                uri: file_path_to_lsp_url(path)?,
3466            },
3467            work_done_progress_params: lsp::WorkDoneProgressParams::default(),
3468            partial_result_params: lsp::PartialResultParams::default(),
3469        })
3470    }
3471
3472    async fn response_from_lsp(
3473        self,
3474        message: Option<Vec<lsp::CodeLens>>,
3475        lsp_store: Entity<LspStore>,
3476        buffer: Entity<Buffer>,
3477        server_id: LanguageServerId,
3478        cx: AsyncApp,
3479    ) -> anyhow::Result<Vec<CodeAction>> {
3480        let snapshot = buffer.read_with(&cx, |buffer, _| buffer.snapshot())?;
3481        let language_server = cx.update(|cx| {
3482            lsp_store
3483                .read(cx)
3484                .language_server_for_id(server_id)
3485                .with_context(|| {
3486                    format!("Missing the language server that just returned a response {server_id}")
3487                })
3488        })??;
3489        let server_capabilities = language_server.capabilities();
3490        let available_commands = server_capabilities
3491            .execute_command_provider
3492            .as_ref()
3493            .map(|options| options.commands.as_slice())
3494            .unwrap_or_default();
3495        Ok(message
3496            .unwrap_or_default()
3497            .into_iter()
3498            .filter(|code_lens| {
3499                code_lens
3500                    .command
3501                    .as_ref()
3502                    .is_none_or(|command| available_commands.contains(&command.command))
3503            })
3504            .map(|code_lens| {
3505                let code_lens_range = range_from_lsp(code_lens.range);
3506                let start = snapshot.clip_point_utf16(code_lens_range.start, Bias::Left);
3507                let end = snapshot.clip_point_utf16(code_lens_range.end, Bias::Right);
3508                let range = snapshot.anchor_before(start)..snapshot.anchor_after(end);
3509                CodeAction {
3510                    server_id,
3511                    range,
3512                    lsp_action: LspAction::CodeLens(code_lens),
3513                    resolved: false,
3514                }
3515            })
3516            .collect())
3517    }
3518
3519    fn to_proto(&self, project_id: u64, buffer: &Buffer) -> proto::GetCodeLens {
3520        proto::GetCodeLens {
3521            project_id,
3522            buffer_id: buffer.remote_id().into(),
3523            version: serialize_version(&buffer.version()),
3524        }
3525    }
3526
3527    async fn from_proto(
3528        message: proto::GetCodeLens,
3529        _: Entity<LspStore>,
3530        buffer: Entity<Buffer>,
3531        mut cx: AsyncApp,
3532    ) -> Result<Self> {
3533        buffer
3534            .update(&mut cx, |buffer, _| {
3535                buffer.wait_for_version(deserialize_version(&message.version))
3536            })?
3537            .await?;
3538        Ok(Self)
3539    }
3540
3541    fn response_to_proto(
3542        response: Vec<CodeAction>,
3543        _: &mut LspStore,
3544        _: PeerId,
3545        buffer_version: &clock::Global,
3546        _: &mut App,
3547    ) -> proto::GetCodeLensResponse {
3548        proto::GetCodeLensResponse {
3549            lens_actions: response
3550                .iter()
3551                .map(LspStore::serialize_code_action)
3552                .collect(),
3553            version: serialize_version(buffer_version),
3554        }
3555    }
3556
3557    async fn response_from_proto(
3558        self,
3559        message: proto::GetCodeLensResponse,
3560        _: Entity<LspStore>,
3561        buffer: Entity<Buffer>,
3562        mut cx: AsyncApp,
3563    ) -> anyhow::Result<Vec<CodeAction>> {
3564        buffer
3565            .update(&mut cx, |buffer, _| {
3566                buffer.wait_for_version(deserialize_version(&message.version))
3567            })?
3568            .await?;
3569        message
3570            .lens_actions
3571            .into_iter()
3572            .map(LspStore::deserialize_code_action)
3573            .collect::<Result<Vec<_>>>()
3574            .context("deserializing proto code lens response")
3575    }
3576
3577    fn buffer_id_from_proto(message: &proto::GetCodeLens) -> Result<BufferId> {
3578        BufferId::new(message.buffer_id)
3579    }
3580}
3581
3582impl LinkedEditingRange {
3583    pub fn check_server_capabilities(capabilities: ServerCapabilities) -> bool {
3584        let Some(linked_editing_options) = capabilities.linked_editing_range_provider else {
3585            return false;
3586        };
3587        if let LinkedEditingRangeServerCapabilities::Simple(false) = linked_editing_options {
3588            return false;
3589        }
3590        true
3591    }
3592}
3593
3594#[async_trait(?Send)]
3595impl LspCommand for LinkedEditingRange {
3596    type Response = Vec<Range<Anchor>>;
3597    type LspRequest = lsp::request::LinkedEditingRange;
3598    type ProtoRequest = proto::LinkedEditingRange;
3599
3600    fn display_name(&self) -> &str {
3601        "Linked editing range"
3602    }
3603
3604    fn check_capabilities(&self, capabilities: AdapterServerCapabilities) -> bool {
3605        Self::check_server_capabilities(capabilities.server_capabilities)
3606    }
3607
3608    fn to_lsp(
3609        &self,
3610        path: &Path,
3611        buffer: &Buffer,
3612        _server: &Arc<LanguageServer>,
3613        _: &App,
3614    ) -> Result<lsp::LinkedEditingRangeParams> {
3615        let position = self.position.to_point_utf16(&buffer.snapshot());
3616        Ok(lsp::LinkedEditingRangeParams {
3617            text_document_position_params: make_lsp_text_document_position(path, position)?,
3618            work_done_progress_params: Default::default(),
3619        })
3620    }
3621
3622    async fn response_from_lsp(
3623        self,
3624        message: Option<lsp::LinkedEditingRanges>,
3625        _: Entity<LspStore>,
3626        buffer: Entity<Buffer>,
3627        _server_id: LanguageServerId,
3628        cx: AsyncApp,
3629    ) -> Result<Vec<Range<Anchor>>> {
3630        if let Some(lsp::LinkedEditingRanges { mut ranges, .. }) = message {
3631            ranges.sort_by_key(|range| range.start);
3632
3633            buffer.read_with(&cx, |buffer, _| {
3634                ranges
3635                    .into_iter()
3636                    .map(|range| {
3637                        let start =
3638                            buffer.clip_point_utf16(point_from_lsp(range.start), Bias::Left);
3639                        let end = buffer.clip_point_utf16(point_from_lsp(range.end), Bias::Left);
3640                        buffer.anchor_before(start)..buffer.anchor_after(end)
3641                    })
3642                    .collect()
3643            })
3644        } else {
3645            Ok(vec![])
3646        }
3647    }
3648
3649    fn to_proto(&self, project_id: u64, buffer: &Buffer) -> proto::LinkedEditingRange {
3650        proto::LinkedEditingRange {
3651            project_id,
3652            buffer_id: buffer.remote_id().to_proto(),
3653            position: Some(serialize_anchor(&self.position)),
3654            version: serialize_version(&buffer.version()),
3655        }
3656    }
3657
3658    async fn from_proto(
3659        message: proto::LinkedEditingRange,
3660        _: Entity<LspStore>,
3661        buffer: Entity<Buffer>,
3662        mut cx: AsyncApp,
3663    ) -> Result<Self> {
3664        let position = message.position.context("invalid position")?;
3665        buffer
3666            .update(&mut cx, |buffer, _| {
3667                buffer.wait_for_version(deserialize_version(&message.version))
3668            })?
3669            .await?;
3670        let position = deserialize_anchor(position).context("invalid position")?;
3671        buffer
3672            .update(&mut cx, |buffer, _| buffer.wait_for_anchors([position]))?
3673            .await?;
3674        Ok(Self { position })
3675    }
3676
3677    fn response_to_proto(
3678        response: Vec<Range<Anchor>>,
3679        _: &mut LspStore,
3680        _: PeerId,
3681        buffer_version: &clock::Global,
3682        _: &mut App,
3683    ) -> proto::LinkedEditingRangeResponse {
3684        proto::LinkedEditingRangeResponse {
3685            items: response
3686                .into_iter()
3687                .map(|range| proto::AnchorRange {
3688                    start: Some(serialize_anchor(&range.start)),
3689                    end: Some(serialize_anchor(&range.end)),
3690                })
3691                .collect(),
3692            version: serialize_version(buffer_version),
3693        }
3694    }
3695
3696    async fn response_from_proto(
3697        self,
3698        message: proto::LinkedEditingRangeResponse,
3699        _: Entity<LspStore>,
3700        buffer: Entity<Buffer>,
3701        mut cx: AsyncApp,
3702    ) -> Result<Vec<Range<Anchor>>> {
3703        buffer
3704            .update(&mut cx, |buffer, _| {
3705                buffer.wait_for_version(deserialize_version(&message.version))
3706            })?
3707            .await?;
3708        let items: Vec<Range<Anchor>> = message
3709            .items
3710            .into_iter()
3711            .filter_map(|range| {
3712                let start = deserialize_anchor(range.start?)?;
3713                let end = deserialize_anchor(range.end?)?;
3714                Some(start..end)
3715            })
3716            .collect();
3717        for range in &items {
3718            buffer
3719                .update(&mut cx, |buffer, _| {
3720                    buffer.wait_for_anchors([range.start, range.end])
3721                })?
3722                .await?;
3723        }
3724        Ok(items)
3725    }
3726
3727    fn buffer_id_from_proto(message: &proto::LinkedEditingRange) -> Result<BufferId> {
3728        BufferId::new(message.buffer_id)
3729    }
3730}
3731
3732impl GetDocumentDiagnostics {
3733    pub fn diagnostics_from_proto(
3734        response: proto::GetDocumentDiagnosticsResponse,
3735    ) -> Vec<LspPullDiagnostics> {
3736        response
3737            .pulled_diagnostics
3738            .into_iter()
3739            .filter_map(|diagnostics| {
3740                Some(LspPullDiagnostics::Response {
3741                    server_id: LanguageServerId::from_proto(diagnostics.server_id),
3742                    uri: lsp::Uri::from_str(diagnostics.uri.as_str()).log_err()?,
3743                    diagnostics: if diagnostics.changed {
3744                        PulledDiagnostics::Unchanged {
3745                            result_id: diagnostics.result_id?,
3746                        }
3747                    } else {
3748                        PulledDiagnostics::Changed {
3749                            result_id: diagnostics.result_id,
3750                            diagnostics: diagnostics
3751                                .diagnostics
3752                                .into_iter()
3753                                .filter_map(|diagnostic| {
3754                                    GetDocumentDiagnostics::deserialize_lsp_diagnostic(diagnostic)
3755                                        .context("deserializing diagnostics")
3756                                        .log_err()
3757                                })
3758                                .collect(),
3759                        }
3760                    },
3761                })
3762            })
3763            .collect()
3764    }
3765
3766    fn deserialize_lsp_diagnostic(diagnostic: proto::LspDiagnostic) -> Result<lsp::Diagnostic> {
3767        let start = diagnostic.start.context("invalid start range")?;
3768        let end = diagnostic.end.context("invalid end range")?;
3769
3770        let range = Range::<PointUtf16> {
3771            start: PointUtf16 {
3772                row: start.row,
3773                column: start.column,
3774            },
3775            end: PointUtf16 {
3776                row: end.row,
3777                column: end.column,
3778            },
3779        };
3780
3781        let data = diagnostic.data.and_then(|data| Value::from_str(&data).ok());
3782        let code = diagnostic.code.map(lsp::NumberOrString::String);
3783
3784        let related_information = diagnostic
3785            .related_information
3786            .into_iter()
3787            .map(|info| {
3788                let start = info.location_range_start.unwrap();
3789                let end = info.location_range_end.unwrap();
3790
3791                lsp::DiagnosticRelatedInformation {
3792                    location: lsp::Location {
3793                        range: lsp::Range {
3794                            start: point_to_lsp(PointUtf16::new(start.row, start.column)),
3795                            end: point_to_lsp(PointUtf16::new(end.row, end.column)),
3796                        },
3797                        uri: lsp::Uri::from_str(&info.location_url.unwrap()).unwrap(),
3798                    },
3799                    message: info.message,
3800                }
3801            })
3802            .collect::<Vec<_>>();
3803
3804        let tags = diagnostic
3805            .tags
3806            .into_iter()
3807            .filter_map(|tag| match proto::LspDiagnosticTag::from_i32(tag) {
3808                Some(proto::LspDiagnosticTag::Unnecessary) => Some(lsp::DiagnosticTag::UNNECESSARY),
3809                Some(proto::LspDiagnosticTag::Deprecated) => Some(lsp::DiagnosticTag::DEPRECATED),
3810                _ => None,
3811            })
3812            .collect::<Vec<_>>();
3813
3814        Ok(lsp::Diagnostic {
3815            range: language::range_to_lsp(range)?,
3816            severity: match proto::lsp_diagnostic::Severity::from_i32(diagnostic.severity).unwrap()
3817            {
3818                proto::lsp_diagnostic::Severity::Error => Some(lsp::DiagnosticSeverity::ERROR),
3819                proto::lsp_diagnostic::Severity::Warning => Some(lsp::DiagnosticSeverity::WARNING),
3820                proto::lsp_diagnostic::Severity::Information => {
3821                    Some(lsp::DiagnosticSeverity::INFORMATION)
3822                }
3823                proto::lsp_diagnostic::Severity::Hint => Some(lsp::DiagnosticSeverity::HINT),
3824                _ => None,
3825            },
3826            code,
3827            code_description: diagnostic
3828                .code_description
3829                .map(|code_description| CodeDescription {
3830                    href: Some(lsp::Uri::from_str(&code_description).unwrap()),
3831                }),
3832            related_information: Some(related_information),
3833            tags: Some(tags),
3834            source: diagnostic.source.clone(),
3835            message: diagnostic.message,
3836            data,
3837        })
3838    }
3839
3840    fn serialize_lsp_diagnostic(diagnostic: lsp::Diagnostic) -> Result<proto::LspDiagnostic> {
3841        let range = language::range_from_lsp(diagnostic.range);
3842        let related_information = diagnostic
3843            .related_information
3844            .unwrap_or_default()
3845            .into_iter()
3846            .map(|related_information| {
3847                let location_range_start =
3848                    point_from_lsp(related_information.location.range.start).0;
3849                let location_range_end = point_from_lsp(related_information.location.range.end).0;
3850
3851                Ok(proto::LspDiagnosticRelatedInformation {
3852                    location_url: Some(related_information.location.uri.to_string()),
3853                    location_range_start: Some(proto::PointUtf16 {
3854                        row: location_range_start.row,
3855                        column: location_range_start.column,
3856                    }),
3857                    location_range_end: Some(proto::PointUtf16 {
3858                        row: location_range_end.row,
3859                        column: location_range_end.column,
3860                    }),
3861                    message: related_information.message,
3862                })
3863            })
3864            .collect::<Result<Vec<_>>>()?;
3865
3866        let tags = diagnostic
3867            .tags
3868            .unwrap_or_default()
3869            .into_iter()
3870            .map(|tag| match tag {
3871                lsp::DiagnosticTag::UNNECESSARY => proto::LspDiagnosticTag::Unnecessary,
3872                lsp::DiagnosticTag::DEPRECATED => proto::LspDiagnosticTag::Deprecated,
3873                _ => proto::LspDiagnosticTag::None,
3874            } as i32)
3875            .collect();
3876
3877        Ok(proto::LspDiagnostic {
3878            start: Some(proto::PointUtf16 {
3879                row: range.start.0.row,
3880                column: range.start.0.column,
3881            }),
3882            end: Some(proto::PointUtf16 {
3883                row: range.end.0.row,
3884                column: range.end.0.column,
3885            }),
3886            severity: match diagnostic.severity {
3887                Some(lsp::DiagnosticSeverity::ERROR) => proto::lsp_diagnostic::Severity::Error,
3888                Some(lsp::DiagnosticSeverity::WARNING) => proto::lsp_diagnostic::Severity::Warning,
3889                Some(lsp::DiagnosticSeverity::INFORMATION) => {
3890                    proto::lsp_diagnostic::Severity::Information
3891                }
3892                Some(lsp::DiagnosticSeverity::HINT) => proto::lsp_diagnostic::Severity::Hint,
3893                _ => proto::lsp_diagnostic::Severity::None,
3894            } as i32,
3895            code: diagnostic.code.as_ref().map(|code| match code {
3896                lsp::NumberOrString::Number(code) => code.to_string(),
3897                lsp::NumberOrString::String(code) => code.clone(),
3898            }),
3899            source: diagnostic.source.clone(),
3900            related_information,
3901            tags,
3902            code_description: diagnostic
3903                .code_description
3904                .and_then(|desc| desc.href.map(|url| url.to_string())),
3905            message: diagnostic.message,
3906            data: diagnostic.data.as_ref().map(|data| data.to_string()),
3907        })
3908    }
3909
3910    pub fn deserialize_workspace_diagnostics_report(
3911        report: lsp::WorkspaceDiagnosticReportResult,
3912        server_id: LanguageServerId,
3913    ) -> Vec<WorkspaceLspPullDiagnostics> {
3914        let mut pulled_diagnostics = HashMap::default();
3915        match report {
3916            lsp::WorkspaceDiagnosticReportResult::Report(workspace_diagnostic_report) => {
3917                for report in workspace_diagnostic_report.items {
3918                    match report {
3919                        lsp::WorkspaceDocumentDiagnosticReport::Full(report) => {
3920                            process_full_workspace_diagnostics_report(
3921                                &mut pulled_diagnostics,
3922                                server_id,
3923                                report,
3924                            )
3925                        }
3926                        lsp::WorkspaceDocumentDiagnosticReport::Unchanged(report) => {
3927                            process_unchanged_workspace_diagnostics_report(
3928                                &mut pulled_diagnostics,
3929                                server_id,
3930                                report,
3931                            )
3932                        }
3933                    }
3934                }
3935            }
3936            lsp::WorkspaceDiagnosticReportResult::Partial(
3937                workspace_diagnostic_report_partial_result,
3938            ) => {
3939                for report in workspace_diagnostic_report_partial_result.items {
3940                    match report {
3941                        lsp::WorkspaceDocumentDiagnosticReport::Full(report) => {
3942                            process_full_workspace_diagnostics_report(
3943                                &mut pulled_diagnostics,
3944                                server_id,
3945                                report,
3946                            )
3947                        }
3948                        lsp::WorkspaceDocumentDiagnosticReport::Unchanged(report) => {
3949                            process_unchanged_workspace_diagnostics_report(
3950                                &mut pulled_diagnostics,
3951                                server_id,
3952                                report,
3953                            )
3954                        }
3955                    }
3956                }
3957            }
3958        }
3959        pulled_diagnostics.into_values().collect()
3960    }
3961}
3962
3963#[derive(Debug)]
3964pub struct WorkspaceLspPullDiagnostics {
3965    pub version: Option<i32>,
3966    pub diagnostics: LspPullDiagnostics,
3967}
3968
3969fn process_full_workspace_diagnostics_report(
3970    diagnostics: &mut HashMap<lsp::Uri, WorkspaceLspPullDiagnostics>,
3971    server_id: LanguageServerId,
3972    report: lsp::WorkspaceFullDocumentDiagnosticReport,
3973) {
3974    let mut new_diagnostics = HashMap::default();
3975    process_full_diagnostics_report(
3976        &mut new_diagnostics,
3977        server_id,
3978        report.uri,
3979        report.full_document_diagnostic_report,
3980    );
3981    diagnostics.extend(new_diagnostics.into_iter().map(|(uri, diagnostics)| {
3982        (
3983            uri,
3984            WorkspaceLspPullDiagnostics {
3985                version: report.version.map(|v| v as i32),
3986                diagnostics,
3987            },
3988        )
3989    }));
3990}
3991
3992fn process_unchanged_workspace_diagnostics_report(
3993    diagnostics: &mut HashMap<lsp::Uri, WorkspaceLspPullDiagnostics>,
3994    server_id: LanguageServerId,
3995    report: lsp::WorkspaceUnchangedDocumentDiagnosticReport,
3996) {
3997    let mut new_diagnostics = HashMap::default();
3998    process_unchanged_diagnostics_report(
3999        &mut new_diagnostics,
4000        server_id,
4001        report.uri,
4002        report.unchanged_document_diagnostic_report,
4003    );
4004    diagnostics.extend(new_diagnostics.into_iter().map(|(uri, diagnostics)| {
4005        (
4006            uri,
4007            WorkspaceLspPullDiagnostics {
4008                version: report.version.map(|v| v as i32),
4009                diagnostics,
4010            },
4011        )
4012    }));
4013}
4014
4015#[async_trait(?Send)]
4016impl LspCommand for GetDocumentDiagnostics {
4017    type Response = Vec<LspPullDiagnostics>;
4018    type LspRequest = lsp::request::DocumentDiagnosticRequest;
4019    type ProtoRequest = proto::GetDocumentDiagnostics;
4020
4021    fn display_name(&self) -> &str {
4022        "Get diagnostics"
4023    }
4024
4025    fn check_capabilities(&self, _: AdapterServerCapabilities) -> bool {
4026        true
4027    }
4028
4029    fn to_lsp(
4030        &self,
4031        path: &Path,
4032        _: &Buffer,
4033        _: &Arc<LanguageServer>,
4034        _: &App,
4035    ) -> Result<lsp::DocumentDiagnosticParams> {
4036        let identifier = match &self.dynamic_caps {
4037            lsp::DiagnosticServerCapabilities::Options(options) => options.identifier.clone(),
4038            lsp::DiagnosticServerCapabilities::RegistrationOptions(options) => {
4039                options.diagnostic_options.identifier.clone()
4040            }
4041        };
4042
4043        Ok(lsp::DocumentDiagnosticParams {
4044            text_document: lsp::TextDocumentIdentifier {
4045                uri: file_path_to_lsp_url(path)?,
4046            },
4047            identifier,
4048            previous_result_id: self.previous_result_id.clone(),
4049            partial_result_params: Default::default(),
4050            work_done_progress_params: Default::default(),
4051        })
4052    }
4053
4054    async fn response_from_lsp(
4055        self,
4056        message: lsp::DocumentDiagnosticReportResult,
4057        _: Entity<LspStore>,
4058        buffer: Entity<Buffer>,
4059        server_id: LanguageServerId,
4060        cx: AsyncApp,
4061    ) -> Result<Self::Response> {
4062        let url = buffer.read_with(&cx, |buffer, cx| {
4063            buffer
4064                .file()
4065                .and_then(|file| file.as_local())
4066                .map(|file| {
4067                    let abs_path = file.abs_path(cx);
4068                    file_path_to_lsp_url(&abs_path)
4069                })
4070                .transpose()?
4071                .with_context(|| format!("missing url on buffer {}", buffer.remote_id()))
4072        })??;
4073
4074        let mut pulled_diagnostics = HashMap::default();
4075        match message {
4076            lsp::DocumentDiagnosticReportResult::Report(report) => match report {
4077                lsp::DocumentDiagnosticReport::Full(report) => {
4078                    if let Some(related_documents) = report.related_documents {
4079                        process_related_documents(
4080                            &mut pulled_diagnostics,
4081                            server_id,
4082                            related_documents,
4083                        );
4084                    }
4085                    process_full_diagnostics_report(
4086                        &mut pulled_diagnostics,
4087                        server_id,
4088                        url,
4089                        report.full_document_diagnostic_report,
4090                    );
4091                }
4092                lsp::DocumentDiagnosticReport::Unchanged(report) => {
4093                    if let Some(related_documents) = report.related_documents {
4094                        process_related_documents(
4095                            &mut pulled_diagnostics,
4096                            server_id,
4097                            related_documents,
4098                        );
4099                    }
4100                    process_unchanged_diagnostics_report(
4101                        &mut pulled_diagnostics,
4102                        server_id,
4103                        url,
4104                        report.unchanged_document_diagnostic_report,
4105                    );
4106                }
4107            },
4108            lsp::DocumentDiagnosticReportResult::Partial(report) => {
4109                if let Some(related_documents) = report.related_documents {
4110                    process_related_documents(
4111                        &mut pulled_diagnostics,
4112                        server_id,
4113                        related_documents,
4114                    );
4115                }
4116            }
4117        }
4118
4119        Ok(pulled_diagnostics.into_values().collect())
4120    }
4121
4122    fn to_proto(&self, project_id: u64, buffer: &Buffer) -> proto::GetDocumentDiagnostics {
4123        proto::GetDocumentDiagnostics {
4124            project_id,
4125            buffer_id: buffer.remote_id().into(),
4126            version: serialize_version(&buffer.version()),
4127        }
4128    }
4129
4130    async fn from_proto(
4131        _: proto::GetDocumentDiagnostics,
4132        _: Entity<LspStore>,
4133        _: Entity<Buffer>,
4134        _: AsyncApp,
4135    ) -> Result<Self> {
4136        anyhow::bail!(
4137            "proto::GetDocumentDiagnostics is not expected to be converted from proto directly, as it needs `previous_result_id` fetched first"
4138        )
4139    }
4140
4141    fn response_to_proto(
4142        response: Self::Response,
4143        _: &mut LspStore,
4144        _: PeerId,
4145        _: &clock::Global,
4146        _: &mut App,
4147    ) -> proto::GetDocumentDiagnosticsResponse {
4148        let pulled_diagnostics = response
4149            .into_iter()
4150            .filter_map(|diagnostics| match diagnostics {
4151                LspPullDiagnostics::Default => None,
4152                LspPullDiagnostics::Response {
4153                    server_id,
4154                    uri,
4155                    diagnostics,
4156                } => {
4157                    let mut changed = false;
4158                    let (diagnostics, result_id) = match diagnostics {
4159                        PulledDiagnostics::Unchanged { result_id } => (Vec::new(), Some(result_id)),
4160                        PulledDiagnostics::Changed {
4161                            result_id,
4162                            diagnostics,
4163                        } => {
4164                            changed = true;
4165                            (diagnostics, result_id)
4166                        }
4167                    };
4168                    Some(proto::PulledDiagnostics {
4169                        changed,
4170                        result_id,
4171                        uri: uri.to_string(),
4172                        server_id: server_id.to_proto(),
4173                        diagnostics: diagnostics
4174                            .into_iter()
4175                            .filter_map(|diagnostic| {
4176                                GetDocumentDiagnostics::serialize_lsp_diagnostic(diagnostic)
4177                                    .context("serializing diagnostics")
4178                                    .log_err()
4179                            })
4180                            .collect(),
4181                    })
4182                }
4183            })
4184            .collect();
4185
4186        proto::GetDocumentDiagnosticsResponse { pulled_diagnostics }
4187    }
4188
4189    async fn response_from_proto(
4190        self,
4191        response: proto::GetDocumentDiagnosticsResponse,
4192        _: Entity<LspStore>,
4193        _: Entity<Buffer>,
4194        _: AsyncApp,
4195    ) -> Result<Self::Response> {
4196        Ok(Self::diagnostics_from_proto(response))
4197    }
4198
4199    fn buffer_id_from_proto(message: &proto::GetDocumentDiagnostics) -> Result<BufferId> {
4200        BufferId::new(message.buffer_id)
4201    }
4202}
4203
4204#[async_trait(?Send)]
4205impl LspCommand for GetDocumentColor {
4206    type Response = Vec<DocumentColor>;
4207    type LspRequest = lsp::request::DocumentColor;
4208    type ProtoRequest = proto::GetDocumentColor;
4209
4210    fn display_name(&self) -> &str {
4211        "Document color"
4212    }
4213
4214    fn check_capabilities(&self, server_capabilities: AdapterServerCapabilities) -> bool {
4215        server_capabilities
4216            .server_capabilities
4217            .color_provider
4218            .as_ref()
4219            .is_some_and(|capability| match capability {
4220                lsp::ColorProviderCapability::Simple(supported) => *supported,
4221                lsp::ColorProviderCapability::ColorProvider(..) => true,
4222                lsp::ColorProviderCapability::Options(..) => true,
4223            })
4224    }
4225
4226    fn to_lsp(
4227        &self,
4228        path: &Path,
4229        _: &Buffer,
4230        _: &Arc<LanguageServer>,
4231        _: &App,
4232    ) -> Result<lsp::DocumentColorParams> {
4233        Ok(lsp::DocumentColorParams {
4234            text_document: make_text_document_identifier(path)?,
4235            work_done_progress_params: Default::default(),
4236            partial_result_params: Default::default(),
4237        })
4238    }
4239
4240    async fn response_from_lsp(
4241        self,
4242        message: Vec<lsp::ColorInformation>,
4243        _: Entity<LspStore>,
4244        _: Entity<Buffer>,
4245        _: LanguageServerId,
4246        _: AsyncApp,
4247    ) -> Result<Self::Response> {
4248        Ok(message
4249            .into_iter()
4250            .map(|color| DocumentColor {
4251                lsp_range: color.range,
4252                color: color.color,
4253                resolved: false,
4254                color_presentations: Vec::new(),
4255            })
4256            .collect())
4257    }
4258
4259    fn to_proto(&self, project_id: u64, buffer: &Buffer) -> Self::ProtoRequest {
4260        proto::GetDocumentColor {
4261            project_id,
4262            buffer_id: buffer.remote_id().to_proto(),
4263            version: serialize_version(&buffer.version()),
4264        }
4265    }
4266
4267    async fn from_proto(
4268        _: Self::ProtoRequest,
4269        _: Entity<LspStore>,
4270        _: Entity<Buffer>,
4271        _: AsyncApp,
4272    ) -> Result<Self> {
4273        Ok(Self {})
4274    }
4275
4276    fn response_to_proto(
4277        response: Self::Response,
4278        _: &mut LspStore,
4279        _: PeerId,
4280        buffer_version: &clock::Global,
4281        _: &mut App,
4282    ) -> proto::GetDocumentColorResponse {
4283        proto::GetDocumentColorResponse {
4284            colors: response
4285                .into_iter()
4286                .map(|color| {
4287                    let start = point_from_lsp(color.lsp_range.start).0;
4288                    let end = point_from_lsp(color.lsp_range.end).0;
4289                    proto::ColorInformation {
4290                        red: color.color.red,
4291                        green: color.color.green,
4292                        blue: color.color.blue,
4293                        alpha: color.color.alpha,
4294                        lsp_range_start: Some(proto::PointUtf16 {
4295                            row: start.row,
4296                            column: start.column,
4297                        }),
4298                        lsp_range_end: Some(proto::PointUtf16 {
4299                            row: end.row,
4300                            column: end.column,
4301                        }),
4302                    }
4303                })
4304                .collect(),
4305            version: serialize_version(buffer_version),
4306        }
4307    }
4308
4309    async fn response_from_proto(
4310        self,
4311        message: proto::GetDocumentColorResponse,
4312        _: Entity<LspStore>,
4313        _: Entity<Buffer>,
4314        _: AsyncApp,
4315    ) -> Result<Self::Response> {
4316        Ok(message
4317            .colors
4318            .into_iter()
4319            .filter_map(|color| {
4320                let start = color.lsp_range_start?;
4321                let start = PointUtf16::new(start.row, start.column);
4322                let end = color.lsp_range_end?;
4323                let end = PointUtf16::new(end.row, end.column);
4324                Some(DocumentColor {
4325                    resolved: false,
4326                    color_presentations: Vec::new(),
4327                    lsp_range: lsp::Range {
4328                        start: point_to_lsp(start),
4329                        end: point_to_lsp(end),
4330                    },
4331                    color: lsp::Color {
4332                        red: color.red,
4333                        green: color.green,
4334                        blue: color.blue,
4335                        alpha: color.alpha,
4336                    },
4337                })
4338            })
4339            .collect())
4340    }
4341
4342    fn buffer_id_from_proto(message: &Self::ProtoRequest) -> Result<BufferId> {
4343        BufferId::new(message.buffer_id)
4344    }
4345}
4346
4347fn process_related_documents(
4348    diagnostics: &mut HashMap<lsp::Uri, LspPullDiagnostics>,
4349    server_id: LanguageServerId,
4350    documents: impl IntoIterator<Item = (lsp::Uri, lsp::DocumentDiagnosticReportKind)>,
4351) {
4352    for (url, report_kind) in documents {
4353        match report_kind {
4354            lsp::DocumentDiagnosticReportKind::Full(report) => {
4355                process_full_diagnostics_report(diagnostics, server_id, url, report)
4356            }
4357            lsp::DocumentDiagnosticReportKind::Unchanged(report) => {
4358                process_unchanged_diagnostics_report(diagnostics, server_id, url, report)
4359            }
4360        }
4361    }
4362}
4363
4364fn process_unchanged_diagnostics_report(
4365    diagnostics: &mut HashMap<lsp::Uri, LspPullDiagnostics>,
4366    server_id: LanguageServerId,
4367    uri: lsp::Uri,
4368    report: lsp::UnchangedDocumentDiagnosticReport,
4369) {
4370    let result_id = report.result_id;
4371    match diagnostics.entry(uri.clone()) {
4372        hash_map::Entry::Occupied(mut o) => match o.get_mut() {
4373            LspPullDiagnostics::Default => {
4374                o.insert(LspPullDiagnostics::Response {
4375                    server_id,
4376                    uri,
4377                    diagnostics: PulledDiagnostics::Unchanged { result_id },
4378                });
4379            }
4380            LspPullDiagnostics::Response {
4381                server_id: existing_server_id,
4382                uri: existing_uri,
4383                diagnostics: existing_diagnostics,
4384            } => {
4385                if server_id != *existing_server_id || &uri != existing_uri {
4386                    debug_panic!(
4387                        "Unexpected state: file {uri} has two different sets of diagnostics reported"
4388                    );
4389                }
4390                match existing_diagnostics {
4391                    PulledDiagnostics::Unchanged { .. } => {
4392                        *existing_diagnostics = PulledDiagnostics::Unchanged { result_id };
4393                    }
4394                    PulledDiagnostics::Changed { .. } => {}
4395                }
4396            }
4397        },
4398        hash_map::Entry::Vacant(v) => {
4399            v.insert(LspPullDiagnostics::Response {
4400                server_id,
4401                uri,
4402                diagnostics: PulledDiagnostics::Unchanged { result_id },
4403            });
4404        }
4405    }
4406}
4407
4408fn process_full_diagnostics_report(
4409    diagnostics: &mut HashMap<lsp::Uri, LspPullDiagnostics>,
4410    server_id: LanguageServerId,
4411    uri: lsp::Uri,
4412    report: lsp::FullDocumentDiagnosticReport,
4413) {
4414    let result_id = report.result_id;
4415    match diagnostics.entry(uri.clone()) {
4416        hash_map::Entry::Occupied(mut o) => match o.get_mut() {
4417            LspPullDiagnostics::Default => {
4418                o.insert(LspPullDiagnostics::Response {
4419                    server_id,
4420                    uri,
4421                    diagnostics: PulledDiagnostics::Changed {
4422                        result_id,
4423                        diagnostics: report.items,
4424                    },
4425                });
4426            }
4427            LspPullDiagnostics::Response {
4428                server_id: existing_server_id,
4429                uri: existing_uri,
4430                diagnostics: existing_diagnostics,
4431            } => {
4432                if server_id != *existing_server_id || &uri != existing_uri {
4433                    debug_panic!(
4434                        "Unexpected state: file {uri} has two different sets of diagnostics reported"
4435                    );
4436                }
4437                match existing_diagnostics {
4438                    PulledDiagnostics::Unchanged { .. } => {
4439                        *existing_diagnostics = PulledDiagnostics::Changed {
4440                            result_id,
4441                            diagnostics: report.items,
4442                        };
4443                    }
4444                    PulledDiagnostics::Changed {
4445                        result_id: existing_result_id,
4446                        diagnostics: existing_diagnostics,
4447                    } => {
4448                        if result_id.is_some() {
4449                            *existing_result_id = result_id;
4450                        }
4451                        existing_diagnostics.extend(report.items);
4452                    }
4453                }
4454            }
4455        },
4456        hash_map::Entry::Vacant(v) => {
4457            v.insert(LspPullDiagnostics::Response {
4458                server_id,
4459                uri,
4460                diagnostics: PulledDiagnostics::Changed {
4461                    result_id,
4462                    diagnostics: report.items,
4463                },
4464            });
4465        }
4466    }
4467}
4468
4469#[cfg(test)]
4470mod tests {
4471    use super::*;
4472    use lsp::{DiagnosticSeverity, DiagnosticTag};
4473    use serde_json::json;
4474
4475    #[test]
4476    fn test_serialize_lsp_diagnostic() {
4477        let lsp_diagnostic = lsp::Diagnostic {
4478            range: lsp::Range {
4479                start: lsp::Position::new(0, 1),
4480                end: lsp::Position::new(2, 3),
4481            },
4482            severity: Some(DiagnosticSeverity::ERROR),
4483            code: Some(lsp::NumberOrString::String("E001".to_string())),
4484            source: Some("test-source".to_string()),
4485            message: "Test error message".to_string(),
4486            related_information: None,
4487            tags: Some(vec![DiagnosticTag::DEPRECATED]),
4488            code_description: None,
4489            data: Some(json!({"detail": "test detail"})),
4490        };
4491
4492        let proto_diagnostic = GetDocumentDiagnostics::serialize_lsp_diagnostic(lsp_diagnostic)
4493            .expect("Failed to serialize diagnostic");
4494
4495        let start = proto_diagnostic.start.unwrap();
4496        let end = proto_diagnostic.end.unwrap();
4497        assert_eq!(start.row, 0);
4498        assert_eq!(start.column, 1);
4499        assert_eq!(end.row, 2);
4500        assert_eq!(end.column, 3);
4501        assert_eq!(
4502            proto_diagnostic.severity,
4503            proto::lsp_diagnostic::Severity::Error as i32
4504        );
4505        assert_eq!(proto_diagnostic.code, Some("E001".to_string()));
4506        assert_eq!(proto_diagnostic.source, Some("test-source".to_string()));
4507        assert_eq!(proto_diagnostic.message, "Test error message");
4508    }
4509
4510    #[test]
4511    fn test_deserialize_lsp_diagnostic() {
4512        let proto_diagnostic = proto::LspDiagnostic {
4513            start: Some(proto::PointUtf16 { row: 0, column: 1 }),
4514            end: Some(proto::PointUtf16 { row: 2, column: 3 }),
4515            severity: proto::lsp_diagnostic::Severity::Warning as i32,
4516            code: Some("ERR".to_string()),
4517            source: Some("Prism".to_string()),
4518            message: "assigned but unused variable - a".to_string(),
4519            related_information: vec![],
4520            tags: vec![],
4521            code_description: None,
4522            data: None,
4523        };
4524
4525        let lsp_diagnostic = GetDocumentDiagnostics::deserialize_lsp_diagnostic(proto_diagnostic)
4526            .expect("Failed to deserialize diagnostic");
4527
4528        assert_eq!(lsp_diagnostic.range.start.line, 0);
4529        assert_eq!(lsp_diagnostic.range.start.character, 1);
4530        assert_eq!(lsp_diagnostic.range.end.line, 2);
4531        assert_eq!(lsp_diagnostic.range.end.character, 3);
4532        assert_eq!(lsp_diagnostic.severity, Some(DiagnosticSeverity::WARNING));
4533        assert_eq!(
4534            lsp_diagnostic.code,
4535            Some(lsp::NumberOrString::String("ERR".to_string()))
4536        );
4537        assert_eq!(lsp_diagnostic.source, Some("Prism".to_string()));
4538        assert_eq!(lsp_diagnostic.message, "assigned but unused variable - a");
4539    }
4540
4541    #[test]
4542    fn test_related_information() {
4543        let related_info = lsp::DiagnosticRelatedInformation {
4544            location: lsp::Location {
4545                uri: lsp::Uri::from_str("file:///test.rs").unwrap(),
4546                range: lsp::Range {
4547                    start: lsp::Position::new(1, 1),
4548                    end: lsp::Position::new(1, 5),
4549                },
4550            },
4551            message: "Related info message".to_string(),
4552        };
4553
4554        let lsp_diagnostic = lsp::Diagnostic {
4555            range: lsp::Range {
4556                start: lsp::Position::new(0, 0),
4557                end: lsp::Position::new(0, 1),
4558            },
4559            severity: Some(DiagnosticSeverity::INFORMATION),
4560            code: None,
4561            source: Some("Prism".to_string()),
4562            message: "assigned but unused variable - a".to_string(),
4563            related_information: Some(vec![related_info]),
4564            tags: None,
4565            code_description: None,
4566            data: None,
4567        };
4568
4569        let proto_diagnostic = GetDocumentDiagnostics::serialize_lsp_diagnostic(lsp_diagnostic)
4570            .expect("Failed to serialize diagnostic");
4571
4572        assert_eq!(proto_diagnostic.related_information.len(), 1);
4573        let related = &proto_diagnostic.related_information[0];
4574        assert_eq!(related.location_url, Some("file:///test.rs".to_string()));
4575        assert_eq!(related.message, "Related info message");
4576    }
4577
4578    #[test]
4579    fn test_invalid_ranges() {
4580        let proto_diagnostic = proto::LspDiagnostic {
4581            start: None,
4582            end: Some(proto::PointUtf16 { row: 2, column: 3 }),
4583            severity: proto::lsp_diagnostic::Severity::Error as i32,
4584            code: None,
4585            source: None,
4586            message: "Test message".to_string(),
4587            related_information: vec![],
4588            tags: vec![],
4589            code_description: None,
4590            data: None,
4591        };
4592
4593        let result = GetDocumentDiagnostics::deserialize_lsp_diagnostic(proto_diagnostic);
4594        assert!(result.is_err());
4595    }
4596}