lsp_command.rs

   1mod signature_help;
   2
   3use crate::{
   4    lsp_store::{LocalLspStore, LspStore},
   5    CodeAction, CoreCompletion, DocumentHighlight, Hover, HoverBlock, HoverBlockKind, InlayHint,
   6    InlayHintLabel, InlayHintLabelPart, InlayHintLabelPartTooltip, InlayHintTooltip, Location,
   7    LocationLink, MarkupContent, ProjectTransaction, ResolveState,
   8};
   9use anyhow::{anyhow, Context, Result};
  10use async_trait::async_trait;
  11use client::proto::{self, PeerId};
  12use clock::Global;
  13use collections::HashSet;
  14use futures::future;
  15use gpui::{AppContext, AsyncAppContext, Entity, Model};
  16use language::{
  17    language_settings::{language_settings, InlayHintKind, LanguageSettings},
  18    point_from_lsp, point_to_lsp,
  19    proto::{deserialize_anchor, deserialize_version, serialize_anchor, serialize_version},
  20    range_from_lsp, range_to_lsp, Anchor, Bias, Buffer, BufferSnapshot, CachedLspAdapter, CharKind,
  21    OffsetRangeExt, PointUtf16, ToOffset, ToPointUtf16, Transaction, Unclipped,
  22};
  23use lsp::{
  24    AdapterServerCapabilities, CodeActionKind, CodeActionOptions, CompletionContext,
  25    CompletionListItemDefaultsEditRange, CompletionTriggerKind, DocumentHighlightKind,
  26    LanguageServer, LanguageServerId, LinkedEditingRangeServerCapabilities, OneOf,
  27    ServerCapabilities,
  28};
  29use signature_help::{lsp_to_proto_signature, proto_to_lsp_signature};
  30use std::{cmp::Reverse, ops::Range, path::Path, sync::Arc};
  31use text::{BufferId, LineEnding};
  32
  33pub use signature_help::{
  34    SignatureHelp, SIGNATURE_HELP_HIGHLIGHT_CURRENT, SIGNATURE_HELP_HIGHLIGHT_OVERLOAD,
  35};
  36
  37pub fn lsp_formatting_options(settings: &LanguageSettings) -> lsp::FormattingOptions {
  38    lsp::FormattingOptions {
  39        tab_size: settings.tab_size.into(),
  40        insert_spaces: !settings.hard_tabs,
  41        trim_trailing_whitespace: Some(settings.remove_trailing_whitespace_on_save),
  42        trim_final_newlines: Some(settings.ensure_final_newline_on_save),
  43        insert_final_newline: Some(settings.ensure_final_newline_on_save),
  44        ..lsp::FormattingOptions::default()
  45    }
  46}
  47
  48#[async_trait(?Send)]
  49pub trait LspCommand: 'static + Sized + Send + std::fmt::Debug {
  50    type Response: 'static + Default + Send + std::fmt::Debug;
  51    type LspRequest: 'static + Send + lsp::request::Request;
  52    type ProtoRequest: 'static + Send + proto::RequestMessage;
  53
  54    fn check_capabilities(&self, _: AdapterServerCapabilities) -> bool {
  55        true
  56    }
  57
  58    fn status(&self) -> Option<String> {
  59        None
  60    }
  61
  62    fn to_lsp(
  63        &self,
  64        path: &Path,
  65        buffer: &Buffer,
  66        language_server: &Arc<LanguageServer>,
  67        cx: &AppContext,
  68    ) -> <Self::LspRequest as lsp::request::Request>::Params;
  69
  70    async fn response_from_lsp(
  71        self,
  72        message: <Self::LspRequest as lsp::request::Request>::Result,
  73        lsp_store: Model<LspStore>,
  74        buffer: Model<Buffer>,
  75        server_id: LanguageServerId,
  76        cx: AsyncAppContext,
  77    ) -> Result<Self::Response>;
  78
  79    fn to_proto(&self, project_id: u64, buffer: &Buffer) -> Self::ProtoRequest;
  80
  81    async fn from_proto(
  82        message: Self::ProtoRequest,
  83        lsp_store: Model<LspStore>,
  84        buffer: Model<Buffer>,
  85        cx: AsyncAppContext,
  86    ) -> Result<Self>;
  87
  88    fn response_to_proto(
  89        response: Self::Response,
  90        lsp_store: &mut LspStore,
  91        peer_id: PeerId,
  92        buffer_version: &clock::Global,
  93        cx: &mut AppContext,
  94    ) -> <Self::ProtoRequest as proto::RequestMessage>::Response;
  95
  96    async fn response_from_proto(
  97        self,
  98        message: <Self::ProtoRequest as proto::RequestMessage>::Response,
  99        lsp_store: Model<LspStore>,
 100        buffer: Model<Buffer>,
 101        cx: AsyncAppContext,
 102    ) -> Result<Self::Response>;
 103
 104    fn buffer_id_from_proto(message: &Self::ProtoRequest) -> Result<BufferId>;
 105}
 106
 107#[derive(Debug)]
 108pub(crate) struct PrepareRename {
 109    pub position: PointUtf16,
 110}
 111
 112#[derive(Debug)]
 113pub(crate) struct PerformRename {
 114    pub position: PointUtf16,
 115    pub new_name: String,
 116    pub push_to_history: bool,
 117}
 118
 119#[derive(Debug)]
 120pub struct GetDefinition {
 121    pub position: PointUtf16,
 122}
 123
 124#[derive(Debug)]
 125pub(crate) struct GetDeclaration {
 126    pub position: PointUtf16,
 127}
 128
 129#[derive(Debug)]
 130pub(crate) struct GetTypeDefinition {
 131    pub position: PointUtf16,
 132}
 133
 134#[derive(Debug)]
 135pub(crate) struct GetImplementation {
 136    pub position: PointUtf16,
 137}
 138#[derive(Debug)]
 139pub(crate) struct GetReferences {
 140    pub position: PointUtf16,
 141}
 142
 143#[derive(Debug)]
 144pub(crate) struct GetDocumentHighlights {
 145    pub position: PointUtf16,
 146}
 147
 148#[derive(Clone, Debug)]
 149pub(crate) struct GetSignatureHelp {
 150    pub position: PointUtf16,
 151}
 152
 153#[derive(Clone, Debug)]
 154pub(crate) struct GetHover {
 155    pub position: PointUtf16,
 156}
 157
 158#[derive(Debug)]
 159pub(crate) struct GetCompletions {
 160    pub position: PointUtf16,
 161    pub context: CompletionContext,
 162}
 163
 164#[derive(Clone, Debug)]
 165pub(crate) struct GetCodeActions {
 166    pub range: Range<Anchor>,
 167    pub kinds: Option<Vec<lsp::CodeActionKind>>,
 168}
 169#[derive(Debug)]
 170pub(crate) struct OnTypeFormatting {
 171    pub position: PointUtf16,
 172    pub trigger: String,
 173    pub options: lsp::FormattingOptions,
 174    pub push_to_history: bool,
 175}
 176#[derive(Debug)]
 177pub(crate) struct InlayHints {
 178    pub range: Range<Anchor>,
 179}
 180#[derive(Debug)]
 181pub(crate) struct LinkedEditingRange {
 182    pub position: Anchor,
 183}
 184
 185#[async_trait(?Send)]
 186impl LspCommand for PrepareRename {
 187    type Response = Option<Range<Anchor>>;
 188    type LspRequest = lsp::request::PrepareRenameRequest;
 189    type ProtoRequest = proto::PrepareRename;
 190
 191    fn check_capabilities(&self, capabilities: AdapterServerCapabilities) -> bool {
 192        if let Some(lsp::OneOf::Right(rename)) = &capabilities.server_capabilities.rename_provider {
 193            rename.prepare_provider == Some(true)
 194        } else {
 195            false
 196        }
 197    }
 198
 199    fn to_lsp(
 200        &self,
 201        path: &Path,
 202        _: &Buffer,
 203        _: &Arc<LanguageServer>,
 204        _: &AppContext,
 205    ) -> lsp::TextDocumentPositionParams {
 206        lsp::TextDocumentPositionParams {
 207            text_document: lsp::TextDocumentIdentifier {
 208                uri: lsp::Url::from_file_path(path).unwrap(),
 209            },
 210            position: point_to_lsp(self.position),
 211        }
 212    }
 213
 214    async fn response_from_lsp(
 215        self,
 216        message: Option<lsp::PrepareRenameResponse>,
 217        _: Model<LspStore>,
 218        buffer: Model<Buffer>,
 219        _: LanguageServerId,
 220        mut cx: AsyncAppContext,
 221    ) -> Result<Option<Range<Anchor>>> {
 222        buffer.update(&mut cx, |buffer, _| {
 223            if let Some(
 224                lsp::PrepareRenameResponse::Range(range)
 225                | lsp::PrepareRenameResponse::RangeWithPlaceholder { range, .. },
 226            ) = message
 227            {
 228                let Range { start, end } = range_from_lsp(range);
 229                if buffer.clip_point_utf16(start, Bias::Left) == start.0
 230                    && buffer.clip_point_utf16(end, Bias::Left) == end.0
 231                {
 232                    return Ok(Some(buffer.anchor_after(start)..buffer.anchor_before(end)));
 233                }
 234            }
 235            Ok(None)
 236        })?
 237    }
 238
 239    fn to_proto(&self, project_id: u64, buffer: &Buffer) -> proto::PrepareRename {
 240        proto::PrepareRename {
 241            project_id,
 242            buffer_id: buffer.remote_id().into(),
 243            position: Some(language::proto::serialize_anchor(
 244                &buffer.anchor_before(self.position),
 245            )),
 246            version: serialize_version(&buffer.version()),
 247        }
 248    }
 249
 250    async fn from_proto(
 251        message: proto::PrepareRename,
 252        _: Model<LspStore>,
 253        buffer: Model<Buffer>,
 254        mut cx: AsyncAppContext,
 255    ) -> Result<Self> {
 256        let position = message
 257            .position
 258            .and_then(deserialize_anchor)
 259            .ok_or_else(|| anyhow!("invalid position"))?;
 260        buffer
 261            .update(&mut cx, |buffer, _| {
 262                buffer.wait_for_version(deserialize_version(&message.version))
 263            })?
 264            .await?;
 265
 266        Ok(Self {
 267            position: buffer.update(&mut cx, |buffer, _| position.to_point_utf16(buffer))?,
 268        })
 269    }
 270
 271    fn response_to_proto(
 272        range: Option<Range<Anchor>>,
 273        _: &mut LspStore,
 274        _: PeerId,
 275        buffer_version: &clock::Global,
 276        _: &mut AppContext,
 277    ) -> proto::PrepareRenameResponse {
 278        proto::PrepareRenameResponse {
 279            can_rename: range.is_some(),
 280            start: range
 281                .as_ref()
 282                .map(|range| language::proto::serialize_anchor(&range.start)),
 283            end: range
 284                .as_ref()
 285                .map(|range| language::proto::serialize_anchor(&range.end)),
 286            version: serialize_version(buffer_version),
 287        }
 288    }
 289
 290    async fn response_from_proto(
 291        self,
 292        message: proto::PrepareRenameResponse,
 293        _: Model<LspStore>,
 294        buffer: Model<Buffer>,
 295        mut cx: AsyncAppContext,
 296    ) -> Result<Option<Range<Anchor>>> {
 297        if message.can_rename {
 298            buffer
 299                .update(&mut cx, |buffer, _| {
 300                    buffer.wait_for_version(deserialize_version(&message.version))
 301                })?
 302                .await?;
 303            let start = message.start.and_then(deserialize_anchor);
 304            let end = message.end.and_then(deserialize_anchor);
 305            Ok(start.zip(end).map(|(start, end)| start..end))
 306        } else {
 307            Ok(None)
 308        }
 309    }
 310
 311    fn buffer_id_from_proto(message: &proto::PrepareRename) -> Result<BufferId> {
 312        BufferId::new(message.buffer_id)
 313    }
 314}
 315
 316#[async_trait(?Send)]
 317impl LspCommand for PerformRename {
 318    type Response = ProjectTransaction;
 319    type LspRequest = lsp::request::Rename;
 320    type ProtoRequest = proto::PerformRename;
 321
 322    fn to_lsp(
 323        &self,
 324        path: &Path,
 325        _: &Buffer,
 326        _: &Arc<LanguageServer>,
 327        _: &AppContext,
 328    ) -> lsp::RenameParams {
 329        lsp::RenameParams {
 330            text_document_position: lsp::TextDocumentPositionParams {
 331                text_document: lsp::TextDocumentIdentifier {
 332                    uri: lsp::Url::from_file_path(path).unwrap(),
 333                },
 334                position: point_to_lsp(self.position),
 335            },
 336            new_name: self.new_name.clone(),
 337            work_done_progress_params: Default::default(),
 338        }
 339    }
 340
 341    async fn response_from_lsp(
 342        self,
 343        message: Option<lsp::WorkspaceEdit>,
 344        lsp_store: Model<LspStore>,
 345        buffer: Model<Buffer>,
 346        server_id: LanguageServerId,
 347        mut cx: AsyncAppContext,
 348    ) -> Result<ProjectTransaction> {
 349        if let Some(edit) = message {
 350            let (lsp_adapter, lsp_server) =
 351                language_server_for_buffer(&lsp_store, &buffer, server_id, &mut cx)?;
 352            LocalLspStore::deserialize_workspace_edit(
 353                lsp_store,
 354                edit,
 355                self.push_to_history,
 356                lsp_adapter,
 357                lsp_server,
 358                &mut cx,
 359            )
 360            .await
 361        } else {
 362            Ok(ProjectTransaction::default())
 363        }
 364    }
 365
 366    fn to_proto(&self, project_id: u64, buffer: &Buffer) -> proto::PerformRename {
 367        proto::PerformRename {
 368            project_id,
 369            buffer_id: buffer.remote_id().into(),
 370            position: Some(language::proto::serialize_anchor(
 371                &buffer.anchor_before(self.position),
 372            )),
 373            new_name: self.new_name.clone(),
 374            version: serialize_version(&buffer.version()),
 375        }
 376    }
 377
 378    async fn from_proto(
 379        message: proto::PerformRename,
 380        _: Model<LspStore>,
 381        buffer: Model<Buffer>,
 382        mut cx: AsyncAppContext,
 383    ) -> Result<Self> {
 384        let position = message
 385            .position
 386            .and_then(deserialize_anchor)
 387            .ok_or_else(|| anyhow!("invalid position"))?;
 388        buffer
 389            .update(&mut cx, |buffer, _| {
 390                buffer.wait_for_version(deserialize_version(&message.version))
 391            })?
 392            .await?;
 393        Ok(Self {
 394            position: buffer.update(&mut cx, |buffer, _| position.to_point_utf16(buffer))?,
 395            new_name: message.new_name,
 396            push_to_history: false,
 397        })
 398    }
 399
 400    fn response_to_proto(
 401        response: ProjectTransaction,
 402        lsp_store: &mut LspStore,
 403        peer_id: PeerId,
 404        _: &clock::Global,
 405        cx: &mut AppContext,
 406    ) -> proto::PerformRenameResponse {
 407        let transaction = lsp_store.buffer_store().update(cx, |buffer_store, cx| {
 408            buffer_store.serialize_project_transaction_for_peer(response, peer_id, cx)
 409        });
 410        proto::PerformRenameResponse {
 411            transaction: Some(transaction),
 412        }
 413    }
 414
 415    async fn response_from_proto(
 416        self,
 417        message: proto::PerformRenameResponse,
 418        lsp_store: Model<LspStore>,
 419        _: Model<Buffer>,
 420        mut cx: AsyncAppContext,
 421    ) -> Result<ProjectTransaction> {
 422        let message = message
 423            .transaction
 424            .ok_or_else(|| anyhow!("missing transaction"))?;
 425        lsp_store
 426            .update(&mut cx, |lsp_store, cx| {
 427                lsp_store.buffer_store().update(cx, |buffer_store, cx| {
 428                    buffer_store.deserialize_project_transaction(message, self.push_to_history, cx)
 429                })
 430            })?
 431            .await
 432    }
 433
 434    fn buffer_id_from_proto(message: &proto::PerformRename) -> Result<BufferId> {
 435        BufferId::new(message.buffer_id)
 436    }
 437}
 438
 439#[async_trait(?Send)]
 440impl LspCommand for GetDefinition {
 441    type Response = Vec<LocationLink>;
 442    type LspRequest = lsp::request::GotoDefinition;
 443    type ProtoRequest = proto::GetDefinition;
 444
 445    fn check_capabilities(&self, capabilities: AdapterServerCapabilities) -> bool {
 446        capabilities
 447            .server_capabilities
 448            .definition_provider
 449            .is_some()
 450    }
 451
 452    fn to_lsp(
 453        &self,
 454        path: &Path,
 455        _: &Buffer,
 456        _: &Arc<LanguageServer>,
 457        _: &AppContext,
 458    ) -> lsp::GotoDefinitionParams {
 459        lsp::GotoDefinitionParams {
 460            text_document_position_params: lsp::TextDocumentPositionParams {
 461                text_document: lsp::TextDocumentIdentifier {
 462                    uri: lsp::Url::from_file_path(path).unwrap(),
 463                },
 464                position: point_to_lsp(self.position),
 465            },
 466            work_done_progress_params: Default::default(),
 467            partial_result_params: Default::default(),
 468        }
 469    }
 470
 471    async fn response_from_lsp(
 472        self,
 473        message: Option<lsp::GotoDefinitionResponse>,
 474        lsp_store: Model<LspStore>,
 475        buffer: Model<Buffer>,
 476        server_id: LanguageServerId,
 477        cx: AsyncAppContext,
 478    ) -> Result<Vec<LocationLink>> {
 479        location_links_from_lsp(message, lsp_store, buffer, server_id, cx).await
 480    }
 481
 482    fn to_proto(&self, project_id: u64, buffer: &Buffer) -> proto::GetDefinition {
 483        proto::GetDefinition {
 484            project_id,
 485            buffer_id: buffer.remote_id().into(),
 486            position: Some(language::proto::serialize_anchor(
 487                &buffer.anchor_before(self.position),
 488            )),
 489            version: serialize_version(&buffer.version()),
 490        }
 491    }
 492
 493    async fn from_proto(
 494        message: proto::GetDefinition,
 495        _: Model<LspStore>,
 496        buffer: Model<Buffer>,
 497        mut cx: AsyncAppContext,
 498    ) -> Result<Self> {
 499        let position = message
 500            .position
 501            .and_then(deserialize_anchor)
 502            .ok_or_else(|| anyhow!("invalid position"))?;
 503        buffer
 504            .update(&mut cx, |buffer, _| {
 505                buffer.wait_for_version(deserialize_version(&message.version))
 506            })?
 507            .await?;
 508        Ok(Self {
 509            position: buffer.update(&mut cx, |buffer, _| position.to_point_utf16(buffer))?,
 510        })
 511    }
 512
 513    fn response_to_proto(
 514        response: Vec<LocationLink>,
 515        lsp_store: &mut LspStore,
 516        peer_id: PeerId,
 517        _: &clock::Global,
 518        cx: &mut AppContext,
 519    ) -> proto::GetDefinitionResponse {
 520        let links = location_links_to_proto(response, lsp_store, peer_id, cx);
 521        proto::GetDefinitionResponse { links }
 522    }
 523
 524    async fn response_from_proto(
 525        self,
 526        message: proto::GetDefinitionResponse,
 527        lsp_store: Model<LspStore>,
 528        _: Model<Buffer>,
 529        cx: AsyncAppContext,
 530    ) -> Result<Vec<LocationLink>> {
 531        location_links_from_proto(message.links, lsp_store, cx).await
 532    }
 533
 534    fn buffer_id_from_proto(message: &proto::GetDefinition) -> Result<BufferId> {
 535        BufferId::new(message.buffer_id)
 536    }
 537}
 538
 539#[async_trait(?Send)]
 540impl LspCommand for GetDeclaration {
 541    type Response = Vec<LocationLink>;
 542    type LspRequest = lsp::request::GotoDeclaration;
 543    type ProtoRequest = proto::GetDeclaration;
 544
 545    fn check_capabilities(&self, capabilities: AdapterServerCapabilities) -> bool {
 546        capabilities
 547            .server_capabilities
 548            .declaration_provider
 549            .is_some()
 550    }
 551
 552    fn to_lsp(
 553        &self,
 554        path: &Path,
 555        _: &Buffer,
 556        _: &Arc<LanguageServer>,
 557        _: &AppContext,
 558    ) -> lsp::GotoDeclarationParams {
 559        lsp::GotoDeclarationParams {
 560            text_document_position_params: lsp::TextDocumentPositionParams {
 561                text_document: lsp::TextDocumentIdentifier {
 562                    uri: lsp::Url::from_file_path(path).unwrap(),
 563                },
 564                position: point_to_lsp(self.position),
 565            },
 566            work_done_progress_params: Default::default(),
 567            partial_result_params: Default::default(),
 568        }
 569    }
 570
 571    async fn response_from_lsp(
 572        self,
 573        message: Option<lsp::GotoDeclarationResponse>,
 574        lsp_store: Model<LspStore>,
 575        buffer: Model<Buffer>,
 576        server_id: LanguageServerId,
 577        cx: AsyncAppContext,
 578    ) -> Result<Vec<LocationLink>> {
 579        location_links_from_lsp(message, lsp_store, buffer, server_id, cx).await
 580    }
 581
 582    fn to_proto(&self, project_id: u64, buffer: &Buffer) -> proto::GetDeclaration {
 583        proto::GetDeclaration {
 584            project_id,
 585            buffer_id: buffer.remote_id().into(),
 586            position: Some(language::proto::serialize_anchor(
 587                &buffer.anchor_before(self.position),
 588            )),
 589            version: serialize_version(&buffer.version()),
 590        }
 591    }
 592
 593    async fn from_proto(
 594        message: proto::GetDeclaration,
 595        _: Model<LspStore>,
 596        buffer: Model<Buffer>,
 597        mut cx: AsyncAppContext,
 598    ) -> Result<Self> {
 599        let position = message
 600            .position
 601            .and_then(deserialize_anchor)
 602            .ok_or_else(|| anyhow!("invalid position"))?;
 603        buffer
 604            .update(&mut cx, |buffer, _| {
 605                buffer.wait_for_version(deserialize_version(&message.version))
 606            })?
 607            .await?;
 608        Ok(Self {
 609            position: buffer.update(&mut cx, |buffer, _| position.to_point_utf16(buffer))?,
 610        })
 611    }
 612
 613    fn response_to_proto(
 614        response: Vec<LocationLink>,
 615        lsp_store: &mut LspStore,
 616        peer_id: PeerId,
 617        _: &clock::Global,
 618        cx: &mut AppContext,
 619    ) -> proto::GetDeclarationResponse {
 620        let links = location_links_to_proto(response, lsp_store, peer_id, cx);
 621        proto::GetDeclarationResponse { links }
 622    }
 623
 624    async fn response_from_proto(
 625        self,
 626        message: proto::GetDeclarationResponse,
 627        lsp_store: Model<LspStore>,
 628        _: Model<Buffer>,
 629        cx: AsyncAppContext,
 630    ) -> Result<Vec<LocationLink>> {
 631        location_links_from_proto(message.links, lsp_store, cx).await
 632    }
 633
 634    fn buffer_id_from_proto(message: &proto::GetDeclaration) -> Result<BufferId> {
 635        BufferId::new(message.buffer_id)
 636    }
 637}
 638
 639#[async_trait(?Send)]
 640impl LspCommand for GetImplementation {
 641    type Response = Vec<LocationLink>;
 642    type LspRequest = lsp::request::GotoImplementation;
 643    type ProtoRequest = proto::GetImplementation;
 644
 645    fn to_lsp(
 646        &self,
 647        path: &Path,
 648        _: &Buffer,
 649        _: &Arc<LanguageServer>,
 650        _: &AppContext,
 651    ) -> lsp::GotoImplementationParams {
 652        lsp::GotoImplementationParams {
 653            text_document_position_params: lsp::TextDocumentPositionParams {
 654                text_document: lsp::TextDocumentIdentifier {
 655                    uri: lsp::Url::from_file_path(path).unwrap(),
 656                },
 657                position: point_to_lsp(self.position),
 658            },
 659            work_done_progress_params: Default::default(),
 660            partial_result_params: Default::default(),
 661        }
 662    }
 663
 664    async fn response_from_lsp(
 665        self,
 666        message: Option<lsp::GotoImplementationResponse>,
 667        lsp_store: Model<LspStore>,
 668        buffer: Model<Buffer>,
 669        server_id: LanguageServerId,
 670        cx: AsyncAppContext,
 671    ) -> Result<Vec<LocationLink>> {
 672        location_links_from_lsp(message, lsp_store, buffer, server_id, cx).await
 673    }
 674
 675    fn to_proto(&self, project_id: u64, buffer: &Buffer) -> proto::GetImplementation {
 676        proto::GetImplementation {
 677            project_id,
 678            buffer_id: buffer.remote_id().into(),
 679            position: Some(language::proto::serialize_anchor(
 680                &buffer.anchor_before(self.position),
 681            )),
 682            version: serialize_version(&buffer.version()),
 683        }
 684    }
 685
 686    async fn from_proto(
 687        message: proto::GetImplementation,
 688        _: Model<LspStore>,
 689        buffer: Model<Buffer>,
 690        mut cx: AsyncAppContext,
 691    ) -> Result<Self> {
 692        let position = message
 693            .position
 694            .and_then(deserialize_anchor)
 695            .ok_or_else(|| anyhow!("invalid position"))?;
 696        buffer
 697            .update(&mut cx, |buffer, _| {
 698                buffer.wait_for_version(deserialize_version(&message.version))
 699            })?
 700            .await?;
 701        Ok(Self {
 702            position: buffer.update(&mut cx, |buffer, _| position.to_point_utf16(buffer))?,
 703        })
 704    }
 705
 706    fn response_to_proto(
 707        response: Vec<LocationLink>,
 708        lsp_store: &mut LspStore,
 709        peer_id: PeerId,
 710        _: &clock::Global,
 711        cx: &mut AppContext,
 712    ) -> proto::GetImplementationResponse {
 713        let links = location_links_to_proto(response, lsp_store, peer_id, cx);
 714        proto::GetImplementationResponse { links }
 715    }
 716
 717    async fn response_from_proto(
 718        self,
 719        message: proto::GetImplementationResponse,
 720        project: Model<LspStore>,
 721        _: Model<Buffer>,
 722        cx: AsyncAppContext,
 723    ) -> Result<Vec<LocationLink>> {
 724        location_links_from_proto(message.links, project, cx).await
 725    }
 726
 727    fn buffer_id_from_proto(message: &proto::GetImplementation) -> Result<BufferId> {
 728        BufferId::new(message.buffer_id)
 729    }
 730}
 731
 732#[async_trait(?Send)]
 733impl LspCommand for GetTypeDefinition {
 734    type Response = Vec<LocationLink>;
 735    type LspRequest = lsp::request::GotoTypeDefinition;
 736    type ProtoRequest = proto::GetTypeDefinition;
 737
 738    fn check_capabilities(&self, capabilities: AdapterServerCapabilities) -> bool {
 739        !matches!(
 740            &capabilities.server_capabilities.type_definition_provider,
 741            None | Some(lsp::TypeDefinitionProviderCapability::Simple(false))
 742        )
 743    }
 744
 745    fn to_lsp(
 746        &self,
 747        path: &Path,
 748        _: &Buffer,
 749        _: &Arc<LanguageServer>,
 750        _: &AppContext,
 751    ) -> lsp::GotoTypeDefinitionParams {
 752        lsp::GotoTypeDefinitionParams {
 753            text_document_position_params: lsp::TextDocumentPositionParams {
 754                text_document: lsp::TextDocumentIdentifier {
 755                    uri: lsp::Url::from_file_path(path).unwrap(),
 756                },
 757                position: point_to_lsp(self.position),
 758            },
 759            work_done_progress_params: Default::default(),
 760            partial_result_params: Default::default(),
 761        }
 762    }
 763
 764    async fn response_from_lsp(
 765        self,
 766        message: Option<lsp::GotoTypeDefinitionResponse>,
 767        project: Model<LspStore>,
 768        buffer: Model<Buffer>,
 769        server_id: LanguageServerId,
 770        cx: AsyncAppContext,
 771    ) -> Result<Vec<LocationLink>> {
 772        location_links_from_lsp(message, project, buffer, server_id, cx).await
 773    }
 774
 775    fn to_proto(&self, project_id: u64, buffer: &Buffer) -> proto::GetTypeDefinition {
 776        proto::GetTypeDefinition {
 777            project_id,
 778            buffer_id: buffer.remote_id().into(),
 779            position: Some(language::proto::serialize_anchor(
 780                &buffer.anchor_before(self.position),
 781            )),
 782            version: serialize_version(&buffer.version()),
 783        }
 784    }
 785
 786    async fn from_proto(
 787        message: proto::GetTypeDefinition,
 788        _: Model<LspStore>,
 789        buffer: Model<Buffer>,
 790        mut cx: AsyncAppContext,
 791    ) -> Result<Self> {
 792        let position = message
 793            .position
 794            .and_then(deserialize_anchor)
 795            .ok_or_else(|| anyhow!("invalid position"))?;
 796        buffer
 797            .update(&mut cx, |buffer, _| {
 798                buffer.wait_for_version(deserialize_version(&message.version))
 799            })?
 800            .await?;
 801        Ok(Self {
 802            position: buffer.update(&mut cx, |buffer, _| position.to_point_utf16(buffer))?,
 803        })
 804    }
 805
 806    fn response_to_proto(
 807        response: Vec<LocationLink>,
 808        lsp_store: &mut LspStore,
 809        peer_id: PeerId,
 810        _: &clock::Global,
 811        cx: &mut AppContext,
 812    ) -> proto::GetTypeDefinitionResponse {
 813        let links = location_links_to_proto(response, lsp_store, peer_id, cx);
 814        proto::GetTypeDefinitionResponse { links }
 815    }
 816
 817    async fn response_from_proto(
 818        self,
 819        message: proto::GetTypeDefinitionResponse,
 820        project: Model<LspStore>,
 821        _: Model<Buffer>,
 822        cx: AsyncAppContext,
 823    ) -> Result<Vec<LocationLink>> {
 824        location_links_from_proto(message.links, project, cx).await
 825    }
 826
 827    fn buffer_id_from_proto(message: &proto::GetTypeDefinition) -> Result<BufferId> {
 828        BufferId::new(message.buffer_id)
 829    }
 830}
 831
 832fn language_server_for_buffer(
 833    lsp_store: &Model<LspStore>,
 834    buffer: &Model<Buffer>,
 835    server_id: LanguageServerId,
 836    cx: &mut AsyncAppContext,
 837) -> Result<(Arc<CachedLspAdapter>, Arc<LanguageServer>)> {
 838    lsp_store
 839        .update(cx, |lsp_store, cx| {
 840            lsp_store
 841                .language_server_for_local_buffer(buffer.read(cx), server_id, cx)
 842                .map(|(adapter, server)| (adapter.clone(), server.clone()))
 843        })?
 844        .ok_or_else(|| anyhow!("no language server found for buffer"))
 845}
 846
 847async fn location_links_from_proto(
 848    proto_links: Vec<proto::LocationLink>,
 849    lsp_store: Model<LspStore>,
 850    mut cx: AsyncAppContext,
 851) -> Result<Vec<LocationLink>> {
 852    let mut links = Vec::new();
 853
 854    for link in proto_links {
 855        let origin = match link.origin {
 856            Some(origin) => {
 857                let buffer_id = BufferId::new(origin.buffer_id)?;
 858                let buffer = lsp_store
 859                    .update(&mut cx, |lsp_store, cx| {
 860                        lsp_store.wait_for_remote_buffer(buffer_id, cx)
 861                    })?
 862                    .await?;
 863                let start = origin
 864                    .start
 865                    .and_then(deserialize_anchor)
 866                    .ok_or_else(|| anyhow!("missing origin start"))?;
 867                let end = origin
 868                    .end
 869                    .and_then(deserialize_anchor)
 870                    .ok_or_else(|| anyhow!("missing origin end"))?;
 871                buffer
 872                    .update(&mut cx, |buffer, _| buffer.wait_for_anchors([start, end]))?
 873                    .await?;
 874                Some(Location {
 875                    buffer,
 876                    range: start..end,
 877                })
 878            }
 879            None => None,
 880        };
 881
 882        let target = link.target.ok_or_else(|| anyhow!("missing target"))?;
 883        let buffer_id = BufferId::new(target.buffer_id)?;
 884        let buffer = lsp_store
 885            .update(&mut cx, |lsp_store, cx| {
 886                lsp_store.wait_for_remote_buffer(buffer_id, cx)
 887            })?
 888            .await?;
 889        let start = target
 890            .start
 891            .and_then(deserialize_anchor)
 892            .ok_or_else(|| anyhow!("missing target start"))?;
 893        let end = target
 894            .end
 895            .and_then(deserialize_anchor)
 896            .ok_or_else(|| anyhow!("missing target end"))?;
 897        buffer
 898            .update(&mut cx, |buffer, _| buffer.wait_for_anchors([start, end]))?
 899            .await?;
 900        let target = Location {
 901            buffer,
 902            range: start..end,
 903        };
 904
 905        links.push(LocationLink { origin, target })
 906    }
 907
 908    Ok(links)
 909}
 910
 911async fn location_links_from_lsp(
 912    message: Option<lsp::GotoDefinitionResponse>,
 913    lsp_store: Model<LspStore>,
 914    buffer: Model<Buffer>,
 915    server_id: LanguageServerId,
 916    mut cx: AsyncAppContext,
 917) -> Result<Vec<LocationLink>> {
 918    let message = match message {
 919        Some(message) => message,
 920        None => return Ok(Vec::new()),
 921    };
 922
 923    let mut unresolved_links = Vec::new();
 924    match message {
 925        lsp::GotoDefinitionResponse::Scalar(loc) => {
 926            unresolved_links.push((None, loc.uri, loc.range));
 927        }
 928
 929        lsp::GotoDefinitionResponse::Array(locs) => {
 930            unresolved_links.extend(locs.into_iter().map(|l| (None, l.uri, l.range)));
 931        }
 932
 933        lsp::GotoDefinitionResponse::Link(links) => {
 934            unresolved_links.extend(links.into_iter().map(|l| {
 935                (
 936                    l.origin_selection_range,
 937                    l.target_uri,
 938                    l.target_selection_range,
 939                )
 940            }));
 941        }
 942    }
 943
 944    let (lsp_adapter, language_server) =
 945        language_server_for_buffer(&lsp_store, &buffer, server_id, &mut cx)?;
 946    let mut definitions = Vec::new();
 947    for (origin_range, target_uri, target_range) in unresolved_links {
 948        let target_buffer_handle = lsp_store
 949            .update(&mut cx, |this, cx| {
 950                this.open_local_buffer_via_lsp(
 951                    target_uri,
 952                    language_server.server_id(),
 953                    lsp_adapter.name.clone(),
 954                    cx,
 955                )
 956            })?
 957            .await?;
 958
 959        cx.update(|cx| {
 960            let origin_location = origin_range.map(|origin_range| {
 961                let origin_buffer = buffer.read(cx);
 962                let origin_start =
 963                    origin_buffer.clip_point_utf16(point_from_lsp(origin_range.start), Bias::Left);
 964                let origin_end =
 965                    origin_buffer.clip_point_utf16(point_from_lsp(origin_range.end), Bias::Left);
 966                Location {
 967                    buffer: buffer.clone(),
 968                    range: origin_buffer.anchor_after(origin_start)
 969                        ..origin_buffer.anchor_before(origin_end),
 970                }
 971            });
 972
 973            let target_buffer = target_buffer_handle.read(cx);
 974            let target_start =
 975                target_buffer.clip_point_utf16(point_from_lsp(target_range.start), Bias::Left);
 976            let target_end =
 977                target_buffer.clip_point_utf16(point_from_lsp(target_range.end), Bias::Left);
 978            let target_location = Location {
 979                buffer: target_buffer_handle,
 980                range: target_buffer.anchor_after(target_start)
 981                    ..target_buffer.anchor_before(target_end),
 982            };
 983
 984            definitions.push(LocationLink {
 985                origin: origin_location,
 986                target: target_location,
 987            })
 988        })?;
 989    }
 990    Ok(definitions)
 991}
 992
 993fn location_links_to_proto(
 994    links: Vec<LocationLink>,
 995    lsp_store: &mut LspStore,
 996    peer_id: PeerId,
 997    cx: &mut AppContext,
 998) -> Vec<proto::LocationLink> {
 999    links
1000        .into_iter()
1001        .map(|definition| {
1002            let origin = definition.origin.map(|origin| {
1003                lsp_store
1004                    .buffer_store()
1005                    .update(cx, |buffer_store, cx| {
1006                        buffer_store.create_buffer_for_peer(&origin.buffer, peer_id, cx)
1007                    })
1008                    .detach_and_log_err(cx);
1009
1010                let buffer_id = origin.buffer.read(cx).remote_id().into();
1011                proto::Location {
1012                    start: Some(serialize_anchor(&origin.range.start)),
1013                    end: Some(serialize_anchor(&origin.range.end)),
1014                    buffer_id,
1015                }
1016            });
1017
1018            lsp_store
1019                .buffer_store()
1020                .update(cx, |buffer_store, cx| {
1021                    buffer_store.create_buffer_for_peer(&definition.target.buffer, peer_id, cx)
1022                })
1023                .detach_and_log_err(cx);
1024
1025            let buffer_id = definition.target.buffer.read(cx).remote_id().into();
1026            let target = proto::Location {
1027                start: Some(serialize_anchor(&definition.target.range.start)),
1028                end: Some(serialize_anchor(&definition.target.range.end)),
1029                buffer_id,
1030            };
1031
1032            proto::LocationLink {
1033                origin,
1034                target: Some(target),
1035            }
1036        })
1037        .collect()
1038}
1039
1040#[async_trait(?Send)]
1041impl LspCommand for GetReferences {
1042    type Response = Vec<Location>;
1043    type LspRequest = lsp::request::References;
1044    type ProtoRequest = proto::GetReferences;
1045
1046    fn status(&self) -> Option<String> {
1047        Some("Finding references...".to_owned())
1048    }
1049
1050    fn check_capabilities(&self, capabilities: AdapterServerCapabilities) -> bool {
1051        match &capabilities.server_capabilities.references_provider {
1052            Some(OneOf::Left(has_support)) => *has_support,
1053            Some(OneOf::Right(_)) => true,
1054            None => false,
1055        }
1056    }
1057
1058    fn to_lsp(
1059        &self,
1060        path: &Path,
1061        _: &Buffer,
1062        _: &Arc<LanguageServer>,
1063        _: &AppContext,
1064    ) -> lsp::ReferenceParams {
1065        lsp::ReferenceParams {
1066            text_document_position: lsp::TextDocumentPositionParams {
1067                text_document: lsp::TextDocumentIdentifier {
1068                    uri: lsp::Url::from_file_path(path).unwrap(),
1069                },
1070                position: point_to_lsp(self.position),
1071            },
1072            work_done_progress_params: Default::default(),
1073            partial_result_params: Default::default(),
1074            context: lsp::ReferenceContext {
1075                include_declaration: true,
1076            },
1077        }
1078    }
1079
1080    async fn response_from_lsp(
1081        self,
1082        locations: Option<Vec<lsp::Location>>,
1083        lsp_store: Model<LspStore>,
1084        buffer: Model<Buffer>,
1085        server_id: LanguageServerId,
1086        mut cx: AsyncAppContext,
1087    ) -> Result<Vec<Location>> {
1088        let mut references = Vec::new();
1089        let (lsp_adapter, language_server) =
1090            language_server_for_buffer(&lsp_store, &buffer, server_id, &mut cx)?;
1091
1092        if let Some(locations) = locations {
1093            for lsp_location in locations {
1094                let target_buffer_handle = lsp_store
1095                    .update(&mut cx, |lsp_store, cx| {
1096                        lsp_store.open_local_buffer_via_lsp(
1097                            lsp_location.uri,
1098                            language_server.server_id(),
1099                            lsp_adapter.name.clone(),
1100                            cx,
1101                        )
1102                    })?
1103                    .await?;
1104
1105                target_buffer_handle
1106                    .clone()
1107                    .update(&mut cx, |target_buffer, _| {
1108                        let target_start = target_buffer
1109                            .clip_point_utf16(point_from_lsp(lsp_location.range.start), Bias::Left);
1110                        let target_end = target_buffer
1111                            .clip_point_utf16(point_from_lsp(lsp_location.range.end), Bias::Left);
1112                        references.push(Location {
1113                            buffer: target_buffer_handle,
1114                            range: target_buffer.anchor_after(target_start)
1115                                ..target_buffer.anchor_before(target_end),
1116                        });
1117                    })?;
1118            }
1119        }
1120
1121        Ok(references)
1122    }
1123
1124    fn to_proto(&self, project_id: u64, buffer: &Buffer) -> proto::GetReferences {
1125        proto::GetReferences {
1126            project_id,
1127            buffer_id: buffer.remote_id().into(),
1128            position: Some(language::proto::serialize_anchor(
1129                &buffer.anchor_before(self.position),
1130            )),
1131            version: serialize_version(&buffer.version()),
1132        }
1133    }
1134
1135    async fn from_proto(
1136        message: proto::GetReferences,
1137        _: Model<LspStore>,
1138        buffer: Model<Buffer>,
1139        mut cx: AsyncAppContext,
1140    ) -> Result<Self> {
1141        let position = message
1142            .position
1143            .and_then(deserialize_anchor)
1144            .ok_or_else(|| anyhow!("invalid position"))?;
1145        buffer
1146            .update(&mut cx, |buffer, _| {
1147                buffer.wait_for_version(deserialize_version(&message.version))
1148            })?
1149            .await?;
1150        Ok(Self {
1151            position: buffer.update(&mut cx, |buffer, _| position.to_point_utf16(buffer))?,
1152        })
1153    }
1154
1155    fn response_to_proto(
1156        response: Vec<Location>,
1157        lsp_store: &mut LspStore,
1158        peer_id: PeerId,
1159        _: &clock::Global,
1160        cx: &mut AppContext,
1161    ) -> proto::GetReferencesResponse {
1162        let locations = response
1163            .into_iter()
1164            .map(|definition| {
1165                lsp_store
1166                    .buffer_store()
1167                    .update(cx, |buffer_store, cx| {
1168                        buffer_store.create_buffer_for_peer(&definition.buffer, peer_id, cx)
1169                    })
1170                    .detach_and_log_err(cx);
1171                let buffer_id = definition.buffer.read(cx).remote_id();
1172                proto::Location {
1173                    start: Some(serialize_anchor(&definition.range.start)),
1174                    end: Some(serialize_anchor(&definition.range.end)),
1175                    buffer_id: buffer_id.into(),
1176                }
1177            })
1178            .collect();
1179        proto::GetReferencesResponse { locations }
1180    }
1181
1182    async fn response_from_proto(
1183        self,
1184        message: proto::GetReferencesResponse,
1185        project: Model<LspStore>,
1186        _: Model<Buffer>,
1187        mut cx: AsyncAppContext,
1188    ) -> Result<Vec<Location>> {
1189        let mut locations = Vec::new();
1190        for location in message.locations {
1191            let buffer_id = BufferId::new(location.buffer_id)?;
1192            let target_buffer = project
1193                .update(&mut cx, |this, cx| {
1194                    this.wait_for_remote_buffer(buffer_id, cx)
1195                })?
1196                .await?;
1197            let start = location
1198                .start
1199                .and_then(deserialize_anchor)
1200                .ok_or_else(|| anyhow!("missing target start"))?;
1201            let end = location
1202                .end
1203                .and_then(deserialize_anchor)
1204                .ok_or_else(|| anyhow!("missing target end"))?;
1205            target_buffer
1206                .update(&mut cx, |buffer, _| buffer.wait_for_anchors([start, end]))?
1207                .await?;
1208            locations.push(Location {
1209                buffer: target_buffer,
1210                range: start..end,
1211            })
1212        }
1213        Ok(locations)
1214    }
1215
1216    fn buffer_id_from_proto(message: &proto::GetReferences) -> Result<BufferId> {
1217        BufferId::new(message.buffer_id)
1218    }
1219}
1220
1221#[async_trait(?Send)]
1222impl LspCommand for GetDocumentHighlights {
1223    type Response = Vec<DocumentHighlight>;
1224    type LspRequest = lsp::request::DocumentHighlightRequest;
1225    type ProtoRequest = proto::GetDocumentHighlights;
1226
1227    fn check_capabilities(&self, capabilities: AdapterServerCapabilities) -> bool {
1228        capabilities
1229            .server_capabilities
1230            .document_highlight_provider
1231            .is_some()
1232    }
1233
1234    fn to_lsp(
1235        &self,
1236        path: &Path,
1237        _: &Buffer,
1238        _: &Arc<LanguageServer>,
1239        _: &AppContext,
1240    ) -> lsp::DocumentHighlightParams {
1241        lsp::DocumentHighlightParams {
1242            text_document_position_params: lsp::TextDocumentPositionParams {
1243                text_document: lsp::TextDocumentIdentifier {
1244                    uri: lsp::Url::from_file_path(path).unwrap(),
1245                },
1246                position: point_to_lsp(self.position),
1247            },
1248            work_done_progress_params: Default::default(),
1249            partial_result_params: Default::default(),
1250        }
1251    }
1252
1253    async fn response_from_lsp(
1254        self,
1255        lsp_highlights: Option<Vec<lsp::DocumentHighlight>>,
1256        _: Model<LspStore>,
1257        buffer: Model<Buffer>,
1258        _: LanguageServerId,
1259        mut cx: AsyncAppContext,
1260    ) -> Result<Vec<DocumentHighlight>> {
1261        buffer.update(&mut cx, |buffer, _| {
1262            let mut lsp_highlights = lsp_highlights.unwrap_or_default();
1263            lsp_highlights.sort_unstable_by_key(|h| (h.range.start, Reverse(h.range.end)));
1264            lsp_highlights
1265                .into_iter()
1266                .map(|lsp_highlight| {
1267                    let start = buffer
1268                        .clip_point_utf16(point_from_lsp(lsp_highlight.range.start), Bias::Left);
1269                    let end = buffer
1270                        .clip_point_utf16(point_from_lsp(lsp_highlight.range.end), Bias::Left);
1271                    DocumentHighlight {
1272                        range: buffer.anchor_after(start)..buffer.anchor_before(end),
1273                        kind: lsp_highlight
1274                            .kind
1275                            .unwrap_or(lsp::DocumentHighlightKind::READ),
1276                    }
1277                })
1278                .collect()
1279        })
1280    }
1281
1282    fn to_proto(&self, project_id: u64, buffer: &Buffer) -> proto::GetDocumentHighlights {
1283        proto::GetDocumentHighlights {
1284            project_id,
1285            buffer_id: buffer.remote_id().into(),
1286            position: Some(language::proto::serialize_anchor(
1287                &buffer.anchor_before(self.position),
1288            )),
1289            version: serialize_version(&buffer.version()),
1290        }
1291    }
1292
1293    async fn from_proto(
1294        message: proto::GetDocumentHighlights,
1295        _: Model<LspStore>,
1296        buffer: Model<Buffer>,
1297        mut cx: AsyncAppContext,
1298    ) -> Result<Self> {
1299        let position = message
1300            .position
1301            .and_then(deserialize_anchor)
1302            .ok_or_else(|| anyhow!("invalid position"))?;
1303        buffer
1304            .update(&mut cx, |buffer, _| {
1305                buffer.wait_for_version(deserialize_version(&message.version))
1306            })?
1307            .await?;
1308        Ok(Self {
1309            position: buffer.update(&mut cx, |buffer, _| position.to_point_utf16(buffer))?,
1310        })
1311    }
1312
1313    fn response_to_proto(
1314        response: Vec<DocumentHighlight>,
1315        _: &mut LspStore,
1316        _: PeerId,
1317        _: &clock::Global,
1318        _: &mut AppContext,
1319    ) -> proto::GetDocumentHighlightsResponse {
1320        let highlights = response
1321            .into_iter()
1322            .map(|highlight| proto::DocumentHighlight {
1323                start: Some(serialize_anchor(&highlight.range.start)),
1324                end: Some(serialize_anchor(&highlight.range.end)),
1325                kind: match highlight.kind {
1326                    DocumentHighlightKind::TEXT => proto::document_highlight::Kind::Text.into(),
1327                    DocumentHighlightKind::WRITE => proto::document_highlight::Kind::Write.into(),
1328                    DocumentHighlightKind::READ => proto::document_highlight::Kind::Read.into(),
1329                    _ => proto::document_highlight::Kind::Text.into(),
1330                },
1331            })
1332            .collect();
1333        proto::GetDocumentHighlightsResponse { highlights }
1334    }
1335
1336    async fn response_from_proto(
1337        self,
1338        message: proto::GetDocumentHighlightsResponse,
1339        _: Model<LspStore>,
1340        buffer: Model<Buffer>,
1341        mut cx: AsyncAppContext,
1342    ) -> Result<Vec<DocumentHighlight>> {
1343        let mut highlights = Vec::new();
1344        for highlight in message.highlights {
1345            let start = highlight
1346                .start
1347                .and_then(deserialize_anchor)
1348                .ok_or_else(|| anyhow!("missing target start"))?;
1349            let end = highlight
1350                .end
1351                .and_then(deserialize_anchor)
1352                .ok_or_else(|| anyhow!("missing target end"))?;
1353            buffer
1354                .update(&mut cx, |buffer, _| buffer.wait_for_anchors([start, end]))?
1355                .await?;
1356            let kind = match proto::document_highlight::Kind::from_i32(highlight.kind) {
1357                Some(proto::document_highlight::Kind::Text) => DocumentHighlightKind::TEXT,
1358                Some(proto::document_highlight::Kind::Read) => DocumentHighlightKind::READ,
1359                Some(proto::document_highlight::Kind::Write) => DocumentHighlightKind::WRITE,
1360                None => DocumentHighlightKind::TEXT,
1361            };
1362            highlights.push(DocumentHighlight {
1363                range: start..end,
1364                kind,
1365            });
1366        }
1367        Ok(highlights)
1368    }
1369
1370    fn buffer_id_from_proto(message: &proto::GetDocumentHighlights) -> Result<BufferId> {
1371        BufferId::new(message.buffer_id)
1372    }
1373}
1374
1375#[async_trait(?Send)]
1376impl LspCommand for GetSignatureHelp {
1377    type Response = Option<SignatureHelp>;
1378    type LspRequest = lsp::SignatureHelpRequest;
1379    type ProtoRequest = proto::GetSignatureHelp;
1380
1381    fn check_capabilities(&self, capabilities: AdapterServerCapabilities) -> bool {
1382        capabilities
1383            .server_capabilities
1384            .signature_help_provider
1385            .is_some()
1386    }
1387
1388    fn to_lsp(
1389        &self,
1390        path: &Path,
1391        _: &Buffer,
1392        _: &Arc<LanguageServer>,
1393        _cx: &AppContext,
1394    ) -> lsp::SignatureHelpParams {
1395        let url_result = lsp::Url::from_file_path(path);
1396        if url_result.is_err() {
1397            log::error!("an invalid file path has been specified");
1398        }
1399
1400        lsp::SignatureHelpParams {
1401            text_document_position_params: lsp::TextDocumentPositionParams {
1402                text_document: lsp::TextDocumentIdentifier {
1403                    uri: url_result.expect("invalid file path"),
1404                },
1405                position: point_to_lsp(self.position),
1406            },
1407            context: None,
1408            work_done_progress_params: Default::default(),
1409        }
1410    }
1411
1412    async fn response_from_lsp(
1413        self,
1414        message: Option<lsp::SignatureHelp>,
1415        _: Model<LspStore>,
1416        buffer: Model<Buffer>,
1417        _: LanguageServerId,
1418        mut cx: AsyncAppContext,
1419    ) -> Result<Self::Response> {
1420        let language = buffer.update(&mut cx, |buffer, _| buffer.language().cloned())?;
1421        Ok(message.and_then(|message| SignatureHelp::new(message, language)))
1422    }
1423
1424    fn to_proto(&self, project_id: u64, buffer: &Buffer) -> Self::ProtoRequest {
1425        let offset = buffer.point_utf16_to_offset(self.position);
1426        proto::GetSignatureHelp {
1427            project_id,
1428            buffer_id: buffer.remote_id().to_proto(),
1429            position: Some(serialize_anchor(&buffer.anchor_after(offset))),
1430            version: serialize_version(&buffer.version()),
1431        }
1432    }
1433
1434    async fn from_proto(
1435        payload: Self::ProtoRequest,
1436        _: Model<LspStore>,
1437        buffer: Model<Buffer>,
1438        mut cx: AsyncAppContext,
1439    ) -> Result<Self> {
1440        buffer
1441            .update(&mut cx, |buffer, _| {
1442                buffer.wait_for_version(deserialize_version(&payload.version))
1443            })?
1444            .await
1445            .with_context(|| format!("waiting for version for buffer {}", buffer.entity_id()))?;
1446        let buffer_snapshot = buffer.update(&mut cx, |buffer, _| buffer.snapshot())?;
1447        Ok(Self {
1448            position: payload
1449                .position
1450                .and_then(deserialize_anchor)
1451                .context("invalid position")?
1452                .to_point_utf16(&buffer_snapshot),
1453        })
1454    }
1455
1456    fn response_to_proto(
1457        response: Self::Response,
1458        _: &mut LspStore,
1459        _: PeerId,
1460        _: &Global,
1461        _: &mut AppContext,
1462    ) -> proto::GetSignatureHelpResponse {
1463        proto::GetSignatureHelpResponse {
1464            signature_help: response
1465                .map(|signature_help| lsp_to_proto_signature(signature_help.original_data)),
1466        }
1467    }
1468
1469    async fn response_from_proto(
1470        self,
1471        response: proto::GetSignatureHelpResponse,
1472        _: Model<LspStore>,
1473        buffer: Model<Buffer>,
1474        mut cx: AsyncAppContext,
1475    ) -> Result<Self::Response> {
1476        let language = buffer.update(&mut cx, |buffer, _| buffer.language().cloned())?;
1477        Ok(response
1478            .signature_help
1479            .map(proto_to_lsp_signature)
1480            .and_then(|lsp_help| SignatureHelp::new(lsp_help, language)))
1481    }
1482
1483    fn buffer_id_from_proto(message: &Self::ProtoRequest) -> Result<BufferId> {
1484        BufferId::new(message.buffer_id)
1485    }
1486}
1487
1488#[async_trait(?Send)]
1489impl LspCommand for GetHover {
1490    type Response = Option<Hover>;
1491    type LspRequest = lsp::request::HoverRequest;
1492    type ProtoRequest = proto::GetHover;
1493
1494    fn check_capabilities(&self, capabilities: AdapterServerCapabilities) -> bool {
1495        match capabilities.server_capabilities.hover_provider {
1496            Some(lsp::HoverProviderCapability::Simple(enabled)) => enabled,
1497            Some(lsp::HoverProviderCapability::Options(_)) => true,
1498            None => false,
1499        }
1500    }
1501
1502    fn to_lsp(
1503        &self,
1504        path: &Path,
1505        _: &Buffer,
1506        _: &Arc<LanguageServer>,
1507        _: &AppContext,
1508    ) -> lsp::HoverParams {
1509        lsp::HoverParams {
1510            text_document_position_params: lsp::TextDocumentPositionParams {
1511                text_document: lsp::TextDocumentIdentifier {
1512                    uri: lsp::Url::from_file_path(path).unwrap(),
1513                },
1514                position: point_to_lsp(self.position),
1515            },
1516            work_done_progress_params: Default::default(),
1517        }
1518    }
1519
1520    async fn response_from_lsp(
1521        self,
1522        message: Option<lsp::Hover>,
1523        _: Model<LspStore>,
1524        buffer: Model<Buffer>,
1525        _: LanguageServerId,
1526        mut cx: AsyncAppContext,
1527    ) -> Result<Self::Response> {
1528        let Some(hover) = message else {
1529            return Ok(None);
1530        };
1531
1532        let (language, range) = buffer.update(&mut cx, |buffer, _| {
1533            (
1534                buffer.language().cloned(),
1535                hover.range.map(|range| {
1536                    let token_start =
1537                        buffer.clip_point_utf16(point_from_lsp(range.start), Bias::Left);
1538                    let token_end = buffer.clip_point_utf16(point_from_lsp(range.end), Bias::Left);
1539                    buffer.anchor_after(token_start)..buffer.anchor_before(token_end)
1540                }),
1541            )
1542        })?;
1543
1544        fn hover_blocks_from_marked_string(marked_string: lsp::MarkedString) -> Option<HoverBlock> {
1545            let block = match marked_string {
1546                lsp::MarkedString::String(content) => HoverBlock {
1547                    text: content,
1548                    kind: HoverBlockKind::Markdown,
1549                },
1550                lsp::MarkedString::LanguageString(lsp::LanguageString { language, value }) => {
1551                    HoverBlock {
1552                        text: value,
1553                        kind: HoverBlockKind::Code { language },
1554                    }
1555                }
1556            };
1557            if block.text.is_empty() {
1558                None
1559            } else {
1560                Some(block)
1561            }
1562        }
1563
1564        let contents = match hover.contents {
1565            lsp::HoverContents::Scalar(marked_string) => {
1566                hover_blocks_from_marked_string(marked_string)
1567                    .into_iter()
1568                    .collect()
1569            }
1570            lsp::HoverContents::Array(marked_strings) => marked_strings
1571                .into_iter()
1572                .filter_map(hover_blocks_from_marked_string)
1573                .collect(),
1574            lsp::HoverContents::Markup(markup_content) => vec![HoverBlock {
1575                text: markup_content.value,
1576                kind: if markup_content.kind == lsp::MarkupKind::Markdown {
1577                    HoverBlockKind::Markdown
1578                } else {
1579                    HoverBlockKind::PlainText
1580                },
1581            }],
1582        };
1583
1584        Ok(Some(Hover {
1585            contents,
1586            range,
1587            language,
1588        }))
1589    }
1590
1591    fn to_proto(&self, project_id: u64, buffer: &Buffer) -> Self::ProtoRequest {
1592        proto::GetHover {
1593            project_id,
1594            buffer_id: buffer.remote_id().into(),
1595            position: Some(language::proto::serialize_anchor(
1596                &buffer.anchor_before(self.position),
1597            )),
1598            version: serialize_version(&buffer.version),
1599        }
1600    }
1601
1602    async fn from_proto(
1603        message: Self::ProtoRequest,
1604        _: Model<LspStore>,
1605        buffer: Model<Buffer>,
1606        mut cx: AsyncAppContext,
1607    ) -> Result<Self> {
1608        let position = message
1609            .position
1610            .and_then(deserialize_anchor)
1611            .ok_or_else(|| anyhow!("invalid position"))?;
1612        buffer
1613            .update(&mut cx, |buffer, _| {
1614                buffer.wait_for_version(deserialize_version(&message.version))
1615            })?
1616            .await?;
1617        Ok(Self {
1618            position: buffer.update(&mut cx, |buffer, _| position.to_point_utf16(buffer))?,
1619        })
1620    }
1621
1622    fn response_to_proto(
1623        response: Self::Response,
1624        _: &mut LspStore,
1625        _: PeerId,
1626        _: &clock::Global,
1627        _: &mut AppContext,
1628    ) -> proto::GetHoverResponse {
1629        if let Some(response) = response {
1630            let (start, end) = if let Some(range) = response.range {
1631                (
1632                    Some(language::proto::serialize_anchor(&range.start)),
1633                    Some(language::proto::serialize_anchor(&range.end)),
1634                )
1635            } else {
1636                (None, None)
1637            };
1638
1639            let contents = response
1640                .contents
1641                .into_iter()
1642                .map(|block| proto::HoverBlock {
1643                    text: block.text,
1644                    is_markdown: block.kind == HoverBlockKind::Markdown,
1645                    language: if let HoverBlockKind::Code { language } = block.kind {
1646                        Some(language)
1647                    } else {
1648                        None
1649                    },
1650                })
1651                .collect();
1652
1653            proto::GetHoverResponse {
1654                start,
1655                end,
1656                contents,
1657            }
1658        } else {
1659            proto::GetHoverResponse {
1660                start: None,
1661                end: None,
1662                contents: Vec::new(),
1663            }
1664        }
1665    }
1666
1667    async fn response_from_proto(
1668        self,
1669        message: proto::GetHoverResponse,
1670        _: Model<LspStore>,
1671        buffer: Model<Buffer>,
1672        mut cx: AsyncAppContext,
1673    ) -> Result<Self::Response> {
1674        let contents: Vec<_> = message
1675            .contents
1676            .into_iter()
1677            .map(|block| HoverBlock {
1678                text: block.text,
1679                kind: if let Some(language) = block.language {
1680                    HoverBlockKind::Code { language }
1681                } else if block.is_markdown {
1682                    HoverBlockKind::Markdown
1683                } else {
1684                    HoverBlockKind::PlainText
1685                },
1686            })
1687            .collect();
1688        if contents.is_empty() {
1689            return Ok(None);
1690        }
1691
1692        let language = buffer.update(&mut cx, |buffer, _| buffer.language().cloned())?;
1693        let range = if let (Some(start), Some(end)) = (message.start, message.end) {
1694            language::proto::deserialize_anchor(start)
1695                .and_then(|start| language::proto::deserialize_anchor(end).map(|end| start..end))
1696        } else {
1697            None
1698        };
1699        if let Some(range) = range.as_ref() {
1700            buffer
1701                .update(&mut cx, |buffer, _| {
1702                    buffer.wait_for_anchors([range.start, range.end])
1703                })?
1704                .await?;
1705        }
1706
1707        Ok(Some(Hover {
1708            contents,
1709            range,
1710            language,
1711        }))
1712    }
1713
1714    fn buffer_id_from_proto(message: &Self::ProtoRequest) -> Result<BufferId> {
1715        BufferId::new(message.buffer_id)
1716    }
1717}
1718
1719#[async_trait(?Send)]
1720impl LspCommand for GetCompletions {
1721    type Response = Vec<CoreCompletion>;
1722    type LspRequest = lsp::request::Completion;
1723    type ProtoRequest = proto::GetCompletions;
1724
1725    fn to_lsp(
1726        &self,
1727        path: &Path,
1728        _: &Buffer,
1729        _: &Arc<LanguageServer>,
1730        _: &AppContext,
1731    ) -> lsp::CompletionParams {
1732        lsp::CompletionParams {
1733            text_document_position: lsp::TextDocumentPositionParams::new(
1734                lsp::TextDocumentIdentifier::new(lsp::Url::from_file_path(path).unwrap()),
1735                point_to_lsp(self.position),
1736            ),
1737            context: Some(self.context.clone()),
1738            work_done_progress_params: Default::default(),
1739            partial_result_params: Default::default(),
1740        }
1741    }
1742
1743    async fn response_from_lsp(
1744        self,
1745        completions: Option<lsp::CompletionResponse>,
1746        lsp_store: Model<LspStore>,
1747        buffer: Model<Buffer>,
1748        server_id: LanguageServerId,
1749        mut cx: AsyncAppContext,
1750    ) -> Result<Self::Response> {
1751        let mut response_list = None;
1752        let mut completions = if let Some(completions) = completions {
1753            match completions {
1754                lsp::CompletionResponse::Array(completions) => completions,
1755
1756                lsp::CompletionResponse::List(mut list) => {
1757                    let items = std::mem::take(&mut list.items);
1758                    response_list = Some(list);
1759                    items
1760                }
1761            }
1762        } else {
1763            Default::default()
1764        };
1765
1766        let language_server_adapter = lsp_store
1767            .update(&mut cx, |lsp_store, _| {
1768                lsp_store.language_server_adapter_for_id(server_id)
1769            })?
1770            .ok_or_else(|| anyhow!("no such language server"))?;
1771
1772        let item_defaults = response_list
1773            .as_ref()
1774            .and_then(|list| list.item_defaults.as_ref());
1775
1776        if let Some(item_defaults) = item_defaults {
1777            let default_data = item_defaults.data.as_ref();
1778            let default_commit_characters = item_defaults.commit_characters.as_ref();
1779            let default_edit_range = item_defaults.edit_range.as_ref();
1780            let default_insert_text_format = item_defaults.insert_text_format.as_ref();
1781            let default_insert_text_mode = item_defaults.insert_text_mode.as_ref();
1782
1783            if default_data.is_some()
1784                || default_commit_characters.is_some()
1785                || default_edit_range.is_some()
1786                || default_insert_text_format.is_some()
1787                || default_insert_text_mode.is_some()
1788            {
1789                for item in completions.iter_mut() {
1790                    if item.data.is_none() && default_data.is_some() {
1791                        item.data = default_data.cloned()
1792                    }
1793                    if item.commit_characters.is_none() && default_commit_characters.is_some() {
1794                        item.commit_characters = default_commit_characters.cloned()
1795                    }
1796                    if item.text_edit.is_none() {
1797                        if let Some(default_edit_range) = default_edit_range {
1798                            match default_edit_range {
1799                                CompletionListItemDefaultsEditRange::Range(range) => {
1800                                    item.text_edit =
1801                                        Some(lsp::CompletionTextEdit::Edit(lsp::TextEdit {
1802                                            range: *range,
1803                                            new_text: item.label.clone(),
1804                                        }))
1805                                }
1806                                CompletionListItemDefaultsEditRange::InsertAndReplace {
1807                                    insert,
1808                                    replace,
1809                                } => {
1810                                    item.text_edit =
1811                                        Some(lsp::CompletionTextEdit::InsertAndReplace(
1812                                            lsp::InsertReplaceEdit {
1813                                                new_text: item.label.clone(),
1814                                                insert: *insert,
1815                                                replace: *replace,
1816                                            },
1817                                        ))
1818                                }
1819                            }
1820                        }
1821                    }
1822                    if item.insert_text_format.is_none() && default_insert_text_format.is_some() {
1823                        item.insert_text_format = default_insert_text_format.cloned()
1824                    }
1825                    if item.insert_text_mode.is_none() && default_insert_text_mode.is_some() {
1826                        item.insert_text_mode = default_insert_text_mode.cloned()
1827                    }
1828                }
1829            }
1830        }
1831
1832        let mut completion_edits = Vec::new();
1833        buffer.update(&mut cx, |buffer, _cx| {
1834            let snapshot = buffer.snapshot();
1835            let clipped_position = buffer.clip_point_utf16(Unclipped(self.position), Bias::Left);
1836
1837            let mut range_for_token = None;
1838            completions.retain_mut(|lsp_completion| {
1839                let edit = match lsp_completion.text_edit.as_ref() {
1840                    // If the language server provides a range to overwrite, then
1841                    // check that the range is valid.
1842                    Some(completion_text_edit) => {
1843                        match parse_completion_text_edit(completion_text_edit, &snapshot) {
1844                            Some(edit) => edit,
1845                            None => return false,
1846                        }
1847                    }
1848
1849                    // If the language server does not provide a range, then infer
1850                    // the range based on the syntax tree.
1851                    None => {
1852                        if self.position != clipped_position {
1853                            log::info!("completion out of expected range");
1854                            return false;
1855                        }
1856
1857                        let default_edit_range = response_list
1858                            .as_ref()
1859                            .and_then(|list| list.item_defaults.as_ref())
1860                            .and_then(|defaults| defaults.edit_range.as_ref())
1861                            .and_then(|range| match range {
1862                                CompletionListItemDefaultsEditRange::Range(r) => Some(r),
1863                                _ => None,
1864                            });
1865
1866                        let range = if let Some(range) = default_edit_range {
1867                            let range = range_from_lsp(*range);
1868                            let start = snapshot.clip_point_utf16(range.start, Bias::Left);
1869                            let end = snapshot.clip_point_utf16(range.end, Bias::Left);
1870                            if start != range.start.0 || end != range.end.0 {
1871                                log::info!("completion out of expected range");
1872                                return false;
1873                            }
1874
1875                            snapshot.anchor_before(start)..snapshot.anchor_after(end)
1876                        } else {
1877                            range_for_token
1878                                .get_or_insert_with(|| {
1879                                    let offset = self.position.to_offset(&snapshot);
1880                                    let (range, kind) = snapshot.surrounding_word(offset);
1881                                    let range = if kind == Some(CharKind::Word) {
1882                                        range
1883                                    } else {
1884                                        offset..offset
1885                                    };
1886
1887                                    snapshot.anchor_before(range.start)
1888                                        ..snapshot.anchor_after(range.end)
1889                                })
1890                                .clone()
1891                        };
1892
1893                        let text = lsp_completion
1894                            .insert_text
1895                            .as_ref()
1896                            .unwrap_or(&lsp_completion.label)
1897                            .clone();
1898                        (range, text)
1899                    }
1900                };
1901
1902                completion_edits.push(edit);
1903                true
1904            });
1905        })?;
1906
1907        language_server_adapter
1908            .process_completions(&mut completions)
1909            .await;
1910
1911        Ok(completions
1912            .into_iter()
1913            .zip(completion_edits)
1914            .map(|(lsp_completion, (old_range, mut new_text))| {
1915                LineEnding::normalize(&mut new_text);
1916                CoreCompletion {
1917                    old_range,
1918                    new_text,
1919                    server_id,
1920                    lsp_completion,
1921                    resolved: false,
1922                }
1923            })
1924            .collect())
1925    }
1926
1927    fn to_proto(&self, project_id: u64, buffer: &Buffer) -> proto::GetCompletions {
1928        let anchor = buffer.anchor_after(self.position);
1929        proto::GetCompletions {
1930            project_id,
1931            buffer_id: buffer.remote_id().into(),
1932            position: Some(language::proto::serialize_anchor(&anchor)),
1933            version: serialize_version(&buffer.version()),
1934        }
1935    }
1936
1937    async fn from_proto(
1938        message: proto::GetCompletions,
1939        _: Model<LspStore>,
1940        buffer: Model<Buffer>,
1941        mut cx: AsyncAppContext,
1942    ) -> Result<Self> {
1943        let version = deserialize_version(&message.version);
1944        buffer
1945            .update(&mut cx, |buffer, _| buffer.wait_for_version(version))?
1946            .await?;
1947        let position = message
1948            .position
1949            .and_then(language::proto::deserialize_anchor)
1950            .map(|p| {
1951                buffer.update(&mut cx, |buffer, _| {
1952                    buffer.clip_point_utf16(Unclipped(p.to_point_utf16(buffer)), Bias::Left)
1953                })
1954            })
1955            .ok_or_else(|| anyhow!("invalid position"))??;
1956        Ok(Self {
1957            position,
1958            context: CompletionContext {
1959                trigger_kind: CompletionTriggerKind::INVOKED,
1960                trigger_character: None,
1961            },
1962        })
1963    }
1964
1965    fn response_to_proto(
1966        completions: Vec<CoreCompletion>,
1967        _: &mut LspStore,
1968        _: PeerId,
1969        buffer_version: &clock::Global,
1970        _: &mut AppContext,
1971    ) -> proto::GetCompletionsResponse {
1972        proto::GetCompletionsResponse {
1973            completions: completions
1974                .iter()
1975                .map(LspStore::serialize_completion)
1976                .collect(),
1977            version: serialize_version(buffer_version),
1978        }
1979    }
1980
1981    async fn response_from_proto(
1982        self,
1983        message: proto::GetCompletionsResponse,
1984        _project: Model<LspStore>,
1985        buffer: Model<Buffer>,
1986        mut cx: AsyncAppContext,
1987    ) -> Result<Self::Response> {
1988        buffer
1989            .update(&mut cx, |buffer, _| {
1990                buffer.wait_for_version(deserialize_version(&message.version))
1991            })?
1992            .await?;
1993
1994        message
1995            .completions
1996            .into_iter()
1997            .map(LspStore::deserialize_completion)
1998            .collect()
1999    }
2000
2001    fn buffer_id_from_proto(message: &proto::GetCompletions) -> Result<BufferId> {
2002        BufferId::new(message.buffer_id)
2003    }
2004}
2005
2006pub(crate) fn parse_completion_text_edit(
2007    edit: &lsp::CompletionTextEdit,
2008    snapshot: &BufferSnapshot,
2009) -> Option<(Range<Anchor>, String)> {
2010    match edit {
2011        lsp::CompletionTextEdit::Edit(edit) => {
2012            let range = range_from_lsp(edit.range);
2013            let start = snapshot.clip_point_utf16(range.start, Bias::Left);
2014            let end = snapshot.clip_point_utf16(range.end, Bias::Left);
2015            if start != range.start.0 || end != range.end.0 {
2016                log::info!("completion out of expected range");
2017                None
2018            } else {
2019                Some((
2020                    snapshot.anchor_before(start)..snapshot.anchor_after(end),
2021                    edit.new_text.clone(),
2022                ))
2023            }
2024        }
2025
2026        lsp::CompletionTextEdit::InsertAndReplace(edit) => {
2027            let range = range_from_lsp(edit.insert);
2028
2029            let start = snapshot.clip_point_utf16(range.start, Bias::Left);
2030            let end = snapshot.clip_point_utf16(range.end, Bias::Left);
2031            if start != range.start.0 || end != range.end.0 {
2032                log::info!("completion out of expected range");
2033                None
2034            } else {
2035                Some((
2036                    snapshot.anchor_before(start)..snapshot.anchor_after(end),
2037                    edit.new_text.clone(),
2038                ))
2039            }
2040        }
2041    }
2042}
2043
2044#[async_trait(?Send)]
2045impl LspCommand for GetCodeActions {
2046    type Response = Vec<CodeAction>;
2047    type LspRequest = lsp::request::CodeActionRequest;
2048    type ProtoRequest = proto::GetCodeActions;
2049
2050    fn check_capabilities(&self, capabilities: AdapterServerCapabilities) -> bool {
2051        match &capabilities.server_capabilities.code_action_provider {
2052            None => false,
2053            Some(lsp::CodeActionProviderCapability::Simple(false)) => false,
2054            _ => {
2055                // If we do know that we want specific code actions AND we know that
2056                // the server only supports specific code actions, then we want to filter
2057                // down to the ones that are supported.
2058                if let Some((requested, supported)) = self
2059                    .kinds
2060                    .as_ref()
2061                    .zip(Self::supported_code_action_kinds(capabilities))
2062                {
2063                    let server_supported = supported.into_iter().collect::<HashSet<_>>();
2064                    requested.iter().any(|kind| server_supported.contains(kind))
2065                } else {
2066                    true
2067                }
2068            }
2069        }
2070    }
2071
2072    fn to_lsp(
2073        &self,
2074        path: &Path,
2075        buffer: &Buffer,
2076        language_server: &Arc<LanguageServer>,
2077        _: &AppContext,
2078    ) -> lsp::CodeActionParams {
2079        let relevant_diagnostics = buffer
2080            .snapshot()
2081            .diagnostics_in_range::<_, language::PointUtf16>(self.range.clone(), false)
2082            .map(|entry| entry.to_lsp_diagnostic_stub())
2083            .collect::<Vec<_>>();
2084
2085        let supported =
2086            Self::supported_code_action_kinds(language_server.adapter_server_capabilities());
2087
2088        let only = if let Some(requested) = &self.kinds {
2089            if let Some(supported_kinds) = supported {
2090                let server_supported = supported_kinds.into_iter().collect::<HashSet<_>>();
2091
2092                let filtered = requested
2093                    .iter()
2094                    .filter(|kind| server_supported.contains(kind))
2095                    .cloned()
2096                    .collect();
2097                Some(filtered)
2098            } else {
2099                Some(requested.clone())
2100            }
2101        } else {
2102            supported
2103        };
2104
2105        lsp::CodeActionParams {
2106            text_document: lsp::TextDocumentIdentifier::new(
2107                lsp::Url::from_file_path(path).unwrap(),
2108            ),
2109            range: range_to_lsp(self.range.to_point_utf16(buffer)),
2110            work_done_progress_params: Default::default(),
2111            partial_result_params: Default::default(),
2112            context: lsp::CodeActionContext {
2113                diagnostics: relevant_diagnostics,
2114                only,
2115                ..lsp::CodeActionContext::default()
2116            },
2117        }
2118    }
2119
2120    async fn response_from_lsp(
2121        self,
2122        actions: Option<lsp::CodeActionResponse>,
2123        _: Model<LspStore>,
2124        _: Model<Buffer>,
2125        server_id: LanguageServerId,
2126        _: AsyncAppContext,
2127    ) -> Result<Vec<CodeAction>> {
2128        let requested_kinds_set = if let Some(kinds) = self.kinds {
2129            Some(kinds.into_iter().collect::<HashSet<_>>())
2130        } else {
2131            None
2132        };
2133
2134        Ok(actions
2135            .unwrap_or_default()
2136            .into_iter()
2137            .filter_map(|entry| {
2138                let lsp::CodeActionOrCommand::CodeAction(lsp_action) = entry else {
2139                    return None;
2140                };
2141
2142                if let Some((requested_kinds, kind)) =
2143                    requested_kinds_set.as_ref().zip(lsp_action.kind.as_ref())
2144                {
2145                    if !requested_kinds.contains(kind) {
2146                        return None;
2147                    }
2148                }
2149
2150                Some(CodeAction {
2151                    server_id,
2152                    range: self.range.clone(),
2153                    lsp_action,
2154                })
2155            })
2156            .collect())
2157    }
2158
2159    fn to_proto(&self, project_id: u64, buffer: &Buffer) -> proto::GetCodeActions {
2160        proto::GetCodeActions {
2161            project_id,
2162            buffer_id: buffer.remote_id().into(),
2163            start: Some(language::proto::serialize_anchor(&self.range.start)),
2164            end: Some(language::proto::serialize_anchor(&self.range.end)),
2165            version: serialize_version(&buffer.version()),
2166        }
2167    }
2168
2169    async fn from_proto(
2170        message: proto::GetCodeActions,
2171        _: Model<LspStore>,
2172        buffer: Model<Buffer>,
2173        mut cx: AsyncAppContext,
2174    ) -> Result<Self> {
2175        let start = message
2176            .start
2177            .and_then(language::proto::deserialize_anchor)
2178            .ok_or_else(|| anyhow!("invalid start"))?;
2179        let end = message
2180            .end
2181            .and_then(language::proto::deserialize_anchor)
2182            .ok_or_else(|| anyhow!("invalid end"))?;
2183        buffer
2184            .update(&mut cx, |buffer, _| {
2185                buffer.wait_for_version(deserialize_version(&message.version))
2186            })?
2187            .await?;
2188
2189        Ok(Self {
2190            range: start..end,
2191            kinds: None,
2192        })
2193    }
2194
2195    fn response_to_proto(
2196        code_actions: Vec<CodeAction>,
2197        _: &mut LspStore,
2198        _: PeerId,
2199        buffer_version: &clock::Global,
2200        _: &mut AppContext,
2201    ) -> proto::GetCodeActionsResponse {
2202        proto::GetCodeActionsResponse {
2203            actions: code_actions
2204                .iter()
2205                .map(LspStore::serialize_code_action)
2206                .collect(),
2207            version: serialize_version(buffer_version),
2208        }
2209    }
2210
2211    async fn response_from_proto(
2212        self,
2213        message: proto::GetCodeActionsResponse,
2214        _: Model<LspStore>,
2215        buffer: Model<Buffer>,
2216        mut cx: AsyncAppContext,
2217    ) -> Result<Vec<CodeAction>> {
2218        buffer
2219            .update(&mut cx, |buffer, _| {
2220                buffer.wait_for_version(deserialize_version(&message.version))
2221            })?
2222            .await?;
2223        message
2224            .actions
2225            .into_iter()
2226            .map(LspStore::deserialize_code_action)
2227            .collect()
2228    }
2229
2230    fn buffer_id_from_proto(message: &proto::GetCodeActions) -> Result<BufferId> {
2231        BufferId::new(message.buffer_id)
2232    }
2233}
2234
2235impl GetCodeActions {
2236    fn supported_code_action_kinds(
2237        capabilities: AdapterServerCapabilities,
2238    ) -> Option<Vec<CodeActionKind>> {
2239        match capabilities.server_capabilities.code_action_provider {
2240            Some(lsp::CodeActionProviderCapability::Options(CodeActionOptions {
2241                code_action_kinds: Some(supported_action_kinds),
2242                ..
2243            })) => Some(supported_action_kinds.clone()),
2244            _ => capabilities.code_action_kinds,
2245        }
2246    }
2247
2248    pub fn can_resolve_actions(capabilities: &ServerCapabilities) -> bool {
2249        capabilities
2250            .code_action_provider
2251            .as_ref()
2252            .and_then(|options| match options {
2253                lsp::CodeActionProviderCapability::Simple(_is_supported) => None,
2254                lsp::CodeActionProviderCapability::Options(options) => options.resolve_provider,
2255            })
2256            .unwrap_or(false)
2257    }
2258}
2259
2260#[async_trait(?Send)]
2261impl LspCommand for OnTypeFormatting {
2262    type Response = Option<Transaction>;
2263    type LspRequest = lsp::request::OnTypeFormatting;
2264    type ProtoRequest = proto::OnTypeFormatting;
2265
2266    fn check_capabilities(&self, capabilities: AdapterServerCapabilities) -> bool {
2267        let Some(on_type_formatting_options) = &capabilities
2268            .server_capabilities
2269            .document_on_type_formatting_provider
2270        else {
2271            return false;
2272        };
2273        on_type_formatting_options
2274            .first_trigger_character
2275            .contains(&self.trigger)
2276            || on_type_formatting_options
2277                .more_trigger_character
2278                .iter()
2279                .flatten()
2280                .any(|chars| chars.contains(&self.trigger))
2281    }
2282
2283    fn to_lsp(
2284        &self,
2285        path: &Path,
2286        _: &Buffer,
2287        _: &Arc<LanguageServer>,
2288        _: &AppContext,
2289    ) -> lsp::DocumentOnTypeFormattingParams {
2290        lsp::DocumentOnTypeFormattingParams {
2291            text_document_position: lsp::TextDocumentPositionParams::new(
2292                lsp::TextDocumentIdentifier::new(lsp::Url::from_file_path(path).unwrap()),
2293                point_to_lsp(self.position),
2294            ),
2295            ch: self.trigger.clone(),
2296            options: self.options.clone(),
2297        }
2298    }
2299
2300    async fn response_from_lsp(
2301        self,
2302        message: Option<Vec<lsp::TextEdit>>,
2303        lsp_store: Model<LspStore>,
2304        buffer: Model<Buffer>,
2305        server_id: LanguageServerId,
2306        mut cx: AsyncAppContext,
2307    ) -> Result<Option<Transaction>> {
2308        if let Some(edits) = message {
2309            let (lsp_adapter, lsp_server) =
2310                language_server_for_buffer(&lsp_store, &buffer, server_id, &mut cx)?;
2311            LocalLspStore::deserialize_text_edits(
2312                lsp_store,
2313                buffer,
2314                edits,
2315                self.push_to_history,
2316                lsp_adapter,
2317                lsp_server,
2318                &mut cx,
2319            )
2320            .await
2321        } else {
2322            Ok(None)
2323        }
2324    }
2325
2326    fn to_proto(&self, project_id: u64, buffer: &Buffer) -> proto::OnTypeFormatting {
2327        proto::OnTypeFormatting {
2328            project_id,
2329            buffer_id: buffer.remote_id().into(),
2330            position: Some(language::proto::serialize_anchor(
2331                &buffer.anchor_before(self.position),
2332            )),
2333            trigger: self.trigger.clone(),
2334            version: serialize_version(&buffer.version()),
2335        }
2336    }
2337
2338    async fn from_proto(
2339        message: proto::OnTypeFormatting,
2340        _: Model<LspStore>,
2341        buffer: Model<Buffer>,
2342        mut cx: AsyncAppContext,
2343    ) -> Result<Self> {
2344        let position = message
2345            .position
2346            .and_then(deserialize_anchor)
2347            .ok_or_else(|| anyhow!("invalid position"))?;
2348        buffer
2349            .update(&mut cx, |buffer, _| {
2350                buffer.wait_for_version(deserialize_version(&message.version))
2351            })?
2352            .await?;
2353
2354        let options = buffer.update(&mut cx, |buffer, cx| {
2355            lsp_formatting_options(
2356                language_settings(buffer.language().map(|l| l.name()), buffer.file(), cx).as_ref(),
2357            )
2358        })?;
2359
2360        Ok(Self {
2361            position: buffer.update(&mut cx, |buffer, _| position.to_point_utf16(buffer))?,
2362            trigger: message.trigger.clone(),
2363            options,
2364            push_to_history: false,
2365        })
2366    }
2367
2368    fn response_to_proto(
2369        response: Option<Transaction>,
2370        _: &mut LspStore,
2371        _: PeerId,
2372        _: &clock::Global,
2373        _: &mut AppContext,
2374    ) -> proto::OnTypeFormattingResponse {
2375        proto::OnTypeFormattingResponse {
2376            transaction: response
2377                .map(|transaction| language::proto::serialize_transaction(&transaction)),
2378        }
2379    }
2380
2381    async fn response_from_proto(
2382        self,
2383        message: proto::OnTypeFormattingResponse,
2384        _: Model<LspStore>,
2385        _: Model<Buffer>,
2386        _: AsyncAppContext,
2387    ) -> Result<Option<Transaction>> {
2388        let Some(transaction) = message.transaction else {
2389            return Ok(None);
2390        };
2391        Ok(Some(language::proto::deserialize_transaction(transaction)?))
2392    }
2393
2394    fn buffer_id_from_proto(message: &proto::OnTypeFormatting) -> Result<BufferId> {
2395        BufferId::new(message.buffer_id)
2396    }
2397}
2398
2399impl InlayHints {
2400    pub async fn lsp_to_project_hint(
2401        lsp_hint: lsp::InlayHint,
2402        buffer_handle: &Model<Buffer>,
2403        server_id: LanguageServerId,
2404        resolve_state: ResolveState,
2405        force_no_type_left_padding: bool,
2406        cx: &mut AsyncAppContext,
2407    ) -> anyhow::Result<InlayHint> {
2408        let kind = lsp_hint.kind.and_then(|kind| match kind {
2409            lsp::InlayHintKind::TYPE => Some(InlayHintKind::Type),
2410            lsp::InlayHintKind::PARAMETER => Some(InlayHintKind::Parameter),
2411            _ => None,
2412        });
2413
2414        let position = buffer_handle.update(cx, |buffer, _| {
2415            let position = buffer.clip_point_utf16(point_from_lsp(lsp_hint.position), Bias::Left);
2416            if kind == Some(InlayHintKind::Parameter) {
2417                buffer.anchor_before(position)
2418            } else {
2419                buffer.anchor_after(position)
2420            }
2421        })?;
2422        let label = Self::lsp_inlay_label_to_project(lsp_hint.label, server_id)
2423            .await
2424            .context("lsp to project inlay hint conversion")?;
2425        let padding_left = if force_no_type_left_padding && kind == Some(InlayHintKind::Type) {
2426            false
2427        } else {
2428            lsp_hint.padding_left.unwrap_or(false)
2429        };
2430
2431        Ok(InlayHint {
2432            position,
2433            padding_left,
2434            padding_right: lsp_hint.padding_right.unwrap_or(false),
2435            label,
2436            kind,
2437            tooltip: lsp_hint.tooltip.map(|tooltip| match tooltip {
2438                lsp::InlayHintTooltip::String(s) => InlayHintTooltip::String(s),
2439                lsp::InlayHintTooltip::MarkupContent(markup_content) => {
2440                    InlayHintTooltip::MarkupContent(MarkupContent {
2441                        kind: match markup_content.kind {
2442                            lsp::MarkupKind::PlainText => HoverBlockKind::PlainText,
2443                            lsp::MarkupKind::Markdown => HoverBlockKind::Markdown,
2444                        },
2445                        value: markup_content.value,
2446                    })
2447                }
2448            }),
2449            resolve_state,
2450        })
2451    }
2452
2453    async fn lsp_inlay_label_to_project(
2454        lsp_label: lsp::InlayHintLabel,
2455        server_id: LanguageServerId,
2456    ) -> anyhow::Result<InlayHintLabel> {
2457        let label = match lsp_label {
2458            lsp::InlayHintLabel::String(s) => InlayHintLabel::String(s),
2459            lsp::InlayHintLabel::LabelParts(lsp_parts) => {
2460                let mut parts = Vec::with_capacity(lsp_parts.len());
2461                for lsp_part in lsp_parts {
2462                    parts.push(InlayHintLabelPart {
2463                        value: lsp_part.value,
2464                        tooltip: lsp_part.tooltip.map(|tooltip| match tooltip {
2465                            lsp::InlayHintLabelPartTooltip::String(s) => {
2466                                InlayHintLabelPartTooltip::String(s)
2467                            }
2468                            lsp::InlayHintLabelPartTooltip::MarkupContent(markup_content) => {
2469                                InlayHintLabelPartTooltip::MarkupContent(MarkupContent {
2470                                    kind: match markup_content.kind {
2471                                        lsp::MarkupKind::PlainText => HoverBlockKind::PlainText,
2472                                        lsp::MarkupKind::Markdown => HoverBlockKind::Markdown,
2473                                    },
2474                                    value: markup_content.value,
2475                                })
2476                            }
2477                        }),
2478                        location: Some(server_id).zip(lsp_part.location),
2479                    });
2480                }
2481                InlayHintLabel::LabelParts(parts)
2482            }
2483        };
2484
2485        Ok(label)
2486    }
2487
2488    pub fn project_to_proto_hint(response_hint: InlayHint) -> proto::InlayHint {
2489        let (state, lsp_resolve_state) = match response_hint.resolve_state {
2490            ResolveState::Resolved => (0, None),
2491            ResolveState::CanResolve(server_id, resolve_data) => (
2492                1,
2493                Some(proto::resolve_state::LspResolveState {
2494                    server_id: server_id.0 as u64,
2495                    value: resolve_data.map(|json_data| {
2496                        serde_json::to_string(&json_data)
2497                            .expect("failed to serialize resolve json data")
2498                    }),
2499                }),
2500            ),
2501            ResolveState::Resolving => (2, None),
2502        };
2503        let resolve_state = Some(proto::ResolveState {
2504            state,
2505            lsp_resolve_state,
2506        });
2507        proto::InlayHint {
2508            position: Some(language::proto::serialize_anchor(&response_hint.position)),
2509            padding_left: response_hint.padding_left,
2510            padding_right: response_hint.padding_right,
2511            label: Some(proto::InlayHintLabel {
2512                label: Some(match response_hint.label {
2513                    InlayHintLabel::String(s) => proto::inlay_hint_label::Label::Value(s),
2514                    InlayHintLabel::LabelParts(label_parts) => {
2515                        proto::inlay_hint_label::Label::LabelParts(proto::InlayHintLabelParts {
2516                            parts: label_parts.into_iter().map(|label_part| {
2517                                let location_url = label_part.location.as_ref().map(|(_, location)| location.uri.to_string());
2518                                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 });
2519                                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 });
2520                                proto::InlayHintLabelPart {
2521                                value: label_part.value,
2522                                tooltip: label_part.tooltip.map(|tooltip| {
2523                                    let proto_tooltip = match tooltip {
2524                                        InlayHintLabelPartTooltip::String(s) => proto::inlay_hint_label_part_tooltip::Content::Value(s),
2525                                        InlayHintLabelPartTooltip::MarkupContent(markup_content) => proto::inlay_hint_label_part_tooltip::Content::MarkupContent(proto::MarkupContent {
2526                                            is_markdown: markup_content.kind == HoverBlockKind::Markdown,
2527                                            value: markup_content.value,
2528                                        }),
2529                                    };
2530                                    proto::InlayHintLabelPartTooltip {content: Some(proto_tooltip)}
2531                                }),
2532                                location_url,
2533                                location_range_start,
2534                                location_range_end,
2535                                language_server_id: label_part.location.as_ref().map(|(server_id, _)| server_id.0 as u64),
2536                            }}).collect()
2537                        })
2538                    }
2539                }),
2540            }),
2541            kind: response_hint.kind.map(|kind| kind.name().to_string()),
2542            tooltip: response_hint.tooltip.map(|response_tooltip| {
2543                let proto_tooltip = match response_tooltip {
2544                    InlayHintTooltip::String(s) => proto::inlay_hint_tooltip::Content::Value(s),
2545                    InlayHintTooltip::MarkupContent(markup_content) => {
2546                        proto::inlay_hint_tooltip::Content::MarkupContent(proto::MarkupContent {
2547                            is_markdown: markup_content.kind == HoverBlockKind::Markdown,
2548                            value: markup_content.value,
2549                        })
2550                    }
2551                };
2552                proto::InlayHintTooltip {
2553                    content: Some(proto_tooltip),
2554                }
2555            }),
2556            resolve_state,
2557        }
2558    }
2559
2560    pub fn proto_to_project_hint(message_hint: proto::InlayHint) -> anyhow::Result<InlayHint> {
2561        let resolve_state = message_hint.resolve_state.as_ref().unwrap_or_else(|| {
2562            panic!("incorrect proto inlay hint message: no resolve state in hint {message_hint:?}",)
2563        });
2564        let resolve_state_data = resolve_state
2565            .lsp_resolve_state.as_ref()
2566            .map(|lsp_resolve_state| {
2567                let value = lsp_resolve_state.value.as_deref().map(|value| {
2568                    serde_json::from_str::<Option<lsp::LSPAny>>(value)
2569                        .with_context(|| format!("incorrect proto inlay hint message: non-json resolve state {lsp_resolve_state:?}"))
2570                }).transpose()?.flatten();
2571                anyhow::Ok((LanguageServerId(lsp_resolve_state.server_id as usize), value))
2572            })
2573            .transpose()?;
2574        let resolve_state = match resolve_state.state {
2575            0 => ResolveState::Resolved,
2576            1 => {
2577                let (server_id, lsp_resolve_state) = resolve_state_data.with_context(|| {
2578                    format!(
2579                        "No lsp resolve data for the hint that can be resolved: {message_hint:?}"
2580                    )
2581                })?;
2582                ResolveState::CanResolve(server_id, lsp_resolve_state)
2583            }
2584            2 => ResolveState::Resolving,
2585            invalid => {
2586                anyhow::bail!("Unexpected resolve state {invalid} for hint {message_hint:?}")
2587            }
2588        };
2589        Ok(InlayHint {
2590            position: message_hint
2591                .position
2592                .and_then(language::proto::deserialize_anchor)
2593                .context("invalid position")?,
2594            label: match message_hint
2595                .label
2596                .and_then(|label| label.label)
2597                .context("missing label")?
2598            {
2599                proto::inlay_hint_label::Label::Value(s) => InlayHintLabel::String(s),
2600                proto::inlay_hint_label::Label::LabelParts(parts) => {
2601                    let mut label_parts = Vec::new();
2602                    for part in parts.parts {
2603                        label_parts.push(InlayHintLabelPart {
2604                            value: part.value,
2605                            tooltip: part.tooltip.map(|tooltip| match tooltip.content {
2606                                Some(proto::inlay_hint_label_part_tooltip::Content::Value(s)) => {
2607                                    InlayHintLabelPartTooltip::String(s)
2608                                }
2609                                Some(
2610                                    proto::inlay_hint_label_part_tooltip::Content::MarkupContent(
2611                                        markup_content,
2612                                    ),
2613                                ) => InlayHintLabelPartTooltip::MarkupContent(MarkupContent {
2614                                    kind: if markup_content.is_markdown {
2615                                        HoverBlockKind::Markdown
2616                                    } else {
2617                                        HoverBlockKind::PlainText
2618                                    },
2619                                    value: markup_content.value,
2620                                }),
2621                                None => InlayHintLabelPartTooltip::String(String::new()),
2622                            }),
2623                            location: {
2624                                match part
2625                                    .location_url
2626                                    .zip(
2627                                        part.location_range_start.and_then(|start| {
2628                                            Some(start..part.location_range_end?)
2629                                        }),
2630                                    )
2631                                    .zip(part.language_server_id)
2632                                {
2633                                    Some(((uri, range), server_id)) => Some((
2634                                        LanguageServerId(server_id as usize),
2635                                        lsp::Location {
2636                                            uri: lsp::Url::parse(&uri)
2637                                                .context("invalid uri in hint part {part:?}")?,
2638                                            range: lsp::Range::new(
2639                                                point_to_lsp(PointUtf16::new(
2640                                                    range.start.row,
2641                                                    range.start.column,
2642                                                )),
2643                                                point_to_lsp(PointUtf16::new(
2644                                                    range.end.row,
2645                                                    range.end.column,
2646                                                )),
2647                                            ),
2648                                        },
2649                                    )),
2650                                    None => None,
2651                                }
2652                            },
2653                        });
2654                    }
2655
2656                    InlayHintLabel::LabelParts(label_parts)
2657                }
2658            },
2659            padding_left: message_hint.padding_left,
2660            padding_right: message_hint.padding_right,
2661            kind: message_hint
2662                .kind
2663                .as_deref()
2664                .and_then(InlayHintKind::from_name),
2665            tooltip: message_hint.tooltip.and_then(|tooltip| {
2666                Some(match tooltip.content? {
2667                    proto::inlay_hint_tooltip::Content::Value(s) => InlayHintTooltip::String(s),
2668                    proto::inlay_hint_tooltip::Content::MarkupContent(markup_content) => {
2669                        InlayHintTooltip::MarkupContent(MarkupContent {
2670                            kind: if markup_content.is_markdown {
2671                                HoverBlockKind::Markdown
2672                            } else {
2673                                HoverBlockKind::PlainText
2674                            },
2675                            value: markup_content.value,
2676                        })
2677                    }
2678                })
2679            }),
2680            resolve_state,
2681        })
2682    }
2683
2684    pub fn project_to_lsp_hint(hint: InlayHint, snapshot: &BufferSnapshot) -> lsp::InlayHint {
2685        lsp::InlayHint {
2686            position: point_to_lsp(hint.position.to_point_utf16(snapshot)),
2687            kind: hint.kind.map(|kind| match kind {
2688                InlayHintKind::Type => lsp::InlayHintKind::TYPE,
2689                InlayHintKind::Parameter => lsp::InlayHintKind::PARAMETER,
2690            }),
2691            text_edits: None,
2692            tooltip: hint.tooltip.and_then(|tooltip| {
2693                Some(match tooltip {
2694                    InlayHintTooltip::String(s) => lsp::InlayHintTooltip::String(s),
2695                    InlayHintTooltip::MarkupContent(markup_content) => {
2696                        lsp::InlayHintTooltip::MarkupContent(lsp::MarkupContent {
2697                            kind: match markup_content.kind {
2698                                HoverBlockKind::PlainText => lsp::MarkupKind::PlainText,
2699                                HoverBlockKind::Markdown => lsp::MarkupKind::Markdown,
2700                                HoverBlockKind::Code { .. } => return None,
2701                            },
2702                            value: markup_content.value,
2703                        })
2704                    }
2705                })
2706            }),
2707            label: match hint.label {
2708                InlayHintLabel::String(s) => lsp::InlayHintLabel::String(s),
2709                InlayHintLabel::LabelParts(label_parts) => lsp::InlayHintLabel::LabelParts(
2710                    label_parts
2711                        .into_iter()
2712                        .map(|part| lsp::InlayHintLabelPart {
2713                            value: part.value,
2714                            tooltip: part.tooltip.and_then(|tooltip| {
2715                                Some(match tooltip {
2716                                    InlayHintLabelPartTooltip::String(s) => {
2717                                        lsp::InlayHintLabelPartTooltip::String(s)
2718                                    }
2719                                    InlayHintLabelPartTooltip::MarkupContent(markup_content) => {
2720                                        lsp::InlayHintLabelPartTooltip::MarkupContent(
2721                                            lsp::MarkupContent {
2722                                                kind: match markup_content.kind {
2723                                                    HoverBlockKind::PlainText => {
2724                                                        lsp::MarkupKind::PlainText
2725                                                    }
2726                                                    HoverBlockKind::Markdown => {
2727                                                        lsp::MarkupKind::Markdown
2728                                                    }
2729                                                    HoverBlockKind::Code { .. } => return None,
2730                                                },
2731                                                value: markup_content.value,
2732                                            },
2733                                        )
2734                                    }
2735                                })
2736                            }),
2737                            location: part.location.map(|(_, location)| location),
2738                            command: None,
2739                        })
2740                        .collect(),
2741                ),
2742            },
2743            padding_left: Some(hint.padding_left),
2744            padding_right: Some(hint.padding_right),
2745            data: match hint.resolve_state {
2746                ResolveState::CanResolve(_, data) => data,
2747                ResolveState::Resolving | ResolveState::Resolved => None,
2748            },
2749        }
2750    }
2751
2752    pub fn can_resolve_inlays(capabilities: &ServerCapabilities) -> bool {
2753        capabilities
2754            .inlay_hint_provider
2755            .as_ref()
2756            .and_then(|options| match options {
2757                OneOf::Left(_is_supported) => None,
2758                OneOf::Right(capabilities) => match capabilities {
2759                    lsp::InlayHintServerCapabilities::Options(o) => o.resolve_provider,
2760                    lsp::InlayHintServerCapabilities::RegistrationOptions(o) => {
2761                        o.inlay_hint_options.resolve_provider
2762                    }
2763                },
2764            })
2765            .unwrap_or(false)
2766    }
2767}
2768
2769#[async_trait(?Send)]
2770impl LspCommand for InlayHints {
2771    type Response = Vec<InlayHint>;
2772    type LspRequest = lsp::InlayHintRequest;
2773    type ProtoRequest = proto::InlayHints;
2774
2775    fn check_capabilities(&self, capabilities: AdapterServerCapabilities) -> bool {
2776        let Some(inlay_hint_provider) = &capabilities.server_capabilities.inlay_hint_provider
2777        else {
2778            return false;
2779        };
2780        match inlay_hint_provider {
2781            lsp::OneOf::Left(enabled) => *enabled,
2782            lsp::OneOf::Right(inlay_hint_capabilities) => match inlay_hint_capabilities {
2783                lsp::InlayHintServerCapabilities::Options(_) => true,
2784                lsp::InlayHintServerCapabilities::RegistrationOptions(_) => false,
2785            },
2786        }
2787    }
2788
2789    fn to_lsp(
2790        &self,
2791        path: &Path,
2792        buffer: &Buffer,
2793        _: &Arc<LanguageServer>,
2794        _: &AppContext,
2795    ) -> lsp::InlayHintParams {
2796        lsp::InlayHintParams {
2797            text_document: lsp::TextDocumentIdentifier {
2798                uri: lsp::Url::from_file_path(path).unwrap(),
2799            },
2800            range: range_to_lsp(self.range.to_point_utf16(buffer)),
2801            work_done_progress_params: Default::default(),
2802        }
2803    }
2804
2805    async fn response_from_lsp(
2806        self,
2807        message: Option<Vec<lsp::InlayHint>>,
2808        lsp_store: Model<LspStore>,
2809        buffer: Model<Buffer>,
2810        server_id: LanguageServerId,
2811        mut cx: AsyncAppContext,
2812    ) -> anyhow::Result<Vec<InlayHint>> {
2813        let (lsp_adapter, lsp_server) =
2814            language_server_for_buffer(&lsp_store, &buffer, server_id, &mut cx)?;
2815        // `typescript-language-server` adds padding to the left for type hints, turning
2816        // `const foo: boolean` into `const foo : boolean` which looks odd.
2817        // `rust-analyzer` does not have the padding for this case, and we have to accommodate both.
2818        //
2819        // We could trim the whole string, but being pessimistic on par with the situation above,
2820        // there might be a hint with multiple whitespaces at the end(s) which we need to display properly.
2821        // Hence let's use a heuristic first to handle the most awkward case and look for more.
2822        let force_no_type_left_padding =
2823            lsp_adapter.name.0.as_ref() == "typescript-language-server";
2824
2825        let hints = message.unwrap_or_default().into_iter().map(|lsp_hint| {
2826            let resolve_state = if InlayHints::can_resolve_inlays(&lsp_server.capabilities()) {
2827                ResolveState::CanResolve(lsp_server.server_id(), lsp_hint.data.clone())
2828            } else {
2829                ResolveState::Resolved
2830            };
2831
2832            let buffer = buffer.clone();
2833            cx.spawn(move |mut cx| async move {
2834                InlayHints::lsp_to_project_hint(
2835                    lsp_hint,
2836                    &buffer,
2837                    server_id,
2838                    resolve_state,
2839                    force_no_type_left_padding,
2840                    &mut cx,
2841                )
2842                .await
2843            })
2844        });
2845        future::join_all(hints)
2846            .await
2847            .into_iter()
2848            .collect::<anyhow::Result<_>>()
2849            .context("lsp to project inlay hints conversion")
2850    }
2851
2852    fn to_proto(&self, project_id: u64, buffer: &Buffer) -> proto::InlayHints {
2853        proto::InlayHints {
2854            project_id,
2855            buffer_id: buffer.remote_id().into(),
2856            start: Some(language::proto::serialize_anchor(&self.range.start)),
2857            end: Some(language::proto::serialize_anchor(&self.range.end)),
2858            version: serialize_version(&buffer.version()),
2859        }
2860    }
2861
2862    async fn from_proto(
2863        message: proto::InlayHints,
2864        _: Model<LspStore>,
2865        buffer: Model<Buffer>,
2866        mut cx: AsyncAppContext,
2867    ) -> Result<Self> {
2868        let start = message
2869            .start
2870            .and_then(language::proto::deserialize_anchor)
2871            .context("invalid start")?;
2872        let end = message
2873            .end
2874            .and_then(language::proto::deserialize_anchor)
2875            .context("invalid end")?;
2876        buffer
2877            .update(&mut cx, |buffer, _| {
2878                buffer.wait_for_version(deserialize_version(&message.version))
2879            })?
2880            .await?;
2881
2882        Ok(Self { range: start..end })
2883    }
2884
2885    fn response_to_proto(
2886        response: Vec<InlayHint>,
2887        _: &mut LspStore,
2888        _: PeerId,
2889        buffer_version: &clock::Global,
2890        _: &mut AppContext,
2891    ) -> proto::InlayHintsResponse {
2892        proto::InlayHintsResponse {
2893            hints: response
2894                .into_iter()
2895                .map(InlayHints::project_to_proto_hint)
2896                .collect(),
2897            version: serialize_version(buffer_version),
2898        }
2899    }
2900
2901    async fn response_from_proto(
2902        self,
2903        message: proto::InlayHintsResponse,
2904        _: Model<LspStore>,
2905        buffer: Model<Buffer>,
2906        mut cx: AsyncAppContext,
2907    ) -> anyhow::Result<Vec<InlayHint>> {
2908        buffer
2909            .update(&mut cx, |buffer, _| {
2910                buffer.wait_for_version(deserialize_version(&message.version))
2911            })?
2912            .await?;
2913
2914        let mut hints = Vec::new();
2915        for message_hint in message.hints {
2916            hints.push(InlayHints::proto_to_project_hint(message_hint)?);
2917        }
2918
2919        Ok(hints)
2920    }
2921
2922    fn buffer_id_from_proto(message: &proto::InlayHints) -> Result<BufferId> {
2923        BufferId::new(message.buffer_id)
2924    }
2925}
2926
2927#[async_trait(?Send)]
2928impl LspCommand for LinkedEditingRange {
2929    type Response = Vec<Range<Anchor>>;
2930    type LspRequest = lsp::request::LinkedEditingRange;
2931    type ProtoRequest = proto::LinkedEditingRange;
2932
2933    fn check_capabilities(&self, capabilities: AdapterServerCapabilities) -> bool {
2934        let Some(linked_editing_options) = &capabilities
2935            .server_capabilities
2936            .linked_editing_range_provider
2937        else {
2938            return false;
2939        };
2940        if let LinkedEditingRangeServerCapabilities::Simple(false) = linked_editing_options {
2941            return false;
2942        }
2943        true
2944    }
2945
2946    fn to_lsp(
2947        &self,
2948        path: &Path,
2949        buffer: &Buffer,
2950        _server: &Arc<LanguageServer>,
2951        _: &AppContext,
2952    ) -> lsp::LinkedEditingRangeParams {
2953        let position = self.position.to_point_utf16(&buffer.snapshot());
2954        lsp::LinkedEditingRangeParams {
2955            text_document_position_params: lsp::TextDocumentPositionParams::new(
2956                lsp::TextDocumentIdentifier::new(lsp::Url::from_file_path(path).unwrap()),
2957                point_to_lsp(position),
2958            ),
2959            work_done_progress_params: Default::default(),
2960        }
2961    }
2962
2963    async fn response_from_lsp(
2964        self,
2965        message: Option<lsp::LinkedEditingRanges>,
2966        _: Model<LspStore>,
2967        buffer: Model<Buffer>,
2968        _server_id: LanguageServerId,
2969        cx: AsyncAppContext,
2970    ) -> Result<Vec<Range<Anchor>>> {
2971        if let Some(lsp::LinkedEditingRanges { mut ranges, .. }) = message {
2972            ranges.sort_by_key(|range| range.start);
2973
2974            buffer.read_with(&cx, |buffer, _| {
2975                ranges
2976                    .into_iter()
2977                    .map(|range| {
2978                        let start =
2979                            buffer.clip_point_utf16(point_from_lsp(range.start), Bias::Left);
2980                        let end = buffer.clip_point_utf16(point_from_lsp(range.end), Bias::Left);
2981                        buffer.anchor_before(start)..buffer.anchor_after(end)
2982                    })
2983                    .collect()
2984            })
2985        } else {
2986            Ok(vec![])
2987        }
2988    }
2989
2990    fn to_proto(&self, project_id: u64, buffer: &Buffer) -> proto::LinkedEditingRange {
2991        proto::LinkedEditingRange {
2992            project_id,
2993            buffer_id: buffer.remote_id().to_proto(),
2994            position: Some(serialize_anchor(&self.position)),
2995            version: serialize_version(&buffer.version()),
2996        }
2997    }
2998
2999    async fn from_proto(
3000        message: proto::LinkedEditingRange,
3001        _: Model<LspStore>,
3002        buffer: Model<Buffer>,
3003        mut cx: AsyncAppContext,
3004    ) -> Result<Self> {
3005        let position = message
3006            .position
3007            .ok_or_else(|| anyhow!("invalid position"))?;
3008        buffer
3009            .update(&mut cx, |buffer, _| {
3010                buffer.wait_for_version(deserialize_version(&message.version))
3011            })?
3012            .await?;
3013        let position = deserialize_anchor(position).ok_or_else(|| anyhow!("invalid position"))?;
3014        buffer
3015            .update(&mut cx, |buffer, _| buffer.wait_for_anchors([position]))?
3016            .await?;
3017        Ok(Self { position })
3018    }
3019
3020    fn response_to_proto(
3021        response: Vec<Range<Anchor>>,
3022        _: &mut LspStore,
3023        _: PeerId,
3024        buffer_version: &clock::Global,
3025        _: &mut AppContext,
3026    ) -> proto::LinkedEditingRangeResponse {
3027        proto::LinkedEditingRangeResponse {
3028            items: response
3029                .into_iter()
3030                .map(|range| proto::AnchorRange {
3031                    start: Some(serialize_anchor(&range.start)),
3032                    end: Some(serialize_anchor(&range.end)),
3033                })
3034                .collect(),
3035            version: serialize_version(buffer_version),
3036        }
3037    }
3038
3039    async fn response_from_proto(
3040        self,
3041        message: proto::LinkedEditingRangeResponse,
3042        _: Model<LspStore>,
3043        buffer: Model<Buffer>,
3044        mut cx: AsyncAppContext,
3045    ) -> Result<Vec<Range<Anchor>>> {
3046        buffer
3047            .update(&mut cx, |buffer, _| {
3048                buffer.wait_for_version(deserialize_version(&message.version))
3049            })?
3050            .await?;
3051        let items: Vec<Range<Anchor>> = message
3052            .items
3053            .into_iter()
3054            .filter_map(|range| {
3055                let start = deserialize_anchor(range.start?)?;
3056                let end = deserialize_anchor(range.end?)?;
3057                Some(start..end)
3058            })
3059            .collect();
3060        for range in &items {
3061            buffer
3062                .update(&mut cx, |buffer, _| {
3063                    buffer.wait_for_anchors([range.start, range.end])
3064                })?
3065                .await?;
3066        }
3067        Ok(items)
3068    }
3069
3070    fn buffer_id_from_proto(message: &proto::LinkedEditingRange) -> Result<BufferId> {
3071        BufferId::new(message.buffer_id)
3072    }
3073}