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