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},
  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(LanguageSettings::for_buffer(buffer, cx).as_ref())
2897        });
2898
2899        Ok(Self {
2900            position: buffer.read_with(&cx, |buffer, _| position.to_point_utf16(buffer)),
2901            trigger: message.trigger.clone(),
2902            options,
2903            push_to_history: false,
2904        })
2905    }
2906
2907    fn response_to_proto(
2908        response: Option<Transaction>,
2909        _: &mut LspStore,
2910        _: PeerId,
2911        _: &clock::Global,
2912        _: &mut App,
2913    ) -> proto::OnTypeFormattingResponse {
2914        proto::OnTypeFormattingResponse {
2915            transaction: response
2916                .map(|transaction| language::proto::serialize_transaction(&transaction)),
2917        }
2918    }
2919
2920    async fn response_from_proto(
2921        self,
2922        message: proto::OnTypeFormattingResponse,
2923        _: Entity<LspStore>,
2924        _: Entity<Buffer>,
2925        _: AsyncApp,
2926    ) -> Result<Option<Transaction>> {
2927        let Some(transaction) = message.transaction else {
2928            return Ok(None);
2929        };
2930        Ok(Some(language::proto::deserialize_transaction(transaction)?))
2931    }
2932
2933    fn buffer_id_from_proto(message: &proto::OnTypeFormatting) -> Result<BufferId> {
2934        BufferId::new(message.buffer_id)
2935    }
2936}
2937
2938impl InlayHints {
2939    pub async fn lsp_to_project_hint(
2940        lsp_hint: lsp::InlayHint,
2941        buffer_handle: &Entity<Buffer>,
2942        server_id: LanguageServerId,
2943        resolve_state: ResolveState,
2944        force_no_type_left_padding: bool,
2945        cx: &mut AsyncApp,
2946    ) -> anyhow::Result<InlayHint> {
2947        let kind = lsp_hint.kind.and_then(|kind| match kind {
2948            lsp::InlayHintKind::TYPE => Some(InlayHintKind::Type),
2949            lsp::InlayHintKind::PARAMETER => Some(InlayHintKind::Parameter),
2950            _ => None,
2951        });
2952
2953        let position = buffer_handle.read_with(cx, |buffer, _| {
2954            let position = buffer.clip_point_utf16(point_from_lsp(lsp_hint.position), Bias::Left);
2955            if kind == Some(InlayHintKind::Parameter) {
2956                buffer.anchor_before(position)
2957            } else {
2958                buffer.anchor_after(position)
2959            }
2960        });
2961        let label = Self::lsp_inlay_label_to_project(lsp_hint.label, server_id)
2962            .await
2963            .context("lsp to project inlay hint conversion")?;
2964        let padding_left = if force_no_type_left_padding && kind == Some(InlayHintKind::Type) {
2965            false
2966        } else {
2967            lsp_hint.padding_left.unwrap_or(false)
2968        };
2969
2970        Ok(InlayHint {
2971            position,
2972            padding_left,
2973            padding_right: lsp_hint.padding_right.unwrap_or(false),
2974            label,
2975            kind,
2976            tooltip: lsp_hint.tooltip.map(|tooltip| match tooltip {
2977                lsp::InlayHintTooltip::String(s) => InlayHintTooltip::String(s),
2978                lsp::InlayHintTooltip::MarkupContent(markup_content) => {
2979                    InlayHintTooltip::MarkupContent(MarkupContent {
2980                        kind: match markup_content.kind {
2981                            lsp::MarkupKind::PlainText => HoverBlockKind::PlainText,
2982                            lsp::MarkupKind::Markdown => HoverBlockKind::Markdown,
2983                        },
2984                        value: markup_content.value,
2985                    })
2986                }
2987            }),
2988            resolve_state,
2989        })
2990    }
2991
2992    async fn lsp_inlay_label_to_project(
2993        lsp_label: lsp::InlayHintLabel,
2994        server_id: LanguageServerId,
2995    ) -> anyhow::Result<InlayHintLabel> {
2996        let label = match lsp_label {
2997            lsp::InlayHintLabel::String(s) => InlayHintLabel::String(s),
2998            lsp::InlayHintLabel::LabelParts(lsp_parts) => {
2999                let mut parts = Vec::with_capacity(lsp_parts.len());
3000                for lsp_part in lsp_parts {
3001                    parts.push(InlayHintLabelPart {
3002                        value: lsp_part.value,
3003                        tooltip: lsp_part.tooltip.map(|tooltip| match tooltip {
3004                            lsp::InlayHintLabelPartTooltip::String(s) => {
3005                                InlayHintLabelPartTooltip::String(s)
3006                            }
3007                            lsp::InlayHintLabelPartTooltip::MarkupContent(markup_content) => {
3008                                InlayHintLabelPartTooltip::MarkupContent(MarkupContent {
3009                                    kind: match markup_content.kind {
3010                                        lsp::MarkupKind::PlainText => HoverBlockKind::PlainText,
3011                                        lsp::MarkupKind::Markdown => HoverBlockKind::Markdown,
3012                                    },
3013                                    value: markup_content.value,
3014                                })
3015                            }
3016                        }),
3017                        location: Some(server_id).zip(lsp_part.location),
3018                    });
3019                }
3020                InlayHintLabel::LabelParts(parts)
3021            }
3022        };
3023
3024        Ok(label)
3025    }
3026
3027    pub fn project_to_proto_hint(response_hint: InlayHint) -> proto::InlayHint {
3028        let (state, lsp_resolve_state) = match response_hint.resolve_state {
3029            ResolveState::Resolved => (0, None),
3030            ResolveState::CanResolve(server_id, resolve_data) => (
3031                1,
3032                Some(proto::resolve_state::LspResolveState {
3033                    server_id: server_id.0 as u64,
3034                    value: resolve_data.map(|json_data| {
3035                        serde_json::to_string(&json_data)
3036                            .expect("failed to serialize resolve json data")
3037                    }),
3038                }),
3039            ),
3040            ResolveState::Resolving => (2, None),
3041        };
3042        let resolve_state = Some(proto::ResolveState {
3043            state,
3044            lsp_resolve_state,
3045        });
3046        proto::InlayHint {
3047            position: Some(language::proto::serialize_anchor(&response_hint.position)),
3048            padding_left: response_hint.padding_left,
3049            padding_right: response_hint.padding_right,
3050            label: Some(proto::InlayHintLabel {
3051                label: Some(match response_hint.label {
3052                    InlayHintLabel::String(s) => proto::inlay_hint_label::Label::Value(s),
3053                    InlayHintLabel::LabelParts(label_parts) => {
3054                        proto::inlay_hint_label::Label::LabelParts(proto::InlayHintLabelParts {
3055                            parts: label_parts.into_iter().map(|label_part| {
3056                                let location_url = label_part.location.as_ref().map(|(_, location)| location.uri.to_string());
3057                                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 });
3058                                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 });
3059                                proto::InlayHintLabelPart {
3060                                value: label_part.value,
3061                                tooltip: label_part.tooltip.map(|tooltip| {
3062                                    let proto_tooltip = match tooltip {
3063                                        InlayHintLabelPartTooltip::String(s) => proto::inlay_hint_label_part_tooltip::Content::Value(s),
3064                                        InlayHintLabelPartTooltip::MarkupContent(markup_content) => proto::inlay_hint_label_part_tooltip::Content::MarkupContent(proto::MarkupContent {
3065                                            is_markdown: markup_content.kind == HoverBlockKind::Markdown,
3066                                            value: markup_content.value,
3067                                        }),
3068                                    };
3069                                    proto::InlayHintLabelPartTooltip {content: Some(proto_tooltip)}
3070                                }),
3071                                location_url,
3072                                location_range_start,
3073                                location_range_end,
3074                                language_server_id: label_part.location.as_ref().map(|(server_id, _)| server_id.0 as u64),
3075                            }}).collect()
3076                        })
3077                    }
3078                }),
3079            }),
3080            kind: response_hint.kind.map(|kind| kind.name().to_string()),
3081            tooltip: response_hint.tooltip.map(|response_tooltip| {
3082                let proto_tooltip = match response_tooltip {
3083                    InlayHintTooltip::String(s) => proto::inlay_hint_tooltip::Content::Value(s),
3084                    InlayHintTooltip::MarkupContent(markup_content) => {
3085                        proto::inlay_hint_tooltip::Content::MarkupContent(proto::MarkupContent {
3086                            is_markdown: markup_content.kind == HoverBlockKind::Markdown,
3087                            value: markup_content.value,
3088                        })
3089                    }
3090                };
3091                proto::InlayHintTooltip {
3092                    content: Some(proto_tooltip),
3093                }
3094            }),
3095            resolve_state,
3096        }
3097    }
3098
3099    pub fn proto_to_project_hint(message_hint: proto::InlayHint) -> anyhow::Result<InlayHint> {
3100        let resolve_state = message_hint.resolve_state.as_ref().unwrap_or_else(|| {
3101            panic!("incorrect proto inlay hint message: no resolve state in hint {message_hint:?}",)
3102        });
3103        let resolve_state_data = resolve_state
3104            .lsp_resolve_state.as_ref()
3105            .map(|lsp_resolve_state| {
3106                let value = lsp_resolve_state.value.as_deref().map(|value| {
3107                    serde_json::from_str::<Option<lsp::LSPAny>>(value)
3108                        .with_context(|| format!("incorrect proto inlay hint message: non-json resolve state {lsp_resolve_state:?}"))
3109                }).transpose()?.flatten();
3110                anyhow::Ok((LanguageServerId(lsp_resolve_state.server_id as usize), value))
3111            })
3112            .transpose()?;
3113        let resolve_state = match resolve_state.state {
3114            0 => ResolveState::Resolved,
3115            1 => {
3116                let (server_id, lsp_resolve_state) = resolve_state_data.with_context(|| {
3117                    format!(
3118                        "No lsp resolve data for the hint that can be resolved: {message_hint:?}"
3119                    )
3120                })?;
3121                ResolveState::CanResolve(server_id, lsp_resolve_state)
3122            }
3123            2 => ResolveState::Resolving,
3124            invalid => {
3125                anyhow::bail!("Unexpected resolve state {invalid} for hint {message_hint:?}")
3126            }
3127        };
3128        Ok(InlayHint {
3129            position: message_hint
3130                .position
3131                .and_then(language::proto::deserialize_anchor)
3132                .context("invalid position")?,
3133            label: match message_hint
3134                .label
3135                .and_then(|label| label.label)
3136                .context("missing label")?
3137            {
3138                proto::inlay_hint_label::Label::Value(s) => InlayHintLabel::String(s),
3139                proto::inlay_hint_label::Label::LabelParts(parts) => {
3140                    let mut label_parts = Vec::new();
3141                    for part in parts.parts {
3142                        label_parts.push(InlayHintLabelPart {
3143                            value: part.value,
3144                            tooltip: part.tooltip.map(|tooltip| match tooltip.content {
3145                                Some(proto::inlay_hint_label_part_tooltip::Content::Value(s)) => {
3146                                    InlayHintLabelPartTooltip::String(s)
3147                                }
3148                                Some(
3149                                    proto::inlay_hint_label_part_tooltip::Content::MarkupContent(
3150                                        markup_content,
3151                                    ),
3152                                ) => InlayHintLabelPartTooltip::MarkupContent(MarkupContent {
3153                                    kind: if markup_content.is_markdown {
3154                                        HoverBlockKind::Markdown
3155                                    } else {
3156                                        HoverBlockKind::PlainText
3157                                    },
3158                                    value: markup_content.value,
3159                                }),
3160                                None => InlayHintLabelPartTooltip::String(String::new()),
3161                            }),
3162                            location: {
3163                                match part
3164                                    .location_url
3165                                    .zip(
3166                                        part.location_range_start.and_then(|start| {
3167                                            Some(start..part.location_range_end?)
3168                                        }),
3169                                    )
3170                                    .zip(part.language_server_id)
3171                                {
3172                                    Some(((uri, range), server_id)) => Some((
3173                                        LanguageServerId(server_id as usize),
3174                                        lsp::Location {
3175                                            uri: lsp::Uri::from_str(&uri)
3176                                                .context("invalid uri in hint part {part:?}")?,
3177                                            range: lsp::Range::new(
3178                                                point_to_lsp(PointUtf16::new(
3179                                                    range.start.row,
3180                                                    range.start.column,
3181                                                )),
3182                                                point_to_lsp(PointUtf16::new(
3183                                                    range.end.row,
3184                                                    range.end.column,
3185                                                )),
3186                                            ),
3187                                        },
3188                                    )),
3189                                    None => None,
3190                                }
3191                            },
3192                        });
3193                    }
3194
3195                    InlayHintLabel::LabelParts(label_parts)
3196                }
3197            },
3198            padding_left: message_hint.padding_left,
3199            padding_right: message_hint.padding_right,
3200            kind: message_hint
3201                .kind
3202                .as_deref()
3203                .and_then(InlayHintKind::from_name),
3204            tooltip: message_hint.tooltip.and_then(|tooltip| {
3205                Some(match tooltip.content? {
3206                    proto::inlay_hint_tooltip::Content::Value(s) => InlayHintTooltip::String(s),
3207                    proto::inlay_hint_tooltip::Content::MarkupContent(markup_content) => {
3208                        InlayHintTooltip::MarkupContent(MarkupContent {
3209                            kind: if markup_content.is_markdown {
3210                                HoverBlockKind::Markdown
3211                            } else {
3212                                HoverBlockKind::PlainText
3213                            },
3214                            value: markup_content.value,
3215                        })
3216                    }
3217                })
3218            }),
3219            resolve_state,
3220        })
3221    }
3222
3223    pub fn project_to_lsp_hint(hint: InlayHint, snapshot: &BufferSnapshot) -> lsp::InlayHint {
3224        lsp::InlayHint {
3225            position: point_to_lsp(hint.position.to_point_utf16(snapshot)),
3226            kind: hint.kind.map(|kind| match kind {
3227                InlayHintKind::Type => lsp::InlayHintKind::TYPE,
3228                InlayHintKind::Parameter => lsp::InlayHintKind::PARAMETER,
3229            }),
3230            text_edits: None,
3231            tooltip: hint.tooltip.and_then(|tooltip| {
3232                Some(match tooltip {
3233                    InlayHintTooltip::String(s) => lsp::InlayHintTooltip::String(s),
3234                    InlayHintTooltip::MarkupContent(markup_content) => {
3235                        lsp::InlayHintTooltip::MarkupContent(lsp::MarkupContent {
3236                            kind: match markup_content.kind {
3237                                HoverBlockKind::PlainText => lsp::MarkupKind::PlainText,
3238                                HoverBlockKind::Markdown => lsp::MarkupKind::Markdown,
3239                                HoverBlockKind::Code { .. } => return None,
3240                            },
3241                            value: markup_content.value,
3242                        })
3243                    }
3244                })
3245            }),
3246            label: match hint.label {
3247                InlayHintLabel::String(s) => lsp::InlayHintLabel::String(s),
3248                InlayHintLabel::LabelParts(label_parts) => lsp::InlayHintLabel::LabelParts(
3249                    label_parts
3250                        .into_iter()
3251                        .map(|part| lsp::InlayHintLabelPart {
3252                            value: part.value,
3253                            tooltip: part.tooltip.and_then(|tooltip| {
3254                                Some(match tooltip {
3255                                    InlayHintLabelPartTooltip::String(s) => {
3256                                        lsp::InlayHintLabelPartTooltip::String(s)
3257                                    }
3258                                    InlayHintLabelPartTooltip::MarkupContent(markup_content) => {
3259                                        lsp::InlayHintLabelPartTooltip::MarkupContent(
3260                                            lsp::MarkupContent {
3261                                                kind: match markup_content.kind {
3262                                                    HoverBlockKind::PlainText => {
3263                                                        lsp::MarkupKind::PlainText
3264                                                    }
3265                                                    HoverBlockKind::Markdown => {
3266                                                        lsp::MarkupKind::Markdown
3267                                                    }
3268                                                    HoverBlockKind::Code { .. } => return None,
3269                                                },
3270                                                value: markup_content.value,
3271                                            },
3272                                        )
3273                                    }
3274                                })
3275                            }),
3276                            location: part.location.map(|(_, location)| location),
3277                            command: None,
3278                        })
3279                        .collect(),
3280                ),
3281            },
3282            padding_left: Some(hint.padding_left),
3283            padding_right: Some(hint.padding_right),
3284            data: match hint.resolve_state {
3285                ResolveState::CanResolve(_, data) => data,
3286                ResolveState::Resolving | ResolveState::Resolved => None,
3287            },
3288        }
3289    }
3290
3291    pub fn can_resolve_inlays(capabilities: &ServerCapabilities) -> bool {
3292        capabilities
3293            .inlay_hint_provider
3294            .as_ref()
3295            .and_then(|options| match options {
3296                OneOf::Left(_is_supported) => None,
3297                OneOf::Right(capabilities) => match capabilities {
3298                    lsp::InlayHintServerCapabilities::Options(o) => o.resolve_provider,
3299                    lsp::InlayHintServerCapabilities::RegistrationOptions(o) => {
3300                        o.inlay_hint_options.resolve_provider
3301                    }
3302                },
3303            })
3304            .unwrap_or(false)
3305    }
3306
3307    pub fn check_capabilities(capabilities: &ServerCapabilities) -> bool {
3308        capabilities
3309            .inlay_hint_provider
3310            .as_ref()
3311            .is_some_and(|inlay_hint_provider| match inlay_hint_provider {
3312                lsp::OneOf::Left(enabled) => *enabled,
3313                lsp::OneOf::Right(_) => true,
3314            })
3315    }
3316}
3317
3318#[async_trait(?Send)]
3319impl LspCommand for InlayHints {
3320    type Response = Vec<InlayHint>;
3321    type LspRequest = lsp::InlayHintRequest;
3322    type ProtoRequest = proto::InlayHints;
3323
3324    fn display_name(&self) -> &str {
3325        "Inlay hints"
3326    }
3327
3328    fn check_capabilities(&self, capabilities: AdapterServerCapabilities) -> bool {
3329        Self::check_capabilities(&capabilities.server_capabilities)
3330    }
3331
3332    fn to_lsp(
3333        &self,
3334        path: &Path,
3335        buffer: &Buffer,
3336        _: &Arc<LanguageServer>,
3337        _: &App,
3338    ) -> Result<lsp::InlayHintParams> {
3339        Ok(lsp::InlayHintParams {
3340            text_document: lsp::TextDocumentIdentifier {
3341                uri: file_path_to_lsp_url(path)?,
3342            },
3343            range: range_to_lsp(self.range.to_point_utf16(buffer))?,
3344            work_done_progress_params: Default::default(),
3345        })
3346    }
3347
3348    async fn response_from_lsp(
3349        self,
3350        message: Option<Vec<lsp::InlayHint>>,
3351        lsp_store: Entity<LspStore>,
3352        buffer: Entity<Buffer>,
3353        server_id: LanguageServerId,
3354        mut cx: AsyncApp,
3355    ) -> anyhow::Result<Vec<InlayHint>> {
3356        let (lsp_adapter, lsp_server) =
3357            language_server_for_buffer(&lsp_store, &buffer, server_id, &mut cx)?;
3358        // `typescript-language-server` adds padding to the left for type hints, turning
3359        // `const foo: boolean` into `const foo : boolean` which looks odd.
3360        // `rust-analyzer` does not have the padding for this case, and we have to accommodate both.
3361        //
3362        // We could trim the whole string, but being pessimistic on par with the situation above,
3363        // there might be a hint with multiple whitespaces at the end(s) which we need to display properly.
3364        // Hence let's use a heuristic first to handle the most awkward case and look for more.
3365        let force_no_type_left_padding =
3366            lsp_adapter.name.0.as_ref() == "typescript-language-server";
3367
3368        let hints = message.unwrap_or_default().into_iter().map(|lsp_hint| {
3369            let resolve_state = if InlayHints::can_resolve_inlays(&lsp_server.capabilities()) {
3370                ResolveState::CanResolve(lsp_server.server_id(), lsp_hint.data.clone())
3371            } else {
3372                ResolveState::Resolved
3373            };
3374
3375            let buffer = buffer.clone();
3376            cx.spawn(async move |cx| {
3377                InlayHints::lsp_to_project_hint(
3378                    lsp_hint,
3379                    &buffer,
3380                    server_id,
3381                    resolve_state,
3382                    force_no_type_left_padding,
3383                    cx,
3384                )
3385                .await
3386            })
3387        });
3388        future::join_all(hints)
3389            .await
3390            .into_iter()
3391            .collect::<anyhow::Result<_>>()
3392            .context("lsp to project inlay hints conversion")
3393    }
3394
3395    fn to_proto(&self, project_id: u64, buffer: &Buffer) -> proto::InlayHints {
3396        proto::InlayHints {
3397            project_id,
3398            buffer_id: buffer.remote_id().into(),
3399            start: Some(language::proto::serialize_anchor(&self.range.start)),
3400            end: Some(language::proto::serialize_anchor(&self.range.end)),
3401            version: serialize_version(&buffer.version()),
3402        }
3403    }
3404
3405    async fn from_proto(
3406        message: proto::InlayHints,
3407        _: Entity<LspStore>,
3408        buffer: Entity<Buffer>,
3409        mut cx: AsyncApp,
3410    ) -> Result<Self> {
3411        let start = message
3412            .start
3413            .and_then(language::proto::deserialize_anchor)
3414            .context("invalid start")?;
3415        let end = message
3416            .end
3417            .and_then(language::proto::deserialize_anchor)
3418            .context("invalid end")?;
3419        buffer
3420            .update(&mut cx, |buffer, _| {
3421                buffer.wait_for_version(deserialize_version(&message.version))
3422            })
3423            .await?;
3424
3425        Ok(Self { range: start..end })
3426    }
3427
3428    fn response_to_proto(
3429        response: Vec<InlayHint>,
3430        _: &mut LspStore,
3431        _: PeerId,
3432        buffer_version: &clock::Global,
3433        _: &mut App,
3434    ) -> proto::InlayHintsResponse {
3435        proto::InlayHintsResponse {
3436            hints: response
3437                .into_iter()
3438                .map(InlayHints::project_to_proto_hint)
3439                .collect(),
3440            version: serialize_version(buffer_version),
3441        }
3442    }
3443
3444    async fn response_from_proto(
3445        self,
3446        message: proto::InlayHintsResponse,
3447        _: Entity<LspStore>,
3448        buffer: Entity<Buffer>,
3449        mut cx: AsyncApp,
3450    ) -> anyhow::Result<Vec<InlayHint>> {
3451        buffer
3452            .update(&mut cx, |buffer, _| {
3453                buffer.wait_for_version(deserialize_version(&message.version))
3454            })
3455            .await?;
3456
3457        let mut hints = Vec::new();
3458        for message_hint in message.hints {
3459            hints.push(InlayHints::proto_to_project_hint(message_hint)?);
3460        }
3461
3462        Ok(hints)
3463    }
3464
3465    fn buffer_id_from_proto(message: &proto::InlayHints) -> Result<BufferId> {
3466        BufferId::new(message.buffer_id)
3467    }
3468}
3469
3470#[async_trait(?Send)]
3471impl LspCommand for GetCodeLens {
3472    type Response = Vec<CodeAction>;
3473    type LspRequest = lsp::CodeLensRequest;
3474    type ProtoRequest = proto::GetCodeLens;
3475
3476    fn display_name(&self) -> &str {
3477        "Code Lens"
3478    }
3479
3480    fn check_capabilities(&self, capabilities: AdapterServerCapabilities) -> bool {
3481        capabilities
3482            .server_capabilities
3483            .code_lens_provider
3484            .is_some()
3485    }
3486
3487    fn to_lsp(
3488        &self,
3489        path: &Path,
3490        _: &Buffer,
3491        _: &Arc<LanguageServer>,
3492        _: &App,
3493    ) -> Result<lsp::CodeLensParams> {
3494        Ok(lsp::CodeLensParams {
3495            text_document: lsp::TextDocumentIdentifier {
3496                uri: file_path_to_lsp_url(path)?,
3497            },
3498            work_done_progress_params: lsp::WorkDoneProgressParams::default(),
3499            partial_result_params: lsp::PartialResultParams::default(),
3500        })
3501    }
3502
3503    async fn response_from_lsp(
3504        self,
3505        message: Option<Vec<lsp::CodeLens>>,
3506        lsp_store: Entity<LspStore>,
3507        buffer: Entity<Buffer>,
3508        server_id: LanguageServerId,
3509        cx: AsyncApp,
3510    ) -> anyhow::Result<Vec<CodeAction>> {
3511        let snapshot = buffer.read_with(&cx, |buffer, _| buffer.snapshot());
3512        let language_server = cx.update(|cx| {
3513            lsp_store
3514                .read(cx)
3515                .language_server_for_id(server_id)
3516                .with_context(|| {
3517                    format!("Missing the language server that just returned a response {server_id}")
3518                })
3519        })?;
3520        let server_capabilities = language_server.capabilities();
3521        let available_commands = server_capabilities
3522            .execute_command_provider
3523            .as_ref()
3524            .map(|options| options.commands.as_slice())
3525            .unwrap_or_default();
3526        Ok(message
3527            .unwrap_or_default()
3528            .into_iter()
3529            .filter(|code_lens| {
3530                code_lens
3531                    .command
3532                    .as_ref()
3533                    .is_none_or(|command| available_commands.contains(&command.command))
3534            })
3535            .map(|code_lens| {
3536                let code_lens_range = range_from_lsp(code_lens.range);
3537                let start = snapshot.clip_point_utf16(code_lens_range.start, Bias::Left);
3538                let end = snapshot.clip_point_utf16(code_lens_range.end, Bias::Right);
3539                let range = snapshot.anchor_before(start)..snapshot.anchor_after(end);
3540                CodeAction {
3541                    server_id,
3542                    range,
3543                    lsp_action: LspAction::CodeLens(code_lens),
3544                    resolved: false,
3545                }
3546            })
3547            .collect())
3548    }
3549
3550    fn to_proto(&self, project_id: u64, buffer: &Buffer) -> proto::GetCodeLens {
3551        proto::GetCodeLens {
3552            project_id,
3553            buffer_id: buffer.remote_id().into(),
3554            version: serialize_version(&buffer.version()),
3555        }
3556    }
3557
3558    async fn from_proto(
3559        message: proto::GetCodeLens,
3560        _: Entity<LspStore>,
3561        buffer: Entity<Buffer>,
3562        mut cx: AsyncApp,
3563    ) -> Result<Self> {
3564        buffer
3565            .update(&mut cx, |buffer, _| {
3566                buffer.wait_for_version(deserialize_version(&message.version))
3567            })
3568            .await?;
3569        Ok(Self)
3570    }
3571
3572    fn response_to_proto(
3573        response: Vec<CodeAction>,
3574        _: &mut LspStore,
3575        _: PeerId,
3576        buffer_version: &clock::Global,
3577        _: &mut App,
3578    ) -> proto::GetCodeLensResponse {
3579        proto::GetCodeLensResponse {
3580            lens_actions: response
3581                .iter()
3582                .map(LspStore::serialize_code_action)
3583                .collect(),
3584            version: serialize_version(buffer_version),
3585        }
3586    }
3587
3588    async fn response_from_proto(
3589        self,
3590        message: proto::GetCodeLensResponse,
3591        _: Entity<LspStore>,
3592        buffer: Entity<Buffer>,
3593        mut cx: AsyncApp,
3594    ) -> anyhow::Result<Vec<CodeAction>> {
3595        buffer
3596            .update(&mut cx, |buffer, _| {
3597                buffer.wait_for_version(deserialize_version(&message.version))
3598            })
3599            .await?;
3600        message
3601            .lens_actions
3602            .into_iter()
3603            .map(LspStore::deserialize_code_action)
3604            .collect::<Result<Vec<_>>>()
3605            .context("deserializing proto code lens response")
3606    }
3607
3608    fn buffer_id_from_proto(message: &proto::GetCodeLens) -> Result<BufferId> {
3609        BufferId::new(message.buffer_id)
3610    }
3611}
3612
3613impl LinkedEditingRange {
3614    pub fn check_server_capabilities(capabilities: ServerCapabilities) -> bool {
3615        let Some(linked_editing_options) = capabilities.linked_editing_range_provider else {
3616            return false;
3617        };
3618        if let LinkedEditingRangeServerCapabilities::Simple(false) = linked_editing_options {
3619            return false;
3620        }
3621        true
3622    }
3623}
3624
3625#[async_trait(?Send)]
3626impl LspCommand for LinkedEditingRange {
3627    type Response = Vec<Range<Anchor>>;
3628    type LspRequest = lsp::request::LinkedEditingRange;
3629    type ProtoRequest = proto::LinkedEditingRange;
3630
3631    fn display_name(&self) -> &str {
3632        "Linked editing range"
3633    }
3634
3635    fn check_capabilities(&self, capabilities: AdapterServerCapabilities) -> bool {
3636        Self::check_server_capabilities(capabilities.server_capabilities)
3637    }
3638
3639    fn to_lsp(
3640        &self,
3641        path: &Path,
3642        buffer: &Buffer,
3643        _server: &Arc<LanguageServer>,
3644        _: &App,
3645    ) -> Result<lsp::LinkedEditingRangeParams> {
3646        let position = self.position.to_point_utf16(&buffer.snapshot());
3647        Ok(lsp::LinkedEditingRangeParams {
3648            text_document_position_params: make_lsp_text_document_position(path, position)?,
3649            work_done_progress_params: Default::default(),
3650        })
3651    }
3652
3653    async fn response_from_lsp(
3654        self,
3655        message: Option<lsp::LinkedEditingRanges>,
3656        _: Entity<LspStore>,
3657        buffer: Entity<Buffer>,
3658        _server_id: LanguageServerId,
3659        cx: AsyncApp,
3660    ) -> Result<Vec<Range<Anchor>>> {
3661        if let Some(lsp::LinkedEditingRanges { mut ranges, .. }) = message {
3662            ranges.sort_by_key(|range| range.start);
3663
3664            Ok(buffer.read_with(&cx, |buffer, _| {
3665                ranges
3666                    .into_iter()
3667                    .map(|range| {
3668                        let start =
3669                            buffer.clip_point_utf16(point_from_lsp(range.start), Bias::Left);
3670                        let end = buffer.clip_point_utf16(point_from_lsp(range.end), Bias::Left);
3671                        buffer.anchor_before(start)..buffer.anchor_after(end)
3672                    })
3673                    .collect()
3674            }))
3675        } else {
3676            Ok(vec![])
3677        }
3678    }
3679
3680    fn to_proto(&self, project_id: u64, buffer: &Buffer) -> proto::LinkedEditingRange {
3681        proto::LinkedEditingRange {
3682            project_id,
3683            buffer_id: buffer.remote_id().to_proto(),
3684            position: Some(serialize_anchor(&self.position)),
3685            version: serialize_version(&buffer.version()),
3686        }
3687    }
3688
3689    async fn from_proto(
3690        message: proto::LinkedEditingRange,
3691        _: Entity<LspStore>,
3692        buffer: Entity<Buffer>,
3693        mut cx: AsyncApp,
3694    ) -> Result<Self> {
3695        let position = message.position.context("invalid position")?;
3696        buffer
3697            .update(&mut cx, |buffer, _| {
3698                buffer.wait_for_version(deserialize_version(&message.version))
3699            })
3700            .await?;
3701        let position = deserialize_anchor(position).context("invalid position")?;
3702        buffer
3703            .update(&mut cx, |buffer, _| buffer.wait_for_anchors([position]))
3704            .await?;
3705        Ok(Self { position })
3706    }
3707
3708    fn response_to_proto(
3709        response: Vec<Range<Anchor>>,
3710        _: &mut LspStore,
3711        _: PeerId,
3712        buffer_version: &clock::Global,
3713        _: &mut App,
3714    ) -> proto::LinkedEditingRangeResponse {
3715        proto::LinkedEditingRangeResponse {
3716            items: response
3717                .into_iter()
3718                .map(|range| proto::AnchorRange {
3719                    start: Some(serialize_anchor(&range.start)),
3720                    end: Some(serialize_anchor(&range.end)),
3721                })
3722                .collect(),
3723            version: serialize_version(buffer_version),
3724        }
3725    }
3726
3727    async fn response_from_proto(
3728        self,
3729        message: proto::LinkedEditingRangeResponse,
3730        _: Entity<LspStore>,
3731        buffer: Entity<Buffer>,
3732        mut cx: AsyncApp,
3733    ) -> Result<Vec<Range<Anchor>>> {
3734        buffer
3735            .update(&mut cx, |buffer, _| {
3736                buffer.wait_for_version(deserialize_version(&message.version))
3737            })
3738            .await?;
3739        let items: Vec<Range<Anchor>> = message
3740            .items
3741            .into_iter()
3742            .filter_map(|range| {
3743                let start = deserialize_anchor(range.start?)?;
3744                let end = deserialize_anchor(range.end?)?;
3745                Some(start..end)
3746            })
3747            .collect();
3748        for range in &items {
3749            buffer
3750                .update(&mut cx, |buffer, _| {
3751                    buffer.wait_for_anchors([range.start, range.end])
3752                })
3753                .await?;
3754        }
3755        Ok(items)
3756    }
3757
3758    fn buffer_id_from_proto(message: &proto::LinkedEditingRange) -> Result<BufferId> {
3759        BufferId::new(message.buffer_id)
3760    }
3761}
3762
3763impl GetDocumentDiagnostics {
3764    pub fn diagnostics_from_proto(
3765        response: proto::GetDocumentDiagnosticsResponse,
3766    ) -> Vec<LspPullDiagnostics> {
3767        response
3768            .pulled_diagnostics
3769            .into_iter()
3770            .filter_map(|diagnostics| {
3771                Some(LspPullDiagnostics::Response {
3772                    registration_id: diagnostics.registration_id.map(SharedString::from),
3773                    server_id: LanguageServerId::from_proto(diagnostics.server_id),
3774                    uri: lsp::Uri::from_str(diagnostics.uri.as_str()).log_err()?,
3775                    diagnostics: if diagnostics.changed {
3776                        PulledDiagnostics::Unchanged {
3777                            result_id: SharedString::new(diagnostics.result_id?),
3778                        }
3779                    } else {
3780                        PulledDiagnostics::Changed {
3781                            result_id: diagnostics.result_id.map(SharedString::new),
3782                            diagnostics: diagnostics
3783                                .diagnostics
3784                                .into_iter()
3785                                .filter_map(|diagnostic| {
3786                                    GetDocumentDiagnostics::deserialize_lsp_diagnostic(diagnostic)
3787                                        .context("deserializing diagnostics")
3788                                        .log_err()
3789                                })
3790                                .collect(),
3791                        }
3792                    },
3793                })
3794            })
3795            .collect()
3796    }
3797
3798    fn deserialize_lsp_diagnostic(diagnostic: proto::LspDiagnostic) -> Result<lsp::Diagnostic> {
3799        let start = diagnostic.start.context("invalid start range")?;
3800        let end = diagnostic.end.context("invalid end range")?;
3801
3802        let range = Range::<PointUtf16> {
3803            start: PointUtf16 {
3804                row: start.row,
3805                column: start.column,
3806            },
3807            end: PointUtf16 {
3808                row: end.row,
3809                column: end.column,
3810            },
3811        };
3812
3813        let data = diagnostic.data.and_then(|data| Value::from_str(&data).ok());
3814        let code = diagnostic.code.map(lsp::NumberOrString::String);
3815
3816        let related_information = diagnostic
3817            .related_information
3818            .into_iter()
3819            .map(|info| {
3820                let start = info.location_range_start.unwrap();
3821                let end = info.location_range_end.unwrap();
3822
3823                lsp::DiagnosticRelatedInformation {
3824                    location: lsp::Location {
3825                        range: lsp::Range {
3826                            start: point_to_lsp(PointUtf16::new(start.row, start.column)),
3827                            end: point_to_lsp(PointUtf16::new(end.row, end.column)),
3828                        },
3829                        uri: lsp::Uri::from_str(&info.location_url.unwrap()).unwrap(),
3830                    },
3831                    message: info.message,
3832                }
3833            })
3834            .collect::<Vec<_>>();
3835
3836        let tags = diagnostic
3837            .tags
3838            .into_iter()
3839            .filter_map(|tag| match proto::LspDiagnosticTag::from_i32(tag) {
3840                Some(proto::LspDiagnosticTag::Unnecessary) => Some(lsp::DiagnosticTag::UNNECESSARY),
3841                Some(proto::LspDiagnosticTag::Deprecated) => Some(lsp::DiagnosticTag::DEPRECATED),
3842                _ => None,
3843            })
3844            .collect::<Vec<_>>();
3845
3846        Ok(lsp::Diagnostic {
3847            range: language::range_to_lsp(range)?,
3848            severity: match proto::lsp_diagnostic::Severity::from_i32(diagnostic.severity).unwrap()
3849            {
3850                proto::lsp_diagnostic::Severity::Error => Some(lsp::DiagnosticSeverity::ERROR),
3851                proto::lsp_diagnostic::Severity::Warning => Some(lsp::DiagnosticSeverity::WARNING),
3852                proto::lsp_diagnostic::Severity::Information => {
3853                    Some(lsp::DiagnosticSeverity::INFORMATION)
3854                }
3855                proto::lsp_diagnostic::Severity::Hint => Some(lsp::DiagnosticSeverity::HINT),
3856                _ => None,
3857            },
3858            code,
3859            code_description: diagnostic
3860                .code_description
3861                .map(|code_description| CodeDescription {
3862                    href: Some(lsp::Uri::from_str(&code_description).unwrap()),
3863                }),
3864            related_information: Some(related_information),
3865            tags: Some(tags),
3866            source: diagnostic.source.clone(),
3867            message: diagnostic.message,
3868            data,
3869        })
3870    }
3871
3872    fn serialize_lsp_diagnostic(diagnostic: lsp::Diagnostic) -> Result<proto::LspDiagnostic> {
3873        let range = language::range_from_lsp(diagnostic.range);
3874        let related_information = diagnostic
3875            .related_information
3876            .unwrap_or_default()
3877            .into_iter()
3878            .map(|related_information| {
3879                let location_range_start =
3880                    point_from_lsp(related_information.location.range.start).0;
3881                let location_range_end = point_from_lsp(related_information.location.range.end).0;
3882
3883                Ok(proto::LspDiagnosticRelatedInformation {
3884                    location_url: Some(related_information.location.uri.to_string()),
3885                    location_range_start: Some(proto::PointUtf16 {
3886                        row: location_range_start.row,
3887                        column: location_range_start.column,
3888                    }),
3889                    location_range_end: Some(proto::PointUtf16 {
3890                        row: location_range_end.row,
3891                        column: location_range_end.column,
3892                    }),
3893                    message: related_information.message,
3894                })
3895            })
3896            .collect::<Result<Vec<_>>>()?;
3897
3898        let tags = diagnostic
3899            .tags
3900            .unwrap_or_default()
3901            .into_iter()
3902            .map(|tag| match tag {
3903                lsp::DiagnosticTag::UNNECESSARY => proto::LspDiagnosticTag::Unnecessary,
3904                lsp::DiagnosticTag::DEPRECATED => proto::LspDiagnosticTag::Deprecated,
3905                _ => proto::LspDiagnosticTag::None,
3906            } as i32)
3907            .collect();
3908
3909        Ok(proto::LspDiagnostic {
3910            start: Some(proto::PointUtf16 {
3911                row: range.start.0.row,
3912                column: range.start.0.column,
3913            }),
3914            end: Some(proto::PointUtf16 {
3915                row: range.end.0.row,
3916                column: range.end.0.column,
3917            }),
3918            severity: match diagnostic.severity {
3919                Some(lsp::DiagnosticSeverity::ERROR) => proto::lsp_diagnostic::Severity::Error,
3920                Some(lsp::DiagnosticSeverity::WARNING) => proto::lsp_diagnostic::Severity::Warning,
3921                Some(lsp::DiagnosticSeverity::INFORMATION) => {
3922                    proto::lsp_diagnostic::Severity::Information
3923                }
3924                Some(lsp::DiagnosticSeverity::HINT) => proto::lsp_diagnostic::Severity::Hint,
3925                _ => proto::lsp_diagnostic::Severity::None,
3926            } as i32,
3927            code: diagnostic.code.as_ref().map(|code| match code {
3928                lsp::NumberOrString::Number(code) => code.to_string(),
3929                lsp::NumberOrString::String(code) => code.clone(),
3930            }),
3931            source: diagnostic.source.clone(),
3932            related_information,
3933            tags,
3934            code_description: diagnostic
3935                .code_description
3936                .and_then(|desc| desc.href.map(|url| url.to_string())),
3937            message: diagnostic.message,
3938            data: diagnostic.data.as_ref().map(|data| data.to_string()),
3939        })
3940    }
3941
3942    pub fn deserialize_workspace_diagnostics_report(
3943        report: lsp::WorkspaceDiagnosticReportResult,
3944        server_id: LanguageServerId,
3945        registration_id: Option<SharedString>,
3946    ) -> Vec<WorkspaceLspPullDiagnostics> {
3947        let mut pulled_diagnostics = HashMap::default();
3948        match report {
3949            lsp::WorkspaceDiagnosticReportResult::Report(workspace_diagnostic_report) => {
3950                for report in workspace_diagnostic_report.items {
3951                    match report {
3952                        lsp::WorkspaceDocumentDiagnosticReport::Full(report) => {
3953                            process_full_workspace_diagnostics_report(
3954                                &mut pulled_diagnostics,
3955                                server_id,
3956                                report,
3957                                registration_id.clone(),
3958                            )
3959                        }
3960                        lsp::WorkspaceDocumentDiagnosticReport::Unchanged(report) => {
3961                            process_unchanged_workspace_diagnostics_report(
3962                                &mut pulled_diagnostics,
3963                                server_id,
3964                                report,
3965                                registration_id.clone(),
3966                            )
3967                        }
3968                    }
3969                }
3970            }
3971            lsp::WorkspaceDiagnosticReportResult::Partial(
3972                workspace_diagnostic_report_partial_result,
3973            ) => {
3974                for report in workspace_diagnostic_report_partial_result.items {
3975                    match report {
3976                        lsp::WorkspaceDocumentDiagnosticReport::Full(report) => {
3977                            process_full_workspace_diagnostics_report(
3978                                &mut pulled_diagnostics,
3979                                server_id,
3980                                report,
3981                                registration_id.clone(),
3982                            )
3983                        }
3984                        lsp::WorkspaceDocumentDiagnosticReport::Unchanged(report) => {
3985                            process_unchanged_workspace_diagnostics_report(
3986                                &mut pulled_diagnostics,
3987                                server_id,
3988                                report,
3989                                registration_id.clone(),
3990                            )
3991                        }
3992                    }
3993                }
3994            }
3995        }
3996        pulled_diagnostics.into_values().collect()
3997    }
3998}
3999
4000#[derive(Debug)]
4001pub struct WorkspaceLspPullDiagnostics {
4002    pub version: Option<i32>,
4003    pub diagnostics: LspPullDiagnostics,
4004}
4005
4006fn process_full_workspace_diagnostics_report(
4007    diagnostics: &mut HashMap<lsp::Uri, WorkspaceLspPullDiagnostics>,
4008    server_id: LanguageServerId,
4009    report: lsp::WorkspaceFullDocumentDiagnosticReport,
4010    registration_id: Option<SharedString>,
4011) {
4012    let mut new_diagnostics = HashMap::default();
4013    process_full_diagnostics_report(
4014        &mut new_diagnostics,
4015        server_id,
4016        report.uri,
4017        report.full_document_diagnostic_report,
4018        registration_id,
4019    );
4020    diagnostics.extend(new_diagnostics.into_iter().map(|(uri, diagnostics)| {
4021        (
4022            uri,
4023            WorkspaceLspPullDiagnostics {
4024                version: report.version.map(|v| v as i32),
4025                diagnostics,
4026            },
4027        )
4028    }));
4029}
4030
4031fn process_unchanged_workspace_diagnostics_report(
4032    diagnostics: &mut HashMap<lsp::Uri, WorkspaceLspPullDiagnostics>,
4033    server_id: LanguageServerId,
4034    report: lsp::WorkspaceUnchangedDocumentDiagnosticReport,
4035    registration_id: Option<SharedString>,
4036) {
4037    let mut new_diagnostics = HashMap::default();
4038    process_unchanged_diagnostics_report(
4039        &mut new_diagnostics,
4040        server_id,
4041        report.uri,
4042        report.unchanged_document_diagnostic_report,
4043        registration_id,
4044    );
4045    diagnostics.extend(new_diagnostics.into_iter().map(|(uri, diagnostics)| {
4046        (
4047            uri,
4048            WorkspaceLspPullDiagnostics {
4049                version: report.version.map(|v| v as i32),
4050                diagnostics,
4051            },
4052        )
4053    }));
4054}
4055
4056#[async_trait(?Send)]
4057impl LspCommand for GetDocumentDiagnostics {
4058    type Response = Vec<LspPullDiagnostics>;
4059    type LspRequest = lsp::request::DocumentDiagnosticRequest;
4060    type ProtoRequest = proto::GetDocumentDiagnostics;
4061
4062    fn display_name(&self) -> &str {
4063        "Get diagnostics"
4064    }
4065
4066    fn check_capabilities(&self, _: AdapterServerCapabilities) -> bool {
4067        true
4068    }
4069
4070    fn to_lsp(
4071        &self,
4072        path: &Path,
4073        _: &Buffer,
4074        _: &Arc<LanguageServer>,
4075        _: &App,
4076    ) -> Result<lsp::DocumentDiagnosticParams> {
4077        Ok(lsp::DocumentDiagnosticParams {
4078            text_document: lsp::TextDocumentIdentifier {
4079                uri: file_path_to_lsp_url(path)?,
4080            },
4081            identifier: self.identifier.clone(),
4082            previous_result_id: self.previous_result_id.clone().map(|id| id.to_string()),
4083            partial_result_params: Default::default(),
4084            work_done_progress_params: Default::default(),
4085        })
4086    }
4087
4088    async fn response_from_lsp(
4089        self,
4090        message: lsp::DocumentDiagnosticReportResult,
4091        _: Entity<LspStore>,
4092        buffer: Entity<Buffer>,
4093        server_id: LanguageServerId,
4094        cx: AsyncApp,
4095    ) -> Result<Self::Response> {
4096        let url = buffer.read_with(&cx, |buffer, cx| {
4097            buffer
4098                .file()
4099                .and_then(|file| file.as_local())
4100                .map(|file| {
4101                    let abs_path = file.abs_path(cx);
4102                    file_path_to_lsp_url(&abs_path)
4103                })
4104                .transpose()?
4105                .with_context(|| format!("missing url on buffer {}", buffer.remote_id()))
4106        })?;
4107
4108        let mut pulled_diagnostics = HashMap::default();
4109        match message {
4110            lsp::DocumentDiagnosticReportResult::Report(report) => match report {
4111                lsp::DocumentDiagnosticReport::Full(report) => {
4112                    if let Some(related_documents) = report.related_documents {
4113                        process_related_documents(
4114                            &mut pulled_diagnostics,
4115                            server_id,
4116                            related_documents,
4117                            self.registration_id.clone(),
4118                        );
4119                    }
4120                    process_full_diagnostics_report(
4121                        &mut pulled_diagnostics,
4122                        server_id,
4123                        url,
4124                        report.full_document_diagnostic_report,
4125                        self.registration_id,
4126                    );
4127                }
4128                lsp::DocumentDiagnosticReport::Unchanged(report) => {
4129                    if let Some(related_documents) = report.related_documents {
4130                        process_related_documents(
4131                            &mut pulled_diagnostics,
4132                            server_id,
4133                            related_documents,
4134                            self.registration_id.clone(),
4135                        );
4136                    }
4137                    process_unchanged_diagnostics_report(
4138                        &mut pulled_diagnostics,
4139                        server_id,
4140                        url,
4141                        report.unchanged_document_diagnostic_report,
4142                        self.registration_id,
4143                    );
4144                }
4145            },
4146            lsp::DocumentDiagnosticReportResult::Partial(report) => {
4147                if let Some(related_documents) = report.related_documents {
4148                    process_related_documents(
4149                        &mut pulled_diagnostics,
4150                        server_id,
4151                        related_documents,
4152                        self.registration_id,
4153                    );
4154                }
4155            }
4156        }
4157
4158        Ok(pulled_diagnostics.into_values().collect())
4159    }
4160
4161    fn to_proto(&self, project_id: u64, buffer: &Buffer) -> proto::GetDocumentDiagnostics {
4162        proto::GetDocumentDiagnostics {
4163            project_id,
4164            buffer_id: buffer.remote_id().into(),
4165            version: serialize_version(&buffer.version()),
4166        }
4167    }
4168
4169    async fn from_proto(
4170        _: proto::GetDocumentDiagnostics,
4171        _: Entity<LspStore>,
4172        _: Entity<Buffer>,
4173        _: AsyncApp,
4174    ) -> Result<Self> {
4175        anyhow::bail!(
4176            "proto::GetDocumentDiagnostics is not expected to be converted from proto directly, as it needs `previous_result_id` fetched first"
4177        )
4178    }
4179
4180    fn response_to_proto(
4181        response: Self::Response,
4182        _: &mut LspStore,
4183        _: PeerId,
4184        _: &clock::Global,
4185        _: &mut App,
4186    ) -> proto::GetDocumentDiagnosticsResponse {
4187        let pulled_diagnostics = response
4188            .into_iter()
4189            .filter_map(|diagnostics| match diagnostics {
4190                LspPullDiagnostics::Default => None,
4191                LspPullDiagnostics::Response {
4192                    server_id,
4193                    uri,
4194                    diagnostics,
4195                    registration_id,
4196                } => {
4197                    let mut changed = false;
4198                    let (diagnostics, result_id) = match diagnostics {
4199                        PulledDiagnostics::Unchanged { result_id } => (Vec::new(), Some(result_id)),
4200                        PulledDiagnostics::Changed {
4201                            result_id,
4202                            diagnostics,
4203                        } => {
4204                            changed = true;
4205                            (diagnostics, result_id)
4206                        }
4207                    };
4208                    Some(proto::PulledDiagnostics {
4209                        changed,
4210                        result_id: result_id.map(|id| id.to_string()),
4211                        uri: uri.to_string(),
4212                        server_id: server_id.to_proto(),
4213                        diagnostics: diagnostics
4214                            .into_iter()
4215                            .filter_map(|diagnostic| {
4216                                GetDocumentDiagnostics::serialize_lsp_diagnostic(diagnostic)
4217                                    .context("serializing diagnostics")
4218                                    .log_err()
4219                            })
4220                            .collect(),
4221                        registration_id: registration_id.as_ref().map(ToString::to_string),
4222                    })
4223                }
4224            })
4225            .collect();
4226
4227        proto::GetDocumentDiagnosticsResponse { pulled_diagnostics }
4228    }
4229
4230    async fn response_from_proto(
4231        self,
4232        response: proto::GetDocumentDiagnosticsResponse,
4233        _: Entity<LspStore>,
4234        _: Entity<Buffer>,
4235        _: AsyncApp,
4236    ) -> Result<Self::Response> {
4237        Ok(Self::diagnostics_from_proto(response))
4238    }
4239
4240    fn buffer_id_from_proto(message: &proto::GetDocumentDiagnostics) -> Result<BufferId> {
4241        BufferId::new(message.buffer_id)
4242    }
4243}
4244
4245#[async_trait(?Send)]
4246impl LspCommand for GetDocumentColor {
4247    type Response = Vec<DocumentColor>;
4248    type LspRequest = lsp::request::DocumentColor;
4249    type ProtoRequest = proto::GetDocumentColor;
4250
4251    fn display_name(&self) -> &str {
4252        "Document color"
4253    }
4254
4255    fn check_capabilities(&self, server_capabilities: AdapterServerCapabilities) -> bool {
4256        server_capabilities
4257            .server_capabilities
4258            .color_provider
4259            .as_ref()
4260            .is_some_and(|capability| match capability {
4261                lsp::ColorProviderCapability::Simple(supported) => *supported,
4262                lsp::ColorProviderCapability::ColorProvider(..) => true,
4263                lsp::ColorProviderCapability::Options(..) => true,
4264            })
4265    }
4266
4267    fn to_lsp(
4268        &self,
4269        path: &Path,
4270        _: &Buffer,
4271        _: &Arc<LanguageServer>,
4272        _: &App,
4273    ) -> Result<lsp::DocumentColorParams> {
4274        Ok(lsp::DocumentColorParams {
4275            text_document: make_text_document_identifier(path)?,
4276            work_done_progress_params: Default::default(),
4277            partial_result_params: Default::default(),
4278        })
4279    }
4280
4281    async fn response_from_lsp(
4282        self,
4283        message: Vec<lsp::ColorInformation>,
4284        _: Entity<LspStore>,
4285        _: Entity<Buffer>,
4286        _: LanguageServerId,
4287        _: AsyncApp,
4288    ) -> Result<Self::Response> {
4289        Ok(message
4290            .into_iter()
4291            .map(|color| DocumentColor {
4292                lsp_range: color.range,
4293                color: color.color,
4294                resolved: false,
4295                color_presentations: Vec::new(),
4296            })
4297            .collect())
4298    }
4299
4300    fn to_proto(&self, project_id: u64, buffer: &Buffer) -> Self::ProtoRequest {
4301        proto::GetDocumentColor {
4302            project_id,
4303            buffer_id: buffer.remote_id().to_proto(),
4304            version: serialize_version(&buffer.version()),
4305        }
4306    }
4307
4308    async fn from_proto(
4309        _: Self::ProtoRequest,
4310        _: Entity<LspStore>,
4311        _: Entity<Buffer>,
4312        _: AsyncApp,
4313    ) -> Result<Self> {
4314        Ok(Self {})
4315    }
4316
4317    fn response_to_proto(
4318        response: Self::Response,
4319        _: &mut LspStore,
4320        _: PeerId,
4321        buffer_version: &clock::Global,
4322        _: &mut App,
4323    ) -> proto::GetDocumentColorResponse {
4324        proto::GetDocumentColorResponse {
4325            colors: response
4326                .into_iter()
4327                .map(|color| {
4328                    let start = point_from_lsp(color.lsp_range.start).0;
4329                    let end = point_from_lsp(color.lsp_range.end).0;
4330                    proto::ColorInformation {
4331                        red: color.color.red,
4332                        green: color.color.green,
4333                        blue: color.color.blue,
4334                        alpha: color.color.alpha,
4335                        lsp_range_start: Some(proto::PointUtf16 {
4336                            row: start.row,
4337                            column: start.column,
4338                        }),
4339                        lsp_range_end: Some(proto::PointUtf16 {
4340                            row: end.row,
4341                            column: end.column,
4342                        }),
4343                    }
4344                })
4345                .collect(),
4346            version: serialize_version(buffer_version),
4347        }
4348    }
4349
4350    async fn response_from_proto(
4351        self,
4352        message: proto::GetDocumentColorResponse,
4353        _: Entity<LspStore>,
4354        _: Entity<Buffer>,
4355        _: AsyncApp,
4356    ) -> Result<Self::Response> {
4357        Ok(message
4358            .colors
4359            .into_iter()
4360            .filter_map(|color| {
4361                let start = color.lsp_range_start?;
4362                let start = PointUtf16::new(start.row, start.column);
4363                let end = color.lsp_range_end?;
4364                let end = PointUtf16::new(end.row, end.column);
4365                Some(DocumentColor {
4366                    resolved: false,
4367                    color_presentations: Vec::new(),
4368                    lsp_range: lsp::Range {
4369                        start: point_to_lsp(start),
4370                        end: point_to_lsp(end),
4371                    },
4372                    color: lsp::Color {
4373                        red: color.red,
4374                        green: color.green,
4375                        blue: color.blue,
4376                        alpha: color.alpha,
4377                    },
4378                })
4379            })
4380            .collect())
4381    }
4382
4383    fn buffer_id_from_proto(message: &Self::ProtoRequest) -> Result<BufferId> {
4384        BufferId::new(message.buffer_id)
4385    }
4386}
4387
4388fn process_related_documents(
4389    diagnostics: &mut HashMap<lsp::Uri, LspPullDiagnostics>,
4390    server_id: LanguageServerId,
4391    documents: impl IntoIterator<Item = (lsp::Uri, lsp::DocumentDiagnosticReportKind)>,
4392    registration_id: Option<SharedString>,
4393) {
4394    for (url, report_kind) in documents {
4395        match report_kind {
4396            lsp::DocumentDiagnosticReportKind::Full(report) => process_full_diagnostics_report(
4397                diagnostics,
4398                server_id,
4399                url,
4400                report,
4401                registration_id.clone(),
4402            ),
4403            lsp::DocumentDiagnosticReportKind::Unchanged(report) => {
4404                process_unchanged_diagnostics_report(
4405                    diagnostics,
4406                    server_id,
4407                    url,
4408                    report,
4409                    registration_id.clone(),
4410                )
4411            }
4412        }
4413    }
4414}
4415
4416fn process_unchanged_diagnostics_report(
4417    diagnostics: &mut HashMap<lsp::Uri, LspPullDiagnostics>,
4418    server_id: LanguageServerId,
4419    uri: lsp::Uri,
4420    report: lsp::UnchangedDocumentDiagnosticReport,
4421    registration_id: Option<SharedString>,
4422) {
4423    let result_id = SharedString::new(report.result_id);
4424    match diagnostics.entry(uri.clone()) {
4425        hash_map::Entry::Occupied(mut o) => match o.get_mut() {
4426            LspPullDiagnostics::Default => {
4427                o.insert(LspPullDiagnostics::Response {
4428                    server_id,
4429                    uri,
4430                    diagnostics: PulledDiagnostics::Unchanged { result_id },
4431                    registration_id,
4432                });
4433            }
4434            LspPullDiagnostics::Response {
4435                server_id: existing_server_id,
4436                uri: existing_uri,
4437                diagnostics: existing_diagnostics,
4438                ..
4439            } => {
4440                if server_id != *existing_server_id || &uri != existing_uri {
4441                    debug_panic!(
4442                        "Unexpected state: file {uri} has two different sets of diagnostics reported"
4443                    );
4444                }
4445                match existing_diagnostics {
4446                    PulledDiagnostics::Unchanged { .. } => {
4447                        *existing_diagnostics = PulledDiagnostics::Unchanged { result_id };
4448                    }
4449                    PulledDiagnostics::Changed { .. } => {}
4450                }
4451            }
4452        },
4453        hash_map::Entry::Vacant(v) => {
4454            v.insert(LspPullDiagnostics::Response {
4455                server_id,
4456                uri,
4457                diagnostics: PulledDiagnostics::Unchanged { result_id },
4458                registration_id,
4459            });
4460        }
4461    }
4462}
4463
4464fn process_full_diagnostics_report(
4465    diagnostics: &mut HashMap<lsp::Uri, LspPullDiagnostics>,
4466    server_id: LanguageServerId,
4467    uri: lsp::Uri,
4468    report: lsp::FullDocumentDiagnosticReport,
4469    registration_id: Option<SharedString>,
4470) {
4471    let result_id = report.result_id.map(SharedString::new);
4472    match diagnostics.entry(uri.clone()) {
4473        hash_map::Entry::Occupied(mut o) => match o.get_mut() {
4474            LspPullDiagnostics::Default => {
4475                o.insert(LspPullDiagnostics::Response {
4476                    server_id,
4477                    uri,
4478                    diagnostics: PulledDiagnostics::Changed {
4479                        result_id,
4480                        diagnostics: report.items,
4481                    },
4482                    registration_id,
4483                });
4484            }
4485            LspPullDiagnostics::Response {
4486                server_id: existing_server_id,
4487                uri: existing_uri,
4488                diagnostics: existing_diagnostics,
4489                ..
4490            } => {
4491                if server_id != *existing_server_id || &uri != existing_uri {
4492                    debug_panic!(
4493                        "Unexpected state: file {uri} has two different sets of diagnostics reported"
4494                    );
4495                }
4496                match existing_diagnostics {
4497                    PulledDiagnostics::Unchanged { .. } => {
4498                        *existing_diagnostics = PulledDiagnostics::Changed {
4499                            result_id,
4500                            diagnostics: report.items,
4501                        };
4502                    }
4503                    PulledDiagnostics::Changed {
4504                        result_id: existing_result_id,
4505                        diagnostics: existing_diagnostics,
4506                    } => {
4507                        if result_id.is_some() {
4508                            *existing_result_id = result_id;
4509                        }
4510                        existing_diagnostics.extend(report.items);
4511                    }
4512                }
4513            }
4514        },
4515        hash_map::Entry::Vacant(v) => {
4516            v.insert(LspPullDiagnostics::Response {
4517                server_id,
4518                uri,
4519                diagnostics: PulledDiagnostics::Changed {
4520                    result_id,
4521                    diagnostics: report.items,
4522                },
4523                registration_id,
4524            });
4525        }
4526    }
4527}
4528
4529#[cfg(test)]
4530mod tests {
4531    use super::*;
4532    use lsp::{DiagnosticSeverity, DiagnosticTag};
4533    use serde_json::json;
4534
4535    #[test]
4536    fn test_serialize_lsp_diagnostic() {
4537        let lsp_diagnostic = lsp::Diagnostic {
4538            range: lsp::Range {
4539                start: lsp::Position::new(0, 1),
4540                end: lsp::Position::new(2, 3),
4541            },
4542            severity: Some(DiagnosticSeverity::ERROR),
4543            code: Some(lsp::NumberOrString::String("E001".to_string())),
4544            source: Some("test-source".to_string()),
4545            message: "Test error message".to_string(),
4546            related_information: None,
4547            tags: Some(vec![DiagnosticTag::DEPRECATED]),
4548            code_description: None,
4549            data: Some(json!({"detail": "test detail"})),
4550        };
4551
4552        let proto_diagnostic = GetDocumentDiagnostics::serialize_lsp_diagnostic(lsp_diagnostic)
4553            .expect("Failed to serialize diagnostic");
4554
4555        let start = proto_diagnostic.start.unwrap();
4556        let end = proto_diagnostic.end.unwrap();
4557        assert_eq!(start.row, 0);
4558        assert_eq!(start.column, 1);
4559        assert_eq!(end.row, 2);
4560        assert_eq!(end.column, 3);
4561        assert_eq!(
4562            proto_diagnostic.severity,
4563            proto::lsp_diagnostic::Severity::Error as i32
4564        );
4565        assert_eq!(proto_diagnostic.code, Some("E001".to_string()));
4566        assert_eq!(proto_diagnostic.source, Some("test-source".to_string()));
4567        assert_eq!(proto_diagnostic.message, "Test error message");
4568    }
4569
4570    #[test]
4571    fn test_deserialize_lsp_diagnostic() {
4572        let proto_diagnostic = proto::LspDiagnostic {
4573            start: Some(proto::PointUtf16 { row: 0, column: 1 }),
4574            end: Some(proto::PointUtf16 { row: 2, column: 3 }),
4575            severity: proto::lsp_diagnostic::Severity::Warning as i32,
4576            code: Some("ERR".to_string()),
4577            source: Some("Prism".to_string()),
4578            message: "assigned but unused variable - a".to_string(),
4579            related_information: vec![],
4580            tags: vec![],
4581            code_description: None,
4582            data: None,
4583        };
4584
4585        let lsp_diagnostic = GetDocumentDiagnostics::deserialize_lsp_diagnostic(proto_diagnostic)
4586            .expect("Failed to deserialize diagnostic");
4587
4588        assert_eq!(lsp_diagnostic.range.start.line, 0);
4589        assert_eq!(lsp_diagnostic.range.start.character, 1);
4590        assert_eq!(lsp_diagnostic.range.end.line, 2);
4591        assert_eq!(lsp_diagnostic.range.end.character, 3);
4592        assert_eq!(lsp_diagnostic.severity, Some(DiagnosticSeverity::WARNING));
4593        assert_eq!(
4594            lsp_diagnostic.code,
4595            Some(lsp::NumberOrString::String("ERR".to_string()))
4596        );
4597        assert_eq!(lsp_diagnostic.source, Some("Prism".to_string()));
4598        assert_eq!(lsp_diagnostic.message, "assigned but unused variable - a");
4599    }
4600
4601    #[test]
4602    fn test_related_information() {
4603        let related_info = lsp::DiagnosticRelatedInformation {
4604            location: lsp::Location {
4605                uri: lsp::Uri::from_str("file:///test.rs").unwrap(),
4606                range: lsp::Range {
4607                    start: lsp::Position::new(1, 1),
4608                    end: lsp::Position::new(1, 5),
4609                },
4610            },
4611            message: "Related info message".to_string(),
4612        };
4613
4614        let lsp_diagnostic = lsp::Diagnostic {
4615            range: lsp::Range {
4616                start: lsp::Position::new(0, 0),
4617                end: lsp::Position::new(0, 1),
4618            },
4619            severity: Some(DiagnosticSeverity::INFORMATION),
4620            code: None,
4621            source: Some("Prism".to_string()),
4622            message: "assigned but unused variable - a".to_string(),
4623            related_information: Some(vec![related_info]),
4624            tags: None,
4625            code_description: None,
4626            data: None,
4627        };
4628
4629        let proto_diagnostic = GetDocumentDiagnostics::serialize_lsp_diagnostic(lsp_diagnostic)
4630            .expect("Failed to serialize diagnostic");
4631
4632        assert_eq!(proto_diagnostic.related_information.len(), 1);
4633        let related = &proto_diagnostic.related_information[0];
4634        assert_eq!(related.location_url, Some("file:///test.rs".to_string()));
4635        assert_eq!(related.message, "Related info message");
4636    }
4637
4638    #[test]
4639    fn test_invalid_ranges() {
4640        let proto_diagnostic = proto::LspDiagnostic {
4641            start: None,
4642            end: Some(proto::PointUtf16 { row: 2, column: 3 }),
4643            severity: proto::lsp_diagnostic::Severity::Error as i32,
4644            code: None,
4645            source: None,
4646            message: "Test message".to_string(),
4647            related_information: vec![],
4648            tags: vec![],
4649            code_description: None,
4650            data: None,
4651        };
4652
4653        let result = GetDocumentDiagnostics::deserialize_lsp_diagnostic(proto_diagnostic);
4654        assert!(result.is_err());
4655    }
4656}