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