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