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