lsp_command.rs

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