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