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                }
1922            })
1923            .collect())
1924    }
1925
1926    fn to_proto(&self, project_id: u64, buffer: &Buffer) -> proto::GetCompletions {
1927        let anchor = buffer.anchor_after(self.position);
1928        proto::GetCompletions {
1929            project_id,
1930            buffer_id: buffer.remote_id().into(),
1931            position: Some(language::proto::serialize_anchor(&anchor)),
1932            version: serialize_version(&buffer.version()),
1933        }
1934    }
1935
1936    async fn from_proto(
1937        message: proto::GetCompletions,
1938        _: Model<LspStore>,
1939        buffer: Model<Buffer>,
1940        mut cx: AsyncAppContext,
1941    ) -> Result<Self> {
1942        let version = deserialize_version(&message.version);
1943        buffer
1944            .update(&mut cx, |buffer, _| buffer.wait_for_version(version))?
1945            .await?;
1946        let position = message
1947            .position
1948            .and_then(language::proto::deserialize_anchor)
1949            .map(|p| {
1950                buffer.update(&mut cx, |buffer, _| {
1951                    buffer.clip_point_utf16(Unclipped(p.to_point_utf16(buffer)), Bias::Left)
1952                })
1953            })
1954            .ok_or_else(|| anyhow!("invalid position"))??;
1955        Ok(Self {
1956            position,
1957            context: CompletionContext {
1958                trigger_kind: CompletionTriggerKind::INVOKED,
1959                trigger_character: None,
1960            },
1961        })
1962    }
1963
1964    fn response_to_proto(
1965        completions: Vec<CoreCompletion>,
1966        _: &mut LspStore,
1967        _: PeerId,
1968        buffer_version: &clock::Global,
1969        _: &mut AppContext,
1970    ) -> proto::GetCompletionsResponse {
1971        proto::GetCompletionsResponse {
1972            completions: completions
1973                .iter()
1974                .map(LspStore::serialize_completion)
1975                .collect(),
1976            version: serialize_version(buffer_version),
1977        }
1978    }
1979
1980    async fn response_from_proto(
1981        self,
1982        message: proto::GetCompletionsResponse,
1983        _project: Model<LspStore>,
1984        buffer: Model<Buffer>,
1985        mut cx: AsyncAppContext,
1986    ) -> Result<Self::Response> {
1987        buffer
1988            .update(&mut cx, |buffer, _| {
1989                buffer.wait_for_version(deserialize_version(&message.version))
1990            })?
1991            .await?;
1992
1993        message
1994            .completions
1995            .into_iter()
1996            .map(LspStore::deserialize_completion)
1997            .collect()
1998    }
1999
2000    fn buffer_id_from_proto(message: &proto::GetCompletions) -> Result<BufferId> {
2001        BufferId::new(message.buffer_id)
2002    }
2003}
2004
2005pub(crate) fn parse_completion_text_edit(
2006    edit: &lsp::CompletionTextEdit,
2007    snapshot: &BufferSnapshot,
2008) -> Option<(Range<Anchor>, String)> {
2009    match edit {
2010        lsp::CompletionTextEdit::Edit(edit) => {
2011            let range = range_from_lsp(edit.range);
2012            let start = snapshot.clip_point_utf16(range.start, Bias::Left);
2013            let end = snapshot.clip_point_utf16(range.end, Bias::Left);
2014            if start != range.start.0 || end != range.end.0 {
2015                log::info!("completion out of expected range");
2016                None
2017            } else {
2018                Some((
2019                    snapshot.anchor_before(start)..snapshot.anchor_after(end),
2020                    edit.new_text.clone(),
2021                ))
2022            }
2023        }
2024
2025        lsp::CompletionTextEdit::InsertAndReplace(edit) => {
2026            let range = range_from_lsp(edit.insert);
2027
2028            let start = snapshot.clip_point_utf16(range.start, Bias::Left);
2029            let end = snapshot.clip_point_utf16(range.end, Bias::Left);
2030            if start != range.start.0 || end != range.end.0 {
2031                log::info!("completion out of expected range");
2032                None
2033            } else {
2034                Some((
2035                    snapshot.anchor_before(start)..snapshot.anchor_after(end),
2036                    edit.new_text.clone(),
2037                ))
2038            }
2039        }
2040    }
2041}
2042
2043#[async_trait(?Send)]
2044impl LspCommand for GetCodeActions {
2045    type Response = Vec<CodeAction>;
2046    type LspRequest = lsp::request::CodeActionRequest;
2047    type ProtoRequest = proto::GetCodeActions;
2048
2049    fn check_capabilities(&self, capabilities: AdapterServerCapabilities) -> bool {
2050        match &capabilities.server_capabilities.code_action_provider {
2051            None => false,
2052            Some(lsp::CodeActionProviderCapability::Simple(false)) => false,
2053            _ => {
2054                // If we do know that we want specific code actions AND we know that
2055                // the server only supports specific code actions, then we want to filter
2056                // down to the ones that are supported.
2057                if let Some((requested, supported)) = self
2058                    .kinds
2059                    .as_ref()
2060                    .zip(Self::supported_code_action_kinds(capabilities))
2061                {
2062                    let server_supported = supported.into_iter().collect::<HashSet<_>>();
2063                    requested.iter().any(|kind| server_supported.contains(kind))
2064                } else {
2065                    true
2066                }
2067            }
2068        }
2069    }
2070
2071    fn to_lsp(
2072        &self,
2073        path: &Path,
2074        buffer: &Buffer,
2075        language_server: &Arc<LanguageServer>,
2076        _: &AppContext,
2077    ) -> lsp::CodeActionParams {
2078        let relevant_diagnostics = buffer
2079            .snapshot()
2080            .diagnostics_in_range::<_, language::PointUtf16>(self.range.clone(), false)
2081            .map(|entry| entry.to_lsp_diagnostic_stub())
2082            .collect::<Vec<_>>();
2083
2084        let supported =
2085            Self::supported_code_action_kinds(language_server.adapter_server_capabilities());
2086
2087        let only = if let Some(requested) = &self.kinds {
2088            if let Some(supported_kinds) = supported {
2089                let server_supported = supported_kinds.into_iter().collect::<HashSet<_>>();
2090
2091                let filtered = requested
2092                    .iter()
2093                    .filter(|kind| server_supported.contains(kind))
2094                    .cloned()
2095                    .collect();
2096                Some(filtered)
2097            } else {
2098                Some(requested.clone())
2099            }
2100        } else {
2101            supported
2102        };
2103
2104        lsp::CodeActionParams {
2105            text_document: lsp::TextDocumentIdentifier::new(
2106                lsp::Url::from_file_path(path).unwrap(),
2107            ),
2108            range: range_to_lsp(self.range.to_point_utf16(buffer)),
2109            work_done_progress_params: Default::default(),
2110            partial_result_params: Default::default(),
2111            context: lsp::CodeActionContext {
2112                diagnostics: relevant_diagnostics,
2113                only,
2114                ..lsp::CodeActionContext::default()
2115            },
2116        }
2117    }
2118
2119    async fn response_from_lsp(
2120        self,
2121        actions: Option<lsp::CodeActionResponse>,
2122        _: Model<LspStore>,
2123        _: Model<Buffer>,
2124        server_id: LanguageServerId,
2125        _: AsyncAppContext,
2126    ) -> Result<Vec<CodeAction>> {
2127        let requested_kinds_set = if let Some(kinds) = self.kinds {
2128            Some(kinds.into_iter().collect::<HashSet<_>>())
2129        } else {
2130            None
2131        };
2132
2133        Ok(actions
2134            .unwrap_or_default()
2135            .into_iter()
2136            .filter_map(|entry| {
2137                let lsp::CodeActionOrCommand::CodeAction(lsp_action) = entry else {
2138                    return None;
2139                };
2140
2141                if let Some((requested_kinds, kind)) =
2142                    requested_kinds_set.as_ref().zip(lsp_action.kind.as_ref())
2143                {
2144                    if !requested_kinds.contains(kind) {
2145                        return None;
2146                    }
2147                }
2148
2149                Some(CodeAction {
2150                    server_id,
2151                    range: self.range.clone(),
2152                    lsp_action,
2153                })
2154            })
2155            .collect())
2156    }
2157
2158    fn to_proto(&self, project_id: u64, buffer: &Buffer) -> proto::GetCodeActions {
2159        proto::GetCodeActions {
2160            project_id,
2161            buffer_id: buffer.remote_id().into(),
2162            start: Some(language::proto::serialize_anchor(&self.range.start)),
2163            end: Some(language::proto::serialize_anchor(&self.range.end)),
2164            version: serialize_version(&buffer.version()),
2165        }
2166    }
2167
2168    async fn from_proto(
2169        message: proto::GetCodeActions,
2170        _: Model<LspStore>,
2171        buffer: Model<Buffer>,
2172        mut cx: AsyncAppContext,
2173    ) -> Result<Self> {
2174        let start = message
2175            .start
2176            .and_then(language::proto::deserialize_anchor)
2177            .ok_or_else(|| anyhow!("invalid start"))?;
2178        let end = message
2179            .end
2180            .and_then(language::proto::deserialize_anchor)
2181            .ok_or_else(|| anyhow!("invalid end"))?;
2182        buffer
2183            .update(&mut cx, |buffer, _| {
2184                buffer.wait_for_version(deserialize_version(&message.version))
2185            })?
2186            .await?;
2187
2188        Ok(Self {
2189            range: start..end,
2190            kinds: None,
2191        })
2192    }
2193
2194    fn response_to_proto(
2195        code_actions: Vec<CodeAction>,
2196        _: &mut LspStore,
2197        _: PeerId,
2198        buffer_version: &clock::Global,
2199        _: &mut AppContext,
2200    ) -> proto::GetCodeActionsResponse {
2201        proto::GetCodeActionsResponse {
2202            actions: code_actions
2203                .iter()
2204                .map(LspStore::serialize_code_action)
2205                .collect(),
2206            version: serialize_version(buffer_version),
2207        }
2208    }
2209
2210    async fn response_from_proto(
2211        self,
2212        message: proto::GetCodeActionsResponse,
2213        _: Model<LspStore>,
2214        buffer: Model<Buffer>,
2215        mut cx: AsyncAppContext,
2216    ) -> Result<Vec<CodeAction>> {
2217        buffer
2218            .update(&mut cx, |buffer, _| {
2219                buffer.wait_for_version(deserialize_version(&message.version))
2220            })?
2221            .await?;
2222        message
2223            .actions
2224            .into_iter()
2225            .map(LspStore::deserialize_code_action)
2226            .collect()
2227    }
2228
2229    fn buffer_id_from_proto(message: &proto::GetCodeActions) -> Result<BufferId> {
2230        BufferId::new(message.buffer_id)
2231    }
2232}
2233
2234impl GetCodeActions {
2235    fn supported_code_action_kinds(
2236        capabilities: AdapterServerCapabilities,
2237    ) -> Option<Vec<CodeActionKind>> {
2238        match capabilities.server_capabilities.code_action_provider {
2239            Some(lsp::CodeActionProviderCapability::Options(CodeActionOptions {
2240                code_action_kinds: Some(supported_action_kinds),
2241                ..
2242            })) => Some(supported_action_kinds.clone()),
2243            _ => capabilities.code_action_kinds,
2244        }
2245    }
2246
2247    pub fn can_resolve_actions(capabilities: &ServerCapabilities) -> bool {
2248        capabilities
2249            .code_action_provider
2250            .as_ref()
2251            .and_then(|options| match options {
2252                lsp::CodeActionProviderCapability::Simple(_is_supported) => None,
2253                lsp::CodeActionProviderCapability::Options(options) => options.resolve_provider,
2254            })
2255            .unwrap_or(false)
2256    }
2257}
2258
2259#[async_trait(?Send)]
2260impl LspCommand for OnTypeFormatting {
2261    type Response = Option<Transaction>;
2262    type LspRequest = lsp::request::OnTypeFormatting;
2263    type ProtoRequest = proto::OnTypeFormatting;
2264
2265    fn check_capabilities(&self, capabilities: AdapterServerCapabilities) -> bool {
2266        let Some(on_type_formatting_options) = &capabilities
2267            .server_capabilities
2268            .document_on_type_formatting_provider
2269        else {
2270            return false;
2271        };
2272        on_type_formatting_options
2273            .first_trigger_character
2274            .contains(&self.trigger)
2275            || on_type_formatting_options
2276                .more_trigger_character
2277                .iter()
2278                .flatten()
2279                .any(|chars| chars.contains(&self.trigger))
2280    }
2281
2282    fn to_lsp(
2283        &self,
2284        path: &Path,
2285        _: &Buffer,
2286        _: &Arc<LanguageServer>,
2287        _: &AppContext,
2288    ) -> lsp::DocumentOnTypeFormattingParams {
2289        lsp::DocumentOnTypeFormattingParams {
2290            text_document_position: lsp::TextDocumentPositionParams::new(
2291                lsp::TextDocumentIdentifier::new(lsp::Url::from_file_path(path).unwrap()),
2292                point_to_lsp(self.position),
2293            ),
2294            ch: self.trigger.clone(),
2295            options: self.options.clone(),
2296        }
2297    }
2298
2299    async fn response_from_lsp(
2300        self,
2301        message: Option<Vec<lsp::TextEdit>>,
2302        lsp_store: Model<LspStore>,
2303        buffer: Model<Buffer>,
2304        server_id: LanguageServerId,
2305        mut cx: AsyncAppContext,
2306    ) -> Result<Option<Transaction>> {
2307        if let Some(edits) = message {
2308            let (lsp_adapter, lsp_server) =
2309                language_server_for_buffer(&lsp_store, &buffer, server_id, &mut cx)?;
2310            LocalLspStore::deserialize_text_edits(
2311                lsp_store,
2312                buffer,
2313                edits,
2314                self.push_to_history,
2315                lsp_adapter,
2316                lsp_server,
2317                &mut cx,
2318            )
2319            .await
2320        } else {
2321            Ok(None)
2322        }
2323    }
2324
2325    fn to_proto(&self, project_id: u64, buffer: &Buffer) -> proto::OnTypeFormatting {
2326        proto::OnTypeFormatting {
2327            project_id,
2328            buffer_id: buffer.remote_id().into(),
2329            position: Some(language::proto::serialize_anchor(
2330                &buffer.anchor_before(self.position),
2331            )),
2332            trigger: self.trigger.clone(),
2333            version: serialize_version(&buffer.version()),
2334        }
2335    }
2336
2337    async fn from_proto(
2338        message: proto::OnTypeFormatting,
2339        _: Model<LspStore>,
2340        buffer: Model<Buffer>,
2341        mut cx: AsyncAppContext,
2342    ) -> Result<Self> {
2343        let position = message
2344            .position
2345            .and_then(deserialize_anchor)
2346            .ok_or_else(|| anyhow!("invalid position"))?;
2347        buffer
2348            .update(&mut cx, |buffer, _| {
2349                buffer.wait_for_version(deserialize_version(&message.version))
2350            })?
2351            .await?;
2352
2353        let options = buffer.update(&mut cx, |buffer, cx| {
2354            lsp_formatting_options(
2355                language_settings(buffer.language().map(|l| l.name()), buffer.file(), cx).as_ref(),
2356            )
2357        })?;
2358
2359        Ok(Self {
2360            position: buffer.update(&mut cx, |buffer, _| position.to_point_utf16(buffer))?,
2361            trigger: message.trigger.clone(),
2362            options,
2363            push_to_history: false,
2364        })
2365    }
2366
2367    fn response_to_proto(
2368        response: Option<Transaction>,
2369        _: &mut LspStore,
2370        _: PeerId,
2371        _: &clock::Global,
2372        _: &mut AppContext,
2373    ) -> proto::OnTypeFormattingResponse {
2374        proto::OnTypeFormattingResponse {
2375            transaction: response
2376                .map(|transaction| language::proto::serialize_transaction(&transaction)),
2377        }
2378    }
2379
2380    async fn response_from_proto(
2381        self,
2382        message: proto::OnTypeFormattingResponse,
2383        _: Model<LspStore>,
2384        _: Model<Buffer>,
2385        _: AsyncAppContext,
2386    ) -> Result<Option<Transaction>> {
2387        let Some(transaction) = message.transaction else {
2388            return Ok(None);
2389        };
2390        Ok(Some(language::proto::deserialize_transaction(transaction)?))
2391    }
2392
2393    fn buffer_id_from_proto(message: &proto::OnTypeFormatting) -> Result<BufferId> {
2394        BufferId::new(message.buffer_id)
2395    }
2396}
2397
2398impl InlayHints {
2399    pub async fn lsp_to_project_hint(
2400        lsp_hint: lsp::InlayHint,
2401        buffer_handle: &Model<Buffer>,
2402        server_id: LanguageServerId,
2403        resolve_state: ResolveState,
2404        force_no_type_left_padding: bool,
2405        cx: &mut AsyncAppContext,
2406    ) -> anyhow::Result<InlayHint> {
2407        let kind = lsp_hint.kind.and_then(|kind| match kind {
2408            lsp::InlayHintKind::TYPE => Some(InlayHintKind::Type),
2409            lsp::InlayHintKind::PARAMETER => Some(InlayHintKind::Parameter),
2410            _ => None,
2411        });
2412
2413        let position = buffer_handle.update(cx, |buffer, _| {
2414            let position = buffer.clip_point_utf16(point_from_lsp(lsp_hint.position), Bias::Left);
2415            if kind == Some(InlayHintKind::Parameter) {
2416                buffer.anchor_before(position)
2417            } else {
2418                buffer.anchor_after(position)
2419            }
2420        })?;
2421        let label = Self::lsp_inlay_label_to_project(lsp_hint.label, server_id)
2422            .await
2423            .context("lsp to project inlay hint conversion")?;
2424        let padding_left = if force_no_type_left_padding && kind == Some(InlayHintKind::Type) {
2425            false
2426        } else {
2427            lsp_hint.padding_left.unwrap_or(false)
2428        };
2429
2430        Ok(InlayHint {
2431            position,
2432            padding_left,
2433            padding_right: lsp_hint.padding_right.unwrap_or(false),
2434            label,
2435            kind,
2436            tooltip: lsp_hint.tooltip.map(|tooltip| match tooltip {
2437                lsp::InlayHintTooltip::String(s) => InlayHintTooltip::String(s),
2438                lsp::InlayHintTooltip::MarkupContent(markup_content) => {
2439                    InlayHintTooltip::MarkupContent(MarkupContent {
2440                        kind: match markup_content.kind {
2441                            lsp::MarkupKind::PlainText => HoverBlockKind::PlainText,
2442                            lsp::MarkupKind::Markdown => HoverBlockKind::Markdown,
2443                        },
2444                        value: markup_content.value,
2445                    })
2446                }
2447            }),
2448            resolve_state,
2449        })
2450    }
2451
2452    async fn lsp_inlay_label_to_project(
2453        lsp_label: lsp::InlayHintLabel,
2454        server_id: LanguageServerId,
2455    ) -> anyhow::Result<InlayHintLabel> {
2456        let label = match lsp_label {
2457            lsp::InlayHintLabel::String(s) => InlayHintLabel::String(s),
2458            lsp::InlayHintLabel::LabelParts(lsp_parts) => {
2459                let mut parts = Vec::with_capacity(lsp_parts.len());
2460                for lsp_part in lsp_parts {
2461                    parts.push(InlayHintLabelPart {
2462                        value: lsp_part.value,
2463                        tooltip: lsp_part.tooltip.map(|tooltip| match tooltip {
2464                            lsp::InlayHintLabelPartTooltip::String(s) => {
2465                                InlayHintLabelPartTooltip::String(s)
2466                            }
2467                            lsp::InlayHintLabelPartTooltip::MarkupContent(markup_content) => {
2468                                InlayHintLabelPartTooltip::MarkupContent(MarkupContent {
2469                                    kind: match markup_content.kind {
2470                                        lsp::MarkupKind::PlainText => HoverBlockKind::PlainText,
2471                                        lsp::MarkupKind::Markdown => HoverBlockKind::Markdown,
2472                                    },
2473                                    value: markup_content.value,
2474                                })
2475                            }
2476                        }),
2477                        location: Some(server_id).zip(lsp_part.location),
2478                    });
2479                }
2480                InlayHintLabel::LabelParts(parts)
2481            }
2482        };
2483
2484        Ok(label)
2485    }
2486
2487    pub fn project_to_proto_hint(response_hint: InlayHint) -> proto::InlayHint {
2488        let (state, lsp_resolve_state) = match response_hint.resolve_state {
2489            ResolveState::Resolved => (0, None),
2490            ResolveState::CanResolve(server_id, resolve_data) => (
2491                1,
2492                Some(proto::resolve_state::LspResolveState {
2493                    server_id: server_id.0 as u64,
2494                    value: resolve_data.map(|json_data| {
2495                        serde_json::to_string(&json_data)
2496                            .expect("failed to serialize resolve json data")
2497                    }),
2498                }),
2499            ),
2500            ResolveState::Resolving => (2, None),
2501        };
2502        let resolve_state = Some(proto::ResolveState {
2503            state,
2504            lsp_resolve_state,
2505        });
2506        proto::InlayHint {
2507            position: Some(language::proto::serialize_anchor(&response_hint.position)),
2508            padding_left: response_hint.padding_left,
2509            padding_right: response_hint.padding_right,
2510            label: Some(proto::InlayHintLabel {
2511                label: Some(match response_hint.label {
2512                    InlayHintLabel::String(s) => proto::inlay_hint_label::Label::Value(s),
2513                    InlayHintLabel::LabelParts(label_parts) => {
2514                        proto::inlay_hint_label::Label::LabelParts(proto::InlayHintLabelParts {
2515                            parts: label_parts.into_iter().map(|label_part| {
2516                                let location_url = label_part.location.as_ref().map(|(_, location)| location.uri.to_string());
2517                                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 });
2518                                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 });
2519                                proto::InlayHintLabelPart {
2520                                value: label_part.value,
2521                                tooltip: label_part.tooltip.map(|tooltip| {
2522                                    let proto_tooltip = match tooltip {
2523                                        InlayHintLabelPartTooltip::String(s) => proto::inlay_hint_label_part_tooltip::Content::Value(s),
2524                                        InlayHintLabelPartTooltip::MarkupContent(markup_content) => proto::inlay_hint_label_part_tooltip::Content::MarkupContent(proto::MarkupContent {
2525                                            is_markdown: markup_content.kind == HoverBlockKind::Markdown,
2526                                            value: markup_content.value,
2527                                        }),
2528                                    };
2529                                    proto::InlayHintLabelPartTooltip {content: Some(proto_tooltip)}
2530                                }),
2531                                location_url,
2532                                location_range_start,
2533                                location_range_end,
2534                                language_server_id: label_part.location.as_ref().map(|(server_id, _)| server_id.0 as u64),
2535                            }}).collect()
2536                        })
2537                    }
2538                }),
2539            }),
2540            kind: response_hint.kind.map(|kind| kind.name().to_string()),
2541            tooltip: response_hint.tooltip.map(|response_tooltip| {
2542                let proto_tooltip = match response_tooltip {
2543                    InlayHintTooltip::String(s) => proto::inlay_hint_tooltip::Content::Value(s),
2544                    InlayHintTooltip::MarkupContent(markup_content) => {
2545                        proto::inlay_hint_tooltip::Content::MarkupContent(proto::MarkupContent {
2546                            is_markdown: markup_content.kind == HoverBlockKind::Markdown,
2547                            value: markup_content.value,
2548                        })
2549                    }
2550                };
2551                proto::InlayHintTooltip {
2552                    content: Some(proto_tooltip),
2553                }
2554            }),
2555            resolve_state,
2556        }
2557    }
2558
2559    pub fn proto_to_project_hint(message_hint: proto::InlayHint) -> anyhow::Result<InlayHint> {
2560        let resolve_state = message_hint.resolve_state.as_ref().unwrap_or_else(|| {
2561            panic!("incorrect proto inlay hint message: no resolve state in hint {message_hint:?}",)
2562        });
2563        let resolve_state_data = resolve_state
2564            .lsp_resolve_state.as_ref()
2565            .map(|lsp_resolve_state| {
2566                let value = lsp_resolve_state.value.as_deref().map(|value| {
2567                    serde_json::from_str::<Option<lsp::LSPAny>>(value)
2568                        .with_context(|| format!("incorrect proto inlay hint message: non-json resolve state {lsp_resolve_state:?}"))
2569                }).transpose()?.flatten();
2570                anyhow::Ok((LanguageServerId(lsp_resolve_state.server_id as usize), value))
2571            })
2572            .transpose()?;
2573        let resolve_state = match resolve_state.state {
2574            0 => ResolveState::Resolved,
2575            1 => {
2576                let (server_id, lsp_resolve_state) = resolve_state_data.with_context(|| {
2577                    format!(
2578                        "No lsp resolve data for the hint that can be resolved: {message_hint:?}"
2579                    )
2580                })?;
2581                ResolveState::CanResolve(server_id, lsp_resolve_state)
2582            }
2583            2 => ResolveState::Resolving,
2584            invalid => {
2585                anyhow::bail!("Unexpected resolve state {invalid} for hint {message_hint:?}")
2586            }
2587        };
2588        Ok(InlayHint {
2589            position: message_hint
2590                .position
2591                .and_then(language::proto::deserialize_anchor)
2592                .context("invalid position")?,
2593            label: match message_hint
2594                .label
2595                .and_then(|label| label.label)
2596                .context("missing label")?
2597            {
2598                proto::inlay_hint_label::Label::Value(s) => InlayHintLabel::String(s),
2599                proto::inlay_hint_label::Label::LabelParts(parts) => {
2600                    let mut label_parts = Vec::new();
2601                    for part in parts.parts {
2602                        label_parts.push(InlayHintLabelPart {
2603                            value: part.value,
2604                            tooltip: part.tooltip.map(|tooltip| match tooltip.content {
2605                                Some(proto::inlay_hint_label_part_tooltip::Content::Value(s)) => {
2606                                    InlayHintLabelPartTooltip::String(s)
2607                                }
2608                                Some(
2609                                    proto::inlay_hint_label_part_tooltip::Content::MarkupContent(
2610                                        markup_content,
2611                                    ),
2612                                ) => InlayHintLabelPartTooltip::MarkupContent(MarkupContent {
2613                                    kind: if markup_content.is_markdown {
2614                                        HoverBlockKind::Markdown
2615                                    } else {
2616                                        HoverBlockKind::PlainText
2617                                    },
2618                                    value: markup_content.value,
2619                                }),
2620                                None => InlayHintLabelPartTooltip::String(String::new()),
2621                            }),
2622                            location: {
2623                                match part
2624                                    .location_url
2625                                    .zip(
2626                                        part.location_range_start.and_then(|start| {
2627                                            Some(start..part.location_range_end?)
2628                                        }),
2629                                    )
2630                                    .zip(part.language_server_id)
2631                                {
2632                                    Some(((uri, range), server_id)) => Some((
2633                                        LanguageServerId(server_id as usize),
2634                                        lsp::Location {
2635                                            uri: lsp::Url::parse(&uri)
2636                                                .context("invalid uri in hint part {part:?}")?,
2637                                            range: lsp::Range::new(
2638                                                point_to_lsp(PointUtf16::new(
2639                                                    range.start.row,
2640                                                    range.start.column,
2641                                                )),
2642                                                point_to_lsp(PointUtf16::new(
2643                                                    range.end.row,
2644                                                    range.end.column,
2645                                                )),
2646                                            ),
2647                                        },
2648                                    )),
2649                                    None => None,
2650                                }
2651                            },
2652                        });
2653                    }
2654
2655                    InlayHintLabel::LabelParts(label_parts)
2656                }
2657            },
2658            padding_left: message_hint.padding_left,
2659            padding_right: message_hint.padding_right,
2660            kind: message_hint
2661                .kind
2662                .as_deref()
2663                .and_then(InlayHintKind::from_name),
2664            tooltip: message_hint.tooltip.and_then(|tooltip| {
2665                Some(match tooltip.content? {
2666                    proto::inlay_hint_tooltip::Content::Value(s) => InlayHintTooltip::String(s),
2667                    proto::inlay_hint_tooltip::Content::MarkupContent(markup_content) => {
2668                        InlayHintTooltip::MarkupContent(MarkupContent {
2669                            kind: if markup_content.is_markdown {
2670                                HoverBlockKind::Markdown
2671                            } else {
2672                                HoverBlockKind::PlainText
2673                            },
2674                            value: markup_content.value,
2675                        })
2676                    }
2677                })
2678            }),
2679            resolve_state,
2680        })
2681    }
2682
2683    pub fn project_to_lsp_hint(hint: InlayHint, snapshot: &BufferSnapshot) -> lsp::InlayHint {
2684        lsp::InlayHint {
2685            position: point_to_lsp(hint.position.to_point_utf16(snapshot)),
2686            kind: hint.kind.map(|kind| match kind {
2687                InlayHintKind::Type => lsp::InlayHintKind::TYPE,
2688                InlayHintKind::Parameter => lsp::InlayHintKind::PARAMETER,
2689            }),
2690            text_edits: None,
2691            tooltip: hint.tooltip.and_then(|tooltip| {
2692                Some(match tooltip {
2693                    InlayHintTooltip::String(s) => lsp::InlayHintTooltip::String(s),
2694                    InlayHintTooltip::MarkupContent(markup_content) => {
2695                        lsp::InlayHintTooltip::MarkupContent(lsp::MarkupContent {
2696                            kind: match markup_content.kind {
2697                                HoverBlockKind::PlainText => lsp::MarkupKind::PlainText,
2698                                HoverBlockKind::Markdown => lsp::MarkupKind::Markdown,
2699                                HoverBlockKind::Code { .. } => return None,
2700                            },
2701                            value: markup_content.value,
2702                        })
2703                    }
2704                })
2705            }),
2706            label: match hint.label {
2707                InlayHintLabel::String(s) => lsp::InlayHintLabel::String(s),
2708                InlayHintLabel::LabelParts(label_parts) => lsp::InlayHintLabel::LabelParts(
2709                    label_parts
2710                        .into_iter()
2711                        .map(|part| lsp::InlayHintLabelPart {
2712                            value: part.value,
2713                            tooltip: part.tooltip.and_then(|tooltip| {
2714                                Some(match tooltip {
2715                                    InlayHintLabelPartTooltip::String(s) => {
2716                                        lsp::InlayHintLabelPartTooltip::String(s)
2717                                    }
2718                                    InlayHintLabelPartTooltip::MarkupContent(markup_content) => {
2719                                        lsp::InlayHintLabelPartTooltip::MarkupContent(
2720                                            lsp::MarkupContent {
2721                                                kind: match markup_content.kind {
2722                                                    HoverBlockKind::PlainText => {
2723                                                        lsp::MarkupKind::PlainText
2724                                                    }
2725                                                    HoverBlockKind::Markdown => {
2726                                                        lsp::MarkupKind::Markdown
2727                                                    }
2728                                                    HoverBlockKind::Code { .. } => return None,
2729                                                },
2730                                                value: markup_content.value,
2731                                            },
2732                                        )
2733                                    }
2734                                })
2735                            }),
2736                            location: part.location.map(|(_, location)| location),
2737                            command: None,
2738                        })
2739                        .collect(),
2740                ),
2741            },
2742            padding_left: Some(hint.padding_left),
2743            padding_right: Some(hint.padding_right),
2744            data: match hint.resolve_state {
2745                ResolveState::CanResolve(_, data) => data,
2746                ResolveState::Resolving | ResolveState::Resolved => None,
2747            },
2748        }
2749    }
2750
2751    pub fn can_resolve_inlays(capabilities: &ServerCapabilities) -> bool {
2752        capabilities
2753            .inlay_hint_provider
2754            .as_ref()
2755            .and_then(|options| match options {
2756                OneOf::Left(_is_supported) => None,
2757                OneOf::Right(capabilities) => match capabilities {
2758                    lsp::InlayHintServerCapabilities::Options(o) => o.resolve_provider,
2759                    lsp::InlayHintServerCapabilities::RegistrationOptions(o) => {
2760                        o.inlay_hint_options.resolve_provider
2761                    }
2762                },
2763            })
2764            .unwrap_or(false)
2765    }
2766}
2767
2768#[async_trait(?Send)]
2769impl LspCommand for InlayHints {
2770    type Response = Vec<InlayHint>;
2771    type LspRequest = lsp::InlayHintRequest;
2772    type ProtoRequest = proto::InlayHints;
2773
2774    fn check_capabilities(&self, capabilities: AdapterServerCapabilities) -> bool {
2775        let Some(inlay_hint_provider) = &capabilities.server_capabilities.inlay_hint_provider
2776        else {
2777            return false;
2778        };
2779        match inlay_hint_provider {
2780            lsp::OneOf::Left(enabled) => *enabled,
2781            lsp::OneOf::Right(inlay_hint_capabilities) => match inlay_hint_capabilities {
2782                lsp::InlayHintServerCapabilities::Options(_) => true,
2783                lsp::InlayHintServerCapabilities::RegistrationOptions(_) => false,
2784            },
2785        }
2786    }
2787
2788    fn to_lsp(
2789        &self,
2790        path: &Path,
2791        buffer: &Buffer,
2792        _: &Arc<LanguageServer>,
2793        _: &AppContext,
2794    ) -> lsp::InlayHintParams {
2795        lsp::InlayHintParams {
2796            text_document: lsp::TextDocumentIdentifier {
2797                uri: lsp::Url::from_file_path(path).unwrap(),
2798            },
2799            range: range_to_lsp(self.range.to_point_utf16(buffer)),
2800            work_done_progress_params: Default::default(),
2801        }
2802    }
2803
2804    async fn response_from_lsp(
2805        self,
2806        message: Option<Vec<lsp::InlayHint>>,
2807        lsp_store: Model<LspStore>,
2808        buffer: Model<Buffer>,
2809        server_id: LanguageServerId,
2810        mut cx: AsyncAppContext,
2811    ) -> anyhow::Result<Vec<InlayHint>> {
2812        let (lsp_adapter, lsp_server) =
2813            language_server_for_buffer(&lsp_store, &buffer, server_id, &mut cx)?;
2814        // `typescript-language-server` adds padding to the left for type hints, turning
2815        // `const foo: boolean` into `const foo : boolean` which looks odd.
2816        // `rust-analyzer` does not have the padding for this case, and we have to accommodate both.
2817        //
2818        // We could trim the whole string, but being pessimistic on par with the situation above,
2819        // there might be a hint with multiple whitespaces at the end(s) which we need to display properly.
2820        // Hence let's use a heuristic first to handle the most awkward case and look for more.
2821        let force_no_type_left_padding =
2822            lsp_adapter.name.0.as_ref() == "typescript-language-server";
2823
2824        let hints = message.unwrap_or_default().into_iter().map(|lsp_hint| {
2825            let resolve_state = if InlayHints::can_resolve_inlays(&lsp_server.capabilities()) {
2826                ResolveState::CanResolve(lsp_server.server_id(), lsp_hint.data.clone())
2827            } else {
2828                ResolveState::Resolved
2829            };
2830
2831            let buffer = buffer.clone();
2832            cx.spawn(move |mut cx| async move {
2833                InlayHints::lsp_to_project_hint(
2834                    lsp_hint,
2835                    &buffer,
2836                    server_id,
2837                    resolve_state,
2838                    force_no_type_left_padding,
2839                    &mut cx,
2840                )
2841                .await
2842            })
2843        });
2844        future::join_all(hints)
2845            .await
2846            .into_iter()
2847            .collect::<anyhow::Result<_>>()
2848            .context("lsp to project inlay hints conversion")
2849    }
2850
2851    fn to_proto(&self, project_id: u64, buffer: &Buffer) -> proto::InlayHints {
2852        proto::InlayHints {
2853            project_id,
2854            buffer_id: buffer.remote_id().into(),
2855            start: Some(language::proto::serialize_anchor(&self.range.start)),
2856            end: Some(language::proto::serialize_anchor(&self.range.end)),
2857            version: serialize_version(&buffer.version()),
2858        }
2859    }
2860
2861    async fn from_proto(
2862        message: proto::InlayHints,
2863        _: Model<LspStore>,
2864        buffer: Model<Buffer>,
2865        mut cx: AsyncAppContext,
2866    ) -> Result<Self> {
2867        let start = message
2868            .start
2869            .and_then(language::proto::deserialize_anchor)
2870            .context("invalid start")?;
2871        let end = message
2872            .end
2873            .and_then(language::proto::deserialize_anchor)
2874            .context("invalid end")?;
2875        buffer
2876            .update(&mut cx, |buffer, _| {
2877                buffer.wait_for_version(deserialize_version(&message.version))
2878            })?
2879            .await?;
2880
2881        Ok(Self { range: start..end })
2882    }
2883
2884    fn response_to_proto(
2885        response: Vec<InlayHint>,
2886        _: &mut LspStore,
2887        _: PeerId,
2888        buffer_version: &clock::Global,
2889        _: &mut AppContext,
2890    ) -> proto::InlayHintsResponse {
2891        proto::InlayHintsResponse {
2892            hints: response
2893                .into_iter()
2894                .map(InlayHints::project_to_proto_hint)
2895                .collect(),
2896            version: serialize_version(buffer_version),
2897        }
2898    }
2899
2900    async fn response_from_proto(
2901        self,
2902        message: proto::InlayHintsResponse,
2903        _: Model<LspStore>,
2904        buffer: Model<Buffer>,
2905        mut cx: AsyncAppContext,
2906    ) -> anyhow::Result<Vec<InlayHint>> {
2907        buffer
2908            .update(&mut cx, |buffer, _| {
2909                buffer.wait_for_version(deserialize_version(&message.version))
2910            })?
2911            .await?;
2912
2913        let mut hints = Vec::new();
2914        for message_hint in message.hints {
2915            hints.push(InlayHints::proto_to_project_hint(message_hint)?);
2916        }
2917
2918        Ok(hints)
2919    }
2920
2921    fn buffer_id_from_proto(message: &proto::InlayHints) -> Result<BufferId> {
2922        BufferId::new(message.buffer_id)
2923    }
2924}
2925
2926#[async_trait(?Send)]
2927impl LspCommand for LinkedEditingRange {
2928    type Response = Vec<Range<Anchor>>;
2929    type LspRequest = lsp::request::LinkedEditingRange;
2930    type ProtoRequest = proto::LinkedEditingRange;
2931
2932    fn check_capabilities(&self, capabilities: AdapterServerCapabilities) -> bool {
2933        let Some(linked_editing_options) = &capabilities
2934            .server_capabilities
2935            .linked_editing_range_provider
2936        else {
2937            return false;
2938        };
2939        if let LinkedEditingRangeServerCapabilities::Simple(false) = linked_editing_options {
2940            return false;
2941        }
2942        true
2943    }
2944
2945    fn to_lsp(
2946        &self,
2947        path: &Path,
2948        buffer: &Buffer,
2949        _server: &Arc<LanguageServer>,
2950        _: &AppContext,
2951    ) -> lsp::LinkedEditingRangeParams {
2952        let position = self.position.to_point_utf16(&buffer.snapshot());
2953        lsp::LinkedEditingRangeParams {
2954            text_document_position_params: lsp::TextDocumentPositionParams::new(
2955                lsp::TextDocumentIdentifier::new(lsp::Url::from_file_path(path).unwrap()),
2956                point_to_lsp(position),
2957            ),
2958            work_done_progress_params: Default::default(),
2959        }
2960    }
2961
2962    async fn response_from_lsp(
2963        self,
2964        message: Option<lsp::LinkedEditingRanges>,
2965        _: Model<LspStore>,
2966        buffer: Model<Buffer>,
2967        _server_id: LanguageServerId,
2968        cx: AsyncAppContext,
2969    ) -> Result<Vec<Range<Anchor>>> {
2970        if let Some(lsp::LinkedEditingRanges { mut ranges, .. }) = message {
2971            ranges.sort_by_key(|range| range.start);
2972
2973            buffer.read_with(&cx, |buffer, _| {
2974                ranges
2975                    .into_iter()
2976                    .map(|range| {
2977                        let start =
2978                            buffer.clip_point_utf16(point_from_lsp(range.start), Bias::Left);
2979                        let end = buffer.clip_point_utf16(point_from_lsp(range.end), Bias::Left);
2980                        buffer.anchor_before(start)..buffer.anchor_after(end)
2981                    })
2982                    .collect()
2983            })
2984        } else {
2985            Ok(vec![])
2986        }
2987    }
2988
2989    fn to_proto(&self, project_id: u64, buffer: &Buffer) -> proto::LinkedEditingRange {
2990        proto::LinkedEditingRange {
2991            project_id,
2992            buffer_id: buffer.remote_id().to_proto(),
2993            position: Some(serialize_anchor(&self.position)),
2994            version: serialize_version(&buffer.version()),
2995        }
2996    }
2997
2998    async fn from_proto(
2999        message: proto::LinkedEditingRange,
3000        _: Model<LspStore>,
3001        buffer: Model<Buffer>,
3002        mut cx: AsyncAppContext,
3003    ) -> Result<Self> {
3004        let position = message
3005            .position
3006            .ok_or_else(|| anyhow!("invalid position"))?;
3007        buffer
3008            .update(&mut cx, |buffer, _| {
3009                buffer.wait_for_version(deserialize_version(&message.version))
3010            })?
3011            .await?;
3012        let position = deserialize_anchor(position).ok_or_else(|| anyhow!("invalid position"))?;
3013        buffer
3014            .update(&mut cx, |buffer, _| buffer.wait_for_anchors([position]))?
3015            .await?;
3016        Ok(Self { position })
3017    }
3018
3019    fn response_to_proto(
3020        response: Vec<Range<Anchor>>,
3021        _: &mut LspStore,
3022        _: PeerId,
3023        buffer_version: &clock::Global,
3024        _: &mut AppContext,
3025    ) -> proto::LinkedEditingRangeResponse {
3026        proto::LinkedEditingRangeResponse {
3027            items: response
3028                .into_iter()
3029                .map(|range| proto::AnchorRange {
3030                    start: Some(serialize_anchor(&range.start)),
3031                    end: Some(serialize_anchor(&range.end)),
3032                })
3033                .collect(),
3034            version: serialize_version(buffer_version),
3035        }
3036    }
3037
3038    async fn response_from_proto(
3039        self,
3040        message: proto::LinkedEditingRangeResponse,
3041        _: Model<LspStore>,
3042        buffer: Model<Buffer>,
3043        mut cx: AsyncAppContext,
3044    ) -> Result<Vec<Range<Anchor>>> {
3045        buffer
3046            .update(&mut cx, |buffer, _| {
3047                buffer.wait_for_version(deserialize_version(&message.version))
3048            })?
3049            .await?;
3050        let items: Vec<Range<Anchor>> = message
3051            .items
3052            .into_iter()
3053            .filter_map(|range| {
3054                let start = deserialize_anchor(range.start?)?;
3055                let end = deserialize_anchor(range.end?)?;
3056                Some(start..end)
3057            })
3058            .collect();
3059        for range in &items {
3060            buffer
3061                .update(&mut cx, |buffer, _| {
3062                    buffer.wait_for_anchors([range.start, range.end])
3063                })?
3064                .await?;
3065        }
3066        Ok(items)
3067    }
3068
3069    fn buffer_id_from_proto(message: &proto::LinkedEditingRange) -> Result<BufferId> {
3070        BufferId::new(message.buffer_id)
3071    }
3072}