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