lsp_command.rs

   1use crate::{
   2    DocumentHighlight, Hover, HoverBlock, HoverBlockKind, InlayHint, InlayHintLabel,
   3    InlayHintLabelPart, InlayHintLabelPartTooltip, InlayHintTooltip, Location, LocationLink,
   4    MarkupContent, Project, ProjectTransaction,
   5};
   6use anyhow::{anyhow, Context, Result};
   7use async_trait::async_trait;
   8use client::proto::{self, PeerId};
   9use fs::LineEnding;
  10use gpui::{AppContext, AsyncAppContext, ModelHandle};
  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, CachedLspAdapter, CharKind, CodeAction,
  16    Completion, OffsetRangeExt, PointUtf16, ToOffset, ToPointUtf16, Transaction, Unclipped,
  17};
  18use lsp::{
  19    CompletionListItemDefaultsEditRange, DocumentHighlightKind, LanguageServer, LanguageServerId,
  20    ServerCapabilities,
  21};
  22use std::{cmp::Reverse, ops::Range, path::Path, sync::Arc};
  23
  24pub fn lsp_formatting_options(tab_size: u32) -> lsp::FormattingOptions {
  25    lsp::FormattingOptions {
  26        tab_size,
  27        insert_spaces: true,
  28        insert_final_newline: Some(true),
  29        ..lsp::FormattingOptions::default()
  30    }
  31}
  32
  33#[async_trait(?Send)]
  34pub(crate) trait LspCommand: 'static + Sized {
  35    type Response: 'static + Default + Send;
  36    type LspRequest: 'static + Send + lsp::request::Request;
  37    type ProtoRequest: 'static + Send + proto::RequestMessage;
  38
  39    fn check_capabilities(&self, _: &lsp::ServerCapabilities) -> bool {
  40        true
  41    }
  42
  43    fn to_lsp(
  44        &self,
  45        path: &Path,
  46        buffer: &Buffer,
  47        language_server: &Arc<LanguageServer>,
  48        cx: &AppContext,
  49    ) -> <Self::LspRequest as lsp::request::Request>::Params;
  50
  51    async fn response_from_lsp(
  52        self,
  53        message: <Self::LspRequest as lsp::request::Request>::Result,
  54        project: ModelHandle<Project>,
  55        buffer: ModelHandle<Buffer>,
  56        server_id: LanguageServerId,
  57        cx: AsyncAppContext,
  58    ) -> Result<Self::Response>;
  59
  60    fn to_proto(&self, project_id: u64, buffer: &Buffer) -> Self::ProtoRequest;
  61
  62    async fn from_proto(
  63        message: Self::ProtoRequest,
  64        project: ModelHandle<Project>,
  65        buffer: ModelHandle<Buffer>,
  66        cx: AsyncAppContext,
  67    ) -> Result<Self>;
  68
  69    fn response_to_proto(
  70        response: Self::Response,
  71        project: &mut Project,
  72        peer_id: PeerId,
  73        buffer_version: &clock::Global,
  74        cx: &mut AppContext,
  75    ) -> <Self::ProtoRequest as proto::RequestMessage>::Response;
  76
  77    async fn response_from_proto(
  78        self,
  79        message: <Self::ProtoRequest as proto::RequestMessage>::Response,
  80        project: ModelHandle<Project>,
  81        buffer: ModelHandle<Buffer>,
  82        cx: AsyncAppContext,
  83    ) -> Result<Self::Response>;
  84
  85    fn buffer_id_from_proto(message: &Self::ProtoRequest) -> u64;
  86}
  87
  88pub(crate) struct PrepareRename {
  89    pub position: PointUtf16,
  90}
  91
  92pub(crate) struct PerformRename {
  93    pub position: PointUtf16,
  94    pub new_name: String,
  95    pub push_to_history: bool,
  96}
  97
  98pub(crate) struct GetDefinition {
  99    pub position: PointUtf16,
 100}
 101
 102pub(crate) struct GetTypeDefinition {
 103    pub position: PointUtf16,
 104}
 105
 106pub(crate) struct GetReferences {
 107    pub position: PointUtf16,
 108}
 109
 110pub(crate) struct GetDocumentHighlights {
 111    pub position: PointUtf16,
 112}
 113
 114pub(crate) struct GetHover {
 115    pub position: PointUtf16,
 116}
 117
 118pub(crate) struct GetCompletions {
 119    pub position: PointUtf16,
 120}
 121
 122pub(crate) struct GetCodeActions {
 123    pub range: Range<Anchor>,
 124}
 125
 126pub(crate) struct OnTypeFormatting {
 127    pub position: PointUtf16,
 128    pub trigger: String,
 129    pub options: FormattingOptions,
 130    pub push_to_history: bool,
 131}
 132
 133pub(crate) struct InlayHints {
 134    pub range: Range<Anchor>,
 135}
 136
 137pub(crate) struct FormattingOptions {
 138    tab_size: u32,
 139}
 140
 141impl From<lsp::FormattingOptions> for FormattingOptions {
 142    fn from(value: lsp::FormattingOptions) -> Self {
 143        Self {
 144            tab_size: value.tab_size,
 145        }
 146    }
 147}
 148
 149#[async_trait(?Send)]
 150impl LspCommand for PrepareRename {
 151    type Response = Option<Range<Anchor>>;
 152    type LspRequest = lsp::request::PrepareRenameRequest;
 153    type ProtoRequest = proto::PrepareRename;
 154
 155    fn check_capabilities(&self, capabilities: &ServerCapabilities) -> bool {
 156        if let Some(lsp::OneOf::Right(rename)) = &capabilities.rename_provider {
 157            rename.prepare_provider == Some(true)
 158        } else {
 159            false
 160        }
 161    }
 162
 163    fn to_lsp(
 164        &self,
 165        path: &Path,
 166        _: &Buffer,
 167        _: &Arc<LanguageServer>,
 168        _: &AppContext,
 169    ) -> lsp::TextDocumentPositionParams {
 170        lsp::TextDocumentPositionParams {
 171            text_document: lsp::TextDocumentIdentifier {
 172                uri: lsp::Url::from_file_path(path).unwrap(),
 173            },
 174            position: point_to_lsp(self.position),
 175        }
 176    }
 177
 178    async fn response_from_lsp(
 179        self,
 180        message: Option<lsp::PrepareRenameResponse>,
 181        _: ModelHandle<Project>,
 182        buffer: ModelHandle<Buffer>,
 183        _: LanguageServerId,
 184        cx: AsyncAppContext,
 185    ) -> Result<Option<Range<Anchor>>> {
 186        buffer.read_with(&cx, |buffer, _| {
 187            if let Some(
 188                lsp::PrepareRenameResponse::Range(range)
 189                | lsp::PrepareRenameResponse::RangeWithPlaceholder { range, .. },
 190            ) = message
 191            {
 192                let Range { start, end } = range_from_lsp(range);
 193                if buffer.clip_point_utf16(start, Bias::Left) == start.0
 194                    && buffer.clip_point_utf16(end, Bias::Left) == end.0
 195                {
 196                    return Ok(Some(buffer.anchor_after(start)..buffer.anchor_before(end)));
 197                }
 198            }
 199            Ok(None)
 200        })
 201    }
 202
 203    fn to_proto(&self, project_id: u64, buffer: &Buffer) -> proto::PrepareRename {
 204        proto::PrepareRename {
 205            project_id,
 206            buffer_id: buffer.remote_id(),
 207            position: Some(language::proto::serialize_anchor(
 208                &buffer.anchor_before(self.position),
 209            )),
 210            version: serialize_version(&buffer.version()),
 211        }
 212    }
 213
 214    async fn from_proto(
 215        message: proto::PrepareRename,
 216        _: ModelHandle<Project>,
 217        buffer: ModelHandle<Buffer>,
 218        mut cx: AsyncAppContext,
 219    ) -> Result<Self> {
 220        let position = message
 221            .position
 222            .and_then(deserialize_anchor)
 223            .ok_or_else(|| anyhow!("invalid position"))?;
 224        buffer
 225            .update(&mut cx, |buffer, _| {
 226                buffer.wait_for_version(deserialize_version(&message.version))
 227            })
 228            .await?;
 229
 230        Ok(Self {
 231            position: buffer.read_with(&cx, |buffer, _| position.to_point_utf16(buffer)),
 232        })
 233    }
 234
 235    fn response_to_proto(
 236        range: Option<Range<Anchor>>,
 237        _: &mut Project,
 238        _: PeerId,
 239        buffer_version: &clock::Global,
 240        _: &mut AppContext,
 241    ) -> proto::PrepareRenameResponse {
 242        proto::PrepareRenameResponse {
 243            can_rename: range.is_some(),
 244            start: range
 245                .as_ref()
 246                .map(|range| language::proto::serialize_anchor(&range.start)),
 247            end: range
 248                .as_ref()
 249                .map(|range| language::proto::serialize_anchor(&range.end)),
 250            version: serialize_version(buffer_version),
 251        }
 252    }
 253
 254    async fn response_from_proto(
 255        self,
 256        message: proto::PrepareRenameResponse,
 257        _: ModelHandle<Project>,
 258        buffer: ModelHandle<Buffer>,
 259        mut cx: AsyncAppContext,
 260    ) -> Result<Option<Range<Anchor>>> {
 261        if message.can_rename {
 262            buffer
 263                .update(&mut cx, |buffer, _| {
 264                    buffer.wait_for_version(deserialize_version(&message.version))
 265                })
 266                .await?;
 267            let start = message.start.and_then(deserialize_anchor);
 268            let end = message.end.and_then(deserialize_anchor);
 269            Ok(start.zip(end).map(|(start, end)| start..end))
 270        } else {
 271            Ok(None)
 272        }
 273    }
 274
 275    fn buffer_id_from_proto(message: &proto::PrepareRename) -> u64 {
 276        message.buffer_id
 277    }
 278}
 279
 280#[async_trait(?Send)]
 281impl LspCommand for PerformRename {
 282    type Response = ProjectTransaction;
 283    type LspRequest = lsp::request::Rename;
 284    type ProtoRequest = proto::PerformRename;
 285
 286    fn to_lsp(
 287        &self,
 288        path: &Path,
 289        _: &Buffer,
 290        _: &Arc<LanguageServer>,
 291        _: &AppContext,
 292    ) -> lsp::RenameParams {
 293        lsp::RenameParams {
 294            text_document_position: lsp::TextDocumentPositionParams {
 295                text_document: lsp::TextDocumentIdentifier {
 296                    uri: lsp::Url::from_file_path(path).unwrap(),
 297                },
 298                position: point_to_lsp(self.position),
 299            },
 300            new_name: self.new_name.clone(),
 301            work_done_progress_params: Default::default(),
 302        }
 303    }
 304
 305    async fn response_from_lsp(
 306        self,
 307        message: Option<lsp::WorkspaceEdit>,
 308        project: ModelHandle<Project>,
 309        buffer: ModelHandle<Buffer>,
 310        server_id: LanguageServerId,
 311        mut cx: AsyncAppContext,
 312    ) -> Result<ProjectTransaction> {
 313        if let Some(edit) = message {
 314            let (lsp_adapter, lsp_server) =
 315                language_server_for_buffer(&project, &buffer, server_id, &mut cx)?;
 316            Project::deserialize_workspace_edit(
 317                project,
 318                edit,
 319                self.push_to_history,
 320                lsp_adapter,
 321                lsp_server,
 322                &mut cx,
 323            )
 324            .await
 325        } else {
 326            Ok(ProjectTransaction::default())
 327        }
 328    }
 329
 330    fn to_proto(&self, project_id: u64, buffer: &Buffer) -> proto::PerformRename {
 331        proto::PerformRename {
 332            project_id,
 333            buffer_id: buffer.remote_id(),
 334            position: Some(language::proto::serialize_anchor(
 335                &buffer.anchor_before(self.position),
 336            )),
 337            new_name: self.new_name.clone(),
 338            version: serialize_version(&buffer.version()),
 339        }
 340    }
 341
 342    async fn from_proto(
 343        message: proto::PerformRename,
 344        _: ModelHandle<Project>,
 345        buffer: ModelHandle<Buffer>,
 346        mut cx: AsyncAppContext,
 347    ) -> Result<Self> {
 348        let position = message
 349            .position
 350            .and_then(deserialize_anchor)
 351            .ok_or_else(|| anyhow!("invalid position"))?;
 352        buffer
 353            .update(&mut cx, |buffer, _| {
 354                buffer.wait_for_version(deserialize_version(&message.version))
 355            })
 356            .await?;
 357        Ok(Self {
 358            position: buffer.read_with(&cx, |buffer, _| position.to_point_utf16(buffer)),
 359            new_name: message.new_name,
 360            push_to_history: false,
 361        })
 362    }
 363
 364    fn response_to_proto(
 365        response: ProjectTransaction,
 366        project: &mut Project,
 367        peer_id: PeerId,
 368        _: &clock::Global,
 369        cx: &mut AppContext,
 370    ) -> proto::PerformRenameResponse {
 371        let transaction = project.serialize_project_transaction_for_peer(response, peer_id, cx);
 372        proto::PerformRenameResponse {
 373            transaction: Some(transaction),
 374        }
 375    }
 376
 377    async fn response_from_proto(
 378        self,
 379        message: proto::PerformRenameResponse,
 380        project: ModelHandle<Project>,
 381        _: ModelHandle<Buffer>,
 382        mut cx: AsyncAppContext,
 383    ) -> Result<ProjectTransaction> {
 384        let message = message
 385            .transaction
 386            .ok_or_else(|| anyhow!("missing transaction"))?;
 387        project
 388            .update(&mut cx, |project, cx| {
 389                project.deserialize_project_transaction(message, self.push_to_history, cx)
 390            })
 391            .await
 392    }
 393
 394    fn buffer_id_from_proto(message: &proto::PerformRename) -> u64 {
 395        message.buffer_id
 396    }
 397}
 398
 399#[async_trait(?Send)]
 400impl LspCommand for GetDefinition {
 401    type Response = Vec<LocationLink>;
 402    type LspRequest = lsp::request::GotoDefinition;
 403    type ProtoRequest = proto::GetDefinition;
 404
 405    fn to_lsp(
 406        &self,
 407        path: &Path,
 408        _: &Buffer,
 409        _: &Arc<LanguageServer>,
 410        _: &AppContext,
 411    ) -> lsp::GotoDefinitionParams {
 412        lsp::GotoDefinitionParams {
 413            text_document_position_params: lsp::TextDocumentPositionParams {
 414                text_document: lsp::TextDocumentIdentifier {
 415                    uri: lsp::Url::from_file_path(path).unwrap(),
 416                },
 417                position: point_to_lsp(self.position),
 418            },
 419            work_done_progress_params: Default::default(),
 420            partial_result_params: Default::default(),
 421        }
 422    }
 423
 424    async fn response_from_lsp(
 425        self,
 426        message: Option<lsp::GotoDefinitionResponse>,
 427        project: ModelHandle<Project>,
 428        buffer: ModelHandle<Buffer>,
 429        server_id: LanguageServerId,
 430        cx: AsyncAppContext,
 431    ) -> Result<Vec<LocationLink>> {
 432        location_links_from_lsp(message, project, buffer, server_id, cx).await
 433    }
 434
 435    fn to_proto(&self, project_id: u64, buffer: &Buffer) -> proto::GetDefinition {
 436        proto::GetDefinition {
 437            project_id,
 438            buffer_id: buffer.remote_id(),
 439            position: Some(language::proto::serialize_anchor(
 440                &buffer.anchor_before(self.position),
 441            )),
 442            version: serialize_version(&buffer.version()),
 443        }
 444    }
 445
 446    async fn from_proto(
 447        message: proto::GetDefinition,
 448        _: ModelHandle<Project>,
 449        buffer: ModelHandle<Buffer>,
 450        mut cx: AsyncAppContext,
 451    ) -> Result<Self> {
 452        let position = message
 453            .position
 454            .and_then(deserialize_anchor)
 455            .ok_or_else(|| anyhow!("invalid position"))?;
 456        buffer
 457            .update(&mut cx, |buffer, _| {
 458                buffer.wait_for_version(deserialize_version(&message.version))
 459            })
 460            .await?;
 461        Ok(Self {
 462            position: buffer.read_with(&cx, |buffer, _| position.to_point_utf16(buffer)),
 463        })
 464    }
 465
 466    fn response_to_proto(
 467        response: Vec<LocationLink>,
 468        project: &mut Project,
 469        peer_id: PeerId,
 470        _: &clock::Global,
 471        cx: &mut AppContext,
 472    ) -> proto::GetDefinitionResponse {
 473        let links = location_links_to_proto(response, project, peer_id, cx);
 474        proto::GetDefinitionResponse { links }
 475    }
 476
 477    async fn response_from_proto(
 478        self,
 479        message: proto::GetDefinitionResponse,
 480        project: ModelHandle<Project>,
 481        _: ModelHandle<Buffer>,
 482        cx: AsyncAppContext,
 483    ) -> Result<Vec<LocationLink>> {
 484        location_links_from_proto(message.links, project, cx).await
 485    }
 486
 487    fn buffer_id_from_proto(message: &proto::GetDefinition) -> u64 {
 488        message.buffer_id
 489    }
 490}
 491
 492#[async_trait(?Send)]
 493impl LspCommand for GetTypeDefinition {
 494    type Response = Vec<LocationLink>;
 495    type LspRequest = lsp::request::GotoTypeDefinition;
 496    type ProtoRequest = proto::GetTypeDefinition;
 497
 498    fn check_capabilities(&self, capabilities: &ServerCapabilities) -> bool {
 499        match &capabilities.type_definition_provider {
 500            None => false,
 501            Some(lsp::TypeDefinitionProviderCapability::Simple(false)) => false,
 502            _ => true,
 503        }
 504    }
 505
 506    fn to_lsp(
 507        &self,
 508        path: &Path,
 509        _: &Buffer,
 510        _: &Arc<LanguageServer>,
 511        _: &AppContext,
 512    ) -> lsp::GotoTypeDefinitionParams {
 513        lsp::GotoTypeDefinitionParams {
 514            text_document_position_params: lsp::TextDocumentPositionParams {
 515                text_document: lsp::TextDocumentIdentifier {
 516                    uri: lsp::Url::from_file_path(path).unwrap(),
 517                },
 518                position: point_to_lsp(self.position),
 519            },
 520            work_done_progress_params: Default::default(),
 521            partial_result_params: Default::default(),
 522        }
 523    }
 524
 525    async fn response_from_lsp(
 526        self,
 527        message: Option<lsp::GotoTypeDefinitionResponse>,
 528        project: ModelHandle<Project>,
 529        buffer: ModelHandle<Buffer>,
 530        server_id: LanguageServerId,
 531        cx: AsyncAppContext,
 532    ) -> Result<Vec<LocationLink>> {
 533        location_links_from_lsp(message, project, buffer, server_id, cx).await
 534    }
 535
 536    fn to_proto(&self, project_id: u64, buffer: &Buffer) -> proto::GetTypeDefinition {
 537        proto::GetTypeDefinition {
 538            project_id,
 539            buffer_id: buffer.remote_id(),
 540            position: Some(language::proto::serialize_anchor(
 541                &buffer.anchor_before(self.position),
 542            )),
 543            version: serialize_version(&buffer.version()),
 544        }
 545    }
 546
 547    async fn from_proto(
 548        message: proto::GetTypeDefinition,
 549        _: ModelHandle<Project>,
 550        buffer: ModelHandle<Buffer>,
 551        mut cx: AsyncAppContext,
 552    ) -> Result<Self> {
 553        let position = message
 554            .position
 555            .and_then(deserialize_anchor)
 556            .ok_or_else(|| anyhow!("invalid position"))?;
 557        buffer
 558            .update(&mut cx, |buffer, _| {
 559                buffer.wait_for_version(deserialize_version(&message.version))
 560            })
 561            .await?;
 562        Ok(Self {
 563            position: buffer.read_with(&cx, |buffer, _| position.to_point_utf16(buffer)),
 564        })
 565    }
 566
 567    fn response_to_proto(
 568        response: Vec<LocationLink>,
 569        project: &mut Project,
 570        peer_id: PeerId,
 571        _: &clock::Global,
 572        cx: &mut AppContext,
 573    ) -> proto::GetTypeDefinitionResponse {
 574        let links = location_links_to_proto(response, project, peer_id, cx);
 575        proto::GetTypeDefinitionResponse { links }
 576    }
 577
 578    async fn response_from_proto(
 579        self,
 580        message: proto::GetTypeDefinitionResponse,
 581        project: ModelHandle<Project>,
 582        _: ModelHandle<Buffer>,
 583        cx: AsyncAppContext,
 584    ) -> Result<Vec<LocationLink>> {
 585        location_links_from_proto(message.links, project, cx).await
 586    }
 587
 588    fn buffer_id_from_proto(message: &proto::GetTypeDefinition) -> u64 {
 589        message.buffer_id
 590    }
 591}
 592
 593fn language_server_for_buffer(
 594    project: &ModelHandle<Project>,
 595    buffer: &ModelHandle<Buffer>,
 596    server_id: LanguageServerId,
 597    cx: &mut AsyncAppContext,
 598) -> Result<(Arc<CachedLspAdapter>, Arc<LanguageServer>)> {
 599    project
 600        .read_with(cx, |project, cx| {
 601            project
 602                .language_server_for_buffer(buffer.read(cx), server_id, cx)
 603                .map(|(adapter, server)| (adapter.clone(), server.clone()))
 604        })
 605        .ok_or_else(|| anyhow!("no language server found for buffer"))
 606}
 607
 608async fn location_links_from_proto(
 609    proto_links: Vec<proto::LocationLink>,
 610    project: ModelHandle<Project>,
 611    mut cx: AsyncAppContext,
 612) -> Result<Vec<LocationLink>> {
 613    let mut links = Vec::new();
 614
 615    for link in proto_links {
 616        let origin = match link.origin {
 617            Some(origin) => {
 618                let buffer = project
 619                    .update(&mut cx, |this, cx| {
 620                        this.wait_for_remote_buffer(origin.buffer_id, cx)
 621                    })
 622                    .await?;
 623                let start = origin
 624                    .start
 625                    .and_then(deserialize_anchor)
 626                    .ok_or_else(|| anyhow!("missing origin start"))?;
 627                let end = origin
 628                    .end
 629                    .and_then(deserialize_anchor)
 630                    .ok_or_else(|| anyhow!("missing origin end"))?;
 631                buffer
 632                    .update(&mut cx, |buffer, _| buffer.wait_for_anchors([start, end]))
 633                    .await?;
 634                Some(Location {
 635                    buffer,
 636                    range: start..end,
 637                })
 638            }
 639            None => None,
 640        };
 641
 642        let target = link.target.ok_or_else(|| anyhow!("missing target"))?;
 643        let buffer = project
 644            .update(&mut cx, |this, cx| {
 645                this.wait_for_remote_buffer(target.buffer_id, cx)
 646            })
 647            .await?;
 648        let start = target
 649            .start
 650            .and_then(deserialize_anchor)
 651            .ok_or_else(|| anyhow!("missing target start"))?;
 652        let end = target
 653            .end
 654            .and_then(deserialize_anchor)
 655            .ok_or_else(|| anyhow!("missing target end"))?;
 656        buffer
 657            .update(&mut cx, |buffer, _| buffer.wait_for_anchors([start, end]))
 658            .await?;
 659        let target = Location {
 660            buffer,
 661            range: start..end,
 662        };
 663
 664        links.push(LocationLink { origin, target })
 665    }
 666
 667    Ok(links)
 668}
 669
 670async fn location_links_from_lsp(
 671    message: Option<lsp::GotoDefinitionResponse>,
 672    project: ModelHandle<Project>,
 673    buffer: ModelHandle<Buffer>,
 674    server_id: LanguageServerId,
 675    mut cx: AsyncAppContext,
 676) -> Result<Vec<LocationLink>> {
 677    let message = match message {
 678        Some(message) => message,
 679        None => return Ok(Vec::new()),
 680    };
 681
 682    let mut unresolved_links = Vec::new();
 683    match message {
 684        lsp::GotoDefinitionResponse::Scalar(loc) => {
 685            unresolved_links.push((None, loc.uri, loc.range));
 686        }
 687
 688        lsp::GotoDefinitionResponse::Array(locs) => {
 689            unresolved_links.extend(locs.into_iter().map(|l| (None, l.uri, l.range)));
 690        }
 691
 692        lsp::GotoDefinitionResponse::Link(links) => {
 693            unresolved_links.extend(links.into_iter().map(|l| {
 694                (
 695                    l.origin_selection_range,
 696                    l.target_uri,
 697                    l.target_selection_range,
 698                )
 699            }));
 700        }
 701    }
 702
 703    let (lsp_adapter, language_server) =
 704        language_server_for_buffer(&project, &buffer, server_id, &mut cx)?;
 705    let mut definitions = Vec::new();
 706    for (origin_range, target_uri, target_range) in unresolved_links {
 707        let target_buffer_handle = project
 708            .update(&mut cx, |this, cx| {
 709                this.open_local_buffer_via_lsp(
 710                    target_uri,
 711                    language_server.server_id(),
 712                    lsp_adapter.name.clone(),
 713                    cx,
 714                )
 715            })
 716            .await?;
 717
 718        cx.read(|cx| {
 719            let origin_location = origin_range.map(|origin_range| {
 720                let origin_buffer = buffer.read(cx);
 721                let origin_start =
 722                    origin_buffer.clip_point_utf16(point_from_lsp(origin_range.start), Bias::Left);
 723                let origin_end =
 724                    origin_buffer.clip_point_utf16(point_from_lsp(origin_range.end), Bias::Left);
 725                Location {
 726                    buffer: buffer.clone(),
 727                    range: origin_buffer.anchor_after(origin_start)
 728                        ..origin_buffer.anchor_before(origin_end),
 729                }
 730            });
 731
 732            let target_buffer = target_buffer_handle.read(cx);
 733            let target_start =
 734                target_buffer.clip_point_utf16(point_from_lsp(target_range.start), Bias::Left);
 735            let target_end =
 736                target_buffer.clip_point_utf16(point_from_lsp(target_range.end), Bias::Left);
 737            let target_location = Location {
 738                buffer: target_buffer_handle,
 739                range: target_buffer.anchor_after(target_start)
 740                    ..target_buffer.anchor_before(target_end),
 741            };
 742
 743            definitions.push(LocationLink {
 744                origin: origin_location,
 745                target: target_location,
 746            })
 747        });
 748    }
 749    Ok(definitions)
 750}
 751
 752fn location_links_to_proto(
 753    links: Vec<LocationLink>,
 754    project: &mut Project,
 755    peer_id: PeerId,
 756    cx: &mut AppContext,
 757) -> Vec<proto::LocationLink> {
 758    links
 759        .into_iter()
 760        .map(|definition| {
 761            let origin = definition.origin.map(|origin| {
 762                let buffer_id = project.create_buffer_for_peer(&origin.buffer, peer_id, cx);
 763                proto::Location {
 764                    start: Some(serialize_anchor(&origin.range.start)),
 765                    end: Some(serialize_anchor(&origin.range.end)),
 766                    buffer_id,
 767                }
 768            });
 769
 770            let buffer_id = project.create_buffer_for_peer(&definition.target.buffer, peer_id, cx);
 771            let target = proto::Location {
 772                start: Some(serialize_anchor(&definition.target.range.start)),
 773                end: Some(serialize_anchor(&definition.target.range.end)),
 774                buffer_id,
 775            };
 776
 777            proto::LocationLink {
 778                origin,
 779                target: Some(target),
 780            }
 781        })
 782        .collect()
 783}
 784
 785#[async_trait(?Send)]
 786impl LspCommand for GetReferences {
 787    type Response = Vec<Location>;
 788    type LspRequest = lsp::request::References;
 789    type ProtoRequest = proto::GetReferences;
 790
 791    fn to_lsp(
 792        &self,
 793        path: &Path,
 794        _: &Buffer,
 795        _: &Arc<LanguageServer>,
 796        _: &AppContext,
 797    ) -> lsp::ReferenceParams {
 798        lsp::ReferenceParams {
 799            text_document_position: lsp::TextDocumentPositionParams {
 800                text_document: lsp::TextDocumentIdentifier {
 801                    uri: lsp::Url::from_file_path(path).unwrap(),
 802                },
 803                position: point_to_lsp(self.position),
 804            },
 805            work_done_progress_params: Default::default(),
 806            partial_result_params: Default::default(),
 807            context: lsp::ReferenceContext {
 808                include_declaration: true,
 809            },
 810        }
 811    }
 812
 813    async fn response_from_lsp(
 814        self,
 815        locations: Option<Vec<lsp::Location>>,
 816        project: ModelHandle<Project>,
 817        buffer: ModelHandle<Buffer>,
 818        server_id: LanguageServerId,
 819        mut cx: AsyncAppContext,
 820    ) -> Result<Vec<Location>> {
 821        let mut references = Vec::new();
 822        let (lsp_adapter, language_server) =
 823            language_server_for_buffer(&project, &buffer, server_id, &mut cx)?;
 824
 825        if let Some(locations) = locations {
 826            for lsp_location in locations {
 827                let target_buffer_handle = project
 828                    .update(&mut cx, |this, cx| {
 829                        this.open_local_buffer_via_lsp(
 830                            lsp_location.uri,
 831                            language_server.server_id(),
 832                            lsp_adapter.name.clone(),
 833                            cx,
 834                        )
 835                    })
 836                    .await?;
 837
 838                cx.read(|cx| {
 839                    let target_buffer = target_buffer_handle.read(cx);
 840                    let target_start = target_buffer
 841                        .clip_point_utf16(point_from_lsp(lsp_location.range.start), Bias::Left);
 842                    let target_end = target_buffer
 843                        .clip_point_utf16(point_from_lsp(lsp_location.range.end), Bias::Left);
 844                    references.push(Location {
 845                        buffer: target_buffer_handle,
 846                        range: target_buffer.anchor_after(target_start)
 847                            ..target_buffer.anchor_before(target_end),
 848                    });
 849                });
 850            }
 851        }
 852
 853        Ok(references)
 854    }
 855
 856    fn to_proto(&self, project_id: u64, buffer: &Buffer) -> proto::GetReferences {
 857        proto::GetReferences {
 858            project_id,
 859            buffer_id: buffer.remote_id(),
 860            position: Some(language::proto::serialize_anchor(
 861                &buffer.anchor_before(self.position),
 862            )),
 863            version: serialize_version(&buffer.version()),
 864        }
 865    }
 866
 867    async fn from_proto(
 868        message: proto::GetReferences,
 869        _: ModelHandle<Project>,
 870        buffer: ModelHandle<Buffer>,
 871        mut cx: AsyncAppContext,
 872    ) -> Result<Self> {
 873        let position = message
 874            .position
 875            .and_then(deserialize_anchor)
 876            .ok_or_else(|| anyhow!("invalid position"))?;
 877        buffer
 878            .update(&mut cx, |buffer, _| {
 879                buffer.wait_for_version(deserialize_version(&message.version))
 880            })
 881            .await?;
 882        Ok(Self {
 883            position: buffer.read_with(&cx, |buffer, _| position.to_point_utf16(buffer)),
 884        })
 885    }
 886
 887    fn response_to_proto(
 888        response: Vec<Location>,
 889        project: &mut Project,
 890        peer_id: PeerId,
 891        _: &clock::Global,
 892        cx: &mut AppContext,
 893    ) -> proto::GetReferencesResponse {
 894        let locations = response
 895            .into_iter()
 896            .map(|definition| {
 897                let buffer_id = project.create_buffer_for_peer(&definition.buffer, peer_id, cx);
 898                proto::Location {
 899                    start: Some(serialize_anchor(&definition.range.start)),
 900                    end: Some(serialize_anchor(&definition.range.end)),
 901                    buffer_id,
 902                }
 903            })
 904            .collect();
 905        proto::GetReferencesResponse { locations }
 906    }
 907
 908    async fn response_from_proto(
 909        self,
 910        message: proto::GetReferencesResponse,
 911        project: ModelHandle<Project>,
 912        _: ModelHandle<Buffer>,
 913        mut cx: AsyncAppContext,
 914    ) -> Result<Vec<Location>> {
 915        let mut locations = Vec::new();
 916        for location in message.locations {
 917            let target_buffer = project
 918                .update(&mut cx, |this, cx| {
 919                    this.wait_for_remote_buffer(location.buffer_id, cx)
 920                })
 921                .await?;
 922            let start = location
 923                .start
 924                .and_then(deserialize_anchor)
 925                .ok_or_else(|| anyhow!("missing target start"))?;
 926            let end = location
 927                .end
 928                .and_then(deserialize_anchor)
 929                .ok_or_else(|| anyhow!("missing target end"))?;
 930            target_buffer
 931                .update(&mut cx, |buffer, _| buffer.wait_for_anchors([start, end]))
 932                .await?;
 933            locations.push(Location {
 934                buffer: target_buffer,
 935                range: start..end,
 936            })
 937        }
 938        Ok(locations)
 939    }
 940
 941    fn buffer_id_from_proto(message: &proto::GetReferences) -> u64 {
 942        message.buffer_id
 943    }
 944}
 945
 946#[async_trait(?Send)]
 947impl LspCommand for GetDocumentHighlights {
 948    type Response = Vec<DocumentHighlight>;
 949    type LspRequest = lsp::request::DocumentHighlightRequest;
 950    type ProtoRequest = proto::GetDocumentHighlights;
 951
 952    fn check_capabilities(&self, capabilities: &ServerCapabilities) -> bool {
 953        capabilities.document_highlight_provider.is_some()
 954    }
 955
 956    fn to_lsp(
 957        &self,
 958        path: &Path,
 959        _: &Buffer,
 960        _: &Arc<LanguageServer>,
 961        _: &AppContext,
 962    ) -> lsp::DocumentHighlightParams {
 963        lsp::DocumentHighlightParams {
 964            text_document_position_params: lsp::TextDocumentPositionParams {
 965                text_document: lsp::TextDocumentIdentifier {
 966                    uri: lsp::Url::from_file_path(path).unwrap(),
 967                },
 968                position: point_to_lsp(self.position),
 969            },
 970            work_done_progress_params: Default::default(),
 971            partial_result_params: Default::default(),
 972        }
 973    }
 974
 975    async fn response_from_lsp(
 976        self,
 977        lsp_highlights: Option<Vec<lsp::DocumentHighlight>>,
 978        _: ModelHandle<Project>,
 979        buffer: ModelHandle<Buffer>,
 980        _: LanguageServerId,
 981        cx: AsyncAppContext,
 982    ) -> Result<Vec<DocumentHighlight>> {
 983        buffer.read_with(&cx, |buffer, _| {
 984            let mut lsp_highlights = lsp_highlights.unwrap_or_default();
 985            lsp_highlights.sort_unstable_by_key(|h| (h.range.start, Reverse(h.range.end)));
 986            Ok(lsp_highlights
 987                .into_iter()
 988                .map(|lsp_highlight| {
 989                    let start = buffer
 990                        .clip_point_utf16(point_from_lsp(lsp_highlight.range.start), Bias::Left);
 991                    let end = buffer
 992                        .clip_point_utf16(point_from_lsp(lsp_highlight.range.end), Bias::Left);
 993                    DocumentHighlight {
 994                        range: buffer.anchor_after(start)..buffer.anchor_before(end),
 995                        kind: lsp_highlight
 996                            .kind
 997                            .unwrap_or(lsp::DocumentHighlightKind::READ),
 998                    }
 999                })
1000                .collect())
1001        })
1002    }
1003
1004    fn to_proto(&self, project_id: u64, buffer: &Buffer) -> proto::GetDocumentHighlights {
1005        proto::GetDocumentHighlights {
1006            project_id,
1007            buffer_id: buffer.remote_id(),
1008            position: Some(language::proto::serialize_anchor(
1009                &buffer.anchor_before(self.position),
1010            )),
1011            version: serialize_version(&buffer.version()),
1012        }
1013    }
1014
1015    async fn from_proto(
1016        message: proto::GetDocumentHighlights,
1017        _: ModelHandle<Project>,
1018        buffer: ModelHandle<Buffer>,
1019        mut cx: AsyncAppContext,
1020    ) -> Result<Self> {
1021        let position = message
1022            .position
1023            .and_then(deserialize_anchor)
1024            .ok_or_else(|| anyhow!("invalid position"))?;
1025        buffer
1026            .update(&mut cx, |buffer, _| {
1027                buffer.wait_for_version(deserialize_version(&message.version))
1028            })
1029            .await?;
1030        Ok(Self {
1031            position: buffer.read_with(&cx, |buffer, _| position.to_point_utf16(buffer)),
1032        })
1033    }
1034
1035    fn response_to_proto(
1036        response: Vec<DocumentHighlight>,
1037        _: &mut Project,
1038        _: PeerId,
1039        _: &clock::Global,
1040        _: &mut AppContext,
1041    ) -> proto::GetDocumentHighlightsResponse {
1042        let highlights = response
1043            .into_iter()
1044            .map(|highlight| proto::DocumentHighlight {
1045                start: Some(serialize_anchor(&highlight.range.start)),
1046                end: Some(serialize_anchor(&highlight.range.end)),
1047                kind: match highlight.kind {
1048                    DocumentHighlightKind::TEXT => proto::document_highlight::Kind::Text.into(),
1049                    DocumentHighlightKind::WRITE => proto::document_highlight::Kind::Write.into(),
1050                    DocumentHighlightKind::READ => proto::document_highlight::Kind::Read.into(),
1051                    _ => proto::document_highlight::Kind::Text.into(),
1052                },
1053            })
1054            .collect();
1055        proto::GetDocumentHighlightsResponse { highlights }
1056    }
1057
1058    async fn response_from_proto(
1059        self,
1060        message: proto::GetDocumentHighlightsResponse,
1061        _: ModelHandle<Project>,
1062        buffer: ModelHandle<Buffer>,
1063        mut cx: AsyncAppContext,
1064    ) -> Result<Vec<DocumentHighlight>> {
1065        let mut highlights = Vec::new();
1066        for highlight in message.highlights {
1067            let start = highlight
1068                .start
1069                .and_then(deserialize_anchor)
1070                .ok_or_else(|| anyhow!("missing target start"))?;
1071            let end = highlight
1072                .end
1073                .and_then(deserialize_anchor)
1074                .ok_or_else(|| anyhow!("missing target end"))?;
1075            buffer
1076                .update(&mut cx, |buffer, _| buffer.wait_for_anchors([start, end]))
1077                .await?;
1078            let kind = match proto::document_highlight::Kind::from_i32(highlight.kind) {
1079                Some(proto::document_highlight::Kind::Text) => DocumentHighlightKind::TEXT,
1080                Some(proto::document_highlight::Kind::Read) => DocumentHighlightKind::READ,
1081                Some(proto::document_highlight::Kind::Write) => DocumentHighlightKind::WRITE,
1082                None => DocumentHighlightKind::TEXT,
1083            };
1084            highlights.push(DocumentHighlight {
1085                range: start..end,
1086                kind,
1087            });
1088        }
1089        Ok(highlights)
1090    }
1091
1092    fn buffer_id_from_proto(message: &proto::GetDocumentHighlights) -> u64 {
1093        message.buffer_id
1094    }
1095}
1096
1097#[async_trait(?Send)]
1098impl LspCommand for GetHover {
1099    type Response = Option<Hover>;
1100    type LspRequest = lsp::request::HoverRequest;
1101    type ProtoRequest = proto::GetHover;
1102
1103    fn to_lsp(
1104        &self,
1105        path: &Path,
1106        _: &Buffer,
1107        _: &Arc<LanguageServer>,
1108        _: &AppContext,
1109    ) -> lsp::HoverParams {
1110        lsp::HoverParams {
1111            text_document_position_params: lsp::TextDocumentPositionParams {
1112                text_document: lsp::TextDocumentIdentifier {
1113                    uri: lsp::Url::from_file_path(path).unwrap(),
1114                },
1115                position: point_to_lsp(self.position),
1116            },
1117            work_done_progress_params: Default::default(),
1118        }
1119    }
1120
1121    async fn response_from_lsp(
1122        self,
1123        message: Option<lsp::Hover>,
1124        _: ModelHandle<Project>,
1125        buffer: ModelHandle<Buffer>,
1126        _: LanguageServerId,
1127        cx: AsyncAppContext,
1128    ) -> Result<Self::Response> {
1129        Ok(message.and_then(|hover| {
1130            let (language, range) = cx.read(|cx| {
1131                let buffer = buffer.read(cx);
1132                (
1133                    buffer.language().cloned(),
1134                    hover.range.map(|range| {
1135                        let token_start =
1136                            buffer.clip_point_utf16(point_from_lsp(range.start), Bias::Left);
1137                        let token_end =
1138                            buffer.clip_point_utf16(point_from_lsp(range.end), Bias::Left);
1139                        buffer.anchor_after(token_start)..buffer.anchor_before(token_end)
1140                    }),
1141                )
1142            });
1143
1144            fn hover_blocks_from_marked_string(
1145                marked_string: lsp::MarkedString,
1146            ) -> Option<HoverBlock> {
1147                let block = match marked_string {
1148                    lsp::MarkedString::String(content) => HoverBlock {
1149                        text: content,
1150                        kind: HoverBlockKind::Markdown,
1151                    },
1152                    lsp::MarkedString::LanguageString(lsp::LanguageString { language, value }) => {
1153                        HoverBlock {
1154                            text: value,
1155                            kind: HoverBlockKind::Code { language },
1156                        }
1157                    }
1158                };
1159                if block.text.is_empty() {
1160                    None
1161                } else {
1162                    Some(block)
1163                }
1164            }
1165
1166            let contents = cx.read(|_| match hover.contents {
1167                lsp::HoverContents::Scalar(marked_string) => {
1168                    hover_blocks_from_marked_string(marked_string)
1169                        .into_iter()
1170                        .collect()
1171                }
1172                lsp::HoverContents::Array(marked_strings) => marked_strings
1173                    .into_iter()
1174                    .filter_map(hover_blocks_from_marked_string)
1175                    .collect(),
1176                lsp::HoverContents::Markup(markup_content) => vec![HoverBlock {
1177                    text: markup_content.value,
1178                    kind: if markup_content.kind == lsp::MarkupKind::Markdown {
1179                        HoverBlockKind::Markdown
1180                    } else {
1181                        HoverBlockKind::PlainText
1182                    },
1183                }],
1184            });
1185
1186            Some(Hover {
1187                contents,
1188                range,
1189                language,
1190            })
1191        }))
1192    }
1193
1194    fn to_proto(&self, project_id: u64, buffer: &Buffer) -> Self::ProtoRequest {
1195        proto::GetHover {
1196            project_id,
1197            buffer_id: buffer.remote_id(),
1198            position: Some(language::proto::serialize_anchor(
1199                &buffer.anchor_before(self.position),
1200            )),
1201            version: serialize_version(&buffer.version),
1202        }
1203    }
1204
1205    async fn from_proto(
1206        message: Self::ProtoRequest,
1207        _: ModelHandle<Project>,
1208        buffer: ModelHandle<Buffer>,
1209        mut cx: AsyncAppContext,
1210    ) -> Result<Self> {
1211        let position = message
1212            .position
1213            .and_then(deserialize_anchor)
1214            .ok_or_else(|| anyhow!("invalid position"))?;
1215        buffer
1216            .update(&mut cx, |buffer, _| {
1217                buffer.wait_for_version(deserialize_version(&message.version))
1218            })
1219            .await?;
1220        Ok(Self {
1221            position: buffer.read_with(&cx, |buffer, _| position.to_point_utf16(buffer)),
1222        })
1223    }
1224
1225    fn response_to_proto(
1226        response: Self::Response,
1227        _: &mut Project,
1228        _: PeerId,
1229        _: &clock::Global,
1230        _: &mut AppContext,
1231    ) -> proto::GetHoverResponse {
1232        if let Some(response) = response {
1233            let (start, end) = if let Some(range) = response.range {
1234                (
1235                    Some(language::proto::serialize_anchor(&range.start)),
1236                    Some(language::proto::serialize_anchor(&range.end)),
1237                )
1238            } else {
1239                (None, None)
1240            };
1241
1242            let contents = response
1243                .contents
1244                .into_iter()
1245                .map(|block| proto::HoverBlock {
1246                    text: block.text,
1247                    is_markdown: block.kind == HoverBlockKind::Markdown,
1248                    language: if let HoverBlockKind::Code { language } = block.kind {
1249                        Some(language)
1250                    } else {
1251                        None
1252                    },
1253                })
1254                .collect();
1255
1256            proto::GetHoverResponse {
1257                start,
1258                end,
1259                contents,
1260            }
1261        } else {
1262            proto::GetHoverResponse {
1263                start: None,
1264                end: None,
1265                contents: Vec::new(),
1266            }
1267        }
1268    }
1269
1270    async fn response_from_proto(
1271        self,
1272        message: proto::GetHoverResponse,
1273        _: ModelHandle<Project>,
1274        buffer: ModelHandle<Buffer>,
1275        cx: AsyncAppContext,
1276    ) -> Result<Self::Response> {
1277        let contents: Vec<_> = message
1278            .contents
1279            .into_iter()
1280            .map(|block| HoverBlock {
1281                text: block.text,
1282                kind: if let Some(language) = block.language {
1283                    HoverBlockKind::Code { language }
1284                } else if block.is_markdown {
1285                    HoverBlockKind::Markdown
1286                } else {
1287                    HoverBlockKind::PlainText
1288                },
1289            })
1290            .collect();
1291        if contents.is_empty() {
1292            return Ok(None);
1293        }
1294
1295        let language = buffer.read_with(&cx, |buffer, _| buffer.language().cloned());
1296        let range = if let (Some(start), Some(end)) = (message.start, message.end) {
1297            language::proto::deserialize_anchor(start)
1298                .and_then(|start| language::proto::deserialize_anchor(end).map(|end| start..end))
1299        } else {
1300            None
1301        };
1302
1303        Ok(Some(Hover {
1304            contents,
1305            range,
1306            language,
1307        }))
1308    }
1309
1310    fn buffer_id_from_proto(message: &Self::ProtoRequest) -> u64 {
1311        message.buffer_id
1312    }
1313}
1314
1315#[async_trait(?Send)]
1316impl LspCommand for GetCompletions {
1317    type Response = Vec<Completion>;
1318    type LspRequest = lsp::request::Completion;
1319    type ProtoRequest = proto::GetCompletions;
1320
1321    fn to_lsp(
1322        &self,
1323        path: &Path,
1324        _: &Buffer,
1325        _: &Arc<LanguageServer>,
1326        _: &AppContext,
1327    ) -> lsp::CompletionParams {
1328        lsp::CompletionParams {
1329            text_document_position: lsp::TextDocumentPositionParams::new(
1330                lsp::TextDocumentIdentifier::new(lsp::Url::from_file_path(path).unwrap()),
1331                point_to_lsp(self.position),
1332            ),
1333            context: Default::default(),
1334            work_done_progress_params: Default::default(),
1335            partial_result_params: Default::default(),
1336        }
1337    }
1338
1339    async fn response_from_lsp(
1340        self,
1341        completions: Option<lsp::CompletionResponse>,
1342        _: ModelHandle<Project>,
1343        buffer: ModelHandle<Buffer>,
1344        server_id: LanguageServerId,
1345        cx: AsyncAppContext,
1346    ) -> Result<Vec<Completion>> {
1347        let mut response_list = None;
1348        let completions = if let Some(completions) = completions {
1349            match completions {
1350                lsp::CompletionResponse::Array(completions) => completions,
1351
1352                lsp::CompletionResponse::List(mut list) => {
1353                    let items = std::mem::take(&mut list.items);
1354                    response_list = Some(list);
1355                    items
1356                }
1357            }
1358        } else {
1359            Default::default()
1360        };
1361
1362        let completions = buffer.read_with(&cx, |buffer, _| {
1363            let language = buffer.language().cloned();
1364            let snapshot = buffer.snapshot();
1365            let clipped_position = buffer.clip_point_utf16(Unclipped(self.position), Bias::Left);
1366
1367            let mut range_for_token = None;
1368            completions
1369                .into_iter()
1370                .filter_map(move |mut lsp_completion| {
1371                    let (old_range, mut new_text) = match lsp_completion.text_edit.as_ref() {
1372                        // If the language server provides a range to overwrite, then
1373                        // check that the range is valid.
1374                        Some(lsp::CompletionTextEdit::Edit(edit)) => {
1375                            let range = range_from_lsp(edit.range);
1376                            let start = snapshot.clip_point_utf16(range.start, Bias::Left);
1377                            let end = snapshot.clip_point_utf16(range.end, Bias::Left);
1378                            if start != range.start.0 || end != range.end.0 {
1379                                log::info!("completion out of expected range");
1380                                return None;
1381                            }
1382                            (
1383                                snapshot.anchor_before(start)..snapshot.anchor_after(end),
1384                                edit.new_text.clone(),
1385                            )
1386                        }
1387
1388                        // If the language server does not provide a range, then infer
1389                        // the range based on the syntax tree.
1390                        None => {
1391                            if self.position != clipped_position {
1392                                log::info!("completion out of expected range");
1393                                return None;
1394                            }
1395
1396                            let default_edit_range = response_list
1397                                .as_ref()
1398                                .and_then(|list| list.item_defaults.as_ref())
1399                                .and_then(|defaults| defaults.edit_range.as_ref())
1400                                .and_then(|range| match range {
1401                                    CompletionListItemDefaultsEditRange::Range(r) => Some(r),
1402                                    _ => None,
1403                                });
1404
1405                            let range = if let Some(range) = default_edit_range {
1406                                let range = range_from_lsp(range.clone());
1407                                let start = snapshot.clip_point_utf16(range.start, Bias::Left);
1408                                let end = snapshot.clip_point_utf16(range.end, Bias::Left);
1409                                if start != range.start.0 || end != range.end.0 {
1410                                    log::info!("completion out of expected range");
1411                                    return None;
1412                                }
1413
1414                                snapshot.anchor_before(start)..snapshot.anchor_after(end)
1415                            } else {
1416                                range_for_token
1417                                    .get_or_insert_with(|| {
1418                                        let offset = self.position.to_offset(&snapshot);
1419                                        let (range, kind) = snapshot.surrounding_word(offset);
1420                                        let range = if kind == Some(CharKind::Word) {
1421                                            range
1422                                        } else {
1423                                            offset..offset
1424                                        };
1425
1426                                        snapshot.anchor_before(range.start)
1427                                            ..snapshot.anchor_after(range.end)
1428                                    })
1429                                    .clone()
1430                            };
1431
1432                            let text = lsp_completion
1433                                .insert_text
1434                                .as_ref()
1435                                .unwrap_or(&lsp_completion.label)
1436                                .clone();
1437                            (range, text)
1438                        }
1439
1440                        Some(lsp::CompletionTextEdit::InsertAndReplace(_)) => {
1441                            log::info!("unsupported insert/replace completion");
1442                            return None;
1443                        }
1444                    };
1445
1446                    let language = language.clone();
1447                    LineEnding::normalize(&mut new_text);
1448                    Some(async move {
1449                        let mut label = None;
1450                        if let Some(language) = language {
1451                            language.process_completion(&mut lsp_completion).await;
1452                            label = language.label_for_completion(&lsp_completion).await;
1453                        }
1454                        Completion {
1455                            old_range,
1456                            new_text,
1457                            label: label.unwrap_or_else(|| {
1458                                language::CodeLabel::plain(
1459                                    lsp_completion.label.clone(),
1460                                    lsp_completion.filter_text.as_deref(),
1461                                )
1462                            }),
1463                            server_id,
1464                            lsp_completion,
1465                        }
1466                    })
1467                })
1468        });
1469
1470        Ok(futures::future::join_all(completions).await)
1471    }
1472
1473    fn to_proto(&self, project_id: u64, buffer: &Buffer) -> proto::GetCompletions {
1474        let anchor = buffer.anchor_after(self.position);
1475        proto::GetCompletions {
1476            project_id,
1477            buffer_id: buffer.remote_id(),
1478            position: Some(language::proto::serialize_anchor(&anchor)),
1479            version: serialize_version(&buffer.version()),
1480        }
1481    }
1482
1483    async fn from_proto(
1484        message: proto::GetCompletions,
1485        _: ModelHandle<Project>,
1486        buffer: ModelHandle<Buffer>,
1487        mut cx: AsyncAppContext,
1488    ) -> Result<Self> {
1489        let version = deserialize_version(&message.version);
1490        buffer
1491            .update(&mut cx, |buffer, _| buffer.wait_for_version(version))
1492            .await?;
1493        let position = message
1494            .position
1495            .and_then(language::proto::deserialize_anchor)
1496            .map(|p| {
1497                buffer.read_with(&cx, |buffer, _| {
1498                    buffer.clip_point_utf16(Unclipped(p.to_point_utf16(buffer)), Bias::Left)
1499                })
1500            })
1501            .ok_or_else(|| anyhow!("invalid position"))?;
1502        Ok(Self { position })
1503    }
1504
1505    fn response_to_proto(
1506        completions: Vec<Completion>,
1507        _: &mut Project,
1508        _: PeerId,
1509        buffer_version: &clock::Global,
1510        _: &mut AppContext,
1511    ) -> proto::GetCompletionsResponse {
1512        proto::GetCompletionsResponse {
1513            completions: completions
1514                .iter()
1515                .map(language::proto::serialize_completion)
1516                .collect(),
1517            version: serialize_version(&buffer_version),
1518        }
1519    }
1520
1521    async fn response_from_proto(
1522        self,
1523        message: proto::GetCompletionsResponse,
1524        _: ModelHandle<Project>,
1525        buffer: ModelHandle<Buffer>,
1526        mut cx: AsyncAppContext,
1527    ) -> Result<Vec<Completion>> {
1528        buffer
1529            .update(&mut cx, |buffer, _| {
1530                buffer.wait_for_version(deserialize_version(&message.version))
1531            })
1532            .await?;
1533
1534        let language = buffer.read_with(&cx, |buffer, _| buffer.language().cloned());
1535        let completions = message.completions.into_iter().map(|completion| {
1536            language::proto::deserialize_completion(completion, language.clone())
1537        });
1538        futures::future::try_join_all(completions).await
1539    }
1540
1541    fn buffer_id_from_proto(message: &proto::GetCompletions) -> u64 {
1542        message.buffer_id
1543    }
1544}
1545
1546#[async_trait(?Send)]
1547impl LspCommand for GetCodeActions {
1548    type Response = Vec<CodeAction>;
1549    type LspRequest = lsp::request::CodeActionRequest;
1550    type ProtoRequest = proto::GetCodeActions;
1551
1552    fn check_capabilities(&self, capabilities: &ServerCapabilities) -> bool {
1553        match &capabilities.code_action_provider {
1554            None => false,
1555            Some(lsp::CodeActionProviderCapability::Simple(false)) => false,
1556            _ => true,
1557        }
1558    }
1559
1560    fn to_lsp(
1561        &self,
1562        path: &Path,
1563        buffer: &Buffer,
1564        language_server: &Arc<LanguageServer>,
1565        _: &AppContext,
1566    ) -> lsp::CodeActionParams {
1567        let relevant_diagnostics = buffer
1568            .snapshot()
1569            .diagnostics_in_range::<_, usize>(self.range.clone(), false)
1570            .map(|entry| entry.to_lsp_diagnostic_stub())
1571            .collect();
1572        lsp::CodeActionParams {
1573            text_document: lsp::TextDocumentIdentifier::new(
1574                lsp::Url::from_file_path(path).unwrap(),
1575            ),
1576            range: range_to_lsp(self.range.to_point_utf16(buffer)),
1577            work_done_progress_params: Default::default(),
1578            partial_result_params: Default::default(),
1579            context: lsp::CodeActionContext {
1580                diagnostics: relevant_diagnostics,
1581                only: language_server.code_action_kinds(),
1582                ..lsp::CodeActionContext::default()
1583            },
1584        }
1585    }
1586
1587    async fn response_from_lsp(
1588        self,
1589        actions: Option<lsp::CodeActionResponse>,
1590        _: ModelHandle<Project>,
1591        _: ModelHandle<Buffer>,
1592        server_id: LanguageServerId,
1593        _: AsyncAppContext,
1594    ) -> Result<Vec<CodeAction>> {
1595        Ok(actions
1596            .unwrap_or_default()
1597            .into_iter()
1598            .filter_map(|entry| {
1599                if let lsp::CodeActionOrCommand::CodeAction(lsp_action) = entry {
1600                    Some(CodeAction {
1601                        server_id,
1602                        range: self.range.clone(),
1603                        lsp_action,
1604                    })
1605                } else {
1606                    None
1607                }
1608            })
1609            .collect())
1610    }
1611
1612    fn to_proto(&self, project_id: u64, buffer: &Buffer) -> proto::GetCodeActions {
1613        proto::GetCodeActions {
1614            project_id,
1615            buffer_id: buffer.remote_id(),
1616            start: Some(language::proto::serialize_anchor(&self.range.start)),
1617            end: Some(language::proto::serialize_anchor(&self.range.end)),
1618            version: serialize_version(&buffer.version()),
1619        }
1620    }
1621
1622    async fn from_proto(
1623        message: proto::GetCodeActions,
1624        _: ModelHandle<Project>,
1625        buffer: ModelHandle<Buffer>,
1626        mut cx: AsyncAppContext,
1627    ) -> Result<Self> {
1628        let start = message
1629            .start
1630            .and_then(language::proto::deserialize_anchor)
1631            .ok_or_else(|| anyhow!("invalid start"))?;
1632        let end = message
1633            .end
1634            .and_then(language::proto::deserialize_anchor)
1635            .ok_or_else(|| anyhow!("invalid end"))?;
1636        buffer
1637            .update(&mut cx, |buffer, _| {
1638                buffer.wait_for_version(deserialize_version(&message.version))
1639            })
1640            .await?;
1641
1642        Ok(Self { range: start..end })
1643    }
1644
1645    fn response_to_proto(
1646        code_actions: Vec<CodeAction>,
1647        _: &mut Project,
1648        _: PeerId,
1649        buffer_version: &clock::Global,
1650        _: &mut AppContext,
1651    ) -> proto::GetCodeActionsResponse {
1652        proto::GetCodeActionsResponse {
1653            actions: code_actions
1654                .iter()
1655                .map(language::proto::serialize_code_action)
1656                .collect(),
1657            version: serialize_version(&buffer_version),
1658        }
1659    }
1660
1661    async fn response_from_proto(
1662        self,
1663        message: proto::GetCodeActionsResponse,
1664        _: ModelHandle<Project>,
1665        buffer: ModelHandle<Buffer>,
1666        mut cx: AsyncAppContext,
1667    ) -> Result<Vec<CodeAction>> {
1668        buffer
1669            .update(&mut cx, |buffer, _| {
1670                buffer.wait_for_version(deserialize_version(&message.version))
1671            })
1672            .await?;
1673        message
1674            .actions
1675            .into_iter()
1676            .map(language::proto::deserialize_code_action)
1677            .collect()
1678    }
1679
1680    fn buffer_id_from_proto(message: &proto::GetCodeActions) -> u64 {
1681        message.buffer_id
1682    }
1683}
1684
1685#[async_trait(?Send)]
1686impl LspCommand for OnTypeFormatting {
1687    type Response = Option<Transaction>;
1688    type LspRequest = lsp::request::OnTypeFormatting;
1689    type ProtoRequest = proto::OnTypeFormatting;
1690
1691    fn check_capabilities(&self, server_capabilities: &lsp::ServerCapabilities) -> bool {
1692        let Some(on_type_formatting_options) = &server_capabilities.document_on_type_formatting_provider else { return false };
1693        on_type_formatting_options
1694            .first_trigger_character
1695            .contains(&self.trigger)
1696            || on_type_formatting_options
1697                .more_trigger_character
1698                .iter()
1699                .flatten()
1700                .any(|chars| chars.contains(&self.trigger))
1701    }
1702
1703    fn to_lsp(
1704        &self,
1705        path: &Path,
1706        _: &Buffer,
1707        _: &Arc<LanguageServer>,
1708        _: &AppContext,
1709    ) -> lsp::DocumentOnTypeFormattingParams {
1710        lsp::DocumentOnTypeFormattingParams {
1711            text_document_position: lsp::TextDocumentPositionParams::new(
1712                lsp::TextDocumentIdentifier::new(lsp::Url::from_file_path(path).unwrap()),
1713                point_to_lsp(self.position),
1714            ),
1715            ch: self.trigger.clone(),
1716            options: lsp_formatting_options(self.options.tab_size),
1717        }
1718    }
1719
1720    async fn response_from_lsp(
1721        self,
1722        message: Option<Vec<lsp::TextEdit>>,
1723        project: ModelHandle<Project>,
1724        buffer: ModelHandle<Buffer>,
1725        server_id: LanguageServerId,
1726        mut cx: AsyncAppContext,
1727    ) -> Result<Option<Transaction>> {
1728        if let Some(edits) = message {
1729            let (lsp_adapter, lsp_server) =
1730                language_server_for_buffer(&project, &buffer, server_id, &mut cx)?;
1731            Project::deserialize_edits(
1732                project,
1733                buffer,
1734                edits,
1735                self.push_to_history,
1736                lsp_adapter,
1737                lsp_server,
1738                &mut cx,
1739            )
1740            .await
1741        } else {
1742            Ok(None)
1743        }
1744    }
1745
1746    fn to_proto(&self, project_id: u64, buffer: &Buffer) -> proto::OnTypeFormatting {
1747        proto::OnTypeFormatting {
1748            project_id,
1749            buffer_id: buffer.remote_id(),
1750            position: Some(language::proto::serialize_anchor(
1751                &buffer.anchor_before(self.position),
1752            )),
1753            trigger: self.trigger.clone(),
1754            version: serialize_version(&buffer.version()),
1755        }
1756    }
1757
1758    async fn from_proto(
1759        message: proto::OnTypeFormatting,
1760        _: ModelHandle<Project>,
1761        buffer: ModelHandle<Buffer>,
1762        mut cx: AsyncAppContext,
1763    ) -> Result<Self> {
1764        let position = message
1765            .position
1766            .and_then(deserialize_anchor)
1767            .ok_or_else(|| anyhow!("invalid position"))?;
1768        buffer
1769            .update(&mut cx, |buffer, _| {
1770                buffer.wait_for_version(deserialize_version(&message.version))
1771            })
1772            .await?;
1773
1774        let tab_size = buffer.read_with(&cx, |buffer, cx| {
1775            language_settings(buffer.language(), buffer.file(), cx).tab_size
1776        });
1777
1778        Ok(Self {
1779            position: buffer.read_with(&cx, |buffer, _| position.to_point_utf16(buffer)),
1780            trigger: message.trigger.clone(),
1781            options: lsp_formatting_options(tab_size.get()).into(),
1782            push_to_history: false,
1783        })
1784    }
1785
1786    fn response_to_proto(
1787        response: Option<Transaction>,
1788        _: &mut Project,
1789        _: PeerId,
1790        _: &clock::Global,
1791        _: &mut AppContext,
1792    ) -> proto::OnTypeFormattingResponse {
1793        proto::OnTypeFormattingResponse {
1794            transaction: response
1795                .map(|transaction| language::proto::serialize_transaction(&transaction)),
1796        }
1797    }
1798
1799    async fn response_from_proto(
1800        self,
1801        message: proto::OnTypeFormattingResponse,
1802        _: ModelHandle<Project>,
1803        _: ModelHandle<Buffer>,
1804        _: AsyncAppContext,
1805    ) -> Result<Option<Transaction>> {
1806        let Some(transaction) = message.transaction else { return Ok(None) };
1807        Ok(Some(language::proto::deserialize_transaction(transaction)?))
1808    }
1809
1810    fn buffer_id_from_proto(message: &proto::OnTypeFormatting) -> u64 {
1811        message.buffer_id
1812    }
1813}
1814
1815#[async_trait(?Send)]
1816impl LspCommand for InlayHints {
1817    type Response = Vec<InlayHint>;
1818    type LspRequest = lsp::InlayHintRequest;
1819    type ProtoRequest = proto::InlayHints;
1820
1821    fn check_capabilities(&self, server_capabilities: &lsp::ServerCapabilities) -> bool {
1822        let Some(inlay_hint_provider) = &server_capabilities.inlay_hint_provider else { return false };
1823        match inlay_hint_provider {
1824            lsp::OneOf::Left(enabled) => *enabled,
1825            lsp::OneOf::Right(inlay_hint_capabilities) => match inlay_hint_capabilities {
1826                lsp::InlayHintServerCapabilities::Options(_) => true,
1827                lsp::InlayHintServerCapabilities::RegistrationOptions(_) => false,
1828            },
1829        }
1830    }
1831
1832    fn to_lsp(
1833        &self,
1834        path: &Path,
1835        buffer: &Buffer,
1836        _: &Arc<LanguageServer>,
1837        _: &AppContext,
1838    ) -> lsp::InlayHintParams {
1839        lsp::InlayHintParams {
1840            text_document: lsp::TextDocumentIdentifier {
1841                uri: lsp::Url::from_file_path(path).unwrap(),
1842            },
1843            range: range_to_lsp(self.range.to_point_utf16(buffer)),
1844            work_done_progress_params: Default::default(),
1845        }
1846    }
1847
1848    async fn response_from_lsp(
1849        self,
1850        message: Option<Vec<lsp::InlayHint>>,
1851        project: ModelHandle<Project>,
1852        buffer: ModelHandle<Buffer>,
1853        server_id: LanguageServerId,
1854        mut cx: AsyncAppContext,
1855    ) -> Result<Vec<InlayHint>> {
1856        let (lsp_adapter, _) = language_server_for_buffer(&project, &buffer, server_id, &mut cx)?;
1857        // `typescript-language-server` adds padding to the left for type hints, turning
1858        // `const foo: boolean` into `const foo : boolean` which looks odd.
1859        // `rust-analyzer` does not have the padding for this case, and we have to accomodate both.
1860        //
1861        // We could trim the whole string, but being pessimistic on par with the situation above,
1862        // there might be a hint with multiple whitespaces at the end(s) which we need to display properly.
1863        // Hence let's use a heuristic first to handle the most awkward case and look for more.
1864        let force_no_type_left_padding =
1865            lsp_adapter.name.0.as_ref() == "typescript-language-server";
1866        cx.read(|cx| {
1867            let origin_buffer = buffer.read(cx);
1868            Ok(message
1869                .unwrap_or_default()
1870                .into_iter()
1871                .map(|lsp_hint| {
1872                    let kind = lsp_hint.kind.and_then(|kind| match kind {
1873                        lsp::InlayHintKind::TYPE => Some(InlayHintKind::Type),
1874                        lsp::InlayHintKind::PARAMETER => Some(InlayHintKind::Parameter),
1875                        _ => None,
1876                    });
1877                    let position = origin_buffer
1878                        .clip_point_utf16(point_from_lsp(lsp_hint.position), Bias::Left);
1879                    let padding_left =
1880                        if force_no_type_left_padding && kind == Some(InlayHintKind::Type) {
1881                            false
1882                        } else {
1883                            lsp_hint.padding_left.unwrap_or(false)
1884                        };
1885                    InlayHint {
1886                        buffer_id: origin_buffer.remote_id(),
1887                        position: if kind == Some(InlayHintKind::Parameter) {
1888                            origin_buffer.anchor_before(position)
1889                        } else {
1890                            origin_buffer.anchor_after(position)
1891                        },
1892                        padding_left,
1893                        padding_right: lsp_hint.padding_right.unwrap_or(false),
1894                        label: match lsp_hint.label {
1895                            lsp::InlayHintLabel::String(s) => InlayHintLabel::String(s),
1896                            lsp::InlayHintLabel::LabelParts(lsp_parts) => {
1897                                InlayHintLabel::LabelParts(
1898                                    lsp_parts
1899                                        .into_iter()
1900                                        .map(|label_part| InlayHintLabelPart {
1901                                            value: label_part.value,
1902                                            tooltip: label_part.tooltip.map(
1903                                                |tooltip| {
1904                                                    match tooltip {
1905                                        lsp::InlayHintLabelPartTooltip::String(s) => {
1906                                            InlayHintLabelPartTooltip::String(s)
1907                                        }
1908                                        lsp::InlayHintLabelPartTooltip::MarkupContent(
1909                                            markup_content,
1910                                        ) => InlayHintLabelPartTooltip::MarkupContent(
1911                                            MarkupContent {
1912                                                kind: format!("{:?}", markup_content.kind),
1913                                                value: markup_content.value,
1914                                            },
1915                                        ),
1916                                    }
1917                                                },
1918                                            ),
1919                                            location: label_part.location.map(|lsp_location| {
1920                                                let target_start = origin_buffer.clip_point_utf16(
1921                                                    point_from_lsp(lsp_location.range.start),
1922                                                    Bias::Left,
1923                                                );
1924                                                let target_end = origin_buffer.clip_point_utf16(
1925                                                    point_from_lsp(lsp_location.range.end),
1926                                                    Bias::Left,
1927                                                );
1928                                                Location {
1929                                                    buffer: buffer.clone(),
1930                                                    range: origin_buffer.anchor_after(target_start)
1931                                                        ..origin_buffer.anchor_before(target_end),
1932                                                }
1933                                            }),
1934                                        })
1935                                        .collect(),
1936                                )
1937                            }
1938                        },
1939                        kind,
1940                        tooltip: lsp_hint.tooltip.map(|tooltip| match tooltip {
1941                            lsp::InlayHintTooltip::String(s) => InlayHintTooltip::String(s),
1942                            lsp::InlayHintTooltip::MarkupContent(markup_content) => {
1943                                InlayHintTooltip::MarkupContent(MarkupContent {
1944                                    kind: format!("{:?}", markup_content.kind),
1945                                    value: markup_content.value,
1946                                })
1947                            }
1948                        }),
1949                    }
1950                })
1951                .collect())
1952        })
1953    }
1954
1955    fn to_proto(&self, project_id: u64, buffer: &Buffer) -> proto::InlayHints {
1956        proto::InlayHints {
1957            project_id,
1958            buffer_id: buffer.remote_id(),
1959            start: Some(language::proto::serialize_anchor(&self.range.start)),
1960            end: Some(language::proto::serialize_anchor(&self.range.end)),
1961            version: serialize_version(&buffer.version()),
1962        }
1963    }
1964
1965    async fn from_proto(
1966        message: proto::InlayHints,
1967        _: ModelHandle<Project>,
1968        buffer: ModelHandle<Buffer>,
1969        mut cx: AsyncAppContext,
1970    ) -> Result<Self> {
1971        let start = message
1972            .start
1973            .and_then(language::proto::deserialize_anchor)
1974            .context("invalid start")?;
1975        let end = message
1976            .end
1977            .and_then(language::proto::deserialize_anchor)
1978            .context("invalid end")?;
1979        buffer
1980            .update(&mut cx, |buffer, _| {
1981                buffer.wait_for_version(deserialize_version(&message.version))
1982            })
1983            .await?;
1984
1985        Ok(Self { range: start..end })
1986    }
1987
1988    fn response_to_proto(
1989        response: Vec<InlayHint>,
1990        _: &mut Project,
1991        _: PeerId,
1992        buffer_version: &clock::Global,
1993        _: &mut AppContext,
1994    ) -> proto::InlayHintsResponse {
1995        proto::InlayHintsResponse {
1996            hints: response
1997                .into_iter()
1998                .map(|response_hint| proto::InlayHint {
1999                    position: Some(language::proto::serialize_anchor(&response_hint.position)),
2000                    padding_left: response_hint.padding_left,
2001                    padding_right: response_hint.padding_right,
2002                    kind: response_hint.kind.map(|kind| kind.name().to_string()),
2003                    // Do not pass extra data such as tooltips to clients: host can put tooltip data from the cache during resolution.
2004                    tooltip: None,
2005                    // Similarly, do not pass label parts to clients: host can return a detailed list during resolution.
2006                    label: Some(proto::InlayHintLabel {
2007                        label: Some(proto::inlay_hint_label::Label::Value(
2008                            match response_hint.label {
2009                                InlayHintLabel::String(s) => s,
2010                                InlayHintLabel::LabelParts(_) => response_hint.text(),
2011                            },
2012                        )),
2013                    }),
2014                })
2015                .collect(),
2016            version: serialize_version(buffer_version),
2017        }
2018    }
2019
2020    async fn response_from_proto(
2021        self,
2022        message: proto::InlayHintsResponse,
2023        project: ModelHandle<Project>,
2024        buffer: ModelHandle<Buffer>,
2025        mut cx: AsyncAppContext,
2026    ) -> Result<Vec<InlayHint>> {
2027        buffer
2028            .update(&mut cx, |buffer, _| {
2029                buffer.wait_for_version(deserialize_version(&message.version))
2030            })
2031            .await?;
2032
2033        let mut hints = Vec::new();
2034        for message_hint in message.hints {
2035            let buffer_id = message_hint
2036                .position
2037                .as_ref()
2038                .and_then(|location| location.buffer_id)
2039                .context("missing buffer id")?;
2040            let hint = InlayHint {
2041                buffer_id,
2042                position: message_hint
2043                    .position
2044                    .and_then(language::proto::deserialize_anchor)
2045                    .context("invalid position")?,
2046                label: match message_hint
2047                    .label
2048                    .and_then(|label| label.label)
2049                    .context("missing label")?
2050                {
2051                    proto::inlay_hint_label::Label::Value(s) => InlayHintLabel::String(s),
2052                    proto::inlay_hint_label::Label::LabelParts(parts) => {
2053                        let mut label_parts = Vec::new();
2054                        for part in parts.parts {
2055                            label_parts.push(InlayHintLabelPart {
2056                                value: part.value,
2057                                tooltip: part.tooltip.map(|tooltip| match tooltip.content {
2058                                    Some(proto::inlay_hint_label_part_tooltip::Content::Value(s)) => InlayHintLabelPartTooltip::String(s),
2059                                    Some(proto::inlay_hint_label_part_tooltip::Content::MarkupContent(markup_content)) => InlayHintLabelPartTooltip::MarkupContent(MarkupContent {
2060                                        kind: markup_content.kind,
2061                                        value: markup_content.value,
2062                                    }),
2063                                    None => InlayHintLabelPartTooltip::String(String::new()),
2064                                }),
2065                                location: match part.location {
2066                                    Some(location) => {
2067                                        let target_buffer = project
2068                                            .update(&mut cx, |this, cx| {
2069                                                this.wait_for_remote_buffer(location.buffer_id, cx)
2070                                            })
2071                                            .await?;
2072                                        Some(Location {
2073                                        range: location
2074                                            .start
2075                                            .and_then(language::proto::deserialize_anchor)
2076                                            .context("invalid start")?
2077                                            ..location
2078                                                .end
2079                                                .and_then(language::proto::deserialize_anchor)
2080                                                .context("invalid end")?,
2081                                        buffer: target_buffer,
2082                                    })},
2083                                    None => None,
2084                                },
2085                            });
2086                        }
2087
2088                        InlayHintLabel::LabelParts(label_parts)
2089                    }
2090                },
2091                padding_left: message_hint.padding_left,
2092                padding_right: message_hint.padding_right,
2093                kind: message_hint
2094                    .kind
2095                    .as_deref()
2096                    .and_then(InlayHintKind::from_name),
2097                tooltip: message_hint.tooltip.and_then(|tooltip| {
2098                    Some(match tooltip.content? {
2099                        proto::inlay_hint_tooltip::Content::Value(s) => InlayHintTooltip::String(s),
2100                        proto::inlay_hint_tooltip::Content::MarkupContent(markup_content) => {
2101                            InlayHintTooltip::MarkupContent(MarkupContent {
2102                                kind: markup_content.kind,
2103                                value: markup_content.value,
2104                            })
2105                        }
2106                    })
2107                }),
2108            };
2109
2110            hints.push(hint);
2111        }
2112
2113        Ok(hints)
2114    }
2115
2116    fn buffer_id_from_proto(message: &proto::InlayHints) -> u64 {
2117        message.buffer_id
2118    }
2119}