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