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