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