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