lsp_command.rs

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