lsp_command.rs

   1use crate::{
   2    DocumentHighlight, Hover, HoverBlock, HoverBlockKind, Location, LocationLink, Project,
   3    ProjectTransaction,
   4};
   5use anyhow::{anyhow, Result};
   6use async_trait::async_trait;
   7use client::proto::{self, PeerId};
   8use fs::LineEnding;
   9use gpui::{AppContext, AsyncAppContext, ModelHandle};
  10use language::{
  11    point_from_lsp, point_to_lsp,
  12    proto::{deserialize_anchor, deserialize_version, serialize_anchor, serialize_version},
  13    range_from_lsp, range_to_lsp, Anchor, Bias, Buffer, CachedLspAdapter, CharKind, CodeAction,
  14    Completion, OffsetRangeExt, PointUtf16, ToOffset, ToPointUtf16, Unclipped,
  15};
  16use lsp::{DocumentHighlightKind, LanguageServer, LanguageServerId, ServerCapabilities};
  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            fn hover_blocks_from_marked_string(
1096                marked_string: lsp::MarkedString,
1097            ) -> Option<HoverBlock> {
1098                let block = match marked_string {
1099                    lsp::MarkedString::String(content) => HoverBlock {
1100                        text: content,
1101                        kind: HoverBlockKind::Markdown,
1102                    },
1103                    lsp::MarkedString::LanguageString(lsp::LanguageString { language, value }) => {
1104                        HoverBlock {
1105                            text: value,
1106                            kind: HoverBlockKind::Code { language },
1107                        }
1108                    }
1109                };
1110                if block.text.is_empty() {
1111                    None
1112                } else {
1113                    Some(block)
1114                }
1115            }
1116
1117            let contents = cx.read(|_| match hover.contents {
1118                lsp::HoverContents::Scalar(marked_string) => {
1119                    hover_blocks_from_marked_string(marked_string)
1120                        .into_iter()
1121                        .collect()
1122                }
1123                lsp::HoverContents::Array(marked_strings) => marked_strings
1124                    .into_iter()
1125                    .filter_map(hover_blocks_from_marked_string)
1126                    .collect(),
1127                lsp::HoverContents::Markup(markup_content) => vec![HoverBlock {
1128                    text: markup_content.value,
1129                    kind: if markup_content.kind == lsp::MarkupKind::Markdown {
1130                        HoverBlockKind::Markdown
1131                    } else {
1132                        HoverBlockKind::PlainText
1133                    },
1134                }],
1135            });
1136
1137            Some(Hover { contents, range })
1138        }))
1139    }
1140
1141    fn to_proto(&self, project_id: u64, buffer: &Buffer) -> Self::ProtoRequest {
1142        proto::GetHover {
1143            project_id,
1144            buffer_id: buffer.remote_id(),
1145            position: Some(language::proto::serialize_anchor(
1146                &buffer.anchor_before(self.position),
1147            )),
1148            version: serialize_version(&buffer.version),
1149        }
1150    }
1151
1152    async fn from_proto(
1153        message: Self::ProtoRequest,
1154        _: ModelHandle<Project>,
1155        buffer: ModelHandle<Buffer>,
1156        mut cx: AsyncAppContext,
1157    ) -> Result<Self> {
1158        let position = message
1159            .position
1160            .and_then(deserialize_anchor)
1161            .ok_or_else(|| anyhow!("invalid position"))?;
1162        buffer
1163            .update(&mut cx, |buffer, _| {
1164                buffer.wait_for_version(deserialize_version(&message.version))
1165            })
1166            .await?;
1167        Ok(Self {
1168            position: buffer.read_with(&cx, |buffer, _| position.to_point_utf16(buffer)),
1169        })
1170    }
1171
1172    fn response_to_proto(
1173        response: Self::Response,
1174        _: &mut Project,
1175        _: PeerId,
1176        _: &clock::Global,
1177        _: &mut AppContext,
1178    ) -> proto::GetHoverResponse {
1179        if let Some(response) = response {
1180            let (start, end) = if let Some(range) = response.range {
1181                (
1182                    Some(language::proto::serialize_anchor(&range.start)),
1183                    Some(language::proto::serialize_anchor(&range.end)),
1184                )
1185            } else {
1186                (None, None)
1187            };
1188
1189            let contents = response
1190                .contents
1191                .into_iter()
1192                .map(|block| proto::HoverBlock {
1193                    text: block.text,
1194                    is_markdown: block.kind == HoverBlockKind::Markdown,
1195                    language: if let HoverBlockKind::Code { language } = block.kind {
1196                        Some(language)
1197                    } else {
1198                        None
1199                    },
1200                })
1201                .collect();
1202
1203            proto::GetHoverResponse {
1204                start,
1205                end,
1206                contents,
1207            }
1208        } else {
1209            proto::GetHoverResponse {
1210                start: None,
1211                end: None,
1212                contents: Vec::new(),
1213            }
1214        }
1215    }
1216
1217    async fn response_from_proto(
1218        self,
1219        message: proto::GetHoverResponse,
1220        _: ModelHandle<Project>,
1221        _: ModelHandle<Buffer>,
1222        _: AsyncAppContext,
1223    ) -> Result<Self::Response> {
1224        let range = if let (Some(start), Some(end)) = (message.start, message.end) {
1225            language::proto::deserialize_anchor(start)
1226                .and_then(|start| language::proto::deserialize_anchor(end).map(|end| start..end))
1227        } else {
1228            None
1229        };
1230
1231        let contents: Vec<_> = message
1232            .contents
1233            .into_iter()
1234            .map(|block| HoverBlock {
1235                text: block.text,
1236                kind: if let Some(language) = block.language {
1237                    HoverBlockKind::Code { language }
1238                } else if block.is_markdown {
1239                    HoverBlockKind::Markdown
1240                } else {
1241                    HoverBlockKind::PlainText
1242                },
1243            })
1244            .collect();
1245
1246        Ok(if contents.is_empty() {
1247            None
1248        } else {
1249            Some(Hover { contents, range })
1250        })
1251    }
1252
1253    fn buffer_id_from_proto(message: &Self::ProtoRequest) -> u64 {
1254        message.buffer_id
1255    }
1256}
1257
1258#[async_trait(?Send)]
1259impl LspCommand for GetCompletions {
1260    type Response = Vec<Completion>;
1261    type LspRequest = lsp::request::Completion;
1262    type ProtoRequest = proto::GetCompletions;
1263
1264    fn to_lsp(
1265        &self,
1266        path: &Path,
1267        _: &Buffer,
1268        _: &Arc<LanguageServer>,
1269        _: &AppContext,
1270    ) -> lsp::CompletionParams {
1271        lsp::CompletionParams {
1272            text_document_position: lsp::TextDocumentPositionParams::new(
1273                lsp::TextDocumentIdentifier::new(lsp::Url::from_file_path(path).unwrap()),
1274                point_to_lsp(self.position),
1275            ),
1276            context: Default::default(),
1277            work_done_progress_params: Default::default(),
1278            partial_result_params: Default::default(),
1279        }
1280    }
1281
1282    async fn response_from_lsp(
1283        self,
1284        completions: Option<lsp::CompletionResponse>,
1285        _: ModelHandle<Project>,
1286        buffer: ModelHandle<Buffer>,
1287        _: LanguageServerId,
1288        cx: AsyncAppContext,
1289    ) -> Result<Vec<Completion>> {
1290        let completions = if let Some(completions) = completions {
1291            match completions {
1292                lsp::CompletionResponse::Array(completions) => completions,
1293                lsp::CompletionResponse::List(list) => list.items,
1294            }
1295        } else {
1296            Default::default()
1297        };
1298
1299        let completions = buffer.read_with(&cx, |buffer, _| {
1300            let language = buffer.language().cloned();
1301            let snapshot = buffer.snapshot();
1302            let clipped_position = buffer.clip_point_utf16(Unclipped(self.position), Bias::Left);
1303            let mut range_for_token = None;
1304            completions
1305                .into_iter()
1306                .filter_map(move |mut lsp_completion| {
1307                    // For now, we can only handle additional edits if they are returned
1308                    // when resolving the completion, not if they are present initially.
1309                    if lsp_completion
1310                        .additional_text_edits
1311                        .as_ref()
1312                        .map_or(false, |edits| !edits.is_empty())
1313                    {
1314                        return None;
1315                    }
1316
1317                    let (old_range, mut new_text) = match lsp_completion.text_edit.as_ref() {
1318                        // If the language server provides a range to overwrite, then
1319                        // check that the range is valid.
1320                        Some(lsp::CompletionTextEdit::Edit(edit)) => {
1321                            let range = range_from_lsp(edit.range);
1322                            let start = snapshot.clip_point_utf16(range.start, Bias::Left);
1323                            let end = snapshot.clip_point_utf16(range.end, Bias::Left);
1324                            if start != range.start.0 || end != range.end.0 {
1325                                log::info!("completion out of expected range");
1326                                return None;
1327                            }
1328                            (
1329                                snapshot.anchor_before(start)..snapshot.anchor_after(end),
1330                                edit.new_text.clone(),
1331                            )
1332                        }
1333                        // If the language server does not provide a range, then infer
1334                        // the range based on the syntax tree.
1335                        None => {
1336                            if self.position != clipped_position {
1337                                log::info!("completion out of expected range");
1338                                return None;
1339                            }
1340                            let Range { start, end } = range_for_token
1341                                .get_or_insert_with(|| {
1342                                    let offset = self.position.to_offset(&snapshot);
1343                                    let (range, kind) = snapshot.surrounding_word(offset);
1344                                    if kind == Some(CharKind::Word) {
1345                                        range
1346                                    } else {
1347                                        offset..offset
1348                                    }
1349                                })
1350                                .clone();
1351                            let text = lsp_completion
1352                                .insert_text
1353                                .as_ref()
1354                                .unwrap_or(&lsp_completion.label)
1355                                .clone();
1356                            (
1357                                snapshot.anchor_before(start)..snapshot.anchor_after(end),
1358                                text,
1359                            )
1360                        }
1361                        Some(lsp::CompletionTextEdit::InsertAndReplace(_)) => {
1362                            log::info!("unsupported insert/replace completion");
1363                            return None;
1364                        }
1365                    };
1366
1367                    let language = language.clone();
1368                    LineEnding::normalize(&mut new_text);
1369                    Some(async move {
1370                        let mut label = None;
1371                        if let Some(language) = language {
1372                            language.process_completion(&mut lsp_completion).await;
1373                            label = language.label_for_completion(&lsp_completion).await;
1374                        }
1375                        Completion {
1376                            old_range,
1377                            new_text,
1378                            label: label.unwrap_or_else(|| {
1379                                language::CodeLabel::plain(
1380                                    lsp_completion.label.clone(),
1381                                    lsp_completion.filter_text.as_deref(),
1382                                )
1383                            }),
1384                            lsp_completion,
1385                        }
1386                    })
1387                })
1388        });
1389
1390        Ok(futures::future::join_all(completions).await)
1391    }
1392
1393    fn to_proto(&self, project_id: u64, buffer: &Buffer) -> proto::GetCompletions {
1394        let anchor = buffer.anchor_after(self.position);
1395        proto::GetCompletions {
1396            project_id,
1397            buffer_id: buffer.remote_id(),
1398            position: Some(language::proto::serialize_anchor(&anchor)),
1399            version: serialize_version(&buffer.version()),
1400        }
1401    }
1402
1403    async fn from_proto(
1404        message: proto::GetCompletions,
1405        _: ModelHandle<Project>,
1406        buffer: ModelHandle<Buffer>,
1407        mut cx: AsyncAppContext,
1408    ) -> Result<Self> {
1409        let version = deserialize_version(&message.version);
1410        buffer
1411            .update(&mut cx, |buffer, _| buffer.wait_for_version(version))
1412            .await?;
1413        let position = message
1414            .position
1415            .and_then(language::proto::deserialize_anchor)
1416            .map(|p| {
1417                buffer.read_with(&cx, |buffer, _| {
1418                    buffer.clip_point_utf16(Unclipped(p.to_point_utf16(buffer)), Bias::Left)
1419                })
1420            })
1421            .ok_or_else(|| anyhow!("invalid position"))?;
1422        Ok(Self { position })
1423    }
1424
1425    fn response_to_proto(
1426        completions: Vec<Completion>,
1427        _: &mut Project,
1428        _: PeerId,
1429        buffer_version: &clock::Global,
1430        _: &mut AppContext,
1431    ) -> proto::GetCompletionsResponse {
1432        proto::GetCompletionsResponse {
1433            completions: completions
1434                .iter()
1435                .map(language::proto::serialize_completion)
1436                .collect(),
1437            version: serialize_version(&buffer_version),
1438        }
1439    }
1440
1441    async fn response_from_proto(
1442        self,
1443        message: proto::GetCompletionsResponse,
1444        _: ModelHandle<Project>,
1445        buffer: ModelHandle<Buffer>,
1446        mut cx: AsyncAppContext,
1447    ) -> Result<Vec<Completion>> {
1448        buffer
1449            .update(&mut cx, |buffer, _| {
1450                buffer.wait_for_version(deserialize_version(&message.version))
1451            })
1452            .await?;
1453
1454        let language = buffer.read_with(&cx, |buffer, _| buffer.language().cloned());
1455        let completions = message.completions.into_iter().map(|completion| {
1456            language::proto::deserialize_completion(completion, language.clone())
1457        });
1458        futures::future::try_join_all(completions).await
1459    }
1460
1461    fn buffer_id_from_proto(message: &proto::GetCompletions) -> u64 {
1462        message.buffer_id
1463    }
1464}
1465
1466#[async_trait(?Send)]
1467impl LspCommand for GetCodeActions {
1468    type Response = Vec<CodeAction>;
1469    type LspRequest = lsp::request::CodeActionRequest;
1470    type ProtoRequest = proto::GetCodeActions;
1471
1472    fn check_capabilities(&self, capabilities: &ServerCapabilities) -> bool {
1473        capabilities.code_action_provider.is_some()
1474    }
1475
1476    fn to_lsp(
1477        &self,
1478        path: &Path,
1479        buffer: &Buffer,
1480        language_server: &Arc<LanguageServer>,
1481        _: &AppContext,
1482    ) -> lsp::CodeActionParams {
1483        let relevant_diagnostics = buffer
1484            .snapshot()
1485            .diagnostics_in_range::<_, usize>(self.range.clone(), false)
1486            .map(|entry| entry.to_lsp_diagnostic_stub())
1487            .collect();
1488        lsp::CodeActionParams {
1489            text_document: lsp::TextDocumentIdentifier::new(
1490                lsp::Url::from_file_path(path).unwrap(),
1491            ),
1492            range: range_to_lsp(self.range.to_point_utf16(buffer)),
1493            work_done_progress_params: Default::default(),
1494            partial_result_params: Default::default(),
1495            context: lsp::CodeActionContext {
1496                diagnostics: relevant_diagnostics,
1497                only: language_server.code_action_kinds(),
1498            },
1499        }
1500    }
1501
1502    async fn response_from_lsp(
1503        self,
1504        actions: Option<lsp::CodeActionResponse>,
1505        _: ModelHandle<Project>,
1506        _: ModelHandle<Buffer>,
1507        server_id: LanguageServerId,
1508        _: AsyncAppContext,
1509    ) -> Result<Vec<CodeAction>> {
1510        Ok(actions
1511            .unwrap_or_default()
1512            .into_iter()
1513            .filter_map(|entry| {
1514                if let lsp::CodeActionOrCommand::CodeAction(lsp_action) = entry {
1515                    Some(CodeAction {
1516                        server_id,
1517                        range: self.range.clone(),
1518                        lsp_action,
1519                    })
1520                } else {
1521                    None
1522                }
1523            })
1524            .collect())
1525    }
1526
1527    fn to_proto(&self, project_id: u64, buffer: &Buffer) -> proto::GetCodeActions {
1528        proto::GetCodeActions {
1529            project_id,
1530            buffer_id: buffer.remote_id(),
1531            start: Some(language::proto::serialize_anchor(&self.range.start)),
1532            end: Some(language::proto::serialize_anchor(&self.range.end)),
1533            version: serialize_version(&buffer.version()),
1534        }
1535    }
1536
1537    async fn from_proto(
1538        message: proto::GetCodeActions,
1539        _: ModelHandle<Project>,
1540        buffer: ModelHandle<Buffer>,
1541        mut cx: AsyncAppContext,
1542    ) -> Result<Self> {
1543        let start = message
1544            .start
1545            .and_then(language::proto::deserialize_anchor)
1546            .ok_or_else(|| anyhow!("invalid start"))?;
1547        let end = message
1548            .end
1549            .and_then(language::proto::deserialize_anchor)
1550            .ok_or_else(|| anyhow!("invalid end"))?;
1551        buffer
1552            .update(&mut cx, |buffer, _| {
1553                buffer.wait_for_version(deserialize_version(&message.version))
1554            })
1555            .await?;
1556
1557        Ok(Self { range: start..end })
1558    }
1559
1560    fn response_to_proto(
1561        code_actions: Vec<CodeAction>,
1562        _: &mut Project,
1563        _: PeerId,
1564        buffer_version: &clock::Global,
1565        _: &mut AppContext,
1566    ) -> proto::GetCodeActionsResponse {
1567        proto::GetCodeActionsResponse {
1568            actions: code_actions
1569                .iter()
1570                .map(language::proto::serialize_code_action)
1571                .collect(),
1572            version: serialize_version(&buffer_version),
1573        }
1574    }
1575
1576    async fn response_from_proto(
1577        self,
1578        message: proto::GetCodeActionsResponse,
1579        _: ModelHandle<Project>,
1580        buffer: ModelHandle<Buffer>,
1581        mut cx: AsyncAppContext,
1582    ) -> Result<Vec<CodeAction>> {
1583        buffer
1584            .update(&mut cx, |buffer, _| {
1585                buffer.wait_for_version(deserialize_version(&message.version))
1586            })
1587            .await?;
1588        message
1589            .actions
1590            .into_iter()
1591            .map(language::proto::deserialize_code_action)
1592            .collect()
1593    }
1594
1595    fn buffer_id_from_proto(message: &proto::GetCodeActions) -> u64 {
1596        message.buffer_id
1597    }
1598}