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