lsp_command.rs

   1mod signature_help;
   2
   3use crate::{
   4    CodeAction, CoreCompletion, DocumentHighlight, Hover, HoverBlock, HoverBlockKind, InlayHint,
   5    InlayHintLabel, InlayHintLabelPart, InlayHintLabelPartTooltip, InlayHintTooltip, Location,
   6    LocationLink, MarkupContent, Project, ProjectTransaction, ResolveState,
   7};
   8use anyhow::{anyhow, Context, Result};
   9use async_trait::async_trait;
  10use client::proto::{self, PeerId};
  11use clock::Global;
  12use futures::future;
  13use gpui::{AppContext, AsyncAppContext, Model};
  14use language::{
  15    language_settings::{language_settings, InlayHintKind},
  16    point_from_lsp, point_to_lsp,
  17    proto::{deserialize_anchor, deserialize_version, serialize_anchor, serialize_version},
  18    range_from_lsp, range_to_lsp, Anchor, Bias, Buffer, BufferSnapshot, CachedLspAdapter, CharKind,
  19    OffsetRangeExt, PointUtf16, ToOffset, ToPointUtf16, Transaction, Unclipped,
  20};
  21use lsp::{
  22    CompletionContext, CompletionListItemDefaultsEditRange, CompletionTriggerKind,
  23    DocumentHighlightKind, LanguageServer, LanguageServerId, LinkedEditingRangeServerCapabilities,
  24    OneOf, ServerCapabilities,
  25};
  26use signature_help::{lsp_to_proto_signature, proto_to_lsp_signature};
  27use std::{cmp::Reverse, ops::Range, path::Path, sync::Arc};
  28use text::{BufferId, LineEnding};
  29
  30pub use signature_help::{
  31    SignatureHelp, SIGNATURE_HELP_HIGHLIGHT_CURRENT, SIGNATURE_HELP_HIGHLIGHT_OVERLOAD,
  32};
  33
  34pub fn lsp_formatting_options(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 = Option<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.and_then(|message| SignatureHelp::new(message, language)))
1287    }
1288
1289    fn to_proto(&self, project_id: u64, buffer: &Buffer) -> Self::ProtoRequest {
1290        let offset = buffer.point_utf16_to_offset(self.position);
1291        proto::GetSignatureHelp {
1292            project_id,
1293            buffer_id: buffer.remote_id().to_proto(),
1294            position: Some(serialize_anchor(&buffer.anchor_after(offset))),
1295            version: serialize_version(&buffer.version()),
1296        }
1297    }
1298
1299    async fn from_proto(
1300        payload: Self::ProtoRequest,
1301        _: Model<Project>,
1302        buffer: Model<Buffer>,
1303        mut cx: AsyncAppContext,
1304    ) -> Result<Self> {
1305        buffer
1306            .update(&mut cx, |buffer, _| {
1307                buffer.wait_for_version(deserialize_version(&payload.version))
1308            })?
1309            .await
1310            .with_context(|| format!("waiting for version for buffer {}", buffer.entity_id()))?;
1311        let buffer_snapshot = buffer.update(&mut cx, |buffer, _| buffer.snapshot())?;
1312        Ok(Self {
1313            position: payload
1314                .position
1315                .and_then(deserialize_anchor)
1316                .context("invalid position")?
1317                .to_point_utf16(&buffer_snapshot),
1318        })
1319    }
1320
1321    fn response_to_proto(
1322        response: Self::Response,
1323        _: &mut Project,
1324        _: PeerId,
1325        _: &Global,
1326        _: &mut AppContext,
1327    ) -> proto::GetSignatureHelpResponse {
1328        proto::GetSignatureHelpResponse {
1329            signature_help: response
1330                .map(|signature_help| lsp_to_proto_signature(signature_help.original_data)),
1331        }
1332    }
1333
1334    async fn response_from_proto(
1335        self,
1336        response: proto::GetSignatureHelpResponse,
1337        _: Model<Project>,
1338        buffer: Model<Buffer>,
1339        mut cx: AsyncAppContext,
1340    ) -> Result<Self::Response> {
1341        let language = buffer.update(&mut cx, |buffer, _| buffer.language().cloned())?;
1342        Ok(response
1343            .signature_help
1344            .map(|proto_help| proto_to_lsp_signature(proto_help))
1345            .and_then(|lsp_help| SignatureHelp::new(lsp_help, language)))
1346    }
1347
1348    fn buffer_id_from_proto(message: &Self::ProtoRequest) -> Result<BufferId> {
1349        BufferId::new(message.buffer_id)
1350    }
1351}
1352
1353#[async_trait(?Send)]
1354impl LspCommand for GetHover {
1355    type Response = Option<Hover>;
1356    type LspRequest = lsp::request::HoverRequest;
1357    type ProtoRequest = proto::GetHover;
1358
1359    fn to_lsp(
1360        &self,
1361        path: &Path,
1362        _: &Buffer,
1363        _: &Arc<LanguageServer>,
1364        _: &AppContext,
1365    ) -> lsp::HoverParams {
1366        lsp::HoverParams {
1367            text_document_position_params: lsp::TextDocumentPositionParams {
1368                text_document: lsp::TextDocumentIdentifier {
1369                    uri: lsp::Url::from_file_path(path).unwrap(),
1370                },
1371                position: point_to_lsp(self.position),
1372            },
1373            work_done_progress_params: Default::default(),
1374        }
1375    }
1376
1377    async fn response_from_lsp(
1378        self,
1379        message: Option<lsp::Hover>,
1380        _: Model<Project>,
1381        buffer: Model<Buffer>,
1382        _: LanguageServerId,
1383        mut cx: AsyncAppContext,
1384    ) -> Result<Self::Response> {
1385        let Some(hover) = message else {
1386            return Ok(None);
1387        };
1388
1389        let (language, range) = buffer.update(&mut cx, |buffer, _| {
1390            (
1391                buffer.language().cloned(),
1392                hover.range.map(|range| {
1393                    let token_start =
1394                        buffer.clip_point_utf16(point_from_lsp(range.start), Bias::Left);
1395                    let token_end = buffer.clip_point_utf16(point_from_lsp(range.end), Bias::Left);
1396                    buffer.anchor_after(token_start)..buffer.anchor_before(token_end)
1397                }),
1398            )
1399        })?;
1400
1401        fn hover_blocks_from_marked_string(marked_string: lsp::MarkedString) -> Option<HoverBlock> {
1402            let block = match marked_string {
1403                lsp::MarkedString::String(content) => HoverBlock {
1404                    text: content,
1405                    kind: HoverBlockKind::Markdown,
1406                },
1407                lsp::MarkedString::LanguageString(lsp::LanguageString { language, value }) => {
1408                    HoverBlock {
1409                        text: value,
1410                        kind: HoverBlockKind::Code { language },
1411                    }
1412                }
1413            };
1414            if block.text.is_empty() {
1415                None
1416            } else {
1417                Some(block)
1418            }
1419        }
1420
1421        let contents = match hover.contents {
1422            lsp::HoverContents::Scalar(marked_string) => {
1423                hover_blocks_from_marked_string(marked_string)
1424                    .into_iter()
1425                    .collect()
1426            }
1427            lsp::HoverContents::Array(marked_strings) => marked_strings
1428                .into_iter()
1429                .filter_map(hover_blocks_from_marked_string)
1430                .collect(),
1431            lsp::HoverContents::Markup(markup_content) => vec![HoverBlock {
1432                text: markup_content.value,
1433                kind: if markup_content.kind == lsp::MarkupKind::Markdown {
1434                    HoverBlockKind::Markdown
1435                } else {
1436                    HoverBlockKind::PlainText
1437                },
1438            }],
1439        };
1440
1441        Ok(Some(Hover {
1442            contents,
1443            range,
1444            language,
1445        }))
1446    }
1447
1448    fn to_proto(&self, project_id: u64, buffer: &Buffer) -> Self::ProtoRequest {
1449        proto::GetHover {
1450            project_id,
1451            buffer_id: buffer.remote_id().into(),
1452            position: Some(language::proto::serialize_anchor(
1453                &buffer.anchor_before(self.position),
1454            )),
1455            version: serialize_version(&buffer.version),
1456        }
1457    }
1458
1459    async fn from_proto(
1460        message: Self::ProtoRequest,
1461        _: Model<Project>,
1462        buffer: Model<Buffer>,
1463        mut cx: AsyncAppContext,
1464    ) -> Result<Self> {
1465        let position = message
1466            .position
1467            .and_then(deserialize_anchor)
1468            .ok_or_else(|| anyhow!("invalid position"))?;
1469        buffer
1470            .update(&mut cx, |buffer, _| {
1471                buffer.wait_for_version(deserialize_version(&message.version))
1472            })?
1473            .await?;
1474        Ok(Self {
1475            position: buffer.update(&mut cx, |buffer, _| position.to_point_utf16(buffer))?,
1476        })
1477    }
1478
1479    fn response_to_proto(
1480        response: Self::Response,
1481        _: &mut Project,
1482        _: PeerId,
1483        _: &clock::Global,
1484        _: &mut AppContext,
1485    ) -> proto::GetHoverResponse {
1486        if let Some(response) = response {
1487            let (start, end) = if let Some(range) = response.range {
1488                (
1489                    Some(language::proto::serialize_anchor(&range.start)),
1490                    Some(language::proto::serialize_anchor(&range.end)),
1491                )
1492            } else {
1493                (None, None)
1494            };
1495
1496            let contents = response
1497                .contents
1498                .into_iter()
1499                .map(|block| proto::HoverBlock {
1500                    text: block.text,
1501                    is_markdown: block.kind == HoverBlockKind::Markdown,
1502                    language: if let HoverBlockKind::Code { language } = block.kind {
1503                        Some(language)
1504                    } else {
1505                        None
1506                    },
1507                })
1508                .collect();
1509
1510            proto::GetHoverResponse {
1511                start,
1512                end,
1513                contents,
1514            }
1515        } else {
1516            proto::GetHoverResponse {
1517                start: None,
1518                end: None,
1519                contents: Vec::new(),
1520            }
1521        }
1522    }
1523
1524    async fn response_from_proto(
1525        self,
1526        message: proto::GetHoverResponse,
1527        _: Model<Project>,
1528        buffer: Model<Buffer>,
1529        mut cx: AsyncAppContext,
1530    ) -> Result<Self::Response> {
1531        let contents: Vec<_> = message
1532            .contents
1533            .into_iter()
1534            .map(|block| HoverBlock {
1535                text: block.text,
1536                kind: if let Some(language) = block.language {
1537                    HoverBlockKind::Code { language }
1538                } else if block.is_markdown {
1539                    HoverBlockKind::Markdown
1540                } else {
1541                    HoverBlockKind::PlainText
1542                },
1543            })
1544            .collect();
1545        if contents.is_empty() {
1546            return Ok(None);
1547        }
1548
1549        let language = buffer.update(&mut cx, |buffer, _| buffer.language().cloned())?;
1550        let range = if let (Some(start), Some(end)) = (message.start, message.end) {
1551            language::proto::deserialize_anchor(start)
1552                .and_then(|start| language::proto::deserialize_anchor(end).map(|end| start..end))
1553        } else {
1554            None
1555        };
1556        if let Some(range) = range.as_ref() {
1557            buffer
1558                .update(&mut cx, |buffer, _| {
1559                    buffer.wait_for_anchors([range.start, range.end])
1560                })?
1561                .await?;
1562        }
1563
1564        Ok(Some(Hover {
1565            contents,
1566            range,
1567            language,
1568        }))
1569    }
1570
1571    fn buffer_id_from_proto(message: &Self::ProtoRequest) -> Result<BufferId> {
1572        BufferId::new(message.buffer_id)
1573    }
1574}
1575
1576#[async_trait(?Send)]
1577impl LspCommand for GetCompletions {
1578    type Response = Vec<CoreCompletion>;
1579    type LspRequest = lsp::request::Completion;
1580    type ProtoRequest = proto::GetCompletions;
1581
1582    fn to_lsp(
1583        &self,
1584        path: &Path,
1585        _: &Buffer,
1586        _: &Arc<LanguageServer>,
1587        _: &AppContext,
1588    ) -> lsp::CompletionParams {
1589        lsp::CompletionParams {
1590            text_document_position: lsp::TextDocumentPositionParams::new(
1591                lsp::TextDocumentIdentifier::new(lsp::Url::from_file_path(path).unwrap()),
1592                point_to_lsp(self.position),
1593            ),
1594            context: Some(self.context.clone()),
1595            work_done_progress_params: Default::default(),
1596            partial_result_params: Default::default(),
1597        }
1598    }
1599
1600    async fn response_from_lsp(
1601        self,
1602        completions: Option<lsp::CompletionResponse>,
1603        project: Model<Project>,
1604        buffer: Model<Buffer>,
1605        server_id: LanguageServerId,
1606        mut cx: AsyncAppContext,
1607    ) -> Result<Self::Response> {
1608        let mut response_list = None;
1609        let mut completions = if let Some(completions) = completions {
1610            match completions {
1611                lsp::CompletionResponse::Array(completions) => completions,
1612
1613                lsp::CompletionResponse::List(mut list) => {
1614                    let items = std::mem::take(&mut list.items);
1615                    response_list = Some(list);
1616                    items
1617                }
1618            }
1619        } else {
1620            Default::default()
1621        };
1622
1623        let language_server_adapter = project
1624            .update(&mut cx, |project, _cx| {
1625                project.language_server_adapter_for_id(server_id)
1626            })?
1627            .ok_or_else(|| anyhow!("no such language server"))?;
1628
1629        let item_defaults = response_list
1630            .as_ref()
1631            .and_then(|list| list.item_defaults.as_ref());
1632
1633        if let Some(item_defaults) = item_defaults {
1634            let default_data = item_defaults.data.as_ref();
1635            let default_commit_characters = item_defaults.commit_characters.as_ref();
1636            let default_insert_text_mode = item_defaults.insert_text_mode.as_ref();
1637
1638            if default_data.is_some()
1639                || default_commit_characters.is_some()
1640                || default_insert_text_mode.is_some()
1641            {
1642                for item in completions.iter_mut() {
1643                    if let Some(data) = default_data {
1644                        item.data = Some(data.clone())
1645                    }
1646                    if let Some(characters) = default_commit_characters {
1647                        item.commit_characters = Some(characters.clone())
1648                    }
1649                    if let Some(text_mode) = default_insert_text_mode {
1650                        item.insert_text_mode = Some(*text_mode)
1651                    }
1652                }
1653            }
1654        }
1655
1656        let mut completion_edits = Vec::new();
1657        buffer.update(&mut cx, |buffer, _cx| {
1658            let snapshot = buffer.snapshot();
1659            let clipped_position = buffer.clip_point_utf16(Unclipped(self.position), Bias::Left);
1660
1661            let mut range_for_token = None;
1662            completions.retain_mut(|lsp_completion| {
1663                let edit = match lsp_completion.text_edit.as_ref() {
1664                    // If the language server provides a range to overwrite, then
1665                    // check that the range is valid.
1666                    Some(completion_text_edit) => {
1667                        match parse_completion_text_edit(completion_text_edit, &snapshot) {
1668                            Some(edit) => edit,
1669                            None => return false,
1670                        }
1671                    }
1672
1673                    // If the language server does not provide a range, then infer
1674                    // the range based on the syntax tree.
1675                    None => {
1676                        if self.position != clipped_position {
1677                            log::info!("completion out of expected range");
1678                            return false;
1679                        }
1680
1681                        let default_edit_range = response_list
1682                            .as_ref()
1683                            .and_then(|list| list.item_defaults.as_ref())
1684                            .and_then(|defaults| defaults.edit_range.as_ref())
1685                            .and_then(|range| match range {
1686                                CompletionListItemDefaultsEditRange::Range(r) => Some(r),
1687                                _ => None,
1688                            });
1689
1690                        let range = if let Some(range) = default_edit_range {
1691                            let range = range_from_lsp(*range);
1692                            let start = snapshot.clip_point_utf16(range.start, Bias::Left);
1693                            let end = snapshot.clip_point_utf16(range.end, Bias::Left);
1694                            if start != range.start.0 || end != range.end.0 {
1695                                log::info!("completion out of expected range");
1696                                return false;
1697                            }
1698
1699                            snapshot.anchor_before(start)..snapshot.anchor_after(end)
1700                        } else {
1701                            range_for_token
1702                                .get_or_insert_with(|| {
1703                                    let offset = self.position.to_offset(&snapshot);
1704                                    let (range, kind) = snapshot.surrounding_word(offset);
1705                                    let range = if kind == Some(CharKind::Word) {
1706                                        range
1707                                    } else {
1708                                        offset..offset
1709                                    };
1710
1711                                    snapshot.anchor_before(range.start)
1712                                        ..snapshot.anchor_after(range.end)
1713                                })
1714                                .clone()
1715                        };
1716
1717                        let text = lsp_completion
1718                            .insert_text
1719                            .as_ref()
1720                            .unwrap_or(&lsp_completion.label)
1721                            .clone();
1722                        (range, text)
1723                    }
1724                };
1725
1726                completion_edits.push(edit);
1727                true
1728            });
1729        })?;
1730
1731        language_server_adapter
1732            .process_completions(&mut completions)
1733            .await;
1734
1735        Ok(completions
1736            .into_iter()
1737            .zip(completion_edits)
1738            .map(|(lsp_completion, (old_range, mut new_text))| {
1739                LineEnding::normalize(&mut new_text);
1740                CoreCompletion {
1741                    old_range,
1742                    new_text,
1743                    server_id,
1744                    lsp_completion,
1745                }
1746            })
1747            .collect())
1748    }
1749
1750    fn to_proto(&self, project_id: u64, buffer: &Buffer) -> proto::GetCompletions {
1751        let anchor = buffer.anchor_after(self.position);
1752        proto::GetCompletions {
1753            project_id,
1754            buffer_id: buffer.remote_id().into(),
1755            position: Some(language::proto::serialize_anchor(&anchor)),
1756            version: serialize_version(&buffer.version()),
1757        }
1758    }
1759
1760    async fn from_proto(
1761        message: proto::GetCompletions,
1762        _: Model<Project>,
1763        buffer: Model<Buffer>,
1764        mut cx: AsyncAppContext,
1765    ) -> Result<Self> {
1766        let version = deserialize_version(&message.version);
1767        buffer
1768            .update(&mut cx, |buffer, _| buffer.wait_for_version(version))?
1769            .await?;
1770        let position = message
1771            .position
1772            .and_then(language::proto::deserialize_anchor)
1773            .map(|p| {
1774                buffer.update(&mut cx, |buffer, _| {
1775                    buffer.clip_point_utf16(Unclipped(p.to_point_utf16(buffer)), Bias::Left)
1776                })
1777            })
1778            .ok_or_else(|| anyhow!("invalid position"))??;
1779        Ok(Self {
1780            position,
1781            context: CompletionContext {
1782                trigger_kind: CompletionTriggerKind::INVOKED,
1783                trigger_character: None,
1784            },
1785        })
1786    }
1787
1788    fn response_to_proto(
1789        completions: Vec<CoreCompletion>,
1790        _: &mut Project,
1791        _: PeerId,
1792        buffer_version: &clock::Global,
1793        _: &mut AppContext,
1794    ) -> proto::GetCompletionsResponse {
1795        proto::GetCompletionsResponse {
1796            completions: completions
1797                .iter()
1798                .map(Project::serialize_completion)
1799                .collect(),
1800            version: serialize_version(buffer_version),
1801        }
1802    }
1803
1804    async fn response_from_proto(
1805        self,
1806        message: proto::GetCompletionsResponse,
1807        _project: Model<Project>,
1808        buffer: Model<Buffer>,
1809        mut cx: AsyncAppContext,
1810    ) -> Result<Self::Response> {
1811        buffer
1812            .update(&mut cx, |buffer, _| {
1813                buffer.wait_for_version(deserialize_version(&message.version))
1814            })?
1815            .await?;
1816
1817        message
1818            .completions
1819            .into_iter()
1820            .map(Project::deserialize_completion)
1821            .collect()
1822    }
1823
1824    fn buffer_id_from_proto(message: &proto::GetCompletions) -> Result<BufferId> {
1825        BufferId::new(message.buffer_id)
1826    }
1827}
1828
1829pub(crate) fn parse_completion_text_edit(
1830    edit: &lsp::CompletionTextEdit,
1831    snapshot: &BufferSnapshot,
1832) -> Option<(Range<Anchor>, String)> {
1833    match edit {
1834        lsp::CompletionTextEdit::Edit(edit) => {
1835            let range = range_from_lsp(edit.range);
1836            let start = snapshot.clip_point_utf16(range.start, Bias::Left);
1837            let end = snapshot.clip_point_utf16(range.end, Bias::Left);
1838            if start != range.start.0 || end != range.end.0 {
1839                log::info!("completion out of expected range");
1840                None
1841            } else {
1842                Some((
1843                    snapshot.anchor_before(start)..snapshot.anchor_after(end),
1844                    edit.new_text.clone(),
1845                ))
1846            }
1847        }
1848
1849        lsp::CompletionTextEdit::InsertAndReplace(edit) => {
1850            let range = range_from_lsp(edit.insert);
1851
1852            let start = snapshot.clip_point_utf16(range.start, Bias::Left);
1853            let end = snapshot.clip_point_utf16(range.end, Bias::Left);
1854            if start != range.start.0 || end != range.end.0 {
1855                log::info!("completion out of expected range");
1856                None
1857            } else {
1858                Some((
1859                    snapshot.anchor_before(start)..snapshot.anchor_after(end),
1860                    edit.new_text.clone(),
1861                ))
1862            }
1863        }
1864    }
1865}
1866
1867#[async_trait(?Send)]
1868impl LspCommand for GetCodeActions {
1869    type Response = Vec<CodeAction>;
1870    type LspRequest = lsp::request::CodeActionRequest;
1871    type ProtoRequest = proto::GetCodeActions;
1872
1873    fn check_capabilities(&self, capabilities: &ServerCapabilities) -> bool {
1874        match &capabilities.code_action_provider {
1875            None => false,
1876            Some(lsp::CodeActionProviderCapability::Simple(false)) => false,
1877            _ => true,
1878        }
1879    }
1880
1881    fn to_lsp(
1882        &self,
1883        path: &Path,
1884        buffer: &Buffer,
1885        language_server: &Arc<LanguageServer>,
1886        _: &AppContext,
1887    ) -> lsp::CodeActionParams {
1888        let relevant_diagnostics = buffer
1889            .snapshot()
1890            .diagnostics_in_range::<_, language::PointUtf16>(self.range.clone(), false)
1891            .map(|entry| entry.to_lsp_diagnostic_stub())
1892            .collect::<Vec<_>>();
1893
1894        lsp::CodeActionParams {
1895            text_document: lsp::TextDocumentIdentifier::new(
1896                lsp::Url::from_file_path(path).unwrap(),
1897            ),
1898            range: range_to_lsp(self.range.to_point_utf16(buffer)),
1899            work_done_progress_params: Default::default(),
1900            partial_result_params: Default::default(),
1901            context: lsp::CodeActionContext {
1902                diagnostics: relevant_diagnostics,
1903                only: self
1904                    .kinds
1905                    .clone()
1906                    .or_else(|| language_server.code_action_kinds()),
1907                ..lsp::CodeActionContext::default()
1908            },
1909        }
1910    }
1911
1912    async fn response_from_lsp(
1913        self,
1914        actions: Option<lsp::CodeActionResponse>,
1915        _: Model<Project>,
1916        _: Model<Buffer>,
1917        server_id: LanguageServerId,
1918        _: AsyncAppContext,
1919    ) -> Result<Vec<CodeAction>> {
1920        Ok(actions
1921            .unwrap_or_default()
1922            .into_iter()
1923            .filter_map(|entry| {
1924                if let lsp::CodeActionOrCommand::CodeAction(lsp_action) = entry {
1925                    Some(CodeAction {
1926                        server_id,
1927                        range: self.range.clone(),
1928                        lsp_action,
1929                    })
1930                } else {
1931                    None
1932                }
1933            })
1934            .collect())
1935    }
1936
1937    fn to_proto(&self, project_id: u64, buffer: &Buffer) -> proto::GetCodeActions {
1938        proto::GetCodeActions {
1939            project_id,
1940            buffer_id: buffer.remote_id().into(),
1941            start: Some(language::proto::serialize_anchor(&self.range.start)),
1942            end: Some(language::proto::serialize_anchor(&self.range.end)),
1943            version: serialize_version(&buffer.version()),
1944        }
1945    }
1946
1947    async fn from_proto(
1948        message: proto::GetCodeActions,
1949        _: Model<Project>,
1950        buffer: Model<Buffer>,
1951        mut cx: AsyncAppContext,
1952    ) -> Result<Self> {
1953        let start = message
1954            .start
1955            .and_then(language::proto::deserialize_anchor)
1956            .ok_or_else(|| anyhow!("invalid start"))?;
1957        let end = message
1958            .end
1959            .and_then(language::proto::deserialize_anchor)
1960            .ok_or_else(|| anyhow!("invalid end"))?;
1961        buffer
1962            .update(&mut cx, |buffer, _| {
1963                buffer.wait_for_version(deserialize_version(&message.version))
1964            })?
1965            .await?;
1966
1967        Ok(Self {
1968            range: start..end,
1969            kinds: None,
1970        })
1971    }
1972
1973    fn response_to_proto(
1974        code_actions: Vec<CodeAction>,
1975        _: &mut Project,
1976        _: PeerId,
1977        buffer_version: &clock::Global,
1978        _: &mut AppContext,
1979    ) -> proto::GetCodeActionsResponse {
1980        proto::GetCodeActionsResponse {
1981            actions: code_actions
1982                .iter()
1983                .map(Project::serialize_code_action)
1984                .collect(),
1985            version: serialize_version(buffer_version),
1986        }
1987    }
1988
1989    async fn response_from_proto(
1990        self,
1991        message: proto::GetCodeActionsResponse,
1992        _: Model<Project>,
1993        buffer: Model<Buffer>,
1994        mut cx: AsyncAppContext,
1995    ) -> Result<Vec<CodeAction>> {
1996        buffer
1997            .update(&mut cx, |buffer, _| {
1998                buffer.wait_for_version(deserialize_version(&message.version))
1999            })?
2000            .await?;
2001        message
2002            .actions
2003            .into_iter()
2004            .map(Project::deserialize_code_action)
2005            .collect()
2006    }
2007
2008    fn buffer_id_from_proto(message: &proto::GetCodeActions) -> Result<BufferId> {
2009        BufferId::new(message.buffer_id)
2010    }
2011}
2012
2013impl GetCodeActions {
2014    pub fn can_resolve_actions(capabilities: &ServerCapabilities) -> bool {
2015        capabilities
2016            .code_action_provider
2017            .as_ref()
2018            .and_then(|options| match options {
2019                lsp::CodeActionProviderCapability::Simple(_is_supported) => None,
2020                lsp::CodeActionProviderCapability::Options(options) => options.resolve_provider,
2021            })
2022            .unwrap_or(false)
2023    }
2024
2025    pub fn supports_code_actions(capabilities: &ServerCapabilities) -> bool {
2026        capabilities
2027            .code_action_provider
2028            .as_ref()
2029            .map(|options| match options {
2030                lsp::CodeActionProviderCapability::Simple(is_supported) => *is_supported,
2031                lsp::CodeActionProviderCapability::Options(_) => true,
2032            })
2033            .unwrap_or(false)
2034    }
2035}
2036
2037#[async_trait(?Send)]
2038impl LspCommand for OnTypeFormatting {
2039    type Response = Option<Transaction>;
2040    type LspRequest = lsp::request::OnTypeFormatting;
2041    type ProtoRequest = proto::OnTypeFormatting;
2042
2043    fn check_capabilities(&self, server_capabilities: &lsp::ServerCapabilities) -> bool {
2044        let Some(on_type_formatting_options) =
2045            &server_capabilities.document_on_type_formatting_provider
2046        else {
2047            return false;
2048        };
2049        on_type_formatting_options
2050            .first_trigger_character
2051            .contains(&self.trigger)
2052            || on_type_formatting_options
2053                .more_trigger_character
2054                .iter()
2055                .flatten()
2056                .any(|chars| chars.contains(&self.trigger))
2057    }
2058
2059    fn to_lsp(
2060        &self,
2061        path: &Path,
2062        _: &Buffer,
2063        _: &Arc<LanguageServer>,
2064        _: &AppContext,
2065    ) -> lsp::DocumentOnTypeFormattingParams {
2066        lsp::DocumentOnTypeFormattingParams {
2067            text_document_position: lsp::TextDocumentPositionParams::new(
2068                lsp::TextDocumentIdentifier::new(lsp::Url::from_file_path(path).unwrap()),
2069                point_to_lsp(self.position),
2070            ),
2071            ch: self.trigger.clone(),
2072            options: lsp_formatting_options(self.options.tab_size),
2073        }
2074    }
2075
2076    async fn response_from_lsp(
2077        self,
2078        message: Option<Vec<lsp::TextEdit>>,
2079        project: Model<Project>,
2080        buffer: Model<Buffer>,
2081        server_id: LanguageServerId,
2082        mut cx: AsyncAppContext,
2083    ) -> Result<Option<Transaction>> {
2084        if let Some(edits) = message {
2085            let (lsp_adapter, lsp_server) =
2086                language_server_for_buffer(&project, &buffer, server_id, &mut cx)?;
2087            Project::deserialize_edits(
2088                project,
2089                buffer,
2090                edits,
2091                self.push_to_history,
2092                lsp_adapter,
2093                lsp_server,
2094                &mut cx,
2095            )
2096            .await
2097        } else {
2098            Ok(None)
2099        }
2100    }
2101
2102    fn to_proto(&self, project_id: u64, buffer: &Buffer) -> proto::OnTypeFormatting {
2103        proto::OnTypeFormatting {
2104            project_id,
2105            buffer_id: buffer.remote_id().into(),
2106            position: Some(language::proto::serialize_anchor(
2107                &buffer.anchor_before(self.position),
2108            )),
2109            trigger: self.trigger.clone(),
2110            version: serialize_version(&buffer.version()),
2111        }
2112    }
2113
2114    async fn from_proto(
2115        message: proto::OnTypeFormatting,
2116        _: Model<Project>,
2117        buffer: Model<Buffer>,
2118        mut cx: AsyncAppContext,
2119    ) -> Result<Self> {
2120        let position = message
2121            .position
2122            .and_then(deserialize_anchor)
2123            .ok_or_else(|| anyhow!("invalid position"))?;
2124        buffer
2125            .update(&mut cx, |buffer, _| {
2126                buffer.wait_for_version(deserialize_version(&message.version))
2127            })?
2128            .await?;
2129
2130        let tab_size = buffer.update(&mut cx, |buffer, cx| {
2131            language_settings(buffer.language(), buffer.file(), cx).tab_size
2132        })?;
2133
2134        Ok(Self {
2135            position: buffer.update(&mut cx, |buffer, _| position.to_point_utf16(buffer))?,
2136            trigger: message.trigger.clone(),
2137            options: lsp_formatting_options(tab_size.get()).into(),
2138            push_to_history: false,
2139        })
2140    }
2141
2142    fn response_to_proto(
2143        response: Option<Transaction>,
2144        _: &mut Project,
2145        _: PeerId,
2146        _: &clock::Global,
2147        _: &mut AppContext,
2148    ) -> proto::OnTypeFormattingResponse {
2149        proto::OnTypeFormattingResponse {
2150            transaction: response
2151                .map(|transaction| language::proto::serialize_transaction(&transaction)),
2152        }
2153    }
2154
2155    async fn response_from_proto(
2156        self,
2157        message: proto::OnTypeFormattingResponse,
2158        _: Model<Project>,
2159        _: Model<Buffer>,
2160        _: AsyncAppContext,
2161    ) -> Result<Option<Transaction>> {
2162        let Some(transaction) = message.transaction else {
2163            return Ok(None);
2164        };
2165        Ok(Some(language::proto::deserialize_transaction(transaction)?))
2166    }
2167
2168    fn buffer_id_from_proto(message: &proto::OnTypeFormatting) -> Result<BufferId> {
2169        BufferId::new(message.buffer_id)
2170    }
2171}
2172
2173impl InlayHints {
2174    pub async fn lsp_to_project_hint(
2175        lsp_hint: lsp::InlayHint,
2176        buffer_handle: &Model<Buffer>,
2177        server_id: LanguageServerId,
2178        resolve_state: ResolveState,
2179        force_no_type_left_padding: bool,
2180        cx: &mut AsyncAppContext,
2181    ) -> anyhow::Result<InlayHint> {
2182        let kind = lsp_hint.kind.and_then(|kind| match kind {
2183            lsp::InlayHintKind::TYPE => Some(InlayHintKind::Type),
2184            lsp::InlayHintKind::PARAMETER => Some(InlayHintKind::Parameter),
2185            _ => None,
2186        });
2187
2188        let position = buffer_handle.update(cx, |buffer, _| {
2189            let position = buffer.clip_point_utf16(point_from_lsp(lsp_hint.position), Bias::Left);
2190            if kind == Some(InlayHintKind::Parameter) {
2191                buffer.anchor_before(position)
2192            } else {
2193                buffer.anchor_after(position)
2194            }
2195        })?;
2196        let label = Self::lsp_inlay_label_to_project(lsp_hint.label, server_id)
2197            .await
2198            .context("lsp to project inlay hint conversion")?;
2199        let padding_left = if force_no_type_left_padding && kind == Some(InlayHintKind::Type) {
2200            false
2201        } else {
2202            lsp_hint.padding_left.unwrap_or(false)
2203        };
2204
2205        Ok(InlayHint {
2206            position,
2207            padding_left,
2208            padding_right: lsp_hint.padding_right.unwrap_or(false),
2209            label,
2210            kind,
2211            tooltip: lsp_hint.tooltip.map(|tooltip| match tooltip {
2212                lsp::InlayHintTooltip::String(s) => InlayHintTooltip::String(s),
2213                lsp::InlayHintTooltip::MarkupContent(markup_content) => {
2214                    InlayHintTooltip::MarkupContent(MarkupContent {
2215                        kind: match markup_content.kind {
2216                            lsp::MarkupKind::PlainText => HoverBlockKind::PlainText,
2217                            lsp::MarkupKind::Markdown => HoverBlockKind::Markdown,
2218                        },
2219                        value: markup_content.value,
2220                    })
2221                }
2222            }),
2223            resolve_state,
2224        })
2225    }
2226
2227    async fn lsp_inlay_label_to_project(
2228        lsp_label: lsp::InlayHintLabel,
2229        server_id: LanguageServerId,
2230    ) -> anyhow::Result<InlayHintLabel> {
2231        let label = match lsp_label {
2232            lsp::InlayHintLabel::String(s) => InlayHintLabel::String(s),
2233            lsp::InlayHintLabel::LabelParts(lsp_parts) => {
2234                let mut parts = Vec::with_capacity(lsp_parts.len());
2235                for lsp_part in lsp_parts {
2236                    parts.push(InlayHintLabelPart {
2237                        value: lsp_part.value,
2238                        tooltip: lsp_part.tooltip.map(|tooltip| match tooltip {
2239                            lsp::InlayHintLabelPartTooltip::String(s) => {
2240                                InlayHintLabelPartTooltip::String(s)
2241                            }
2242                            lsp::InlayHintLabelPartTooltip::MarkupContent(markup_content) => {
2243                                InlayHintLabelPartTooltip::MarkupContent(MarkupContent {
2244                                    kind: match markup_content.kind {
2245                                        lsp::MarkupKind::PlainText => HoverBlockKind::PlainText,
2246                                        lsp::MarkupKind::Markdown => HoverBlockKind::Markdown,
2247                                    },
2248                                    value: markup_content.value,
2249                                })
2250                            }
2251                        }),
2252                        location: Some(server_id).zip(lsp_part.location),
2253                    });
2254                }
2255                InlayHintLabel::LabelParts(parts)
2256            }
2257        };
2258
2259        Ok(label)
2260    }
2261
2262    pub fn project_to_proto_hint(response_hint: InlayHint) -> proto::InlayHint {
2263        let (state, lsp_resolve_state) = match response_hint.resolve_state {
2264            ResolveState::Resolved => (0, None),
2265            ResolveState::CanResolve(server_id, resolve_data) => (
2266                1,
2267                resolve_data
2268                    .map(|json_data| {
2269                        serde_json::to_string(&json_data)
2270                            .expect("failed to serialize resolve json data")
2271                    })
2272                    .map(|value| proto::resolve_state::LspResolveState {
2273                        server_id: server_id.0 as u64,
2274                        value,
2275                    }),
2276            ),
2277            ResolveState::Resolving => (2, None),
2278        };
2279        let resolve_state = Some(proto::ResolveState {
2280            state,
2281            lsp_resolve_state,
2282        });
2283        proto::InlayHint {
2284            position: Some(language::proto::serialize_anchor(&response_hint.position)),
2285            padding_left: response_hint.padding_left,
2286            padding_right: response_hint.padding_right,
2287            label: Some(proto::InlayHintLabel {
2288                label: Some(match response_hint.label {
2289                    InlayHintLabel::String(s) => proto::inlay_hint_label::Label::Value(s),
2290                    InlayHintLabel::LabelParts(label_parts) => {
2291                        proto::inlay_hint_label::Label::LabelParts(proto::InlayHintLabelParts {
2292                            parts: label_parts.into_iter().map(|label_part| {
2293                                let location_url = label_part.location.as_ref().map(|(_, location)| location.uri.to_string());
2294                                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 });
2295                                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 });
2296                                proto::InlayHintLabelPart {
2297                                value: label_part.value,
2298                                tooltip: label_part.tooltip.map(|tooltip| {
2299                                    let proto_tooltip = match tooltip {
2300                                        InlayHintLabelPartTooltip::String(s) => proto::inlay_hint_label_part_tooltip::Content::Value(s),
2301                                        InlayHintLabelPartTooltip::MarkupContent(markup_content) => proto::inlay_hint_label_part_tooltip::Content::MarkupContent(proto::MarkupContent {
2302                                            is_markdown: markup_content.kind == HoverBlockKind::Markdown,
2303                                            value: markup_content.value,
2304                                        }),
2305                                    };
2306                                    proto::InlayHintLabelPartTooltip {content: Some(proto_tooltip)}
2307                                }),
2308                                location_url,
2309                                location_range_start,
2310                                location_range_end,
2311                                language_server_id: label_part.location.as_ref().map(|(server_id, _)| server_id.0 as u64),
2312                            }}).collect()
2313                        })
2314                    }
2315                }),
2316            }),
2317            kind: response_hint.kind.map(|kind| kind.name().to_string()),
2318            tooltip: response_hint.tooltip.map(|response_tooltip| {
2319                let proto_tooltip = match response_tooltip {
2320                    InlayHintTooltip::String(s) => proto::inlay_hint_tooltip::Content::Value(s),
2321                    InlayHintTooltip::MarkupContent(markup_content) => {
2322                        proto::inlay_hint_tooltip::Content::MarkupContent(proto::MarkupContent {
2323                            is_markdown: markup_content.kind == HoverBlockKind::Markdown,
2324                            value: markup_content.value,
2325                        })
2326                    }
2327                };
2328                proto::InlayHintTooltip {
2329                    content: Some(proto_tooltip),
2330                }
2331            }),
2332            resolve_state,
2333        }
2334    }
2335
2336    pub fn proto_to_project_hint(message_hint: proto::InlayHint) -> anyhow::Result<InlayHint> {
2337        let resolve_state = message_hint.resolve_state.as_ref().unwrap_or_else(|| {
2338            panic!("incorrect proto inlay hint message: no resolve state in hint {message_hint:?}",)
2339        });
2340        let resolve_state_data = resolve_state
2341            .lsp_resolve_state.as_ref()
2342            .map(|lsp_resolve_state| {
2343                serde_json::from_str::<Option<lsp::LSPAny>>(&lsp_resolve_state.value)
2344                    .with_context(|| format!("incorrect proto inlay hint message: non-json resolve state {lsp_resolve_state:?}"))
2345                    .map(|state| (LanguageServerId(lsp_resolve_state.server_id as usize), state))
2346            })
2347            .transpose()?;
2348        let resolve_state = match resolve_state.state {
2349            0 => ResolveState::Resolved,
2350            1 => {
2351                let (server_id, lsp_resolve_state) = resolve_state_data.with_context(|| {
2352                    format!(
2353                        "No lsp resolve data for the hint that can be resolved: {message_hint:?}"
2354                    )
2355                })?;
2356                ResolveState::CanResolve(server_id, lsp_resolve_state)
2357            }
2358            2 => ResolveState::Resolving,
2359            invalid => {
2360                anyhow::bail!("Unexpected resolve state {invalid} for hint {message_hint:?}")
2361            }
2362        };
2363        Ok(InlayHint {
2364            position: message_hint
2365                .position
2366                .and_then(language::proto::deserialize_anchor)
2367                .context("invalid position")?,
2368            label: match message_hint
2369                .label
2370                .and_then(|label| label.label)
2371                .context("missing label")?
2372            {
2373                proto::inlay_hint_label::Label::Value(s) => InlayHintLabel::String(s),
2374                proto::inlay_hint_label::Label::LabelParts(parts) => {
2375                    let mut label_parts = Vec::new();
2376                    for part in parts.parts {
2377                        label_parts.push(InlayHintLabelPart {
2378                            value: part.value,
2379                            tooltip: part.tooltip.map(|tooltip| match tooltip.content {
2380                                Some(proto::inlay_hint_label_part_tooltip::Content::Value(s)) => {
2381                                    InlayHintLabelPartTooltip::String(s)
2382                                }
2383                                Some(
2384                                    proto::inlay_hint_label_part_tooltip::Content::MarkupContent(
2385                                        markup_content,
2386                                    ),
2387                                ) => InlayHintLabelPartTooltip::MarkupContent(MarkupContent {
2388                                    kind: if markup_content.is_markdown {
2389                                        HoverBlockKind::Markdown
2390                                    } else {
2391                                        HoverBlockKind::PlainText
2392                                    },
2393                                    value: markup_content.value,
2394                                }),
2395                                None => InlayHintLabelPartTooltip::String(String::new()),
2396                            }),
2397                            location: {
2398                                match part
2399                                    .location_url
2400                                    .zip(
2401                                        part.location_range_start.and_then(|start| {
2402                                            Some(start..part.location_range_end?)
2403                                        }),
2404                                    )
2405                                    .zip(part.language_server_id)
2406                                {
2407                                    Some(((uri, range), server_id)) => Some((
2408                                        LanguageServerId(server_id as usize),
2409                                        lsp::Location {
2410                                            uri: lsp::Url::parse(&uri)
2411                                                .context("invalid uri in hint part {part:?}")?,
2412                                            range: lsp::Range::new(
2413                                                point_to_lsp(PointUtf16::new(
2414                                                    range.start.row,
2415                                                    range.start.column,
2416                                                )),
2417                                                point_to_lsp(PointUtf16::new(
2418                                                    range.end.row,
2419                                                    range.end.column,
2420                                                )),
2421                                            ),
2422                                        },
2423                                    )),
2424                                    None => None,
2425                                }
2426                            },
2427                        });
2428                    }
2429
2430                    InlayHintLabel::LabelParts(label_parts)
2431                }
2432            },
2433            padding_left: message_hint.padding_left,
2434            padding_right: message_hint.padding_right,
2435            kind: message_hint
2436                .kind
2437                .as_deref()
2438                .and_then(InlayHintKind::from_name),
2439            tooltip: message_hint.tooltip.and_then(|tooltip| {
2440                Some(match tooltip.content? {
2441                    proto::inlay_hint_tooltip::Content::Value(s) => InlayHintTooltip::String(s),
2442                    proto::inlay_hint_tooltip::Content::MarkupContent(markup_content) => {
2443                        InlayHintTooltip::MarkupContent(MarkupContent {
2444                            kind: if markup_content.is_markdown {
2445                                HoverBlockKind::Markdown
2446                            } else {
2447                                HoverBlockKind::PlainText
2448                            },
2449                            value: markup_content.value,
2450                        })
2451                    }
2452                })
2453            }),
2454            resolve_state,
2455        })
2456    }
2457
2458    pub fn project_to_lsp_hint(hint: InlayHint, snapshot: &BufferSnapshot) -> lsp::InlayHint {
2459        lsp::InlayHint {
2460            position: point_to_lsp(hint.position.to_point_utf16(snapshot)),
2461            kind: hint.kind.map(|kind| match kind {
2462                InlayHintKind::Type => lsp::InlayHintKind::TYPE,
2463                InlayHintKind::Parameter => lsp::InlayHintKind::PARAMETER,
2464            }),
2465            text_edits: None,
2466            tooltip: hint.tooltip.and_then(|tooltip| {
2467                Some(match tooltip {
2468                    InlayHintTooltip::String(s) => lsp::InlayHintTooltip::String(s),
2469                    InlayHintTooltip::MarkupContent(markup_content) => {
2470                        lsp::InlayHintTooltip::MarkupContent(lsp::MarkupContent {
2471                            kind: match markup_content.kind {
2472                                HoverBlockKind::PlainText => lsp::MarkupKind::PlainText,
2473                                HoverBlockKind::Markdown => lsp::MarkupKind::Markdown,
2474                                HoverBlockKind::Code { .. } => return None,
2475                            },
2476                            value: markup_content.value,
2477                        })
2478                    }
2479                })
2480            }),
2481            label: match hint.label {
2482                InlayHintLabel::String(s) => lsp::InlayHintLabel::String(s),
2483                InlayHintLabel::LabelParts(label_parts) => lsp::InlayHintLabel::LabelParts(
2484                    label_parts
2485                        .into_iter()
2486                        .map(|part| lsp::InlayHintLabelPart {
2487                            value: part.value,
2488                            tooltip: part.tooltip.and_then(|tooltip| {
2489                                Some(match tooltip {
2490                                    InlayHintLabelPartTooltip::String(s) => {
2491                                        lsp::InlayHintLabelPartTooltip::String(s)
2492                                    }
2493                                    InlayHintLabelPartTooltip::MarkupContent(markup_content) => {
2494                                        lsp::InlayHintLabelPartTooltip::MarkupContent(
2495                                            lsp::MarkupContent {
2496                                                kind: match markup_content.kind {
2497                                                    HoverBlockKind::PlainText => {
2498                                                        lsp::MarkupKind::PlainText
2499                                                    }
2500                                                    HoverBlockKind::Markdown => {
2501                                                        lsp::MarkupKind::Markdown
2502                                                    }
2503                                                    HoverBlockKind::Code { .. } => return None,
2504                                                },
2505                                                value: markup_content.value,
2506                                            },
2507                                        )
2508                                    }
2509                                })
2510                            }),
2511                            location: part.location.map(|(_, location)| location),
2512                            command: None,
2513                        })
2514                        .collect(),
2515                ),
2516            },
2517            padding_left: Some(hint.padding_left),
2518            padding_right: Some(hint.padding_right),
2519            data: match hint.resolve_state {
2520                ResolveState::CanResolve(_, data) => data,
2521                ResolveState::Resolving | ResolveState::Resolved => None,
2522            },
2523        }
2524    }
2525
2526    pub fn can_resolve_inlays(capabilities: &ServerCapabilities) -> bool {
2527        capabilities
2528            .inlay_hint_provider
2529            .as_ref()
2530            .and_then(|options| match options {
2531                OneOf::Left(_is_supported) => None,
2532                OneOf::Right(capabilities) => match capabilities {
2533                    lsp::InlayHintServerCapabilities::Options(o) => o.resolve_provider,
2534                    lsp::InlayHintServerCapabilities::RegistrationOptions(o) => {
2535                        o.inlay_hint_options.resolve_provider
2536                    }
2537                },
2538            })
2539            .unwrap_or(false)
2540    }
2541}
2542
2543#[async_trait(?Send)]
2544impl LspCommand for InlayHints {
2545    type Response = Vec<InlayHint>;
2546    type LspRequest = lsp::InlayHintRequest;
2547    type ProtoRequest = proto::InlayHints;
2548
2549    fn check_capabilities(&self, server_capabilities: &lsp::ServerCapabilities) -> bool {
2550        let Some(inlay_hint_provider) = &server_capabilities.inlay_hint_provider else {
2551            return false;
2552        };
2553        match inlay_hint_provider {
2554            lsp::OneOf::Left(enabled) => *enabled,
2555            lsp::OneOf::Right(inlay_hint_capabilities) => match inlay_hint_capabilities {
2556                lsp::InlayHintServerCapabilities::Options(_) => true,
2557                lsp::InlayHintServerCapabilities::RegistrationOptions(_) => false,
2558            },
2559        }
2560    }
2561
2562    fn to_lsp(
2563        &self,
2564        path: &Path,
2565        buffer: &Buffer,
2566        _: &Arc<LanguageServer>,
2567        _: &AppContext,
2568    ) -> lsp::InlayHintParams {
2569        lsp::InlayHintParams {
2570            text_document: lsp::TextDocumentIdentifier {
2571                uri: lsp::Url::from_file_path(path).unwrap(),
2572            },
2573            range: range_to_lsp(self.range.to_point_utf16(buffer)),
2574            work_done_progress_params: Default::default(),
2575        }
2576    }
2577
2578    async fn response_from_lsp(
2579        self,
2580        message: Option<Vec<lsp::InlayHint>>,
2581        project: Model<Project>,
2582        buffer: Model<Buffer>,
2583        server_id: LanguageServerId,
2584        mut cx: AsyncAppContext,
2585    ) -> anyhow::Result<Vec<InlayHint>> {
2586        let (lsp_adapter, lsp_server) =
2587            language_server_for_buffer(&project, &buffer, server_id, &mut cx)?;
2588        // `typescript-language-server` adds padding to the left for type hints, turning
2589        // `const foo: boolean` into `const foo : boolean` which looks odd.
2590        // `rust-analyzer` does not have the padding for this case, and we have to accommodate both.
2591        //
2592        // We could trim the whole string, but being pessimistic on par with the situation above,
2593        // there might be a hint with multiple whitespaces at the end(s) which we need to display properly.
2594        // Hence let's use a heuristic first to handle the most awkward case and look for more.
2595        let force_no_type_left_padding =
2596            lsp_adapter.name.0.as_ref() == "typescript-language-server";
2597
2598        let hints = message.unwrap_or_default().into_iter().map(|lsp_hint| {
2599            let resolve_state = if InlayHints::can_resolve_inlays(&lsp_server.capabilities()) {
2600                ResolveState::CanResolve(lsp_server.server_id(), lsp_hint.data.clone())
2601            } else {
2602                ResolveState::Resolved
2603            };
2604
2605            let buffer = buffer.clone();
2606            cx.spawn(move |mut cx| async move {
2607                InlayHints::lsp_to_project_hint(
2608                    lsp_hint,
2609                    &buffer,
2610                    server_id,
2611                    resolve_state,
2612                    force_no_type_left_padding,
2613                    &mut cx,
2614                )
2615                .await
2616            })
2617        });
2618        future::join_all(hints)
2619            .await
2620            .into_iter()
2621            .collect::<anyhow::Result<_>>()
2622            .context("lsp to project inlay hints conversion")
2623    }
2624
2625    fn to_proto(&self, project_id: u64, buffer: &Buffer) -> proto::InlayHints {
2626        proto::InlayHints {
2627            project_id,
2628            buffer_id: buffer.remote_id().into(),
2629            start: Some(language::proto::serialize_anchor(&self.range.start)),
2630            end: Some(language::proto::serialize_anchor(&self.range.end)),
2631            version: serialize_version(&buffer.version()),
2632        }
2633    }
2634
2635    async fn from_proto(
2636        message: proto::InlayHints,
2637        _: Model<Project>,
2638        buffer: Model<Buffer>,
2639        mut cx: AsyncAppContext,
2640    ) -> Result<Self> {
2641        let start = message
2642            .start
2643            .and_then(language::proto::deserialize_anchor)
2644            .context("invalid start")?;
2645        let end = message
2646            .end
2647            .and_then(language::proto::deserialize_anchor)
2648            .context("invalid end")?;
2649        buffer
2650            .update(&mut cx, |buffer, _| {
2651                buffer.wait_for_version(deserialize_version(&message.version))
2652            })?
2653            .await?;
2654
2655        Ok(Self { range: start..end })
2656    }
2657
2658    fn response_to_proto(
2659        response: Vec<InlayHint>,
2660        _: &mut Project,
2661        _: PeerId,
2662        buffer_version: &clock::Global,
2663        _: &mut AppContext,
2664    ) -> proto::InlayHintsResponse {
2665        proto::InlayHintsResponse {
2666            hints: response
2667                .into_iter()
2668                .map(|response_hint| InlayHints::project_to_proto_hint(response_hint))
2669                .collect(),
2670            version: serialize_version(buffer_version),
2671        }
2672    }
2673
2674    async fn response_from_proto(
2675        self,
2676        message: proto::InlayHintsResponse,
2677        _: Model<Project>,
2678        buffer: Model<Buffer>,
2679        mut cx: AsyncAppContext,
2680    ) -> anyhow::Result<Vec<InlayHint>> {
2681        buffer
2682            .update(&mut cx, |buffer, _| {
2683                buffer.wait_for_version(deserialize_version(&message.version))
2684            })?
2685            .await?;
2686
2687        let mut hints = Vec::new();
2688        for message_hint in message.hints {
2689            hints.push(InlayHints::proto_to_project_hint(message_hint)?);
2690        }
2691
2692        Ok(hints)
2693    }
2694
2695    fn buffer_id_from_proto(message: &proto::InlayHints) -> Result<BufferId> {
2696        BufferId::new(message.buffer_id)
2697    }
2698}
2699
2700#[async_trait(?Send)]
2701impl LspCommand for LinkedEditingRange {
2702    type Response = Vec<Range<Anchor>>;
2703    type LspRequest = lsp::request::LinkedEditingRange;
2704    type ProtoRequest = proto::LinkedEditingRange;
2705
2706    fn check_capabilities(&self, server_capabilities: &lsp::ServerCapabilities) -> bool {
2707        let Some(linked_editing_options) = &server_capabilities.linked_editing_range_provider
2708        else {
2709            return false;
2710        };
2711        if let LinkedEditingRangeServerCapabilities::Simple(false) = linked_editing_options {
2712            return false;
2713        }
2714        return true;
2715    }
2716
2717    fn to_lsp(
2718        &self,
2719        path: &Path,
2720        buffer: &Buffer,
2721        _server: &Arc<LanguageServer>,
2722        _: &AppContext,
2723    ) -> lsp::LinkedEditingRangeParams {
2724        let position = self.position.to_point_utf16(&buffer.snapshot());
2725        lsp::LinkedEditingRangeParams {
2726            text_document_position_params: lsp::TextDocumentPositionParams::new(
2727                lsp::TextDocumentIdentifier::new(lsp::Url::from_file_path(path).unwrap()),
2728                point_to_lsp(position),
2729            ),
2730            work_done_progress_params: Default::default(),
2731        }
2732    }
2733
2734    async fn response_from_lsp(
2735        self,
2736        message: Option<lsp::LinkedEditingRanges>,
2737        _project: Model<Project>,
2738        buffer: Model<Buffer>,
2739        _server_id: LanguageServerId,
2740        cx: AsyncAppContext,
2741    ) -> Result<Vec<Range<Anchor>>> {
2742        if let Some(lsp::LinkedEditingRanges { mut ranges, .. }) = message {
2743            ranges.sort_by_key(|range| range.start);
2744            let ranges = buffer.read_with(&cx, |buffer, _| {
2745                ranges
2746                    .into_iter()
2747                    .map(|range| {
2748                        let start =
2749                            buffer.clip_point_utf16(point_from_lsp(range.start), Bias::Left);
2750                        let end = buffer.clip_point_utf16(point_from_lsp(range.end), Bias::Left);
2751                        buffer.anchor_before(start)..buffer.anchor_after(end)
2752                    })
2753                    .collect()
2754            });
2755
2756            ranges
2757        } else {
2758            Ok(vec![])
2759        }
2760    }
2761
2762    fn to_proto(&self, project_id: u64, buffer: &Buffer) -> proto::LinkedEditingRange {
2763        proto::LinkedEditingRange {
2764            project_id,
2765            buffer_id: buffer.remote_id().to_proto(),
2766            position: Some(serialize_anchor(&self.position)),
2767            version: serialize_version(&buffer.version()),
2768        }
2769    }
2770
2771    async fn from_proto(
2772        message: proto::LinkedEditingRange,
2773        _project: Model<Project>,
2774        buffer: Model<Buffer>,
2775        mut cx: AsyncAppContext,
2776    ) -> Result<Self> {
2777        let position = message
2778            .position
2779            .ok_or_else(|| anyhow!("invalid position"))?;
2780        buffer
2781            .update(&mut cx, |buffer, _| {
2782                buffer.wait_for_version(deserialize_version(&message.version))
2783            })?
2784            .await?;
2785        let position = deserialize_anchor(position).ok_or_else(|| anyhow!("invalid position"))?;
2786        buffer
2787            .update(&mut cx, |buffer, _| buffer.wait_for_anchors([position]))?
2788            .await?;
2789        Ok(Self { position })
2790    }
2791
2792    fn response_to_proto(
2793        response: Vec<Range<Anchor>>,
2794        _: &mut Project,
2795        _: PeerId,
2796        buffer_version: &clock::Global,
2797        _: &mut AppContext,
2798    ) -> proto::LinkedEditingRangeResponse {
2799        proto::LinkedEditingRangeResponse {
2800            items: response
2801                .into_iter()
2802                .map(|range| proto::AnchorRange {
2803                    start: Some(serialize_anchor(&range.start)),
2804                    end: Some(serialize_anchor(&range.end)),
2805                })
2806                .collect(),
2807            version: serialize_version(buffer_version),
2808        }
2809    }
2810
2811    async fn response_from_proto(
2812        self,
2813        message: proto::LinkedEditingRangeResponse,
2814        _: Model<Project>,
2815        buffer: Model<Buffer>,
2816        mut cx: AsyncAppContext,
2817    ) -> Result<Vec<Range<Anchor>>> {
2818        buffer
2819            .update(&mut cx, |buffer, _| {
2820                buffer.wait_for_version(deserialize_version(&message.version))
2821            })?
2822            .await?;
2823        let items: Vec<Range<Anchor>> = message
2824            .items
2825            .into_iter()
2826            .filter_map(|range| {
2827                let start = deserialize_anchor(range.start?)?;
2828                let end = deserialize_anchor(range.end?)?;
2829                Some(start..end)
2830            })
2831            .collect();
2832        for range in &items {
2833            buffer
2834                .update(&mut cx, |buffer, _| {
2835                    buffer.wait_for_anchors([range.start, range.end])
2836                })?
2837                .await?;
2838        }
2839        Ok(items)
2840    }
2841
2842    fn buffer_id_from_proto(message: &proto::LinkedEditingRange) -> Result<BufferId> {
2843        BufferId::new(message.buffer_id)
2844    }
2845}