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