lsp_command.rs

   1use crate::{
   2    DocumentHighlight, Hover, HoverBlock, Location, LocationLink, Project, ProjectTransaction,
   3};
   4use anyhow::{anyhow, Result};
   5use async_trait::async_trait;
   6use client::proto::{self, PeerId};
   7use fs::LineEnding;
   8use gpui::{AppContext, AsyncAppContext, ModelHandle};
   9use language::{
  10    point_from_lsp, point_to_lsp,
  11    proto::{deserialize_anchor, deserialize_version, serialize_anchor, serialize_version},
  12    range_from_lsp, range_to_lsp, Anchor, Bias, Buffer, CachedLspAdapter, CharKind, CodeAction,
  13    Completion, OffsetRangeExt, PointUtf16, ToOffset, ToPointUtf16, Unclipped,
  14};
  15use lsp::{DocumentHighlightKind, LanguageServer, LanguageServerId, ServerCapabilities};
  16use pulldown_cmark::{CodeBlockKind, Event, Options, Parser, Tag};
  17use std::{cmp::Reverse, ops::Range, path::Path, sync::Arc};
  18
  19#[async_trait(?Send)]
  20pub(crate) trait LspCommand: 'static + Sized {
  21    type Response: 'static + Default + Send;
  22    type LspRequest: 'static + Send + lsp::request::Request;
  23    type ProtoRequest: 'static + Send + proto::RequestMessage;
  24
  25    fn check_capabilities(&self, _: &lsp::ServerCapabilities) -> bool {
  26        true
  27    }
  28
  29    fn to_lsp(
  30        &self,
  31        path: &Path,
  32        buffer: &Buffer,
  33        language_server: &Arc<LanguageServer>,
  34        cx: &AppContext,
  35    ) -> <Self::LspRequest as lsp::request::Request>::Params;
  36
  37    async fn response_from_lsp(
  38        self,
  39        message: <Self::LspRequest as lsp::request::Request>::Result,
  40        project: ModelHandle<Project>,
  41        buffer: ModelHandle<Buffer>,
  42        server_id: LanguageServerId,
  43        cx: AsyncAppContext,
  44    ) -> Result<Self::Response>;
  45
  46    fn to_proto(&self, project_id: u64, buffer: &Buffer) -> Self::ProtoRequest;
  47
  48    async fn from_proto(
  49        message: Self::ProtoRequest,
  50        project: ModelHandle<Project>,
  51        buffer: ModelHandle<Buffer>,
  52        cx: AsyncAppContext,
  53    ) -> Result<Self>;
  54
  55    fn response_to_proto(
  56        response: Self::Response,
  57        project: &mut Project,
  58        peer_id: PeerId,
  59        buffer_version: &clock::Global,
  60        cx: &mut AppContext,
  61    ) -> <Self::ProtoRequest as proto::RequestMessage>::Response;
  62
  63    async fn response_from_proto(
  64        self,
  65        message: <Self::ProtoRequest as proto::RequestMessage>::Response,
  66        project: ModelHandle<Project>,
  67        buffer: ModelHandle<Buffer>,
  68        cx: AsyncAppContext,
  69    ) -> Result<Self::Response>;
  70
  71    fn buffer_id_from_proto(message: &Self::ProtoRequest) -> u64;
  72}
  73
  74pub(crate) struct PrepareRename {
  75    pub position: PointUtf16,
  76}
  77
  78pub(crate) struct PerformRename {
  79    pub position: PointUtf16,
  80    pub new_name: String,
  81    pub push_to_history: bool,
  82}
  83
  84pub(crate) struct GetDefinition {
  85    pub position: PointUtf16,
  86}
  87
  88pub(crate) struct GetTypeDefinition {
  89    pub position: PointUtf16,
  90}
  91
  92pub(crate) struct GetReferences {
  93    pub position: PointUtf16,
  94}
  95
  96pub(crate) struct GetDocumentHighlights {
  97    pub position: PointUtf16,
  98}
  99
 100pub(crate) struct GetHover {
 101    pub position: PointUtf16,
 102}
 103
 104pub(crate) struct GetCompletions {
 105    pub position: PointUtf16,
 106}
 107
 108pub(crate) struct GetCodeActions {
 109    pub range: Range<Anchor>,
 110}
 111
 112#[async_trait(?Send)]
 113impl LspCommand for PrepareRename {
 114    type Response = Option<Range<Anchor>>;
 115    type LspRequest = lsp::request::PrepareRenameRequest;
 116    type ProtoRequest = proto::PrepareRename;
 117
 118    fn check_capabilities(&self, capabilities: &ServerCapabilities) -> bool {
 119        if let Some(lsp::OneOf::Right(rename)) = &capabilities.rename_provider {
 120            rename.prepare_provider == Some(true)
 121        } else {
 122            false
 123        }
 124    }
 125
 126    fn to_lsp(
 127        &self,
 128        path: &Path,
 129        _: &Buffer,
 130        _: &Arc<LanguageServer>,
 131        _: &AppContext,
 132    ) -> lsp::TextDocumentPositionParams {
 133        lsp::TextDocumentPositionParams {
 134            text_document: lsp::TextDocumentIdentifier {
 135                uri: lsp::Url::from_file_path(path).unwrap(),
 136            },
 137            position: point_to_lsp(self.position),
 138        }
 139    }
 140
 141    async fn response_from_lsp(
 142        self,
 143        message: Option<lsp::PrepareRenameResponse>,
 144        _: ModelHandle<Project>,
 145        buffer: ModelHandle<Buffer>,
 146        _: LanguageServerId,
 147        cx: AsyncAppContext,
 148    ) -> Result<Option<Range<Anchor>>> {
 149        buffer.read_with(&cx, |buffer, _| {
 150            if let Some(
 151                lsp::PrepareRenameResponse::Range(range)
 152                | lsp::PrepareRenameResponse::RangeWithPlaceholder { range, .. },
 153            ) = message
 154            {
 155                let Range { start, end } = range_from_lsp(range);
 156                if buffer.clip_point_utf16(start, Bias::Left) == start.0
 157                    && buffer.clip_point_utf16(end, Bias::Left) == end.0
 158                {
 159                    return Ok(Some(buffer.anchor_after(start)..buffer.anchor_before(end)));
 160                }
 161            }
 162            Ok(None)
 163        })
 164    }
 165
 166    fn to_proto(&self, project_id: u64, buffer: &Buffer) -> proto::PrepareRename {
 167        proto::PrepareRename {
 168            project_id,
 169            buffer_id: buffer.remote_id(),
 170            position: Some(language::proto::serialize_anchor(
 171                &buffer.anchor_before(self.position),
 172            )),
 173            version: serialize_version(&buffer.version()),
 174        }
 175    }
 176
 177    async fn from_proto(
 178        message: proto::PrepareRename,
 179        _: ModelHandle<Project>,
 180        buffer: ModelHandle<Buffer>,
 181        mut cx: AsyncAppContext,
 182    ) -> Result<Self> {
 183        let position = message
 184            .position
 185            .and_then(deserialize_anchor)
 186            .ok_or_else(|| anyhow!("invalid position"))?;
 187        buffer
 188            .update(&mut cx, |buffer, _| {
 189                buffer.wait_for_version(deserialize_version(&message.version))
 190            })
 191            .await?;
 192
 193        Ok(Self {
 194            position: buffer.read_with(&cx, |buffer, _| position.to_point_utf16(buffer)),
 195        })
 196    }
 197
 198    fn response_to_proto(
 199        range: Option<Range<Anchor>>,
 200        _: &mut Project,
 201        _: PeerId,
 202        buffer_version: &clock::Global,
 203        _: &mut AppContext,
 204    ) -> proto::PrepareRenameResponse {
 205        proto::PrepareRenameResponse {
 206            can_rename: range.is_some(),
 207            start: range
 208                .as_ref()
 209                .map(|range| language::proto::serialize_anchor(&range.start)),
 210            end: range
 211                .as_ref()
 212                .map(|range| language::proto::serialize_anchor(&range.end)),
 213            version: serialize_version(buffer_version),
 214        }
 215    }
 216
 217    async fn response_from_proto(
 218        self,
 219        message: proto::PrepareRenameResponse,
 220        _: ModelHandle<Project>,
 221        buffer: ModelHandle<Buffer>,
 222        mut cx: AsyncAppContext,
 223    ) -> Result<Option<Range<Anchor>>> {
 224        if message.can_rename {
 225            buffer
 226                .update(&mut cx, |buffer, _| {
 227                    buffer.wait_for_version(deserialize_version(&message.version))
 228                })
 229                .await?;
 230            let start = message.start.and_then(deserialize_anchor);
 231            let end = message.end.and_then(deserialize_anchor);
 232            Ok(start.zip(end).map(|(start, end)| start..end))
 233        } else {
 234            Ok(None)
 235        }
 236    }
 237
 238    fn buffer_id_from_proto(message: &proto::PrepareRename) -> u64 {
 239        message.buffer_id
 240    }
 241}
 242
 243#[async_trait(?Send)]
 244impl LspCommand for PerformRename {
 245    type Response = ProjectTransaction;
 246    type LspRequest = lsp::request::Rename;
 247    type ProtoRequest = proto::PerformRename;
 248
 249    fn to_lsp(
 250        &self,
 251        path: &Path,
 252        _: &Buffer,
 253        _: &Arc<LanguageServer>,
 254        _: &AppContext,
 255    ) -> lsp::RenameParams {
 256        lsp::RenameParams {
 257            text_document_position: lsp::TextDocumentPositionParams {
 258                text_document: lsp::TextDocumentIdentifier {
 259                    uri: lsp::Url::from_file_path(path).unwrap(),
 260                },
 261                position: point_to_lsp(self.position),
 262            },
 263            new_name: self.new_name.clone(),
 264            work_done_progress_params: Default::default(),
 265        }
 266    }
 267
 268    async fn response_from_lsp(
 269        self,
 270        message: Option<lsp::WorkspaceEdit>,
 271        project: ModelHandle<Project>,
 272        buffer: ModelHandle<Buffer>,
 273        server_id: LanguageServerId,
 274        mut cx: AsyncAppContext,
 275    ) -> Result<ProjectTransaction> {
 276        if let Some(edit) = message {
 277            let (lsp_adapter, lsp_server) =
 278                language_server_for_buffer(&project, &buffer, server_id, &mut cx)?;
 279            Project::deserialize_workspace_edit(
 280                project,
 281                edit,
 282                self.push_to_history,
 283                lsp_adapter,
 284                lsp_server,
 285                &mut cx,
 286            )
 287            .await
 288        } else {
 289            Ok(ProjectTransaction::default())
 290        }
 291    }
 292
 293    fn to_proto(&self, project_id: u64, buffer: &Buffer) -> proto::PerformRename {
 294        proto::PerformRename {
 295            project_id,
 296            buffer_id: buffer.remote_id(),
 297            position: Some(language::proto::serialize_anchor(
 298                &buffer.anchor_before(self.position),
 299            )),
 300            new_name: self.new_name.clone(),
 301            version: serialize_version(&buffer.version()),
 302        }
 303    }
 304
 305    async fn from_proto(
 306        message: proto::PerformRename,
 307        _: ModelHandle<Project>,
 308        buffer: ModelHandle<Buffer>,
 309        mut cx: AsyncAppContext,
 310    ) -> Result<Self> {
 311        let position = message
 312            .position
 313            .and_then(deserialize_anchor)
 314            .ok_or_else(|| anyhow!("invalid position"))?;
 315        buffer
 316            .update(&mut cx, |buffer, _| {
 317                buffer.wait_for_version(deserialize_version(&message.version))
 318            })
 319            .await?;
 320        Ok(Self {
 321            position: buffer.read_with(&cx, |buffer, _| position.to_point_utf16(buffer)),
 322            new_name: message.new_name,
 323            push_to_history: false,
 324        })
 325    }
 326
 327    fn response_to_proto(
 328        response: ProjectTransaction,
 329        project: &mut Project,
 330        peer_id: PeerId,
 331        _: &clock::Global,
 332        cx: &mut AppContext,
 333    ) -> proto::PerformRenameResponse {
 334        let transaction = project.serialize_project_transaction_for_peer(response, peer_id, cx);
 335        proto::PerformRenameResponse {
 336            transaction: Some(transaction),
 337        }
 338    }
 339
 340    async fn response_from_proto(
 341        self,
 342        message: proto::PerformRenameResponse,
 343        project: ModelHandle<Project>,
 344        _: ModelHandle<Buffer>,
 345        mut cx: AsyncAppContext,
 346    ) -> Result<ProjectTransaction> {
 347        let message = message
 348            .transaction
 349            .ok_or_else(|| anyhow!("missing transaction"))?;
 350        project
 351            .update(&mut cx, |project, cx| {
 352                project.deserialize_project_transaction(message, self.push_to_history, cx)
 353            })
 354            .await
 355    }
 356
 357    fn buffer_id_from_proto(message: &proto::PerformRename) -> u64 {
 358        message.buffer_id
 359    }
 360}
 361
 362#[async_trait(?Send)]
 363impl LspCommand for GetDefinition {
 364    type Response = Vec<LocationLink>;
 365    type LspRequest = lsp::request::GotoDefinition;
 366    type ProtoRequest = proto::GetDefinition;
 367
 368    fn to_lsp(
 369        &self,
 370        path: &Path,
 371        _: &Buffer,
 372        _: &Arc<LanguageServer>,
 373        _: &AppContext,
 374    ) -> lsp::GotoDefinitionParams {
 375        lsp::GotoDefinitionParams {
 376            text_document_position_params: lsp::TextDocumentPositionParams {
 377                text_document: lsp::TextDocumentIdentifier {
 378                    uri: lsp::Url::from_file_path(path).unwrap(),
 379                },
 380                position: point_to_lsp(self.position),
 381            },
 382            work_done_progress_params: Default::default(),
 383            partial_result_params: Default::default(),
 384        }
 385    }
 386
 387    async fn response_from_lsp(
 388        self,
 389        message: Option<lsp::GotoDefinitionResponse>,
 390        project: ModelHandle<Project>,
 391        buffer: ModelHandle<Buffer>,
 392        server_id: LanguageServerId,
 393        cx: AsyncAppContext,
 394    ) -> Result<Vec<LocationLink>> {
 395        location_links_from_lsp(message, project, buffer, server_id, cx).await
 396    }
 397
 398    fn to_proto(&self, project_id: u64, buffer: &Buffer) -> proto::GetDefinition {
 399        proto::GetDefinition {
 400            project_id,
 401            buffer_id: buffer.remote_id(),
 402            position: Some(language::proto::serialize_anchor(
 403                &buffer.anchor_before(self.position),
 404            )),
 405            version: serialize_version(&buffer.version()),
 406        }
 407    }
 408
 409    async fn from_proto(
 410        message: proto::GetDefinition,
 411        _: ModelHandle<Project>,
 412        buffer: ModelHandle<Buffer>,
 413        mut cx: AsyncAppContext,
 414    ) -> Result<Self> {
 415        let position = message
 416            .position
 417            .and_then(deserialize_anchor)
 418            .ok_or_else(|| anyhow!("invalid position"))?;
 419        buffer
 420            .update(&mut cx, |buffer, _| {
 421                buffer.wait_for_version(deserialize_version(&message.version))
 422            })
 423            .await?;
 424        Ok(Self {
 425            position: buffer.read_with(&cx, |buffer, _| position.to_point_utf16(buffer)),
 426        })
 427    }
 428
 429    fn response_to_proto(
 430        response: Vec<LocationLink>,
 431        project: &mut Project,
 432        peer_id: PeerId,
 433        _: &clock::Global,
 434        cx: &mut AppContext,
 435    ) -> proto::GetDefinitionResponse {
 436        let links = location_links_to_proto(response, project, peer_id, cx);
 437        proto::GetDefinitionResponse { links }
 438    }
 439
 440    async fn response_from_proto(
 441        self,
 442        message: proto::GetDefinitionResponse,
 443        project: ModelHandle<Project>,
 444        _: ModelHandle<Buffer>,
 445        cx: AsyncAppContext,
 446    ) -> Result<Vec<LocationLink>> {
 447        location_links_from_proto(message.links, project, cx).await
 448    }
 449
 450    fn buffer_id_from_proto(message: &proto::GetDefinition) -> u64 {
 451        message.buffer_id
 452    }
 453}
 454
 455#[async_trait(?Send)]
 456impl LspCommand for GetTypeDefinition {
 457    type Response = Vec<LocationLink>;
 458    type LspRequest = lsp::request::GotoTypeDefinition;
 459    type ProtoRequest = proto::GetTypeDefinition;
 460
 461    fn to_lsp(
 462        &self,
 463        path: &Path,
 464        _: &Buffer,
 465        _: &Arc<LanguageServer>,
 466        _: &AppContext,
 467    ) -> lsp::GotoTypeDefinitionParams {
 468        lsp::GotoTypeDefinitionParams {
 469            text_document_position_params: lsp::TextDocumentPositionParams {
 470                text_document: lsp::TextDocumentIdentifier {
 471                    uri: lsp::Url::from_file_path(path).unwrap(),
 472                },
 473                position: point_to_lsp(self.position),
 474            },
 475            work_done_progress_params: Default::default(),
 476            partial_result_params: Default::default(),
 477        }
 478    }
 479
 480    async fn response_from_lsp(
 481        self,
 482        message: Option<lsp::GotoTypeDefinitionResponse>,
 483        project: ModelHandle<Project>,
 484        buffer: ModelHandle<Buffer>,
 485        server_id: LanguageServerId,
 486        cx: AsyncAppContext,
 487    ) -> Result<Vec<LocationLink>> {
 488        location_links_from_lsp(message, project, buffer, server_id, cx).await
 489    }
 490
 491    fn to_proto(&self, project_id: u64, buffer: &Buffer) -> proto::GetTypeDefinition {
 492        proto::GetTypeDefinition {
 493            project_id,
 494            buffer_id: buffer.remote_id(),
 495            position: Some(language::proto::serialize_anchor(
 496                &buffer.anchor_before(self.position),
 497            )),
 498            version: serialize_version(&buffer.version()),
 499        }
 500    }
 501
 502    async fn from_proto(
 503        message: proto::GetTypeDefinition,
 504        _: ModelHandle<Project>,
 505        buffer: ModelHandle<Buffer>,
 506        mut cx: AsyncAppContext,
 507    ) -> Result<Self> {
 508        let position = message
 509            .position
 510            .and_then(deserialize_anchor)
 511            .ok_or_else(|| anyhow!("invalid position"))?;
 512        buffer
 513            .update(&mut cx, |buffer, _| {
 514                buffer.wait_for_version(deserialize_version(&message.version))
 515            })
 516            .await?;
 517        Ok(Self {
 518            position: buffer.read_with(&cx, |buffer, _| position.to_point_utf16(buffer)),
 519        })
 520    }
 521
 522    fn response_to_proto(
 523        response: Vec<LocationLink>,
 524        project: &mut Project,
 525        peer_id: PeerId,
 526        _: &clock::Global,
 527        cx: &mut AppContext,
 528    ) -> proto::GetTypeDefinitionResponse {
 529        let links = location_links_to_proto(response, project, peer_id, cx);
 530        proto::GetTypeDefinitionResponse { links }
 531    }
 532
 533    async fn response_from_proto(
 534        self,
 535        message: proto::GetTypeDefinitionResponse,
 536        project: ModelHandle<Project>,
 537        _: ModelHandle<Buffer>,
 538        cx: AsyncAppContext,
 539    ) -> Result<Vec<LocationLink>> {
 540        location_links_from_proto(message.links, project, cx).await
 541    }
 542
 543    fn buffer_id_from_proto(message: &proto::GetTypeDefinition) -> u64 {
 544        message.buffer_id
 545    }
 546}
 547
 548fn language_server_for_buffer(
 549    project: &ModelHandle<Project>,
 550    buffer: &ModelHandle<Buffer>,
 551    server_id: LanguageServerId,
 552    cx: &mut AsyncAppContext,
 553) -> Result<(Arc<CachedLspAdapter>, Arc<LanguageServer>)> {
 554    project
 555        .read_with(cx, |project, cx| {
 556            project
 557                .language_server_for_buffer(buffer.read(cx), server_id, cx)
 558                .map(|(adapter, server)| (adapter.clone(), server.clone()))
 559        })
 560        .ok_or_else(|| anyhow!("no language server found for buffer"))
 561}
 562
 563async fn location_links_from_proto(
 564    proto_links: Vec<proto::LocationLink>,
 565    project: ModelHandle<Project>,
 566    mut cx: AsyncAppContext,
 567) -> Result<Vec<LocationLink>> {
 568    let mut links = Vec::new();
 569
 570    for link in proto_links {
 571        let origin = match link.origin {
 572            Some(origin) => {
 573                let buffer = project
 574                    .update(&mut cx, |this, cx| {
 575                        this.wait_for_remote_buffer(origin.buffer_id, cx)
 576                    })
 577                    .await?;
 578                let start = origin
 579                    .start
 580                    .and_then(deserialize_anchor)
 581                    .ok_or_else(|| anyhow!("missing origin start"))?;
 582                let end = origin
 583                    .end
 584                    .and_then(deserialize_anchor)
 585                    .ok_or_else(|| anyhow!("missing origin end"))?;
 586                buffer
 587                    .update(&mut cx, |buffer, _| buffer.wait_for_anchors([start, end]))
 588                    .await?;
 589                Some(Location {
 590                    buffer,
 591                    range: start..end,
 592                })
 593            }
 594            None => None,
 595        };
 596
 597        let target = link.target.ok_or_else(|| anyhow!("missing target"))?;
 598        let buffer = project
 599            .update(&mut cx, |this, cx| {
 600                this.wait_for_remote_buffer(target.buffer_id, cx)
 601            })
 602            .await?;
 603        let start = target
 604            .start
 605            .and_then(deserialize_anchor)
 606            .ok_or_else(|| anyhow!("missing target start"))?;
 607        let end = target
 608            .end
 609            .and_then(deserialize_anchor)
 610            .ok_or_else(|| anyhow!("missing target end"))?;
 611        buffer
 612            .update(&mut cx, |buffer, _| buffer.wait_for_anchors([start, end]))
 613            .await?;
 614        let target = Location {
 615            buffer,
 616            range: start..end,
 617        };
 618
 619        links.push(LocationLink { origin, target })
 620    }
 621
 622    Ok(links)
 623}
 624
 625async fn location_links_from_lsp(
 626    message: Option<lsp::GotoDefinitionResponse>,
 627    project: ModelHandle<Project>,
 628    buffer: ModelHandle<Buffer>,
 629    server_id: LanguageServerId,
 630    mut cx: AsyncAppContext,
 631) -> Result<Vec<LocationLink>> {
 632    let message = match message {
 633        Some(message) => message,
 634        None => return Ok(Vec::new()),
 635    };
 636
 637    let mut unresolved_links = Vec::new();
 638    match message {
 639        lsp::GotoDefinitionResponse::Scalar(loc) => {
 640            unresolved_links.push((None, loc.uri, loc.range));
 641        }
 642
 643        lsp::GotoDefinitionResponse::Array(locs) => {
 644            unresolved_links.extend(locs.into_iter().map(|l| (None, l.uri, l.range)));
 645        }
 646
 647        lsp::GotoDefinitionResponse::Link(links) => {
 648            unresolved_links.extend(links.into_iter().map(|l| {
 649                (
 650                    l.origin_selection_range,
 651                    l.target_uri,
 652                    l.target_selection_range,
 653                )
 654            }));
 655        }
 656    }
 657
 658    let (lsp_adapter, language_server) =
 659        language_server_for_buffer(&project, &buffer, server_id, &mut cx)?;
 660    let mut definitions = Vec::new();
 661    for (origin_range, target_uri, target_range) in unresolved_links {
 662        let target_buffer_handle = project
 663            .update(&mut cx, |this, cx| {
 664                this.open_local_buffer_via_lsp(
 665                    target_uri,
 666                    language_server.server_id(),
 667                    lsp_adapter.name.clone(),
 668                    cx,
 669                )
 670            })
 671            .await?;
 672
 673        cx.read(|cx| {
 674            let origin_location = origin_range.map(|origin_range| {
 675                let origin_buffer = buffer.read(cx);
 676                let origin_start =
 677                    origin_buffer.clip_point_utf16(point_from_lsp(origin_range.start), Bias::Left);
 678                let origin_end =
 679                    origin_buffer.clip_point_utf16(point_from_lsp(origin_range.end), Bias::Left);
 680                Location {
 681                    buffer: buffer.clone(),
 682                    range: origin_buffer.anchor_after(origin_start)
 683                        ..origin_buffer.anchor_before(origin_end),
 684                }
 685            });
 686
 687            let target_buffer = target_buffer_handle.read(cx);
 688            let target_start =
 689                target_buffer.clip_point_utf16(point_from_lsp(target_range.start), Bias::Left);
 690            let target_end =
 691                target_buffer.clip_point_utf16(point_from_lsp(target_range.end), Bias::Left);
 692            let target_location = Location {
 693                buffer: target_buffer_handle,
 694                range: target_buffer.anchor_after(target_start)
 695                    ..target_buffer.anchor_before(target_end),
 696            };
 697
 698            definitions.push(LocationLink {
 699                origin: origin_location,
 700                target: target_location,
 701            })
 702        });
 703    }
 704    Ok(definitions)
 705}
 706
 707fn location_links_to_proto(
 708    links: Vec<LocationLink>,
 709    project: &mut Project,
 710    peer_id: PeerId,
 711    cx: &mut AppContext,
 712) -> Vec<proto::LocationLink> {
 713    links
 714        .into_iter()
 715        .map(|definition| {
 716            let origin = definition.origin.map(|origin| {
 717                let buffer_id = project.create_buffer_for_peer(&origin.buffer, peer_id, cx);
 718                proto::Location {
 719                    start: Some(serialize_anchor(&origin.range.start)),
 720                    end: Some(serialize_anchor(&origin.range.end)),
 721                    buffer_id,
 722                }
 723            });
 724
 725            let buffer_id = project.create_buffer_for_peer(&definition.target.buffer, peer_id, cx);
 726            let target = proto::Location {
 727                start: Some(serialize_anchor(&definition.target.range.start)),
 728                end: Some(serialize_anchor(&definition.target.range.end)),
 729                buffer_id,
 730            };
 731
 732            proto::LocationLink {
 733                origin,
 734                target: Some(target),
 735            }
 736        })
 737        .collect()
 738}
 739
 740#[async_trait(?Send)]
 741impl LspCommand for GetReferences {
 742    type Response = Vec<Location>;
 743    type LspRequest = lsp::request::References;
 744    type ProtoRequest = proto::GetReferences;
 745
 746    fn to_lsp(
 747        &self,
 748        path: &Path,
 749        _: &Buffer,
 750        _: &Arc<LanguageServer>,
 751        _: &AppContext,
 752    ) -> lsp::ReferenceParams {
 753        lsp::ReferenceParams {
 754            text_document_position: lsp::TextDocumentPositionParams {
 755                text_document: lsp::TextDocumentIdentifier {
 756                    uri: lsp::Url::from_file_path(path).unwrap(),
 757                },
 758                position: point_to_lsp(self.position),
 759            },
 760            work_done_progress_params: Default::default(),
 761            partial_result_params: Default::default(),
 762            context: lsp::ReferenceContext {
 763                include_declaration: true,
 764            },
 765        }
 766    }
 767
 768    async fn response_from_lsp(
 769        self,
 770        locations: Option<Vec<lsp::Location>>,
 771        project: ModelHandle<Project>,
 772        buffer: ModelHandle<Buffer>,
 773        server_id: LanguageServerId,
 774        mut cx: AsyncAppContext,
 775    ) -> Result<Vec<Location>> {
 776        let mut references = Vec::new();
 777        let (lsp_adapter, language_server) =
 778            language_server_for_buffer(&project, &buffer, server_id, &mut cx)?;
 779
 780        if let Some(locations) = locations {
 781            for lsp_location in locations {
 782                let target_buffer_handle = project
 783                    .update(&mut cx, |this, cx| {
 784                        this.open_local_buffer_via_lsp(
 785                            lsp_location.uri,
 786                            language_server.server_id(),
 787                            lsp_adapter.name.clone(),
 788                            cx,
 789                        )
 790                    })
 791                    .await?;
 792
 793                cx.read(|cx| {
 794                    let target_buffer = target_buffer_handle.read(cx);
 795                    let target_start = target_buffer
 796                        .clip_point_utf16(point_from_lsp(lsp_location.range.start), Bias::Left);
 797                    let target_end = target_buffer
 798                        .clip_point_utf16(point_from_lsp(lsp_location.range.end), Bias::Left);
 799                    references.push(Location {
 800                        buffer: target_buffer_handle,
 801                        range: target_buffer.anchor_after(target_start)
 802                            ..target_buffer.anchor_before(target_end),
 803                    });
 804                });
 805            }
 806        }
 807
 808        Ok(references)
 809    }
 810
 811    fn to_proto(&self, project_id: u64, buffer: &Buffer) -> proto::GetReferences {
 812        proto::GetReferences {
 813            project_id,
 814            buffer_id: buffer.remote_id(),
 815            position: Some(language::proto::serialize_anchor(
 816                &buffer.anchor_before(self.position),
 817            )),
 818            version: serialize_version(&buffer.version()),
 819        }
 820    }
 821
 822    async fn from_proto(
 823        message: proto::GetReferences,
 824        _: ModelHandle<Project>,
 825        buffer: ModelHandle<Buffer>,
 826        mut cx: AsyncAppContext,
 827    ) -> Result<Self> {
 828        let position = message
 829            .position
 830            .and_then(deserialize_anchor)
 831            .ok_or_else(|| anyhow!("invalid position"))?;
 832        buffer
 833            .update(&mut cx, |buffer, _| {
 834                buffer.wait_for_version(deserialize_version(&message.version))
 835            })
 836            .await?;
 837        Ok(Self {
 838            position: buffer.read_with(&cx, |buffer, _| position.to_point_utf16(buffer)),
 839        })
 840    }
 841
 842    fn response_to_proto(
 843        response: Vec<Location>,
 844        project: &mut Project,
 845        peer_id: PeerId,
 846        _: &clock::Global,
 847        cx: &mut AppContext,
 848    ) -> proto::GetReferencesResponse {
 849        let locations = response
 850            .into_iter()
 851            .map(|definition| {
 852                let buffer_id = project.create_buffer_for_peer(&definition.buffer, peer_id, cx);
 853                proto::Location {
 854                    start: Some(serialize_anchor(&definition.range.start)),
 855                    end: Some(serialize_anchor(&definition.range.end)),
 856                    buffer_id,
 857                }
 858            })
 859            .collect();
 860        proto::GetReferencesResponse { locations }
 861    }
 862
 863    async fn response_from_proto(
 864        self,
 865        message: proto::GetReferencesResponse,
 866        project: ModelHandle<Project>,
 867        _: ModelHandle<Buffer>,
 868        mut cx: AsyncAppContext,
 869    ) -> Result<Vec<Location>> {
 870        let mut locations = Vec::new();
 871        for location in message.locations {
 872            let target_buffer = project
 873                .update(&mut cx, |this, cx| {
 874                    this.wait_for_remote_buffer(location.buffer_id, cx)
 875                })
 876                .await?;
 877            let start = location
 878                .start
 879                .and_then(deserialize_anchor)
 880                .ok_or_else(|| anyhow!("missing target start"))?;
 881            let end = location
 882                .end
 883                .and_then(deserialize_anchor)
 884                .ok_or_else(|| anyhow!("missing target end"))?;
 885            target_buffer
 886                .update(&mut cx, |buffer, _| buffer.wait_for_anchors([start, end]))
 887                .await?;
 888            locations.push(Location {
 889                buffer: target_buffer,
 890                range: start..end,
 891            })
 892        }
 893        Ok(locations)
 894    }
 895
 896    fn buffer_id_from_proto(message: &proto::GetReferences) -> u64 {
 897        message.buffer_id
 898    }
 899}
 900
 901#[async_trait(?Send)]
 902impl LspCommand for GetDocumentHighlights {
 903    type Response = Vec<DocumentHighlight>;
 904    type LspRequest = lsp::request::DocumentHighlightRequest;
 905    type ProtoRequest = proto::GetDocumentHighlights;
 906
 907    fn check_capabilities(&self, capabilities: &ServerCapabilities) -> bool {
 908        capabilities.document_highlight_provider.is_some()
 909    }
 910
 911    fn to_lsp(
 912        &self,
 913        path: &Path,
 914        _: &Buffer,
 915        _: &Arc<LanguageServer>,
 916        _: &AppContext,
 917    ) -> lsp::DocumentHighlightParams {
 918        lsp::DocumentHighlightParams {
 919            text_document_position_params: lsp::TextDocumentPositionParams {
 920                text_document: lsp::TextDocumentIdentifier {
 921                    uri: lsp::Url::from_file_path(path).unwrap(),
 922                },
 923                position: point_to_lsp(self.position),
 924            },
 925            work_done_progress_params: Default::default(),
 926            partial_result_params: Default::default(),
 927        }
 928    }
 929
 930    async fn response_from_lsp(
 931        self,
 932        lsp_highlights: Option<Vec<lsp::DocumentHighlight>>,
 933        _: ModelHandle<Project>,
 934        buffer: ModelHandle<Buffer>,
 935        _: LanguageServerId,
 936        cx: AsyncAppContext,
 937    ) -> Result<Vec<DocumentHighlight>> {
 938        buffer.read_with(&cx, |buffer, _| {
 939            let mut lsp_highlights = lsp_highlights.unwrap_or_default();
 940            lsp_highlights.sort_unstable_by_key(|h| (h.range.start, Reverse(h.range.end)));
 941            Ok(lsp_highlights
 942                .into_iter()
 943                .map(|lsp_highlight| {
 944                    let start = buffer
 945                        .clip_point_utf16(point_from_lsp(lsp_highlight.range.start), Bias::Left);
 946                    let end = buffer
 947                        .clip_point_utf16(point_from_lsp(lsp_highlight.range.end), Bias::Left);
 948                    DocumentHighlight {
 949                        range: buffer.anchor_after(start)..buffer.anchor_before(end),
 950                        kind: lsp_highlight
 951                            .kind
 952                            .unwrap_or(lsp::DocumentHighlightKind::READ),
 953                    }
 954                })
 955                .collect())
 956        })
 957    }
 958
 959    fn to_proto(&self, project_id: u64, buffer: &Buffer) -> proto::GetDocumentHighlights {
 960        proto::GetDocumentHighlights {
 961            project_id,
 962            buffer_id: buffer.remote_id(),
 963            position: Some(language::proto::serialize_anchor(
 964                &buffer.anchor_before(self.position),
 965            )),
 966            version: serialize_version(&buffer.version()),
 967        }
 968    }
 969
 970    async fn from_proto(
 971        message: proto::GetDocumentHighlights,
 972        _: ModelHandle<Project>,
 973        buffer: ModelHandle<Buffer>,
 974        mut cx: AsyncAppContext,
 975    ) -> Result<Self> {
 976        let position = message
 977            .position
 978            .and_then(deserialize_anchor)
 979            .ok_or_else(|| anyhow!("invalid position"))?;
 980        buffer
 981            .update(&mut cx, |buffer, _| {
 982                buffer.wait_for_version(deserialize_version(&message.version))
 983            })
 984            .await?;
 985        Ok(Self {
 986            position: buffer.read_with(&cx, |buffer, _| position.to_point_utf16(buffer)),
 987        })
 988    }
 989
 990    fn response_to_proto(
 991        response: Vec<DocumentHighlight>,
 992        _: &mut Project,
 993        _: PeerId,
 994        _: &clock::Global,
 995        _: &mut AppContext,
 996    ) -> proto::GetDocumentHighlightsResponse {
 997        let highlights = response
 998            .into_iter()
 999            .map(|highlight| proto::DocumentHighlight {
1000                start: Some(serialize_anchor(&highlight.range.start)),
1001                end: Some(serialize_anchor(&highlight.range.end)),
1002                kind: match highlight.kind {
1003                    DocumentHighlightKind::TEXT => proto::document_highlight::Kind::Text.into(),
1004                    DocumentHighlightKind::WRITE => proto::document_highlight::Kind::Write.into(),
1005                    DocumentHighlightKind::READ => proto::document_highlight::Kind::Read.into(),
1006                    _ => proto::document_highlight::Kind::Text.into(),
1007                },
1008            })
1009            .collect();
1010        proto::GetDocumentHighlightsResponse { highlights }
1011    }
1012
1013    async fn response_from_proto(
1014        self,
1015        message: proto::GetDocumentHighlightsResponse,
1016        _: ModelHandle<Project>,
1017        buffer: ModelHandle<Buffer>,
1018        mut cx: AsyncAppContext,
1019    ) -> Result<Vec<DocumentHighlight>> {
1020        let mut highlights = Vec::new();
1021        for highlight in message.highlights {
1022            let start = highlight
1023                .start
1024                .and_then(deserialize_anchor)
1025                .ok_or_else(|| anyhow!("missing target start"))?;
1026            let end = highlight
1027                .end
1028                .and_then(deserialize_anchor)
1029                .ok_or_else(|| anyhow!("missing target end"))?;
1030            buffer
1031                .update(&mut cx, |buffer, _| buffer.wait_for_anchors([start, end]))
1032                .await?;
1033            let kind = match proto::document_highlight::Kind::from_i32(highlight.kind) {
1034                Some(proto::document_highlight::Kind::Text) => DocumentHighlightKind::TEXT,
1035                Some(proto::document_highlight::Kind::Read) => DocumentHighlightKind::READ,
1036                Some(proto::document_highlight::Kind::Write) => DocumentHighlightKind::WRITE,
1037                None => DocumentHighlightKind::TEXT,
1038            };
1039            highlights.push(DocumentHighlight {
1040                range: start..end,
1041                kind,
1042            });
1043        }
1044        Ok(highlights)
1045    }
1046
1047    fn buffer_id_from_proto(message: &proto::GetDocumentHighlights) -> u64 {
1048        message.buffer_id
1049    }
1050}
1051
1052#[async_trait(?Send)]
1053impl LspCommand for GetHover {
1054    type Response = Option<Hover>;
1055    type LspRequest = lsp::request::HoverRequest;
1056    type ProtoRequest = proto::GetHover;
1057
1058    fn to_lsp(
1059        &self,
1060        path: &Path,
1061        _: &Buffer,
1062        _: &Arc<LanguageServer>,
1063        _: &AppContext,
1064    ) -> lsp::HoverParams {
1065        lsp::HoverParams {
1066            text_document_position_params: lsp::TextDocumentPositionParams {
1067                text_document: lsp::TextDocumentIdentifier {
1068                    uri: lsp::Url::from_file_path(path).unwrap(),
1069                },
1070                position: point_to_lsp(self.position),
1071            },
1072            work_done_progress_params: Default::default(),
1073        }
1074    }
1075
1076    async fn response_from_lsp(
1077        self,
1078        message: Option<lsp::Hover>,
1079        _: ModelHandle<Project>,
1080        buffer: ModelHandle<Buffer>,
1081        _: LanguageServerId,
1082        cx: AsyncAppContext,
1083    ) -> Result<Self::Response> {
1084        Ok(message.and_then(|hover| {
1085            let range = hover.range.map(|range| {
1086                cx.read(|cx| {
1087                    let buffer = buffer.read(cx);
1088                    let token_start =
1089                        buffer.clip_point_utf16(point_from_lsp(range.start), Bias::Left);
1090                    let token_end = buffer.clip_point_utf16(point_from_lsp(range.end), Bias::Left);
1091                    buffer.anchor_after(token_start)..buffer.anchor_before(token_end)
1092                })
1093            });
1094
1095            let contents = cx.read(|_| match hover.contents {
1096                lsp::HoverContents::Scalar(marked_string) => {
1097                    HoverBlock::try_new(marked_string).map(|contents| vec![contents])
1098                }
1099                lsp::HoverContents::Array(marked_strings) => {
1100                    let content: Vec<HoverBlock> = marked_strings
1101                        .into_iter()
1102                        .filter_map(HoverBlock::try_new)
1103                        .collect();
1104                    if content.is_empty() {
1105                        None
1106                    } else {
1107                        Some(content)
1108                    }
1109                }
1110                lsp::HoverContents::Markup(markup_content) => {
1111                    let mut contents = Vec::new();
1112                    let mut language = None;
1113                    let mut current_text = String::new();
1114                    for event in Parser::new_ext(&markup_content.value, Options::all()) {
1115                        match event {
1116                            Event::SoftBreak => {
1117                                current_text.push(' ');
1118                            }
1119                            Event::Text(text) | Event::Code(text) => {
1120                                current_text.push_str(&text.to_string());
1121                            }
1122                            Event::Start(Tag::CodeBlock(CodeBlockKind::Fenced(new_language))) => {
1123                                if !current_text.is_empty() {
1124                                    let text = std::mem::take(&mut current_text).trim().to_string();
1125                                    contents.push(HoverBlock { text, language });
1126                                }
1127
1128                                language = if new_language.is_empty() {
1129                                    None
1130                                } else {
1131                                    Some(new_language.to_string())
1132                                };
1133                            }
1134                            Event::End(Tag::CodeBlock(_))
1135                            | Event::End(Tag::Paragraph)
1136                            | Event::End(Tag::Heading(_, _, _))
1137                            | Event::End(Tag::BlockQuote)
1138                            | Event::HardBreak => {
1139                                if !current_text.is_empty() {
1140                                    let text = std::mem::take(&mut current_text).trim().to_string();
1141                                    contents.push(HoverBlock { text, language });
1142                                }
1143                                language = None;
1144                            }
1145                            _ => {}
1146                        }
1147                    }
1148
1149                    if !current_text.trim().is_empty() {
1150                        contents.push(HoverBlock {
1151                            text: current_text,
1152                            language,
1153                        });
1154                    }
1155
1156                    if contents.is_empty() {
1157                        None
1158                    } else {
1159                        Some(contents)
1160                    }
1161                }
1162            });
1163
1164            contents.map(|contents| Hover { contents, range })
1165        }))
1166    }
1167
1168    fn to_proto(&self, project_id: u64, buffer: &Buffer) -> Self::ProtoRequest {
1169        proto::GetHover {
1170            project_id,
1171            buffer_id: buffer.remote_id(),
1172            position: Some(language::proto::serialize_anchor(
1173                &buffer.anchor_before(self.position),
1174            )),
1175            version: serialize_version(&buffer.version),
1176        }
1177    }
1178
1179    async fn from_proto(
1180        message: Self::ProtoRequest,
1181        _: ModelHandle<Project>,
1182        buffer: ModelHandle<Buffer>,
1183        mut cx: AsyncAppContext,
1184    ) -> Result<Self> {
1185        let position = message
1186            .position
1187            .and_then(deserialize_anchor)
1188            .ok_or_else(|| anyhow!("invalid position"))?;
1189        buffer
1190            .update(&mut cx, |buffer, _| {
1191                buffer.wait_for_version(deserialize_version(&message.version))
1192            })
1193            .await?;
1194        Ok(Self {
1195            position: buffer.read_with(&cx, |buffer, _| position.to_point_utf16(buffer)),
1196        })
1197    }
1198
1199    fn response_to_proto(
1200        response: Self::Response,
1201        _: &mut Project,
1202        _: PeerId,
1203        _: &clock::Global,
1204        _: &mut AppContext,
1205    ) -> proto::GetHoverResponse {
1206        if let Some(response) = response {
1207            let (start, end) = if let Some(range) = response.range {
1208                (
1209                    Some(language::proto::serialize_anchor(&range.start)),
1210                    Some(language::proto::serialize_anchor(&range.end)),
1211                )
1212            } else {
1213                (None, None)
1214            };
1215
1216            let contents = response
1217                .contents
1218                .into_iter()
1219                .map(|block| proto::HoverBlock {
1220                    text: block.text,
1221                    language: block.language,
1222                })
1223                .collect();
1224
1225            proto::GetHoverResponse {
1226                start,
1227                end,
1228                contents,
1229            }
1230        } else {
1231            proto::GetHoverResponse {
1232                start: None,
1233                end: None,
1234                contents: Vec::new(),
1235            }
1236        }
1237    }
1238
1239    async fn response_from_proto(
1240        self,
1241        message: proto::GetHoverResponse,
1242        _: ModelHandle<Project>,
1243        _: ModelHandle<Buffer>,
1244        _: AsyncAppContext,
1245    ) -> Result<Self::Response> {
1246        let range = if let (Some(start), Some(end)) = (message.start, message.end) {
1247            language::proto::deserialize_anchor(start)
1248                .and_then(|start| language::proto::deserialize_anchor(end).map(|end| start..end))
1249        } else {
1250            None
1251        };
1252
1253        let contents: Vec<_> = message
1254            .contents
1255            .into_iter()
1256            .map(|block| HoverBlock {
1257                text: block.text,
1258                language: block.language,
1259            })
1260            .collect();
1261
1262        Ok(if contents.is_empty() {
1263            None
1264        } else {
1265            Some(Hover { contents, range })
1266        })
1267    }
1268
1269    fn buffer_id_from_proto(message: &Self::ProtoRequest) -> u64 {
1270        message.buffer_id
1271    }
1272}
1273
1274#[async_trait(?Send)]
1275impl LspCommand for GetCompletions {
1276    type Response = Vec<Completion>;
1277    type LspRequest = lsp::request::Completion;
1278    type ProtoRequest = proto::GetCompletions;
1279
1280    fn to_lsp(
1281        &self,
1282        path: &Path,
1283        _: &Buffer,
1284        _: &Arc<LanguageServer>,
1285        _: &AppContext,
1286    ) -> lsp::CompletionParams {
1287        lsp::CompletionParams {
1288            text_document_position: lsp::TextDocumentPositionParams::new(
1289                lsp::TextDocumentIdentifier::new(lsp::Url::from_file_path(path).unwrap()),
1290                point_to_lsp(self.position),
1291            ),
1292            context: Default::default(),
1293            work_done_progress_params: Default::default(),
1294            partial_result_params: Default::default(),
1295        }
1296    }
1297
1298    async fn response_from_lsp(
1299        self,
1300        completions: Option<lsp::CompletionResponse>,
1301        _: ModelHandle<Project>,
1302        buffer: ModelHandle<Buffer>,
1303        _: LanguageServerId,
1304        cx: AsyncAppContext,
1305    ) -> Result<Vec<Completion>> {
1306        let completions = if let Some(completions) = completions {
1307            match completions {
1308                lsp::CompletionResponse::Array(completions) => completions,
1309                lsp::CompletionResponse::List(list) => list.items,
1310            }
1311        } else {
1312            Default::default()
1313        };
1314
1315        let completions = buffer.read_with(&cx, |buffer, _| {
1316            let language = buffer.language().cloned();
1317            let snapshot = buffer.snapshot();
1318            let clipped_position = buffer.clip_point_utf16(Unclipped(self.position), Bias::Left);
1319            let mut range_for_token = None;
1320            completions
1321                .into_iter()
1322                .filter_map(move |mut lsp_completion| {
1323                    // For now, we can only handle additional edits if they are returned
1324                    // when resolving the completion, not if they are present initially.
1325                    if lsp_completion
1326                        .additional_text_edits
1327                        .as_ref()
1328                        .map_or(false, |edits| !edits.is_empty())
1329                    {
1330                        return None;
1331                    }
1332
1333                    let (old_range, mut new_text) = match lsp_completion.text_edit.as_ref() {
1334                        // If the language server provides a range to overwrite, then
1335                        // check that the range is valid.
1336                        Some(lsp::CompletionTextEdit::Edit(edit)) => {
1337                            let range = range_from_lsp(edit.range);
1338                            let start = snapshot.clip_point_utf16(range.start, Bias::Left);
1339                            let end = snapshot.clip_point_utf16(range.end, Bias::Left);
1340                            if start != range.start.0 || end != range.end.0 {
1341                                log::info!("completion out of expected range");
1342                                return None;
1343                            }
1344                            (
1345                                snapshot.anchor_before(start)..snapshot.anchor_after(end),
1346                                edit.new_text.clone(),
1347                            )
1348                        }
1349                        // If the language server does not provide a range, then infer
1350                        // the range based on the syntax tree.
1351                        None => {
1352                            if self.position != clipped_position {
1353                                log::info!("completion out of expected range");
1354                                return None;
1355                            }
1356                            let Range { start, end } = range_for_token
1357                                .get_or_insert_with(|| {
1358                                    let offset = self.position.to_offset(&snapshot);
1359                                    let (range, kind) = snapshot.surrounding_word(offset);
1360                                    if kind == Some(CharKind::Word) {
1361                                        range
1362                                    } else {
1363                                        offset..offset
1364                                    }
1365                                })
1366                                .clone();
1367                            let text = lsp_completion
1368                                .insert_text
1369                                .as_ref()
1370                                .unwrap_or(&lsp_completion.label)
1371                                .clone();
1372                            (
1373                                snapshot.anchor_before(start)..snapshot.anchor_after(end),
1374                                text,
1375                            )
1376                        }
1377                        Some(lsp::CompletionTextEdit::InsertAndReplace(_)) => {
1378                            log::info!("unsupported insert/replace completion");
1379                            return None;
1380                        }
1381                    };
1382
1383                    let language = language.clone();
1384                    LineEnding::normalize(&mut new_text);
1385                    Some(async move {
1386                        let mut label = None;
1387                        if let Some(language) = language {
1388                            language.process_completion(&mut lsp_completion).await;
1389                            label = language.label_for_completion(&lsp_completion).await;
1390                        }
1391                        Completion {
1392                            old_range,
1393                            new_text,
1394                            label: label.unwrap_or_else(|| {
1395                                language::CodeLabel::plain(
1396                                    lsp_completion.label.clone(),
1397                                    lsp_completion.filter_text.as_deref(),
1398                                )
1399                            }),
1400                            lsp_completion,
1401                        }
1402                    })
1403                })
1404        });
1405
1406        Ok(futures::future::join_all(completions).await)
1407    }
1408
1409    fn to_proto(&self, project_id: u64, buffer: &Buffer) -> proto::GetCompletions {
1410        let anchor = buffer.anchor_after(self.position);
1411        proto::GetCompletions {
1412            project_id,
1413            buffer_id: buffer.remote_id(),
1414            position: Some(language::proto::serialize_anchor(&anchor)),
1415            version: serialize_version(&buffer.version()),
1416        }
1417    }
1418
1419    async fn from_proto(
1420        message: proto::GetCompletions,
1421        _: ModelHandle<Project>,
1422        buffer: ModelHandle<Buffer>,
1423        mut cx: AsyncAppContext,
1424    ) -> Result<Self> {
1425        let version = deserialize_version(&message.version);
1426        buffer
1427            .update(&mut cx, |buffer, _| buffer.wait_for_version(version))
1428            .await?;
1429        let position = message
1430            .position
1431            .and_then(language::proto::deserialize_anchor)
1432            .map(|p| {
1433                buffer.read_with(&cx, |buffer, _| {
1434                    buffer.clip_point_utf16(Unclipped(p.to_point_utf16(buffer)), Bias::Left)
1435                })
1436            })
1437            .ok_or_else(|| anyhow!("invalid position"))?;
1438        Ok(Self { position })
1439    }
1440
1441    fn response_to_proto(
1442        completions: Vec<Completion>,
1443        _: &mut Project,
1444        _: PeerId,
1445        buffer_version: &clock::Global,
1446        _: &mut AppContext,
1447    ) -> proto::GetCompletionsResponse {
1448        proto::GetCompletionsResponse {
1449            completions: completions
1450                .iter()
1451                .map(language::proto::serialize_completion)
1452                .collect(),
1453            version: serialize_version(&buffer_version),
1454        }
1455    }
1456
1457    async fn response_from_proto(
1458        self,
1459        message: proto::GetCompletionsResponse,
1460        _: ModelHandle<Project>,
1461        buffer: ModelHandle<Buffer>,
1462        mut cx: AsyncAppContext,
1463    ) -> Result<Vec<Completion>> {
1464        buffer
1465            .update(&mut cx, |buffer, _| {
1466                buffer.wait_for_version(deserialize_version(&message.version))
1467            })
1468            .await?;
1469
1470        let language = buffer.read_with(&cx, |buffer, _| buffer.language().cloned());
1471        let completions = message.completions.into_iter().map(|completion| {
1472            language::proto::deserialize_completion(completion, language.clone())
1473        });
1474        futures::future::try_join_all(completions).await
1475    }
1476
1477    fn buffer_id_from_proto(message: &proto::GetCompletions) -> u64 {
1478        message.buffer_id
1479    }
1480}
1481
1482#[async_trait(?Send)]
1483impl LspCommand for GetCodeActions {
1484    type Response = Vec<CodeAction>;
1485    type LspRequest = lsp::request::CodeActionRequest;
1486    type ProtoRequest = proto::GetCodeActions;
1487
1488    fn check_capabilities(&self, capabilities: &ServerCapabilities) -> bool {
1489        capabilities.code_action_provider.is_some()
1490    }
1491
1492    fn to_lsp(
1493        &self,
1494        path: &Path,
1495        buffer: &Buffer,
1496        language_server: &Arc<LanguageServer>,
1497        _: &AppContext,
1498    ) -> lsp::CodeActionParams {
1499        let relevant_diagnostics = buffer
1500            .snapshot()
1501            .diagnostics_in_range::<_, usize>(self.range.clone(), false)
1502            .map(|entry| entry.to_lsp_diagnostic_stub())
1503            .collect();
1504        lsp::CodeActionParams {
1505            text_document: lsp::TextDocumentIdentifier::new(
1506                lsp::Url::from_file_path(path).unwrap(),
1507            ),
1508            range: range_to_lsp(self.range.to_point_utf16(buffer)),
1509            work_done_progress_params: Default::default(),
1510            partial_result_params: Default::default(),
1511            context: lsp::CodeActionContext {
1512                diagnostics: relevant_diagnostics,
1513                only: language_server.code_action_kinds(),
1514            },
1515        }
1516    }
1517
1518    async fn response_from_lsp(
1519        self,
1520        actions: Option<lsp::CodeActionResponse>,
1521        _: ModelHandle<Project>,
1522        _: ModelHandle<Buffer>,
1523        server_id: LanguageServerId,
1524        _: AsyncAppContext,
1525    ) -> Result<Vec<CodeAction>> {
1526        Ok(actions
1527            .unwrap_or_default()
1528            .into_iter()
1529            .filter_map(|entry| {
1530                if let lsp::CodeActionOrCommand::CodeAction(lsp_action) = entry {
1531                    Some(CodeAction {
1532                        server_id,
1533                        range: self.range.clone(),
1534                        lsp_action,
1535                    })
1536                } else {
1537                    None
1538                }
1539            })
1540            .collect())
1541    }
1542
1543    fn to_proto(&self, project_id: u64, buffer: &Buffer) -> proto::GetCodeActions {
1544        proto::GetCodeActions {
1545            project_id,
1546            buffer_id: buffer.remote_id(),
1547            start: Some(language::proto::serialize_anchor(&self.range.start)),
1548            end: Some(language::proto::serialize_anchor(&self.range.end)),
1549            version: serialize_version(&buffer.version()),
1550        }
1551    }
1552
1553    async fn from_proto(
1554        message: proto::GetCodeActions,
1555        _: ModelHandle<Project>,
1556        buffer: ModelHandle<Buffer>,
1557        mut cx: AsyncAppContext,
1558    ) -> Result<Self> {
1559        let start = message
1560            .start
1561            .and_then(language::proto::deserialize_anchor)
1562            .ok_or_else(|| anyhow!("invalid start"))?;
1563        let end = message
1564            .end
1565            .and_then(language::proto::deserialize_anchor)
1566            .ok_or_else(|| anyhow!("invalid end"))?;
1567        buffer
1568            .update(&mut cx, |buffer, _| {
1569                buffer.wait_for_version(deserialize_version(&message.version))
1570            })
1571            .await?;
1572
1573        Ok(Self { range: start..end })
1574    }
1575
1576    fn response_to_proto(
1577        code_actions: Vec<CodeAction>,
1578        _: &mut Project,
1579        _: PeerId,
1580        buffer_version: &clock::Global,
1581        _: &mut AppContext,
1582    ) -> proto::GetCodeActionsResponse {
1583        proto::GetCodeActionsResponse {
1584            actions: code_actions
1585                .iter()
1586                .map(language::proto::serialize_code_action)
1587                .collect(),
1588            version: serialize_version(&buffer_version),
1589        }
1590    }
1591
1592    async fn response_from_proto(
1593        self,
1594        message: proto::GetCodeActionsResponse,
1595        _: ModelHandle<Project>,
1596        buffer: ModelHandle<Buffer>,
1597        mut cx: AsyncAppContext,
1598    ) -> Result<Vec<CodeAction>> {
1599        buffer
1600            .update(&mut cx, |buffer, _| {
1601                buffer.wait_for_version(deserialize_version(&message.version))
1602            })
1603            .await?;
1604        message
1605            .actions
1606            .into_iter()
1607            .map(language::proto::deserialize_code_action)
1608            .collect()
1609    }
1610
1611    fn buffer_id_from_proto(message: &proto::GetCodeActions) -> u64 {
1612        message.buffer_id
1613    }
1614}