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, PeerId};
   7use gpui::{AppContext, AsyncAppContext, ModelHandle};
   8use language::{
   9    point_from_lsp, point_to_lsp,
  10    proto::{deserialize_anchor, deserialize_version, serialize_anchor, serialize_version},
  11    range_from_lsp, Anchor, Bias, Buffer, CachedLspAdapter, PointUtf16, ToPointUtf16,
  12};
  13use lsp::{DocumentHighlightKind, LanguageServer, ServerCapabilities};
  14use pulldown_cmark::{CodeBlockKind, Event, Options, Parser, Tag};
  15use std::{cmp::Reverse, ops::Range, path::Path, sync::Arc};
  16
  17#[async_trait(?Send)]
  18pub(crate) trait LspCommand: 'static + Sized {
  19    type Response: 'static + Default + Send;
  20    type LspRequest: 'static + Send + lsp::request::Request;
  21    type ProtoRequest: 'static + Send + proto::RequestMessage;
  22
  23    fn check_capabilities(&self, _: &lsp::ServerCapabilities) -> bool {
  24        true
  25    }
  26
  27    fn to_lsp(
  28        &self,
  29        path: &Path,
  30        cx: &AppContext,
  31    ) -> <Self::LspRequest as lsp::request::Request>::Params;
  32    async fn response_from_lsp(
  33        self,
  34        message: <Self::LspRequest as lsp::request::Request>::Result,
  35        project: ModelHandle<Project>,
  36        buffer: ModelHandle<Buffer>,
  37        cx: AsyncAppContext,
  38    ) -> Result<Self::Response>;
  39
  40    fn to_proto(&self, project_id: u64, buffer: &Buffer) -> Self::ProtoRequest;
  41    async fn from_proto(
  42        message: Self::ProtoRequest,
  43        project: ModelHandle<Project>,
  44        buffer: ModelHandle<Buffer>,
  45        cx: AsyncAppContext,
  46    ) -> Result<Self>;
  47    fn response_to_proto(
  48        response: Self::Response,
  49        project: &mut Project,
  50        peer_id: PeerId,
  51        buffer_version: &clock::Global,
  52        cx: &AppContext,
  53    ) -> <Self::ProtoRequest as proto::RequestMessage>::Response;
  54    async fn response_from_proto(
  55        self,
  56        message: <Self::ProtoRequest as proto::RequestMessage>::Response,
  57        project: ModelHandle<Project>,
  58        buffer: ModelHandle<Buffer>,
  59        cx: AsyncAppContext,
  60    ) -> Result<Self::Response>;
  61    fn buffer_id_from_proto(message: &Self::ProtoRequest) -> u64;
  62}
  63
  64pub(crate) struct PrepareRename {
  65    pub position: PointUtf16,
  66}
  67
  68pub(crate) struct PerformRename {
  69    pub position: PointUtf16,
  70    pub new_name: String,
  71    pub push_to_history: bool,
  72}
  73
  74pub(crate) struct GetDefinition {
  75    pub position: PointUtf16,
  76}
  77
  78pub(crate) struct GetTypeDefinition {
  79    pub position: PointUtf16,
  80}
  81
  82pub(crate) struct GetReferences {
  83    pub position: PointUtf16,
  84}
  85
  86pub(crate) struct GetDocumentHighlights {
  87    pub position: PointUtf16,
  88}
  89
  90pub(crate) struct GetHover {
  91    pub position: PointUtf16,
  92}
  93
  94#[async_trait(?Send)]
  95impl LspCommand for PrepareRename {
  96    type Response = Option<Range<Anchor>>;
  97    type LspRequest = lsp::request::PrepareRenameRequest;
  98    type ProtoRequest = proto::PrepareRename;
  99
 100    fn check_capabilities(&self, capabilities: &ServerCapabilities) -> bool {
 101        if let Some(lsp::OneOf::Right(rename)) = &capabilities.rename_provider {
 102            rename.prepare_provider == Some(true)
 103        } else {
 104            false
 105        }
 106    }
 107
 108    fn to_lsp(&self, path: &Path, _: &AppContext) -> lsp::TextDocumentPositionParams {
 109        lsp::TextDocumentPositionParams {
 110            text_document: lsp::TextDocumentIdentifier {
 111                uri: lsp::Url::from_file_path(path).unwrap(),
 112            },
 113            position: point_to_lsp(self.position),
 114        }
 115    }
 116
 117    async fn response_from_lsp(
 118        self,
 119        message: Option<lsp::PrepareRenameResponse>,
 120        _: ModelHandle<Project>,
 121        buffer: ModelHandle<Buffer>,
 122        cx: AsyncAppContext,
 123    ) -> Result<Option<Range<Anchor>>> {
 124        buffer.read_with(&cx, |buffer, _| {
 125            if let Some(
 126                lsp::PrepareRenameResponse::Range(range)
 127                | lsp::PrepareRenameResponse::RangeWithPlaceholder { range, .. },
 128            ) = message
 129            {
 130                let Range { start, end } = range_from_lsp(range);
 131                if buffer.clip_point_utf16(start, Bias::Left) == start
 132                    && buffer.clip_point_utf16(end, Bias::Left) == end
 133                {
 134                    return Ok(Some(
 135                        buffer.clamped_anchor_after(start)..buffer.clamped_anchor_before(end),
 136                    ));
 137                }
 138            }
 139            Ok(None)
 140        })
 141    }
 142
 143    fn to_proto(&self, project_id: u64, buffer: &Buffer) -> proto::PrepareRename {
 144        proto::PrepareRename {
 145            project_id,
 146            buffer_id: buffer.remote_id(),
 147            position: Some(language::proto::serialize_anchor(
 148                &buffer.clamped_anchor_before(self.position),
 149            )),
 150            version: serialize_version(&buffer.version()),
 151        }
 152    }
 153
 154    async fn from_proto(
 155        message: proto::PrepareRename,
 156        _: ModelHandle<Project>,
 157        buffer: ModelHandle<Buffer>,
 158        mut cx: AsyncAppContext,
 159    ) -> Result<Self> {
 160        let position = message
 161            .position
 162            .and_then(deserialize_anchor)
 163            .ok_or_else(|| anyhow!("invalid position"))?;
 164        buffer
 165            .update(&mut cx, |buffer, _| {
 166                buffer.wait_for_version(deserialize_version(message.version))
 167            })
 168            .await;
 169
 170        Ok(Self {
 171            position: buffer.read_with(&cx, |buffer, _| position.to_point_utf16(buffer)),
 172        })
 173    }
 174
 175    fn response_to_proto(
 176        range: Option<Range<Anchor>>,
 177        _: &mut Project,
 178        _: PeerId,
 179        buffer_version: &clock::Global,
 180        _: &AppContext,
 181    ) -> proto::PrepareRenameResponse {
 182        proto::PrepareRenameResponse {
 183            can_rename: range.is_some(),
 184            start: range
 185                .as_ref()
 186                .map(|range| language::proto::serialize_anchor(&range.start)),
 187            end: range
 188                .as_ref()
 189                .map(|range| language::proto::serialize_anchor(&range.end)),
 190            version: serialize_version(buffer_version),
 191        }
 192    }
 193
 194    async fn response_from_proto(
 195        self,
 196        message: proto::PrepareRenameResponse,
 197        _: ModelHandle<Project>,
 198        buffer: ModelHandle<Buffer>,
 199        mut cx: AsyncAppContext,
 200    ) -> Result<Option<Range<Anchor>>> {
 201        if message.can_rename {
 202            buffer
 203                .update(&mut cx, |buffer, _| {
 204                    buffer.wait_for_version(deserialize_version(message.version))
 205                })
 206                .await;
 207            let start = message.start.and_then(deserialize_anchor);
 208            let end = message.end.and_then(deserialize_anchor);
 209            Ok(start.zip(end).map(|(start, end)| start..end))
 210        } else {
 211            Ok(None)
 212        }
 213    }
 214
 215    fn buffer_id_from_proto(message: &proto::PrepareRename) -> u64 {
 216        message.buffer_id
 217    }
 218}
 219
 220#[async_trait(?Send)]
 221impl LspCommand for PerformRename {
 222    type Response = ProjectTransaction;
 223    type LspRequest = lsp::request::Rename;
 224    type ProtoRequest = proto::PerformRename;
 225
 226    fn to_lsp(&self, path: &Path, _: &AppContext) -> lsp::RenameParams {
 227        lsp::RenameParams {
 228            text_document_position: lsp::TextDocumentPositionParams {
 229                text_document: lsp::TextDocumentIdentifier {
 230                    uri: lsp::Url::from_file_path(path).unwrap(),
 231                },
 232                position: point_to_lsp(self.position),
 233            },
 234            new_name: self.new_name.clone(),
 235            work_done_progress_params: Default::default(),
 236        }
 237    }
 238
 239    async fn response_from_lsp(
 240        self,
 241        message: Option<lsp::WorkspaceEdit>,
 242        project: ModelHandle<Project>,
 243        buffer: ModelHandle<Buffer>,
 244        mut cx: AsyncAppContext,
 245    ) -> Result<ProjectTransaction> {
 246        if let Some(edit) = message {
 247            let (lsp_adapter, lsp_server) = language_server_for_buffer(&project, &buffer, &mut cx)?;
 248            Project::deserialize_workspace_edit(
 249                project,
 250                edit,
 251                self.push_to_history,
 252                lsp_adapter,
 253                lsp_server,
 254                &mut cx,
 255            )
 256            .await
 257        } else {
 258            Ok(ProjectTransaction::default())
 259        }
 260    }
 261
 262    fn to_proto(&self, project_id: u64, buffer: &Buffer) -> proto::PerformRename {
 263        proto::PerformRename {
 264            project_id,
 265            buffer_id: buffer.remote_id(),
 266            position: Some(language::proto::serialize_anchor(
 267                &buffer.clamped_anchor_before(self.position),
 268            )),
 269            new_name: self.new_name.clone(),
 270            version: serialize_version(&buffer.version()),
 271        }
 272    }
 273
 274    async fn from_proto(
 275        message: proto::PerformRename,
 276        _: ModelHandle<Project>,
 277        buffer: ModelHandle<Buffer>,
 278        mut cx: AsyncAppContext,
 279    ) -> Result<Self> {
 280        let position = message
 281            .position
 282            .and_then(deserialize_anchor)
 283            .ok_or_else(|| anyhow!("invalid position"))?;
 284        buffer
 285            .update(&mut cx, |buffer, _| {
 286                buffer.wait_for_version(deserialize_version(message.version))
 287            })
 288            .await;
 289        Ok(Self {
 290            position: buffer.read_with(&cx, |buffer, _| position.to_point_utf16(buffer)),
 291            new_name: message.new_name,
 292            push_to_history: false,
 293        })
 294    }
 295
 296    fn response_to_proto(
 297        response: ProjectTransaction,
 298        project: &mut Project,
 299        peer_id: PeerId,
 300        _: &clock::Global,
 301        cx: &AppContext,
 302    ) -> proto::PerformRenameResponse {
 303        let transaction = project.serialize_project_transaction_for_peer(response, peer_id, cx);
 304        proto::PerformRenameResponse {
 305            transaction: Some(transaction),
 306        }
 307    }
 308
 309    async fn response_from_proto(
 310        self,
 311        message: proto::PerformRenameResponse,
 312        project: ModelHandle<Project>,
 313        _: ModelHandle<Buffer>,
 314        mut cx: AsyncAppContext,
 315    ) -> Result<ProjectTransaction> {
 316        let message = message
 317            .transaction
 318            .ok_or_else(|| anyhow!("missing transaction"))?;
 319        project
 320            .update(&mut cx, |project, cx| {
 321                project.deserialize_project_transaction(message, self.push_to_history, cx)
 322            })
 323            .await
 324    }
 325
 326    fn buffer_id_from_proto(message: &proto::PerformRename) -> u64 {
 327        message.buffer_id
 328    }
 329}
 330
 331#[async_trait(?Send)]
 332impl LspCommand for GetDefinition {
 333    type Response = Vec<LocationLink>;
 334    type LspRequest = lsp::request::GotoDefinition;
 335    type ProtoRequest = proto::GetDefinition;
 336
 337    fn to_lsp(&self, path: &Path, _: &AppContext) -> lsp::GotoDefinitionParams {
 338        lsp::GotoDefinitionParams {
 339            text_document_position_params: lsp::TextDocumentPositionParams {
 340                text_document: lsp::TextDocumentIdentifier {
 341                    uri: lsp::Url::from_file_path(path).unwrap(),
 342                },
 343                position: point_to_lsp(self.position),
 344            },
 345            work_done_progress_params: Default::default(),
 346            partial_result_params: Default::default(),
 347        }
 348    }
 349
 350    async fn response_from_lsp(
 351        self,
 352        message: Option<lsp::GotoDefinitionResponse>,
 353        project: ModelHandle<Project>,
 354        buffer: ModelHandle<Buffer>,
 355        cx: AsyncAppContext,
 356    ) -> Result<Vec<LocationLink>> {
 357        location_links_from_lsp(message, project, buffer, cx).await
 358    }
 359
 360    fn to_proto(&self, project_id: u64, buffer: &Buffer) -> proto::GetDefinition {
 361        proto::GetDefinition {
 362            project_id,
 363            buffer_id: buffer.remote_id(),
 364            position: Some(language::proto::serialize_anchor(
 365                &buffer.clamped_anchor_before(self.position),
 366            )),
 367            version: serialize_version(&buffer.version()),
 368        }
 369    }
 370
 371    async fn from_proto(
 372        message: proto::GetDefinition,
 373        _: ModelHandle<Project>,
 374        buffer: ModelHandle<Buffer>,
 375        mut cx: AsyncAppContext,
 376    ) -> Result<Self> {
 377        let position = message
 378            .position
 379            .and_then(deserialize_anchor)
 380            .ok_or_else(|| anyhow!("invalid position"))?;
 381        buffer
 382            .update(&mut cx, |buffer, _| {
 383                buffer.wait_for_version(deserialize_version(message.version))
 384            })
 385            .await;
 386        Ok(Self {
 387            position: buffer.read_with(&cx, |buffer, _| position.to_point_utf16(buffer)),
 388        })
 389    }
 390
 391    fn response_to_proto(
 392        response: Vec<LocationLink>,
 393        project: &mut Project,
 394        peer_id: PeerId,
 395        _: &clock::Global,
 396        cx: &AppContext,
 397    ) -> proto::GetDefinitionResponse {
 398        let links = location_links_to_proto(response, project, peer_id, cx);
 399        proto::GetDefinitionResponse { links }
 400    }
 401
 402    async fn response_from_proto(
 403        self,
 404        message: proto::GetDefinitionResponse,
 405        project: ModelHandle<Project>,
 406        _: ModelHandle<Buffer>,
 407        cx: AsyncAppContext,
 408    ) -> Result<Vec<LocationLink>> {
 409        location_links_from_proto(message.links, project, cx).await
 410    }
 411
 412    fn buffer_id_from_proto(message: &proto::GetDefinition) -> u64 {
 413        message.buffer_id
 414    }
 415}
 416
 417#[async_trait(?Send)]
 418impl LspCommand for GetTypeDefinition {
 419    type Response = Vec<LocationLink>;
 420    type LspRequest = lsp::request::GotoTypeDefinition;
 421    type ProtoRequest = proto::GetTypeDefinition;
 422
 423    fn to_lsp(&self, path: &Path, _: &AppContext) -> lsp::GotoTypeDefinitionParams {
 424        lsp::GotoTypeDefinitionParams {
 425            text_document_position_params: lsp::TextDocumentPositionParams {
 426                text_document: lsp::TextDocumentIdentifier {
 427                    uri: lsp::Url::from_file_path(path).unwrap(),
 428                },
 429                position: point_to_lsp(self.position),
 430            },
 431            work_done_progress_params: Default::default(),
 432            partial_result_params: Default::default(),
 433        }
 434    }
 435
 436    async fn response_from_lsp(
 437        self,
 438        message: Option<lsp::GotoTypeDefinitionResponse>,
 439        project: ModelHandle<Project>,
 440        buffer: ModelHandle<Buffer>,
 441        cx: AsyncAppContext,
 442    ) -> Result<Vec<LocationLink>> {
 443        location_links_from_lsp(message, project, buffer, cx).await
 444    }
 445
 446    fn to_proto(&self, project_id: u64, buffer: &Buffer) -> proto::GetTypeDefinition {
 447        proto::GetTypeDefinition {
 448            project_id,
 449            buffer_id: buffer.remote_id(),
 450            position: Some(language::proto::serialize_anchor(
 451                &buffer.clamped_anchor_before(self.position),
 452            )),
 453            version: serialize_version(&buffer.version()),
 454        }
 455    }
 456
 457    async fn from_proto(
 458        message: proto::GetTypeDefinition,
 459        _: ModelHandle<Project>,
 460        buffer: ModelHandle<Buffer>,
 461        mut cx: AsyncAppContext,
 462    ) -> Result<Self> {
 463        let position = message
 464            .position
 465            .and_then(deserialize_anchor)
 466            .ok_or_else(|| anyhow!("invalid position"))?;
 467        buffer
 468            .update(&mut cx, |buffer, _| {
 469                buffer.wait_for_version(deserialize_version(message.version))
 470            })
 471            .await;
 472        Ok(Self {
 473            position: buffer.read_with(&cx, |buffer, _| position.to_point_utf16(buffer)),
 474        })
 475    }
 476
 477    fn response_to_proto(
 478        response: Vec<LocationLink>,
 479        project: &mut Project,
 480        peer_id: PeerId,
 481        _: &clock::Global,
 482        cx: &AppContext,
 483    ) -> proto::GetTypeDefinitionResponse {
 484        let links = location_links_to_proto(response, project, peer_id, cx);
 485        proto::GetTypeDefinitionResponse { links }
 486    }
 487
 488    async fn response_from_proto(
 489        self,
 490        message: proto::GetTypeDefinitionResponse,
 491        project: ModelHandle<Project>,
 492        _: ModelHandle<Buffer>,
 493        cx: AsyncAppContext,
 494    ) -> Result<Vec<LocationLink>> {
 495        location_links_from_proto(message.links, project, cx).await
 496    }
 497
 498    fn buffer_id_from_proto(message: &proto::GetTypeDefinition) -> u64 {
 499        message.buffer_id
 500    }
 501}
 502
 503fn language_server_for_buffer(
 504    project: &ModelHandle<Project>,
 505    buffer: &ModelHandle<Buffer>,
 506    cx: &mut AsyncAppContext,
 507) -> Result<(Arc<CachedLspAdapter>, Arc<LanguageServer>)> {
 508    project
 509        .read_with(cx, |project, cx| {
 510            project
 511                .language_server_for_buffer(buffer.read(cx), cx)
 512                .map(|(adapter, server)| (adapter.clone(), server.clone()))
 513        })
 514        .ok_or_else(|| anyhow!("no language server found for buffer"))
 515}
 516
 517async fn location_links_from_proto(
 518    proto_links: Vec<proto::LocationLink>,
 519    project: ModelHandle<Project>,
 520    mut cx: AsyncAppContext,
 521) -> Result<Vec<LocationLink>> {
 522    let mut links = Vec::new();
 523
 524    for link in proto_links {
 525        let origin = match link.origin {
 526            Some(origin) => {
 527                let buffer = project
 528                    .update(&mut cx, |this, cx| {
 529                        this.wait_for_buffer(origin.buffer_id, cx)
 530                    })
 531                    .await?;
 532                let start = origin
 533                    .start
 534                    .and_then(deserialize_anchor)
 535                    .ok_or_else(|| anyhow!("missing origin start"))?;
 536                let end = origin
 537                    .end
 538                    .and_then(deserialize_anchor)
 539                    .ok_or_else(|| anyhow!("missing origin end"))?;
 540                buffer
 541                    .update(&mut cx, |buffer, _| buffer.wait_for_anchors([&start, &end]))
 542                    .await;
 543                Some(Location {
 544                    buffer,
 545                    range: start..end,
 546                })
 547            }
 548            None => None,
 549        };
 550
 551        let target = link.target.ok_or_else(|| anyhow!("missing target"))?;
 552        let buffer = project
 553            .update(&mut cx, |this, cx| {
 554                this.wait_for_buffer(target.buffer_id, cx)
 555            })
 556            .await?;
 557        let start = target
 558            .start
 559            .and_then(deserialize_anchor)
 560            .ok_or_else(|| anyhow!("missing target start"))?;
 561        let end = target
 562            .end
 563            .and_then(deserialize_anchor)
 564            .ok_or_else(|| anyhow!("missing target end"))?;
 565        buffer
 566            .update(&mut cx, |buffer, _| buffer.wait_for_anchors([&start, &end]))
 567            .await;
 568        let target = Location {
 569            buffer,
 570            range: start..end,
 571        };
 572
 573        links.push(LocationLink { origin, target })
 574    }
 575
 576    Ok(links)
 577}
 578
 579async fn location_links_from_lsp(
 580    message: Option<lsp::GotoDefinitionResponse>,
 581    project: ModelHandle<Project>,
 582    buffer: ModelHandle<Buffer>,
 583    mut cx: AsyncAppContext,
 584) -> Result<Vec<LocationLink>> {
 585    let message = match message {
 586        Some(message) => message,
 587        None => return Ok(Vec::new()),
 588    };
 589
 590    let mut unresolved_links = Vec::new();
 591    match message {
 592        lsp::GotoDefinitionResponse::Scalar(loc) => {
 593            unresolved_links.push((None, loc.uri, loc.range));
 594        }
 595
 596        lsp::GotoDefinitionResponse::Array(locs) => {
 597            unresolved_links.extend(locs.into_iter().map(|l| (None, l.uri, l.range)));
 598        }
 599
 600        lsp::GotoDefinitionResponse::Link(links) => {
 601            unresolved_links.extend(links.into_iter().map(|l| {
 602                (
 603                    l.origin_selection_range,
 604                    l.target_uri,
 605                    l.target_selection_range,
 606                )
 607            }));
 608        }
 609    }
 610
 611    let (lsp_adapter, language_server) = language_server_for_buffer(&project, &buffer, &mut cx)?;
 612    let mut definitions = Vec::new();
 613    for (origin_range, target_uri, target_range) in unresolved_links {
 614        let target_buffer_handle = project
 615            .update(&mut cx, |this, cx| {
 616                this.open_local_buffer_via_lsp(
 617                    target_uri,
 618                    language_server.server_id(),
 619                    lsp_adapter.name.clone(),
 620                    cx,
 621                )
 622            })
 623            .await?;
 624
 625        cx.read(|cx| {
 626            let origin_location = origin_range.map(|origin_range| {
 627                let origin_buffer = buffer.read(cx);
 628                let origin_start =
 629                    origin_buffer.clip_point_utf16(point_from_lsp(origin_range.start), Bias::Left);
 630                let origin_end =
 631                    origin_buffer.clip_point_utf16(point_from_lsp(origin_range.end), Bias::Left);
 632                Location {
 633                    buffer: buffer.clone(),
 634                    range: origin_buffer.clamped_anchor_after(origin_start)
 635                        ..origin_buffer.clamped_anchor_before(origin_end),
 636                }
 637            });
 638
 639            let target_buffer = target_buffer_handle.read(cx);
 640            let target_start =
 641                target_buffer.clip_point_utf16(point_from_lsp(target_range.start), Bias::Left);
 642            let target_end =
 643                target_buffer.clip_point_utf16(point_from_lsp(target_range.end), Bias::Left);
 644            let target_location = Location {
 645                buffer: target_buffer_handle,
 646                range: target_buffer.clamped_anchor_after(target_start)
 647                    ..target_buffer.clamped_anchor_before(target_end),
 648            };
 649
 650            definitions.push(LocationLink {
 651                origin: origin_location,
 652                target: target_location,
 653            })
 654        });
 655    }
 656    Ok(definitions)
 657}
 658
 659fn location_links_to_proto(
 660    links: Vec<LocationLink>,
 661    project: &mut Project,
 662    peer_id: PeerId,
 663    cx: &AppContext,
 664) -> Vec<proto::LocationLink> {
 665    links
 666        .into_iter()
 667        .map(|definition| {
 668            let origin = definition.origin.map(|origin| {
 669                let buffer_id = project.create_buffer_for_peer(&origin.buffer, peer_id, cx);
 670                proto::Location {
 671                    start: Some(serialize_anchor(&origin.range.start)),
 672                    end: Some(serialize_anchor(&origin.range.end)),
 673                    buffer_id,
 674                }
 675            });
 676
 677            let buffer_id = project.create_buffer_for_peer(&definition.target.buffer, peer_id, cx);
 678            let target = proto::Location {
 679                start: Some(serialize_anchor(&definition.target.range.start)),
 680                end: Some(serialize_anchor(&definition.target.range.end)),
 681                buffer_id,
 682            };
 683
 684            proto::LocationLink {
 685                origin,
 686                target: Some(target),
 687            }
 688        })
 689        .collect()
 690}
 691
 692#[async_trait(?Send)]
 693impl LspCommand for GetReferences {
 694    type Response = Vec<Location>;
 695    type LspRequest = lsp::request::References;
 696    type ProtoRequest = proto::GetReferences;
 697
 698    fn to_lsp(&self, path: &Path, _: &AppContext) -> lsp::ReferenceParams {
 699        lsp::ReferenceParams {
 700            text_document_position: lsp::TextDocumentPositionParams {
 701                text_document: lsp::TextDocumentIdentifier {
 702                    uri: lsp::Url::from_file_path(path).unwrap(),
 703                },
 704                position: point_to_lsp(self.position),
 705            },
 706            work_done_progress_params: Default::default(),
 707            partial_result_params: Default::default(),
 708            context: lsp::ReferenceContext {
 709                include_declaration: true,
 710            },
 711        }
 712    }
 713
 714    async fn response_from_lsp(
 715        self,
 716        locations: Option<Vec<lsp::Location>>,
 717        project: ModelHandle<Project>,
 718        buffer: ModelHandle<Buffer>,
 719        mut cx: AsyncAppContext,
 720    ) -> Result<Vec<Location>> {
 721        let mut references = Vec::new();
 722        let (lsp_adapter, language_server) =
 723            language_server_for_buffer(&project, &buffer, &mut cx)?;
 724
 725        if let Some(locations) = locations {
 726            for lsp_location in locations {
 727                let target_buffer_handle = project
 728                    .update(&mut cx, |this, cx| {
 729                        this.open_local_buffer_via_lsp(
 730                            lsp_location.uri,
 731                            language_server.server_id(),
 732                            lsp_adapter.name.clone(),
 733                            cx,
 734                        )
 735                    })
 736                    .await?;
 737
 738                cx.read(|cx| {
 739                    let target_buffer = target_buffer_handle.read(cx);
 740                    let target_start = target_buffer
 741                        .clip_point_utf16(point_from_lsp(lsp_location.range.start), Bias::Left);
 742                    let target_end = target_buffer
 743                        .clip_point_utf16(point_from_lsp(lsp_location.range.end), Bias::Left);
 744                    references.push(Location {
 745                        buffer: target_buffer_handle,
 746                        range: target_buffer.clamped_anchor_after(target_start)
 747                            ..target_buffer.clamped_anchor_before(target_end),
 748                    });
 749                });
 750            }
 751        }
 752
 753        Ok(references)
 754    }
 755
 756    fn to_proto(&self, project_id: u64, buffer: &Buffer) -> proto::GetReferences {
 757        proto::GetReferences {
 758            project_id,
 759            buffer_id: buffer.remote_id(),
 760            position: Some(language::proto::serialize_anchor(
 761                &buffer.clamped_anchor_before(self.position),
 762            )),
 763            version: serialize_version(&buffer.version()),
 764        }
 765    }
 766
 767    async fn from_proto(
 768        message: proto::GetReferences,
 769        _: ModelHandle<Project>,
 770        buffer: ModelHandle<Buffer>,
 771        mut cx: AsyncAppContext,
 772    ) -> Result<Self> {
 773        let position = message
 774            .position
 775            .and_then(deserialize_anchor)
 776            .ok_or_else(|| anyhow!("invalid position"))?;
 777        buffer
 778            .update(&mut cx, |buffer, _| {
 779                buffer.wait_for_version(deserialize_version(message.version))
 780            })
 781            .await;
 782        Ok(Self {
 783            position: buffer.read_with(&cx, |buffer, _| position.to_point_utf16(buffer)),
 784        })
 785    }
 786
 787    fn response_to_proto(
 788        response: Vec<Location>,
 789        project: &mut Project,
 790        peer_id: PeerId,
 791        _: &clock::Global,
 792        cx: &AppContext,
 793    ) -> proto::GetReferencesResponse {
 794        let locations = response
 795            .into_iter()
 796            .map(|definition| {
 797                let buffer_id = project.create_buffer_for_peer(&definition.buffer, peer_id, cx);
 798                proto::Location {
 799                    start: Some(serialize_anchor(&definition.range.start)),
 800                    end: Some(serialize_anchor(&definition.range.end)),
 801                    buffer_id,
 802                }
 803            })
 804            .collect();
 805        proto::GetReferencesResponse { locations }
 806    }
 807
 808    async fn response_from_proto(
 809        self,
 810        message: proto::GetReferencesResponse,
 811        project: ModelHandle<Project>,
 812        _: ModelHandle<Buffer>,
 813        mut cx: AsyncAppContext,
 814    ) -> Result<Vec<Location>> {
 815        let mut locations = Vec::new();
 816        for location in message.locations {
 817            let target_buffer = project
 818                .update(&mut cx, |this, cx| {
 819                    this.wait_for_buffer(location.buffer_id, cx)
 820                })
 821                .await?;
 822            let start = location
 823                .start
 824                .and_then(deserialize_anchor)
 825                .ok_or_else(|| anyhow!("missing target start"))?;
 826            let end = location
 827                .end
 828                .and_then(deserialize_anchor)
 829                .ok_or_else(|| anyhow!("missing target end"))?;
 830            target_buffer
 831                .update(&mut cx, |buffer, _| buffer.wait_for_anchors([&start, &end]))
 832                .await;
 833            locations.push(Location {
 834                buffer: target_buffer,
 835                range: start..end,
 836            })
 837        }
 838        Ok(locations)
 839    }
 840
 841    fn buffer_id_from_proto(message: &proto::GetReferences) -> u64 {
 842        message.buffer_id
 843    }
 844}
 845
 846#[async_trait(?Send)]
 847impl LspCommand for GetDocumentHighlights {
 848    type Response = Vec<DocumentHighlight>;
 849    type LspRequest = lsp::request::DocumentHighlightRequest;
 850    type ProtoRequest = proto::GetDocumentHighlights;
 851
 852    fn check_capabilities(&self, capabilities: &ServerCapabilities) -> bool {
 853        capabilities.document_highlight_provider.is_some()
 854    }
 855
 856    fn to_lsp(&self, path: &Path, _: &AppContext) -> lsp::DocumentHighlightParams {
 857        lsp::DocumentHighlightParams {
 858            text_document_position_params: lsp::TextDocumentPositionParams {
 859                text_document: lsp::TextDocumentIdentifier {
 860                    uri: lsp::Url::from_file_path(path).unwrap(),
 861                },
 862                position: point_to_lsp(self.position),
 863            },
 864            work_done_progress_params: Default::default(),
 865            partial_result_params: Default::default(),
 866        }
 867    }
 868
 869    async fn response_from_lsp(
 870        self,
 871        lsp_highlights: Option<Vec<lsp::DocumentHighlight>>,
 872        _: ModelHandle<Project>,
 873        buffer: ModelHandle<Buffer>,
 874        cx: AsyncAppContext,
 875    ) -> Result<Vec<DocumentHighlight>> {
 876        buffer.read_with(&cx, |buffer, _| {
 877            let mut lsp_highlights = lsp_highlights.unwrap_or_default();
 878            lsp_highlights.sort_unstable_by_key(|h| (h.range.start, Reverse(h.range.end)));
 879            Ok(lsp_highlights
 880                .into_iter()
 881                .map(|lsp_highlight| {
 882                    let start = buffer
 883                        .clip_point_utf16(point_from_lsp(lsp_highlight.range.start), Bias::Left);
 884                    let end = buffer
 885                        .clip_point_utf16(point_from_lsp(lsp_highlight.range.end), Bias::Left);
 886                    DocumentHighlight {
 887                        range: buffer.clamped_anchor_after(start)
 888                            ..buffer.clamped_anchor_before(end),
 889                        kind: lsp_highlight
 890                            .kind
 891                            .unwrap_or(lsp::DocumentHighlightKind::READ),
 892                    }
 893                })
 894                .collect())
 895        })
 896    }
 897
 898    fn to_proto(&self, project_id: u64, buffer: &Buffer) -> proto::GetDocumentHighlights {
 899        proto::GetDocumentHighlights {
 900            project_id,
 901            buffer_id: buffer.remote_id(),
 902            position: Some(language::proto::serialize_anchor(
 903                &buffer.clamped_anchor_before(self.position),
 904            )),
 905            version: serialize_version(&buffer.version()),
 906        }
 907    }
 908
 909    async fn from_proto(
 910        message: proto::GetDocumentHighlights,
 911        _: ModelHandle<Project>,
 912        buffer: ModelHandle<Buffer>,
 913        mut cx: AsyncAppContext,
 914    ) -> Result<Self> {
 915        let position = message
 916            .position
 917            .and_then(deserialize_anchor)
 918            .ok_or_else(|| anyhow!("invalid position"))?;
 919        buffer
 920            .update(&mut cx, |buffer, _| {
 921                buffer.wait_for_version(deserialize_version(message.version))
 922            })
 923            .await;
 924        Ok(Self {
 925            position: buffer.read_with(&cx, |buffer, _| position.to_point_utf16(buffer)),
 926        })
 927    }
 928
 929    fn response_to_proto(
 930        response: Vec<DocumentHighlight>,
 931        _: &mut Project,
 932        _: PeerId,
 933        _: &clock::Global,
 934        _: &AppContext,
 935    ) -> proto::GetDocumentHighlightsResponse {
 936        let highlights = response
 937            .into_iter()
 938            .map(|highlight| proto::DocumentHighlight {
 939                start: Some(serialize_anchor(&highlight.range.start)),
 940                end: Some(serialize_anchor(&highlight.range.end)),
 941                kind: match highlight.kind {
 942                    DocumentHighlightKind::TEXT => proto::document_highlight::Kind::Text.into(),
 943                    DocumentHighlightKind::WRITE => proto::document_highlight::Kind::Write.into(),
 944                    DocumentHighlightKind::READ => proto::document_highlight::Kind::Read.into(),
 945                    _ => proto::document_highlight::Kind::Text.into(),
 946                },
 947            })
 948            .collect();
 949        proto::GetDocumentHighlightsResponse { highlights }
 950    }
 951
 952    async fn response_from_proto(
 953        self,
 954        message: proto::GetDocumentHighlightsResponse,
 955        _: ModelHandle<Project>,
 956        buffer: ModelHandle<Buffer>,
 957        mut cx: AsyncAppContext,
 958    ) -> Result<Vec<DocumentHighlight>> {
 959        let mut highlights = Vec::new();
 960        for highlight in message.highlights {
 961            let start = highlight
 962                .start
 963                .and_then(deserialize_anchor)
 964                .ok_or_else(|| anyhow!("missing target start"))?;
 965            let end = highlight
 966                .end
 967                .and_then(deserialize_anchor)
 968                .ok_or_else(|| anyhow!("missing target end"))?;
 969            buffer
 970                .update(&mut cx, |buffer, _| buffer.wait_for_anchors([&start, &end]))
 971                .await;
 972            let kind = match proto::document_highlight::Kind::from_i32(highlight.kind) {
 973                Some(proto::document_highlight::Kind::Text) => DocumentHighlightKind::TEXT,
 974                Some(proto::document_highlight::Kind::Read) => DocumentHighlightKind::READ,
 975                Some(proto::document_highlight::Kind::Write) => DocumentHighlightKind::WRITE,
 976                None => DocumentHighlightKind::TEXT,
 977            };
 978            highlights.push(DocumentHighlight {
 979                range: start..end,
 980                kind,
 981            });
 982        }
 983        Ok(highlights)
 984    }
 985
 986    fn buffer_id_from_proto(message: &proto::GetDocumentHighlights) -> u64 {
 987        message.buffer_id
 988    }
 989}
 990
 991#[async_trait(?Send)]
 992impl LspCommand for GetHover {
 993    type Response = Option<Hover>;
 994    type LspRequest = lsp::request::HoverRequest;
 995    type ProtoRequest = proto::GetHover;
 996
 997    fn to_lsp(&self, path: &Path, _: &AppContext) -> lsp::HoverParams {
 998        lsp::HoverParams {
 999            text_document_position_params: lsp::TextDocumentPositionParams {
1000                text_document: lsp::TextDocumentIdentifier {
1001                    uri: lsp::Url::from_file_path(path).unwrap(),
1002                },
1003                position: point_to_lsp(self.position),
1004            },
1005            work_done_progress_params: Default::default(),
1006        }
1007    }
1008
1009    async fn response_from_lsp(
1010        self,
1011        message: Option<lsp::Hover>,
1012        _: ModelHandle<Project>,
1013        buffer: ModelHandle<Buffer>,
1014        cx: AsyncAppContext,
1015    ) -> Result<Self::Response> {
1016        Ok(message.and_then(|hover| {
1017            let range = hover.range.map(|range| {
1018                cx.read(|cx| {
1019                    let buffer = buffer.read(cx);
1020                    let token_start =
1021                        buffer.clip_point_utf16(point_from_lsp(range.start), Bias::Left);
1022                    let token_end = buffer.clip_point_utf16(point_from_lsp(range.end), Bias::Left);
1023                    buffer.clamped_anchor_after(token_start)
1024                        ..buffer.clamped_anchor_before(token_end)
1025                })
1026            });
1027
1028            let contents = cx.read(|_| match hover.contents {
1029                lsp::HoverContents::Scalar(marked_string) => {
1030                    HoverBlock::try_new(marked_string).map(|contents| vec![contents])
1031                }
1032                lsp::HoverContents::Array(marked_strings) => {
1033                    let content: Vec<HoverBlock> = marked_strings
1034                        .into_iter()
1035                        .filter_map(HoverBlock::try_new)
1036                        .collect();
1037                    if content.is_empty() {
1038                        None
1039                    } else {
1040                        Some(content)
1041                    }
1042                }
1043                lsp::HoverContents::Markup(markup_content) => {
1044                    let mut contents = Vec::new();
1045                    let mut language = None;
1046                    let mut current_text = String::new();
1047                    for event in Parser::new_ext(&markup_content.value, Options::all()) {
1048                        match event {
1049                            Event::SoftBreak => {
1050                                current_text.push(' ');
1051                            }
1052                            Event::Text(text) | Event::Code(text) => {
1053                                current_text.push_str(&text.to_string());
1054                            }
1055                            Event::Start(Tag::CodeBlock(CodeBlockKind::Fenced(new_language))) => {
1056                                if !current_text.is_empty() {
1057                                    let text = std::mem::take(&mut current_text).trim().to_string();
1058                                    contents.push(HoverBlock { text, language });
1059                                }
1060
1061                                language = if new_language.is_empty() {
1062                                    None
1063                                } else {
1064                                    Some(new_language.to_string())
1065                                };
1066                            }
1067                            Event::End(Tag::CodeBlock(_))
1068                            | Event::End(Tag::Paragraph)
1069                            | Event::End(Tag::Heading(_, _, _))
1070                            | Event::End(Tag::BlockQuote)
1071                            | Event::HardBreak => {
1072                                if !current_text.is_empty() {
1073                                    let text = std::mem::take(&mut current_text).trim().to_string();
1074                                    contents.push(HoverBlock { text, language });
1075                                }
1076                                language = None;
1077                            }
1078                            _ => {}
1079                        }
1080                    }
1081
1082                    if !current_text.trim().is_empty() {
1083                        contents.push(HoverBlock {
1084                            text: current_text,
1085                            language,
1086                        });
1087                    }
1088
1089                    if contents.is_empty() {
1090                        None
1091                    } else {
1092                        Some(contents)
1093                    }
1094                }
1095            });
1096
1097            contents.map(|contents| Hover { contents, range })
1098        }))
1099    }
1100
1101    fn to_proto(&self, project_id: u64, buffer: &Buffer) -> Self::ProtoRequest {
1102        proto::GetHover {
1103            project_id,
1104            buffer_id: buffer.remote_id(),
1105            position: Some(language::proto::serialize_anchor(
1106                &buffer.clamped_anchor_before(self.position),
1107            )),
1108            version: serialize_version(&buffer.version),
1109        }
1110    }
1111
1112    async fn from_proto(
1113        message: Self::ProtoRequest,
1114        _: ModelHandle<Project>,
1115        buffer: ModelHandle<Buffer>,
1116        mut cx: AsyncAppContext,
1117    ) -> Result<Self> {
1118        let position = message
1119            .position
1120            .and_then(deserialize_anchor)
1121            .ok_or_else(|| anyhow!("invalid position"))?;
1122        buffer
1123            .update(&mut cx, |buffer, _| {
1124                buffer.wait_for_version(deserialize_version(message.version))
1125            })
1126            .await;
1127        Ok(Self {
1128            position: buffer.read_with(&cx, |buffer, _| position.to_point_utf16(buffer)),
1129        })
1130    }
1131
1132    fn response_to_proto(
1133        response: Self::Response,
1134        _: &mut Project,
1135        _: PeerId,
1136        _: &clock::Global,
1137        _: &AppContext,
1138    ) -> proto::GetHoverResponse {
1139        if let Some(response) = response {
1140            let (start, end) = if let Some(range) = response.range {
1141                (
1142                    Some(language::proto::serialize_anchor(&range.start)),
1143                    Some(language::proto::serialize_anchor(&range.end)),
1144                )
1145            } else {
1146                (None, None)
1147            };
1148
1149            let contents = response
1150                .contents
1151                .into_iter()
1152                .map(|block| proto::HoverBlock {
1153                    text: block.text,
1154                    language: block.language,
1155                })
1156                .collect();
1157
1158            proto::GetHoverResponse {
1159                start,
1160                end,
1161                contents,
1162            }
1163        } else {
1164            proto::GetHoverResponse {
1165                start: None,
1166                end: None,
1167                contents: Vec::new(),
1168            }
1169        }
1170    }
1171
1172    async fn response_from_proto(
1173        self,
1174        message: proto::GetHoverResponse,
1175        _: ModelHandle<Project>,
1176        _: ModelHandle<Buffer>,
1177        _: AsyncAppContext,
1178    ) -> Result<Self::Response> {
1179        let range = if let (Some(start), Some(end)) = (message.start, message.end) {
1180            language::proto::deserialize_anchor(start)
1181                .and_then(|start| language::proto::deserialize_anchor(end).map(|end| start..end))
1182        } else {
1183            None
1184        };
1185
1186        let contents: Vec<_> = message
1187            .contents
1188            .into_iter()
1189            .map(|block| HoverBlock {
1190                text: block.text,
1191                language: block.language,
1192            })
1193            .collect();
1194
1195        Ok(if contents.is_empty() {
1196            None
1197        } else {
1198            Some(Hover { contents, range })
1199        })
1200    }
1201
1202    fn buffer_id_from_proto(message: &Self::ProtoRequest) -> u64 {
1203        message.buffer_id
1204    }
1205}