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