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