lsp_command.rs

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