lsp_command.rs

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