lsp_command.rs

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