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