lsp_command.rs

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