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