lsp_command.rs

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