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