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