lsp_command.rs

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