lsp_command.rs

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