lsp_command.rs

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