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        server_id: 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                            server_id,
1429                            lsp_completion,
1430                        }
1431                    })
1432                })
1433        });
1434
1435        Ok(futures::future::join_all(completions).await)
1436    }
1437
1438    fn to_proto(&self, project_id: u64, buffer: &Buffer) -> proto::GetCompletions {
1439        let anchor = buffer.anchor_after(self.position);
1440        proto::GetCompletions {
1441            project_id,
1442            buffer_id: buffer.remote_id(),
1443            position: Some(language::proto::serialize_anchor(&anchor)),
1444            version: serialize_version(&buffer.version()),
1445        }
1446    }
1447
1448    async fn from_proto(
1449        message: proto::GetCompletions,
1450        _: ModelHandle<Project>,
1451        buffer: ModelHandle<Buffer>,
1452        mut cx: AsyncAppContext,
1453    ) -> Result<Self> {
1454        let version = deserialize_version(&message.version);
1455        buffer
1456            .update(&mut cx, |buffer, _| buffer.wait_for_version(version))
1457            .await?;
1458        let position = message
1459            .position
1460            .and_then(language::proto::deserialize_anchor)
1461            .map(|p| {
1462                buffer.read_with(&cx, |buffer, _| {
1463                    buffer.clip_point_utf16(Unclipped(p.to_point_utf16(buffer)), Bias::Left)
1464                })
1465            })
1466            .ok_or_else(|| anyhow!("invalid position"))?;
1467        Ok(Self { position })
1468    }
1469
1470    fn response_to_proto(
1471        completions: Vec<Completion>,
1472        _: &mut Project,
1473        _: PeerId,
1474        buffer_version: &clock::Global,
1475        _: &mut AppContext,
1476    ) -> proto::GetCompletionsResponse {
1477        proto::GetCompletionsResponse {
1478            completions: completions
1479                .iter()
1480                .map(language::proto::serialize_completion)
1481                .collect(),
1482            version: serialize_version(&buffer_version),
1483        }
1484    }
1485
1486    async fn response_from_proto(
1487        self,
1488        message: proto::GetCompletionsResponse,
1489        _: ModelHandle<Project>,
1490        buffer: ModelHandle<Buffer>,
1491        mut cx: AsyncAppContext,
1492    ) -> Result<Vec<Completion>> {
1493        buffer
1494            .update(&mut cx, |buffer, _| {
1495                buffer.wait_for_version(deserialize_version(&message.version))
1496            })
1497            .await?;
1498
1499        let language = buffer.read_with(&cx, |buffer, _| buffer.language().cloned());
1500        let completions = message.completions.into_iter().map(|completion| {
1501            language::proto::deserialize_completion(completion, language.clone())
1502        });
1503        futures::future::try_join_all(completions).await
1504    }
1505
1506    fn buffer_id_from_proto(message: &proto::GetCompletions) -> u64 {
1507        message.buffer_id
1508    }
1509}
1510
1511#[async_trait(?Send)]
1512impl LspCommand for GetCodeActions {
1513    type Response = Vec<CodeAction>;
1514    type LspRequest = lsp::request::CodeActionRequest;
1515    type ProtoRequest = proto::GetCodeActions;
1516
1517    fn check_capabilities(&self, capabilities: &ServerCapabilities) -> bool {
1518        match &capabilities.code_action_provider {
1519            None => false,
1520            Some(lsp::CodeActionProviderCapability::Simple(false)) => false,
1521            _ => true,
1522        }
1523    }
1524
1525    fn to_lsp(
1526        &self,
1527        path: &Path,
1528        buffer: &Buffer,
1529        language_server: &Arc<LanguageServer>,
1530        _: &AppContext,
1531    ) -> lsp::CodeActionParams {
1532        let relevant_diagnostics = buffer
1533            .snapshot()
1534            .diagnostics_in_range::<_, usize>(self.range.clone(), false)
1535            .map(|entry| entry.to_lsp_diagnostic_stub())
1536            .collect();
1537        lsp::CodeActionParams {
1538            text_document: lsp::TextDocumentIdentifier::new(
1539                lsp::Url::from_file_path(path).unwrap(),
1540            ),
1541            range: range_to_lsp(self.range.to_point_utf16(buffer)),
1542            work_done_progress_params: Default::default(),
1543            partial_result_params: Default::default(),
1544            context: lsp::CodeActionContext {
1545                diagnostics: relevant_diagnostics,
1546                only: language_server.code_action_kinds(),
1547                ..lsp::CodeActionContext::default()
1548            },
1549        }
1550    }
1551
1552    async fn response_from_lsp(
1553        self,
1554        actions: Option<lsp::CodeActionResponse>,
1555        _: ModelHandle<Project>,
1556        _: ModelHandle<Buffer>,
1557        server_id: LanguageServerId,
1558        _: AsyncAppContext,
1559    ) -> Result<Vec<CodeAction>> {
1560        Ok(actions
1561            .unwrap_or_default()
1562            .into_iter()
1563            .filter_map(|entry| {
1564                if let lsp::CodeActionOrCommand::CodeAction(lsp_action) = entry {
1565                    Some(CodeAction {
1566                        server_id,
1567                        range: self.range.clone(),
1568                        lsp_action,
1569                    })
1570                } else {
1571                    None
1572                }
1573            })
1574            .collect())
1575    }
1576
1577    fn to_proto(&self, project_id: u64, buffer: &Buffer) -> proto::GetCodeActions {
1578        proto::GetCodeActions {
1579            project_id,
1580            buffer_id: buffer.remote_id(),
1581            start: Some(language::proto::serialize_anchor(&self.range.start)),
1582            end: Some(language::proto::serialize_anchor(&self.range.end)),
1583            version: serialize_version(&buffer.version()),
1584        }
1585    }
1586
1587    async fn from_proto(
1588        message: proto::GetCodeActions,
1589        _: ModelHandle<Project>,
1590        buffer: ModelHandle<Buffer>,
1591        mut cx: AsyncAppContext,
1592    ) -> Result<Self> {
1593        let start = message
1594            .start
1595            .and_then(language::proto::deserialize_anchor)
1596            .ok_or_else(|| anyhow!("invalid start"))?;
1597        let end = message
1598            .end
1599            .and_then(language::proto::deserialize_anchor)
1600            .ok_or_else(|| anyhow!("invalid end"))?;
1601        buffer
1602            .update(&mut cx, |buffer, _| {
1603                buffer.wait_for_version(deserialize_version(&message.version))
1604            })
1605            .await?;
1606
1607        Ok(Self { range: start..end })
1608    }
1609
1610    fn response_to_proto(
1611        code_actions: Vec<CodeAction>,
1612        _: &mut Project,
1613        _: PeerId,
1614        buffer_version: &clock::Global,
1615        _: &mut AppContext,
1616    ) -> proto::GetCodeActionsResponse {
1617        proto::GetCodeActionsResponse {
1618            actions: code_actions
1619                .iter()
1620                .map(language::proto::serialize_code_action)
1621                .collect(),
1622            version: serialize_version(&buffer_version),
1623        }
1624    }
1625
1626    async fn response_from_proto(
1627        self,
1628        message: proto::GetCodeActionsResponse,
1629        _: ModelHandle<Project>,
1630        buffer: ModelHandle<Buffer>,
1631        mut cx: AsyncAppContext,
1632    ) -> Result<Vec<CodeAction>> {
1633        buffer
1634            .update(&mut cx, |buffer, _| {
1635                buffer.wait_for_version(deserialize_version(&message.version))
1636            })
1637            .await?;
1638        message
1639            .actions
1640            .into_iter()
1641            .map(language::proto::deserialize_code_action)
1642            .collect()
1643    }
1644
1645    fn buffer_id_from_proto(message: &proto::GetCodeActions) -> u64 {
1646        message.buffer_id
1647    }
1648}
1649
1650#[async_trait(?Send)]
1651impl LspCommand for OnTypeFormatting {
1652    type Response = Option<Transaction>;
1653    type LspRequest = lsp::request::OnTypeFormatting;
1654    type ProtoRequest = proto::OnTypeFormatting;
1655
1656    fn check_capabilities(&self, server_capabilities: &lsp::ServerCapabilities) -> bool {
1657        let Some(on_type_formatting_options) = &server_capabilities.document_on_type_formatting_provider else { return false };
1658        on_type_formatting_options
1659            .first_trigger_character
1660            .contains(&self.trigger)
1661            || on_type_formatting_options
1662                .more_trigger_character
1663                .iter()
1664                .flatten()
1665                .any(|chars| chars.contains(&self.trigger))
1666    }
1667
1668    fn to_lsp(
1669        &self,
1670        path: &Path,
1671        _: &Buffer,
1672        _: &Arc<LanguageServer>,
1673        _: &AppContext,
1674    ) -> lsp::DocumentOnTypeFormattingParams {
1675        lsp::DocumentOnTypeFormattingParams {
1676            text_document_position: lsp::TextDocumentPositionParams::new(
1677                lsp::TextDocumentIdentifier::new(lsp::Url::from_file_path(path).unwrap()),
1678                point_to_lsp(self.position),
1679            ),
1680            ch: self.trigger.clone(),
1681            options: lsp_formatting_options(self.options.tab_size),
1682        }
1683    }
1684
1685    async fn response_from_lsp(
1686        self,
1687        message: Option<Vec<lsp::TextEdit>>,
1688        project: ModelHandle<Project>,
1689        buffer: ModelHandle<Buffer>,
1690        server_id: LanguageServerId,
1691        mut cx: AsyncAppContext,
1692    ) -> Result<Option<Transaction>> {
1693        if let Some(edits) = message {
1694            let (lsp_adapter, lsp_server) =
1695                language_server_for_buffer(&project, &buffer, server_id, &mut cx)?;
1696            Project::deserialize_edits(
1697                project,
1698                buffer,
1699                edits,
1700                self.push_to_history,
1701                lsp_adapter,
1702                lsp_server,
1703                &mut cx,
1704            )
1705            .await
1706        } else {
1707            Ok(None)
1708        }
1709    }
1710
1711    fn to_proto(&self, project_id: u64, buffer: &Buffer) -> proto::OnTypeFormatting {
1712        proto::OnTypeFormatting {
1713            project_id,
1714            buffer_id: buffer.remote_id(),
1715            position: Some(language::proto::serialize_anchor(
1716                &buffer.anchor_before(self.position),
1717            )),
1718            trigger: self.trigger.clone(),
1719            version: serialize_version(&buffer.version()),
1720        }
1721    }
1722
1723    async fn from_proto(
1724        message: proto::OnTypeFormatting,
1725        _: ModelHandle<Project>,
1726        buffer: ModelHandle<Buffer>,
1727        mut cx: AsyncAppContext,
1728    ) -> Result<Self> {
1729        let position = message
1730            .position
1731            .and_then(deserialize_anchor)
1732            .ok_or_else(|| anyhow!("invalid position"))?;
1733        buffer
1734            .update(&mut cx, |buffer, _| {
1735                buffer.wait_for_version(deserialize_version(&message.version))
1736            })
1737            .await?;
1738
1739        let tab_size = buffer.read_with(&cx, |buffer, cx| {
1740            language_settings(buffer.language(), buffer.file(), cx).tab_size
1741        });
1742
1743        Ok(Self {
1744            position: buffer.read_with(&cx, |buffer, _| position.to_point_utf16(buffer)),
1745            trigger: message.trigger.clone(),
1746            options: lsp_formatting_options(tab_size.get()).into(),
1747            push_to_history: false,
1748        })
1749    }
1750
1751    fn response_to_proto(
1752        response: Option<Transaction>,
1753        _: &mut Project,
1754        _: PeerId,
1755        _: &clock::Global,
1756        _: &mut AppContext,
1757    ) -> proto::OnTypeFormattingResponse {
1758        proto::OnTypeFormattingResponse {
1759            transaction: response
1760                .map(|transaction| language::proto::serialize_transaction(&transaction)),
1761        }
1762    }
1763
1764    async fn response_from_proto(
1765        self,
1766        message: proto::OnTypeFormattingResponse,
1767        _: ModelHandle<Project>,
1768        _: ModelHandle<Buffer>,
1769        _: AsyncAppContext,
1770    ) -> Result<Option<Transaction>> {
1771        let Some(transaction) = message.transaction else { return Ok(None) };
1772        Ok(Some(language::proto::deserialize_transaction(transaction)?))
1773    }
1774
1775    fn buffer_id_from_proto(message: &proto::OnTypeFormatting) -> u64 {
1776        message.buffer_id
1777    }
1778}
1779
1780#[async_trait(?Send)]
1781impl LspCommand for InlayHints {
1782    type Response = Vec<InlayHint>;
1783    type LspRequest = lsp::InlayHintRequest;
1784    type ProtoRequest = proto::InlayHints;
1785
1786    fn check_capabilities(&self, server_capabilities: &lsp::ServerCapabilities) -> bool {
1787        let Some(inlay_hint_provider) = &server_capabilities.inlay_hint_provider else { return false };
1788        match inlay_hint_provider {
1789            lsp::OneOf::Left(enabled) => *enabled,
1790            lsp::OneOf::Right(inlay_hint_capabilities) => match inlay_hint_capabilities {
1791                lsp::InlayHintServerCapabilities::Options(_) => true,
1792                lsp::InlayHintServerCapabilities::RegistrationOptions(_) => false,
1793            },
1794        }
1795    }
1796
1797    fn to_lsp(
1798        &self,
1799        path: &Path,
1800        buffer: &Buffer,
1801        _: &Arc<LanguageServer>,
1802        _: &AppContext,
1803    ) -> lsp::InlayHintParams {
1804        lsp::InlayHintParams {
1805            text_document: lsp::TextDocumentIdentifier {
1806                uri: lsp::Url::from_file_path(path).unwrap(),
1807            },
1808            range: range_to_lsp(self.range.to_point_utf16(buffer)),
1809            work_done_progress_params: Default::default(),
1810        }
1811    }
1812
1813    async fn response_from_lsp(
1814        self,
1815        message: Option<Vec<lsp::InlayHint>>,
1816        project: ModelHandle<Project>,
1817        buffer: ModelHandle<Buffer>,
1818        server_id: LanguageServerId,
1819        mut cx: AsyncAppContext,
1820    ) -> Result<Vec<InlayHint>> {
1821        let (lsp_adapter, _) = language_server_for_buffer(&project, &buffer, server_id, &mut cx)?;
1822        // `typescript-language-server` adds padding to the left for type hints, turning
1823        // `const foo: boolean` into `const foo : boolean` which looks odd.
1824        // `rust-analyzer` does not have the padding for this case, and we have to accomodate both.
1825        //
1826        // We could trim the whole string, but being pessimistic on par with the situation above,
1827        // there might be a hint with multiple whitespaces at the end(s) which we need to display properly.
1828        // Hence let's use a heuristic first to handle the most awkward case and look for more.
1829        let force_no_type_left_padding =
1830            lsp_adapter.name.0.as_ref() == "typescript-language-server";
1831        cx.read(|cx| {
1832            let origin_buffer = buffer.read(cx);
1833            Ok(message
1834                .unwrap_or_default()
1835                .into_iter()
1836                .map(|lsp_hint| {
1837                    let kind = lsp_hint.kind.and_then(|kind| match kind {
1838                        lsp::InlayHintKind::TYPE => Some(InlayHintKind::Type),
1839                        lsp::InlayHintKind::PARAMETER => Some(InlayHintKind::Parameter),
1840                        _ => None,
1841                    });
1842                    let position = origin_buffer
1843                        .clip_point_utf16(point_from_lsp(lsp_hint.position), Bias::Left);
1844                    let padding_left =
1845                        if force_no_type_left_padding && kind == Some(InlayHintKind::Type) {
1846                            false
1847                        } else {
1848                            lsp_hint.padding_left.unwrap_or(false)
1849                        };
1850                    InlayHint {
1851                        buffer_id: origin_buffer.remote_id(),
1852                        position: if kind == Some(InlayHintKind::Parameter) {
1853                            origin_buffer.anchor_before(position)
1854                        } else {
1855                            origin_buffer.anchor_after(position)
1856                        },
1857                        padding_left,
1858                        padding_right: lsp_hint.padding_right.unwrap_or(false),
1859                        label: match lsp_hint.label {
1860                            lsp::InlayHintLabel::String(s) => InlayHintLabel::String(s),
1861                            lsp::InlayHintLabel::LabelParts(lsp_parts) => {
1862                                InlayHintLabel::LabelParts(
1863                                    lsp_parts
1864                                        .into_iter()
1865                                        .map(|label_part| InlayHintLabelPart {
1866                                            value: label_part.value,
1867                                            tooltip: label_part.tooltip.map(
1868                                                |tooltip| {
1869                                                    match tooltip {
1870                                        lsp::InlayHintLabelPartTooltip::String(s) => {
1871                                            InlayHintLabelPartTooltip::String(s)
1872                                        }
1873                                        lsp::InlayHintLabelPartTooltip::MarkupContent(
1874                                            markup_content,
1875                                        ) => InlayHintLabelPartTooltip::MarkupContent(
1876                                            MarkupContent {
1877                                                kind: format!("{:?}", markup_content.kind),
1878                                                value: markup_content.value,
1879                                            },
1880                                        ),
1881                                    }
1882                                                },
1883                                            ),
1884                                            location: label_part.location.map(|lsp_location| {
1885                                                let target_start = origin_buffer.clip_point_utf16(
1886                                                    point_from_lsp(lsp_location.range.start),
1887                                                    Bias::Left,
1888                                                );
1889                                                let target_end = origin_buffer.clip_point_utf16(
1890                                                    point_from_lsp(lsp_location.range.end),
1891                                                    Bias::Left,
1892                                                );
1893                                                Location {
1894                                                    buffer: buffer.clone(),
1895                                                    range: origin_buffer.anchor_after(target_start)
1896                                                        ..origin_buffer.anchor_before(target_end),
1897                                                }
1898                                            }),
1899                                        })
1900                                        .collect(),
1901                                )
1902                            }
1903                        },
1904                        kind,
1905                        tooltip: lsp_hint.tooltip.map(|tooltip| match tooltip {
1906                            lsp::InlayHintTooltip::String(s) => InlayHintTooltip::String(s),
1907                            lsp::InlayHintTooltip::MarkupContent(markup_content) => {
1908                                InlayHintTooltip::MarkupContent(MarkupContent {
1909                                    kind: format!("{:?}", markup_content.kind),
1910                                    value: markup_content.value,
1911                                })
1912                            }
1913                        }),
1914                    }
1915                })
1916                .collect())
1917        })
1918    }
1919
1920    fn to_proto(&self, project_id: u64, buffer: &Buffer) -> proto::InlayHints {
1921        proto::InlayHints {
1922            project_id,
1923            buffer_id: buffer.remote_id(),
1924            start: Some(language::proto::serialize_anchor(&self.range.start)),
1925            end: Some(language::proto::serialize_anchor(&self.range.end)),
1926            version: serialize_version(&buffer.version()),
1927        }
1928    }
1929
1930    async fn from_proto(
1931        message: proto::InlayHints,
1932        _: ModelHandle<Project>,
1933        buffer: ModelHandle<Buffer>,
1934        mut cx: AsyncAppContext,
1935    ) -> Result<Self> {
1936        let start = message
1937            .start
1938            .and_then(language::proto::deserialize_anchor)
1939            .context("invalid start")?;
1940        let end = message
1941            .end
1942            .and_then(language::proto::deserialize_anchor)
1943            .context("invalid end")?;
1944        buffer
1945            .update(&mut cx, |buffer, _| {
1946                buffer.wait_for_version(deserialize_version(&message.version))
1947            })
1948            .await?;
1949
1950        Ok(Self { range: start..end })
1951    }
1952
1953    fn response_to_proto(
1954        response: Vec<InlayHint>,
1955        _: &mut Project,
1956        _: PeerId,
1957        buffer_version: &clock::Global,
1958        _: &mut AppContext,
1959    ) -> proto::InlayHintsResponse {
1960        proto::InlayHintsResponse {
1961            hints: response
1962                .into_iter()
1963                .map(|response_hint| proto::InlayHint {
1964                    position: Some(language::proto::serialize_anchor(&response_hint.position)),
1965                    padding_left: response_hint.padding_left,
1966                    padding_right: response_hint.padding_right,
1967                    kind: response_hint.kind.map(|kind| kind.name().to_string()),
1968                    // Do not pass extra data such as tooltips to clients: host can put tooltip data from the cache during resolution.
1969                    tooltip: None,
1970                    // Similarly, do not pass label parts to clients: host can return a detailed list during resolution.
1971                    label: Some(proto::InlayHintLabel {
1972                        label: Some(proto::inlay_hint_label::Label::Value(
1973                            match response_hint.label {
1974                                InlayHintLabel::String(s) => s,
1975                                InlayHintLabel::LabelParts(_) => response_hint.text(),
1976                            },
1977                        )),
1978                    }),
1979                })
1980                .collect(),
1981            version: serialize_version(buffer_version),
1982        }
1983    }
1984
1985    async fn response_from_proto(
1986        self,
1987        message: proto::InlayHintsResponse,
1988        project: ModelHandle<Project>,
1989        buffer: ModelHandle<Buffer>,
1990        mut cx: AsyncAppContext,
1991    ) -> Result<Vec<InlayHint>> {
1992        buffer
1993            .update(&mut cx, |buffer, _| {
1994                buffer.wait_for_version(deserialize_version(&message.version))
1995            })
1996            .await?;
1997
1998        let mut hints = Vec::new();
1999        for message_hint in message.hints {
2000            let buffer_id = message_hint
2001                .position
2002                .as_ref()
2003                .and_then(|location| location.buffer_id)
2004                .context("missing buffer id")?;
2005            let hint = InlayHint {
2006                buffer_id,
2007                position: message_hint
2008                    .position
2009                    .and_then(language::proto::deserialize_anchor)
2010                    .context("invalid position")?,
2011                label: match message_hint
2012                    .label
2013                    .and_then(|label| label.label)
2014                    .context("missing label")?
2015                {
2016                    proto::inlay_hint_label::Label::Value(s) => InlayHintLabel::String(s),
2017                    proto::inlay_hint_label::Label::LabelParts(parts) => {
2018                        let mut label_parts = Vec::new();
2019                        for part in parts.parts {
2020                            label_parts.push(InlayHintLabelPart {
2021                                value: part.value,
2022                                tooltip: part.tooltip.map(|tooltip| match tooltip.content {
2023                                    Some(proto::inlay_hint_label_part_tooltip::Content::Value(s)) => InlayHintLabelPartTooltip::String(s),
2024                                    Some(proto::inlay_hint_label_part_tooltip::Content::MarkupContent(markup_content)) => InlayHintLabelPartTooltip::MarkupContent(MarkupContent {
2025                                        kind: markup_content.kind,
2026                                        value: markup_content.value,
2027                                    }),
2028                                    None => InlayHintLabelPartTooltip::String(String::new()),
2029                                }),
2030                                location: match part.location {
2031                                    Some(location) => {
2032                                        let target_buffer = project
2033                                            .update(&mut cx, |this, cx| {
2034                                                this.wait_for_remote_buffer(location.buffer_id, cx)
2035                                            })
2036                                            .await?;
2037                                        Some(Location {
2038                                        range: location
2039                                            .start
2040                                            .and_then(language::proto::deserialize_anchor)
2041                                            .context("invalid start")?
2042                                            ..location
2043                                                .end
2044                                                .and_then(language::proto::deserialize_anchor)
2045                                                .context("invalid end")?,
2046                                        buffer: target_buffer,
2047                                    })},
2048                                    None => None,
2049                                },
2050                            });
2051                        }
2052
2053                        InlayHintLabel::LabelParts(label_parts)
2054                    }
2055                },
2056                padding_left: message_hint.padding_left,
2057                padding_right: message_hint.padding_right,
2058                kind: message_hint
2059                    .kind
2060                    .as_deref()
2061                    .and_then(InlayHintKind::from_name),
2062                tooltip: message_hint.tooltip.and_then(|tooltip| {
2063                    Some(match tooltip.content? {
2064                        proto::inlay_hint_tooltip::Content::Value(s) => InlayHintTooltip::String(s),
2065                        proto::inlay_hint_tooltip::Content::MarkupContent(markup_content) => {
2066                            InlayHintTooltip::MarkupContent(MarkupContent {
2067                                kind: markup_content.kind,
2068                                value: markup_content.value,
2069                            })
2070                        }
2071                    })
2072                }),
2073            };
2074
2075            hints.push(hint);
2076        }
2077
2078        Ok(hints)
2079    }
2080
2081    fn buffer_id_from_proto(message: &proto::InlayHints) -> u64 {
2082        message.buffer_id
2083    }
2084}