lsp_command.rs

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