2022-06-13 23:21:53 +00:00
|
|
|
use crate::{
|
2023-04-26 20:23:29 +00:00
|
|
|
DocumentHighlight, Hover, HoverBlock, HoverBlockKind, Location, LocationLink, Project,
|
|
|
|
ProjectTransaction,
|
2022-06-13 23:21:53 +00:00
|
|
|
};
|
2023-05-19 10:18:50 +00:00
|
|
|
use anyhow::{anyhow, Context, Result};
|
2022-02-19 00:07:30 +00:00
|
|
|
use async_trait::async_trait;
|
2022-12-14 14:55:56 +00:00
|
|
|
use client::proto::{self, PeerId};
|
2023-04-11 12:52:07 +00:00
|
|
|
use fs::LineEnding;
|
2022-02-19 00:45:52 +00:00
|
|
|
use gpui::{AppContext, AsyncAppContext, ModelHandle};
|
2022-02-17 20:44:14 +00:00
|
|
|
use language::{
|
2023-05-23 19:58:40 +00:00
|
|
|
language_settings::language_settings,
|
2022-03-31 22:39:52 +00:00
|
|
|
point_from_lsp, point_to_lsp,
|
2022-03-04 21:36:23 +00:00
|
|
|
proto::{deserialize_anchor, deserialize_version, serialize_anchor, serialize_version},
|
2023-04-11 13:11:30 +00:00
|
|
|
range_from_lsp, range_to_lsp, Anchor, Bias, Buffer, CachedLspAdapter, CharKind, CodeAction,
|
|
|
|
Completion, OffsetRangeExt, PointUtf16, ToOffset, ToPointUtf16, Unclipped,
|
2022-02-17 20:44:14 +00:00
|
|
|
};
|
2023-04-20 00:37:28 +00:00
|
|
|
use lsp::{DocumentHighlightKind, LanguageServer, LanguageServerId, ServerCapabilities};
|
2022-07-29 22:04:14 +00:00
|
|
|
use std::{cmp::Reverse, ops::Range, path::Path, sync::Arc};
|
2022-02-17 20:44:14 +00:00
|
|
|
|
2023-05-23 14:38:05 +00:00
|
|
|
pub fn lsp_formatting_options(tab_size: u32) -> lsp::FormattingOptions {
|
|
|
|
lsp::FormattingOptions {
|
|
|
|
tab_size,
|
|
|
|
insert_spaces: true,
|
|
|
|
insert_final_newline: Some(true),
|
|
|
|
..lsp::FormattingOptions::default()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-02-19 00:07:30 +00:00
|
|
|
#[async_trait(?Send)]
|
2022-02-18 18:45:06 +00:00
|
|
|
pub(crate) trait LspCommand: 'static + Sized {
|
2022-02-17 20:44:14 +00:00
|
|
|
type Response: 'static + Default + Send;
|
|
|
|
type LspRequest: 'static + Send + lsp::request::Request;
|
|
|
|
type ProtoRequest: 'static + Send + proto::RequestMessage;
|
|
|
|
|
2022-03-03 21:39:40 +00:00
|
|
|
fn check_capabilities(&self, _: &lsp::ServerCapabilities) -> bool {
|
|
|
|
true
|
|
|
|
}
|
|
|
|
|
2022-02-17 20:44:14 +00:00
|
|
|
fn to_lsp(
|
|
|
|
&self,
|
|
|
|
path: &Path,
|
2023-04-11 13:11:30 +00:00
|
|
|
buffer: &Buffer,
|
|
|
|
language_server: &Arc<LanguageServer>,
|
2022-02-17 20:44:14 +00:00
|
|
|
cx: &AppContext,
|
|
|
|
) -> <Self::LspRequest as lsp::request::Request>::Params;
|
2023-04-07 15:46:05 +00:00
|
|
|
|
2022-02-19 00:07:30 +00:00
|
|
|
async fn response_from_lsp(
|
2022-02-17 20:44:14 +00:00
|
|
|
self,
|
|
|
|
message: <Self::LspRequest as lsp::request::Request>::Result,
|
|
|
|
project: ModelHandle<Project>,
|
2022-02-18 18:45:06 +00:00
|
|
|
buffer: ModelHandle<Buffer>,
|
2023-04-20 00:37:28 +00:00
|
|
|
server_id: LanguageServerId,
|
2022-02-17 20:44:14 +00:00
|
|
|
cx: AsyncAppContext,
|
2022-02-19 00:07:30 +00:00
|
|
|
) -> Result<Self::Response>;
|
2022-02-18 18:45:06 +00:00
|
|
|
|
2022-02-19 00:45:52 +00:00
|
|
|
fn to_proto(&self, project_id: u64, buffer: &Buffer) -> Self::ProtoRequest;
|
2023-04-07 15:46:05 +00:00
|
|
|
|
2022-03-03 11:18:19 +00:00
|
|
|
async fn from_proto(
|
2022-02-18 18:45:06 +00:00
|
|
|
message: Self::ProtoRequest,
|
2022-03-03 11:18:19 +00:00
|
|
|
project: ModelHandle<Project>,
|
|
|
|
buffer: ModelHandle<Buffer>,
|
|
|
|
cx: AsyncAppContext,
|
2022-02-18 18:45:06 +00:00
|
|
|
) -> Result<Self>;
|
2023-04-07 15:46:05 +00:00
|
|
|
|
2022-02-18 18:45:06 +00:00
|
|
|
fn response_to_proto(
|
|
|
|
response: Self::Response,
|
|
|
|
project: &mut Project,
|
|
|
|
peer_id: PeerId,
|
|
|
|
buffer_version: &clock::Global,
|
2023-04-10 06:43:29 +00:00
|
|
|
cx: &mut AppContext,
|
2022-02-18 18:45:06 +00:00
|
|
|
) -> <Self::ProtoRequest as proto::RequestMessage>::Response;
|
2023-04-07 15:46:05 +00:00
|
|
|
|
2022-02-19 00:07:30 +00:00
|
|
|
async fn response_from_proto(
|
2022-02-17 20:44:14 +00:00
|
|
|
self,
|
|
|
|
message: <Self::ProtoRequest as proto::RequestMessage>::Response,
|
|
|
|
project: ModelHandle<Project>,
|
2022-02-18 18:45:06 +00:00
|
|
|
buffer: ModelHandle<Buffer>,
|
2022-02-17 20:44:14 +00:00
|
|
|
cx: AsyncAppContext,
|
2022-02-19 00:07:30 +00:00
|
|
|
) -> Result<Self::Response>;
|
2023-04-07 15:46:05 +00:00
|
|
|
|
2022-02-19 00:45:52 +00:00
|
|
|
fn buffer_id_from_proto(message: &Self::ProtoRequest) -> u64;
|
2022-02-17 20:44:14 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
pub(crate) struct PrepareRename {
|
|
|
|
pub position: PointUtf16,
|
|
|
|
}
|
|
|
|
|
|
|
|
pub(crate) struct PerformRename {
|
|
|
|
pub position: PointUtf16,
|
|
|
|
pub new_name: String,
|
2022-02-18 10:41:47 +00:00
|
|
|
pub push_to_history: bool,
|
2022-02-17 20:44:14 +00:00
|
|
|
}
|
|
|
|
|
2022-02-19 00:45:52 +00:00
|
|
|
pub(crate) struct GetDefinition {
|
|
|
|
pub position: PointUtf16,
|
|
|
|
}
|
|
|
|
|
2022-07-29 15:41:08 +00:00
|
|
|
pub(crate) struct GetTypeDefinition {
|
|
|
|
pub position: PointUtf16,
|
|
|
|
}
|
|
|
|
|
2022-02-22 22:27:05 +00:00
|
|
|
pub(crate) struct GetReferences {
|
|
|
|
pub position: PointUtf16,
|
|
|
|
}
|
|
|
|
|
2022-02-23 01:05:55 +00:00
|
|
|
pub(crate) struct GetDocumentHighlights {
|
|
|
|
pub position: PointUtf16,
|
|
|
|
}
|
|
|
|
|
2022-05-30 15:00:45 +00:00
|
|
|
pub(crate) struct GetHover {
|
|
|
|
pub position: PointUtf16,
|
|
|
|
}
|
|
|
|
|
2023-04-11 12:52:07 +00:00
|
|
|
pub(crate) struct GetCompletions {
|
|
|
|
pub position: PointUtf16,
|
|
|
|
}
|
|
|
|
|
2023-04-11 13:11:30 +00:00
|
|
|
pub(crate) struct GetCodeActions {
|
|
|
|
pub range: Range<Anchor>,
|
|
|
|
}
|
|
|
|
|
2023-05-19 10:18:50 +00:00
|
|
|
pub(crate) struct OnTypeFormatting {
|
|
|
|
pub position: PointUtf16,
|
2023-05-23 14:11:23 +00:00
|
|
|
pub trigger: String,
|
2023-05-23 14:38:05 +00:00
|
|
|
pub options: FormattingOptions,
|
|
|
|
}
|
|
|
|
|
|
|
|
pub(crate) struct FormattingOptions {
|
|
|
|
tab_size: u32,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl From<lsp::FormattingOptions> for FormattingOptions {
|
|
|
|
fn from(value: lsp::FormattingOptions) -> Self {
|
|
|
|
Self {
|
|
|
|
tab_size: value.tab_size,
|
|
|
|
}
|
|
|
|
}
|
2023-05-19 10:18:50 +00:00
|
|
|
}
|
|
|
|
|
2022-02-19 00:07:30 +00:00
|
|
|
#[async_trait(?Send)]
|
2022-02-17 20:44:14 +00:00
|
|
|
impl LspCommand for PrepareRename {
|
|
|
|
type Response = Option<Range<Anchor>>;
|
|
|
|
type LspRequest = lsp::request::PrepareRenameRequest;
|
|
|
|
type ProtoRequest = proto::PrepareRename;
|
|
|
|
|
2022-04-22 13:43:23 +00:00
|
|
|
fn check_capabilities(&self, capabilities: &ServerCapabilities) -> bool {
|
|
|
|
if let Some(lsp::OneOf::Right(rename)) = &capabilities.rename_provider {
|
|
|
|
rename.prepare_provider == Some(true)
|
|
|
|
} else {
|
|
|
|
false
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-04-11 13:11:30 +00:00
|
|
|
fn to_lsp(
|
|
|
|
&self,
|
|
|
|
path: &Path,
|
|
|
|
_: &Buffer,
|
|
|
|
_: &Arc<LanguageServer>,
|
|
|
|
_: &AppContext,
|
|
|
|
) -> lsp::TextDocumentPositionParams {
|
2022-02-17 20:44:14 +00:00
|
|
|
lsp::TextDocumentPositionParams {
|
|
|
|
text_document: lsp::TextDocumentIdentifier {
|
|
|
|
uri: lsp::Url::from_file_path(path).unwrap(),
|
|
|
|
},
|
2022-03-31 22:39:52 +00:00
|
|
|
position: point_to_lsp(self.position),
|
2022-02-17 20:44:14 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-02-19 00:07:30 +00:00
|
|
|
async fn response_from_lsp(
|
2022-02-17 20:44:14 +00:00
|
|
|
self,
|
|
|
|
message: Option<lsp::PrepareRenameResponse>,
|
|
|
|
_: ModelHandle<Project>,
|
2022-02-18 18:45:06 +00:00
|
|
|
buffer: ModelHandle<Buffer>,
|
2023-04-20 00:37:28 +00:00
|
|
|
_: LanguageServerId,
|
2022-02-17 20:44:14 +00:00
|
|
|
cx: AsyncAppContext,
|
2022-02-19 00:07:30 +00:00
|
|
|
) -> Result<Option<Range<Anchor>>> {
|
|
|
|
buffer.read_with(&cx, |buffer, _| {
|
|
|
|
if let Some(
|
2022-02-17 20:44:14 +00:00
|
|
|
lsp::PrepareRenameResponse::Range(range)
|
2022-02-19 00:07:30 +00:00
|
|
|
| lsp::PrepareRenameResponse::RangeWithPlaceholder { range, .. },
|
|
|
|
) = message
|
|
|
|
{
|
|
|
|
let Range { start, end } = range_from_lsp(range);
|
2022-11-17 03:20:16 +00:00
|
|
|
if buffer.clip_point_utf16(start, Bias::Left) == start.0
|
|
|
|
&& buffer.clip_point_utf16(end, Bias::Left) == end.0
|
2022-02-19 00:07:30 +00:00
|
|
|
{
|
2022-11-21 16:47:46 +00:00
|
|
|
return Ok(Some(buffer.anchor_after(start)..buffer.anchor_before(end)));
|
2022-02-19 00:07:30 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
Ok(None)
|
|
|
|
})
|
2022-02-17 20:44:14 +00:00
|
|
|
}
|
|
|
|
|
2022-02-19 00:45:52 +00:00
|
|
|
fn to_proto(&self, project_id: u64, buffer: &Buffer) -> proto::PrepareRename {
|
2022-02-18 18:45:06 +00:00
|
|
|
proto::PrepareRename {
|
|
|
|
project_id,
|
2022-02-19 00:45:52 +00:00
|
|
|
buffer_id: buffer.remote_id(),
|
2022-02-18 18:45:06 +00:00
|
|
|
position: Some(language::proto::serialize_anchor(
|
2022-11-17 03:20:16 +00:00
|
|
|
&buffer.anchor_before(self.position),
|
2022-02-18 18:45:06 +00:00
|
|
|
)),
|
2022-03-04 21:36:23 +00:00
|
|
|
version: serialize_version(&buffer.version()),
|
2022-02-18 18:45:06 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-03-03 11:18:19 +00:00
|
|
|
async fn from_proto(
|
|
|
|
message: proto::PrepareRename,
|
|
|
|
_: ModelHandle<Project>,
|
|
|
|
buffer: ModelHandle<Buffer>,
|
|
|
|
mut cx: AsyncAppContext,
|
|
|
|
) -> Result<Self> {
|
2022-02-18 18:45:06 +00:00
|
|
|
let position = message
|
|
|
|
.position
|
|
|
|
.and_then(deserialize_anchor)
|
|
|
|
.ok_or_else(|| anyhow!("invalid position"))?;
|
2022-03-03 11:18:19 +00:00
|
|
|
buffer
|
|
|
|
.update(&mut cx, |buffer, _| {
|
2023-04-10 23:06:28 +00:00
|
|
|
buffer.wait_for_version(deserialize_version(&message.version))
|
2022-03-03 11:18:19 +00:00
|
|
|
})
|
2023-04-10 23:06:28 +00:00
|
|
|
.await?;
|
2022-03-03 11:18:19 +00:00
|
|
|
|
2022-02-18 18:45:06 +00:00
|
|
|
Ok(Self {
|
2022-03-03 11:18:19 +00:00
|
|
|
position: buffer.read_with(&cx, |buffer, _| position.to_point_utf16(buffer)),
|
2022-02-18 18:45:06 +00:00
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
fn response_to_proto(
|
|
|
|
range: Option<Range<Anchor>>,
|
|
|
|
_: &mut Project,
|
|
|
|
_: PeerId,
|
|
|
|
buffer_version: &clock::Global,
|
2023-04-10 06:43:29 +00:00
|
|
|
_: &mut AppContext,
|
2022-02-18 18:45:06 +00:00
|
|
|
) -> proto::PrepareRenameResponse {
|
|
|
|
proto::PrepareRenameResponse {
|
|
|
|
can_rename: range.is_some(),
|
|
|
|
start: range
|
|
|
|
.as_ref()
|
|
|
|
.map(|range| language::proto::serialize_anchor(&range.start)),
|
|
|
|
end: range
|
|
|
|
.as_ref()
|
|
|
|
.map(|range| language::proto::serialize_anchor(&range.end)),
|
2022-03-04 21:36:23 +00:00
|
|
|
version: serialize_version(buffer_version),
|
2022-02-18 18:45:06 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-02-19 00:07:30 +00:00
|
|
|
async fn response_from_proto(
|
2022-02-17 20:44:14 +00:00
|
|
|
self,
|
|
|
|
message: proto::PrepareRenameResponse,
|
|
|
|
_: ModelHandle<Project>,
|
2022-02-18 18:45:06 +00:00
|
|
|
buffer: ModelHandle<Buffer>,
|
2022-02-18 10:41:47 +00:00
|
|
|
mut cx: AsyncAppContext,
|
2022-02-19 00:07:30 +00:00
|
|
|
) -> Result<Option<Range<Anchor>>> {
|
|
|
|
if message.can_rename {
|
|
|
|
buffer
|
|
|
|
.update(&mut cx, |buffer, _| {
|
2023-04-10 23:06:28 +00:00
|
|
|
buffer.wait_for_version(deserialize_version(&message.version))
|
2022-02-19 00:07:30 +00:00
|
|
|
})
|
2023-04-10 23:06:28 +00:00
|
|
|
.await?;
|
2022-02-19 00:07:30 +00:00
|
|
|
let start = message.start.and_then(deserialize_anchor);
|
|
|
|
let end = message.end.and_then(deserialize_anchor);
|
|
|
|
Ok(start.zip(end).map(|(start, end)| start..end))
|
|
|
|
} else {
|
|
|
|
Ok(None)
|
2022-02-17 20:44:14 +00:00
|
|
|
}
|
|
|
|
}
|
2022-02-19 00:45:52 +00:00
|
|
|
|
|
|
|
fn buffer_id_from_proto(message: &proto::PrepareRename) -> u64 {
|
|
|
|
message.buffer_id
|
|
|
|
}
|
2022-02-17 20:44:14 +00:00
|
|
|
}
|
|
|
|
|
2022-02-19 00:07:30 +00:00
|
|
|
#[async_trait(?Send)]
|
2022-02-17 20:44:14 +00:00
|
|
|
impl LspCommand for PerformRename {
|
|
|
|
type Response = ProjectTransaction;
|
|
|
|
type LspRequest = lsp::request::Rename;
|
|
|
|
type ProtoRequest = proto::PerformRename;
|
|
|
|
|
2023-04-11 13:11:30 +00:00
|
|
|
fn to_lsp(
|
|
|
|
&self,
|
|
|
|
path: &Path,
|
|
|
|
_: &Buffer,
|
|
|
|
_: &Arc<LanguageServer>,
|
|
|
|
_: &AppContext,
|
|
|
|
) -> lsp::RenameParams {
|
2022-02-17 20:44:14 +00:00
|
|
|
lsp::RenameParams {
|
|
|
|
text_document_position: lsp::TextDocumentPositionParams {
|
|
|
|
text_document: lsp::TextDocumentIdentifier {
|
|
|
|
uri: lsp::Url::from_file_path(path).unwrap(),
|
|
|
|
},
|
2022-03-31 22:39:52 +00:00
|
|
|
position: point_to_lsp(self.position),
|
2022-02-17 20:44:14 +00:00
|
|
|
},
|
|
|
|
new_name: self.new_name.clone(),
|
|
|
|
work_done_progress_params: Default::default(),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-02-19 00:07:30 +00:00
|
|
|
async fn response_from_lsp(
|
2022-02-17 20:44:14 +00:00
|
|
|
self,
|
|
|
|
message: Option<lsp::WorkspaceEdit>,
|
|
|
|
project: ModelHandle<Project>,
|
2022-02-18 18:45:06 +00:00
|
|
|
buffer: ModelHandle<Buffer>,
|
2023-04-20 00:37:28 +00:00
|
|
|
server_id: LanguageServerId,
|
2022-02-17 20:44:14 +00:00
|
|
|
mut cx: AsyncAppContext,
|
2022-02-19 00:07:30 +00:00
|
|
|
) -> Result<ProjectTransaction> {
|
|
|
|
if let Some(edit) = message {
|
2023-04-07 15:46:05 +00:00
|
|
|
let (lsp_adapter, lsp_server) =
|
|
|
|
language_server_for_buffer(&project, &buffer, server_id, &mut cx)?;
|
2022-02-19 00:07:30 +00:00
|
|
|
Project::deserialize_workspace_edit(
|
|
|
|
project,
|
|
|
|
edit,
|
|
|
|
self.push_to_history,
|
2022-03-29 23:57:18 +00:00
|
|
|
lsp_adapter,
|
|
|
|
lsp_server,
|
2022-02-19 00:07:30 +00:00
|
|
|
&mut cx,
|
|
|
|
)
|
|
|
|
.await
|
|
|
|
} else {
|
|
|
|
Ok(ProjectTransaction::default())
|
2022-02-17 20:44:14 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-02-19 00:45:52 +00:00
|
|
|
fn to_proto(&self, project_id: u64, buffer: &Buffer) -> proto::PerformRename {
|
2022-02-18 18:45:06 +00:00
|
|
|
proto::PerformRename {
|
|
|
|
project_id,
|
2022-02-19 00:45:52 +00:00
|
|
|
buffer_id: buffer.remote_id(),
|
2022-02-18 18:45:06 +00:00
|
|
|
position: Some(language::proto::serialize_anchor(
|
2022-11-17 03:20:16 +00:00
|
|
|
&buffer.anchor_before(self.position),
|
2022-02-18 18:45:06 +00:00
|
|
|
)),
|
|
|
|
new_name: self.new_name.clone(),
|
2022-03-04 21:36:23 +00:00
|
|
|
version: serialize_version(&buffer.version()),
|
2022-02-18 18:45:06 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-03-03 11:18:19 +00:00
|
|
|
async fn from_proto(
|
|
|
|
message: proto::PerformRename,
|
|
|
|
_: ModelHandle<Project>,
|
|
|
|
buffer: ModelHandle<Buffer>,
|
|
|
|
mut cx: AsyncAppContext,
|
|
|
|
) -> Result<Self> {
|
2022-02-18 18:45:06 +00:00
|
|
|
let position = message
|
|
|
|
.position
|
|
|
|
.and_then(deserialize_anchor)
|
|
|
|
.ok_or_else(|| anyhow!("invalid position"))?;
|
2022-03-03 11:18:19 +00:00
|
|
|
buffer
|
|
|
|
.update(&mut cx, |buffer, _| {
|
2023-04-10 23:06:28 +00:00
|
|
|
buffer.wait_for_version(deserialize_version(&message.version))
|
2022-03-03 11:18:19 +00:00
|
|
|
})
|
2023-04-10 23:06:28 +00:00
|
|
|
.await?;
|
2022-02-18 18:45:06 +00:00
|
|
|
Ok(Self {
|
2022-03-03 11:18:19 +00:00
|
|
|
position: buffer.read_with(&cx, |buffer, _| position.to_point_utf16(buffer)),
|
2022-02-18 18:45:06 +00:00
|
|
|
new_name: message.new_name,
|
|
|
|
push_to_history: false,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
fn response_to_proto(
|
|
|
|
response: ProjectTransaction,
|
|
|
|
project: &mut Project,
|
|
|
|
peer_id: PeerId,
|
|
|
|
_: &clock::Global,
|
2023-04-10 06:43:29 +00:00
|
|
|
cx: &mut AppContext,
|
2022-02-18 18:45:06 +00:00
|
|
|
) -> proto::PerformRenameResponse {
|
|
|
|
let transaction = project.serialize_project_transaction_for_peer(response, peer_id, cx);
|
|
|
|
proto::PerformRenameResponse {
|
|
|
|
transaction: Some(transaction),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-02-19 00:07:30 +00:00
|
|
|
async fn response_from_proto(
|
2022-02-17 20:44:14 +00:00
|
|
|
self,
|
|
|
|
message: proto::PerformRenameResponse,
|
|
|
|
project: ModelHandle<Project>,
|
2022-02-18 18:45:06 +00:00
|
|
|
_: ModelHandle<Buffer>,
|
2022-02-17 20:44:14 +00:00
|
|
|
mut cx: AsyncAppContext,
|
2022-02-19 00:07:30 +00:00
|
|
|
) -> Result<ProjectTransaction> {
|
|
|
|
let message = message
|
|
|
|
.transaction
|
|
|
|
.ok_or_else(|| anyhow!("missing transaction"))?;
|
|
|
|
project
|
|
|
|
.update(&mut cx, |project, cx| {
|
2022-02-28 19:36:43 +00:00
|
|
|
project.deserialize_project_transaction(message, self.push_to_history, cx)
|
2022-02-19 00:07:30 +00:00
|
|
|
})
|
|
|
|
.await
|
2022-02-17 20:44:14 +00:00
|
|
|
}
|
2022-02-19 00:45:52 +00:00
|
|
|
|
|
|
|
fn buffer_id_from_proto(message: &proto::PerformRename) -> u64 {
|
|
|
|
message.buffer_id
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[async_trait(?Send)]
|
|
|
|
impl LspCommand for GetDefinition {
|
2022-06-13 23:21:53 +00:00
|
|
|
type Response = Vec<LocationLink>;
|
2022-02-19 00:45:52 +00:00
|
|
|
type LspRequest = lsp::request::GotoDefinition;
|
|
|
|
type ProtoRequest = proto::GetDefinition;
|
|
|
|
|
2023-04-11 13:11:30 +00:00
|
|
|
fn to_lsp(
|
|
|
|
&self,
|
|
|
|
path: &Path,
|
|
|
|
_: &Buffer,
|
|
|
|
_: &Arc<LanguageServer>,
|
|
|
|
_: &AppContext,
|
|
|
|
) -> lsp::GotoDefinitionParams {
|
2022-02-19 00:45:52 +00:00
|
|
|
lsp::GotoDefinitionParams {
|
|
|
|
text_document_position_params: lsp::TextDocumentPositionParams {
|
|
|
|
text_document: lsp::TextDocumentIdentifier {
|
|
|
|
uri: lsp::Url::from_file_path(path).unwrap(),
|
|
|
|
},
|
2022-03-31 22:39:52 +00:00
|
|
|
position: point_to_lsp(self.position),
|
2022-02-19 00:45:52 +00:00
|
|
|
},
|
|
|
|
work_done_progress_params: Default::default(),
|
|
|
|
partial_result_params: Default::default(),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
async fn response_from_lsp(
|
|
|
|
self,
|
|
|
|
message: Option<lsp::GotoDefinitionResponse>,
|
|
|
|
project: ModelHandle<Project>,
|
|
|
|
buffer: ModelHandle<Buffer>,
|
2023-04-20 00:37:28 +00:00
|
|
|
server_id: LanguageServerId,
|
2022-07-29 22:04:14 +00:00
|
|
|
cx: AsyncAppContext,
|
2022-06-13 23:21:53 +00:00
|
|
|
) -> Result<Vec<LocationLink>> {
|
2023-04-07 15:46:05 +00:00
|
|
|
location_links_from_lsp(message, project, buffer, server_id, cx).await
|
2022-02-19 00:45:52 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
fn to_proto(&self, project_id: u64, buffer: &Buffer) -> proto::GetDefinition {
|
|
|
|
proto::GetDefinition {
|
|
|
|
project_id,
|
|
|
|
buffer_id: buffer.remote_id(),
|
|
|
|
position: Some(language::proto::serialize_anchor(
|
2022-11-17 03:20:16 +00:00
|
|
|
&buffer.anchor_before(self.position),
|
2022-02-19 00:45:52 +00:00
|
|
|
)),
|
2022-03-04 21:36:23 +00:00
|
|
|
version: serialize_version(&buffer.version()),
|
2022-02-19 00:45:52 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-03-03 11:18:19 +00:00
|
|
|
async fn from_proto(
|
|
|
|
message: proto::GetDefinition,
|
|
|
|
_: ModelHandle<Project>,
|
|
|
|
buffer: ModelHandle<Buffer>,
|
|
|
|
mut cx: AsyncAppContext,
|
|
|
|
) -> Result<Self> {
|
2022-02-19 00:45:52 +00:00
|
|
|
let position = message
|
|
|
|
.position
|
|
|
|
.and_then(deserialize_anchor)
|
|
|
|
.ok_or_else(|| anyhow!("invalid position"))?;
|
2022-03-03 11:18:19 +00:00
|
|
|
buffer
|
|
|
|
.update(&mut cx, |buffer, _| {
|
2023-04-10 23:06:28 +00:00
|
|
|
buffer.wait_for_version(deserialize_version(&message.version))
|
2022-03-03 11:18:19 +00:00
|
|
|
})
|
2023-04-10 23:06:28 +00:00
|
|
|
.await?;
|
2022-02-19 00:45:52 +00:00
|
|
|
Ok(Self {
|
2022-03-03 11:18:19 +00:00
|
|
|
position: buffer.read_with(&cx, |buffer, _| position.to_point_utf16(buffer)),
|
2022-02-19 00:45:52 +00:00
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
fn response_to_proto(
|
2022-06-13 23:21:53 +00:00
|
|
|
response: Vec<LocationLink>,
|
2022-02-19 00:45:52 +00:00
|
|
|
project: &mut Project,
|
|
|
|
peer_id: PeerId,
|
|
|
|
_: &clock::Global,
|
2023-04-10 06:43:29 +00:00
|
|
|
cx: &mut AppContext,
|
2022-02-19 00:45:52 +00:00
|
|
|
) -> proto::GetDefinitionResponse {
|
2022-07-29 22:04:14 +00:00
|
|
|
let links = location_links_to_proto(response, project, peer_id, cx);
|
2022-06-13 23:21:53 +00:00
|
|
|
proto::GetDefinitionResponse { links }
|
2022-02-19 00:45:52 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
async fn response_from_proto(
|
|
|
|
self,
|
|
|
|
message: proto::GetDefinitionResponse,
|
|
|
|
project: ModelHandle<Project>,
|
|
|
|
_: ModelHandle<Buffer>,
|
2022-07-29 22:04:14 +00:00
|
|
|
cx: AsyncAppContext,
|
2022-06-13 23:21:53 +00:00
|
|
|
) -> Result<Vec<LocationLink>> {
|
2022-07-29 22:04:14 +00:00
|
|
|
location_links_from_proto(message.links, project, cx).await
|
2022-02-19 00:45:52 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
fn buffer_id_from_proto(message: &proto::GetDefinition) -> u64 {
|
|
|
|
message.buffer_id
|
|
|
|
}
|
2022-02-17 20:44:14 +00:00
|
|
|
}
|
2022-02-22 22:27:05 +00:00
|
|
|
|
2022-07-29 15:41:08 +00:00
|
|
|
#[async_trait(?Send)]
|
|
|
|
impl LspCommand for GetTypeDefinition {
|
|
|
|
type Response = Vec<LocationLink>;
|
|
|
|
type LspRequest = lsp::request::GotoTypeDefinition;
|
|
|
|
type ProtoRequest = proto::GetTypeDefinition;
|
|
|
|
|
2023-04-11 13:11:30 +00:00
|
|
|
fn to_lsp(
|
|
|
|
&self,
|
|
|
|
path: &Path,
|
|
|
|
_: &Buffer,
|
|
|
|
_: &Arc<LanguageServer>,
|
|
|
|
_: &AppContext,
|
|
|
|
) -> lsp::GotoTypeDefinitionParams {
|
2022-07-29 15:41:08 +00:00
|
|
|
lsp::GotoTypeDefinitionParams {
|
|
|
|
text_document_position_params: lsp::TextDocumentPositionParams {
|
|
|
|
text_document: lsp::TextDocumentIdentifier {
|
|
|
|
uri: lsp::Url::from_file_path(path).unwrap(),
|
|
|
|
},
|
|
|
|
position: point_to_lsp(self.position),
|
|
|
|
},
|
|
|
|
work_done_progress_params: Default::default(),
|
|
|
|
partial_result_params: Default::default(),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
async fn response_from_lsp(
|
|
|
|
self,
|
|
|
|
message: Option<lsp::GotoTypeDefinitionResponse>,
|
|
|
|
project: ModelHandle<Project>,
|
|
|
|
buffer: ModelHandle<Buffer>,
|
2023-04-20 00:37:28 +00:00
|
|
|
server_id: LanguageServerId,
|
2022-07-29 22:04:14 +00:00
|
|
|
cx: AsyncAppContext,
|
2022-07-29 15:41:08 +00:00
|
|
|
) -> Result<Vec<LocationLink>> {
|
2023-04-07 15:46:05 +00:00
|
|
|
location_links_from_lsp(message, project, buffer, server_id, cx).await
|
2022-07-29 15:41:08 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
fn to_proto(&self, project_id: u64, buffer: &Buffer) -> proto::GetTypeDefinition {
|
|
|
|
proto::GetTypeDefinition {
|
|
|
|
project_id,
|
|
|
|
buffer_id: buffer.remote_id(),
|
|
|
|
position: Some(language::proto::serialize_anchor(
|
2022-11-17 03:20:16 +00:00
|
|
|
&buffer.anchor_before(self.position),
|
2022-07-29 15:41:08 +00:00
|
|
|
)),
|
|
|
|
version: serialize_version(&buffer.version()),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
async fn from_proto(
|
|
|
|
message: proto::GetTypeDefinition,
|
|
|
|
_: ModelHandle<Project>,
|
|
|
|
buffer: ModelHandle<Buffer>,
|
|
|
|
mut cx: AsyncAppContext,
|
|
|
|
) -> Result<Self> {
|
|
|
|
let position = message
|
|
|
|
.position
|
|
|
|
.and_then(deserialize_anchor)
|
|
|
|
.ok_or_else(|| anyhow!("invalid position"))?;
|
|
|
|
buffer
|
|
|
|
.update(&mut cx, |buffer, _| {
|
2023-04-10 23:06:28 +00:00
|
|
|
buffer.wait_for_version(deserialize_version(&message.version))
|
2022-07-29 15:41:08 +00:00
|
|
|
})
|
2023-04-10 23:06:28 +00:00
|
|
|
.await?;
|
2022-07-29 15:41:08 +00:00
|
|
|
Ok(Self {
|
|
|
|
position: buffer.read_with(&cx, |buffer, _| position.to_point_utf16(buffer)),
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
fn response_to_proto(
|
|
|
|
response: Vec<LocationLink>,
|
|
|
|
project: &mut Project,
|
|
|
|
peer_id: PeerId,
|
|
|
|
_: &clock::Global,
|
2023-04-10 06:43:29 +00:00
|
|
|
cx: &mut AppContext,
|
2022-07-29 15:41:08 +00:00
|
|
|
) -> proto::GetTypeDefinitionResponse {
|
2022-07-29 22:04:14 +00:00
|
|
|
let links = location_links_to_proto(response, project, peer_id, cx);
|
2022-07-29 15:41:08 +00:00
|
|
|
proto::GetTypeDefinitionResponse { links }
|
|
|
|
}
|
|
|
|
|
|
|
|
async fn response_from_proto(
|
|
|
|
self,
|
|
|
|
message: proto::GetTypeDefinitionResponse,
|
|
|
|
project: ModelHandle<Project>,
|
|
|
|
_: ModelHandle<Buffer>,
|
2022-07-29 22:04:14 +00:00
|
|
|
cx: AsyncAppContext,
|
2022-07-29 15:41:08 +00:00
|
|
|
) -> Result<Vec<LocationLink>> {
|
2022-07-29 22:04:14 +00:00
|
|
|
location_links_from_proto(message.links, project, cx).await
|
|
|
|
}
|
2022-07-29 15:41:08 +00:00
|
|
|
|
2022-07-29 22:04:14 +00:00
|
|
|
fn buffer_id_from_proto(message: &proto::GetTypeDefinition) -> u64 {
|
|
|
|
message.buffer_id
|
|
|
|
}
|
|
|
|
}
|
2022-07-29 15:41:08 +00:00
|
|
|
|
2022-07-29 22:04:14 +00:00
|
|
|
fn language_server_for_buffer(
|
|
|
|
project: &ModelHandle<Project>,
|
|
|
|
buffer: &ModelHandle<Buffer>,
|
2023-04-20 00:37:28 +00:00
|
|
|
server_id: LanguageServerId,
|
2022-07-29 22:04:14 +00:00
|
|
|
cx: &mut AsyncAppContext,
|
|
|
|
) -> Result<(Arc<CachedLspAdapter>, Arc<LanguageServer>)> {
|
|
|
|
project
|
|
|
|
.read_with(cx, |project, cx| {
|
|
|
|
project
|
2023-04-07 15:46:05 +00:00
|
|
|
.language_server_for_buffer(buffer.read(cx), server_id, cx)
|
2022-07-29 22:04:14 +00:00
|
|
|
.map(|(adapter, server)| (adapter.clone(), server.clone()))
|
|
|
|
})
|
|
|
|
.ok_or_else(|| anyhow!("no language server found for buffer"))
|
|
|
|
}
|
|
|
|
|
|
|
|
async fn location_links_from_proto(
|
|
|
|
proto_links: Vec<proto::LocationLink>,
|
|
|
|
project: ModelHandle<Project>,
|
|
|
|
mut cx: AsyncAppContext,
|
|
|
|
) -> Result<Vec<LocationLink>> {
|
|
|
|
let mut links = Vec::new();
|
|
|
|
|
|
|
|
for link in proto_links {
|
|
|
|
let origin = match link.origin {
|
|
|
|
Some(origin) => {
|
|
|
|
let buffer = project
|
2022-08-17 09:10:09 +00:00
|
|
|
.update(&mut cx, |this, cx| {
|
2023-01-04 23:00:43 +00:00
|
|
|
this.wait_for_remote_buffer(origin.buffer_id, cx)
|
2022-08-17 09:10:09 +00:00
|
|
|
})
|
2022-07-29 22:04:14 +00:00
|
|
|
.await?;
|
|
|
|
let start = origin
|
|
|
|
.start
|
|
|
|
.and_then(deserialize_anchor)
|
|
|
|
.ok_or_else(|| anyhow!("missing origin start"))?;
|
|
|
|
let end = origin
|
|
|
|
.end
|
|
|
|
.and_then(deserialize_anchor)
|
|
|
|
.ok_or_else(|| anyhow!("missing origin end"))?;
|
|
|
|
buffer
|
2023-04-18 23:13:18 +00:00
|
|
|
.update(&mut cx, |buffer, _| buffer.wait_for_anchors([start, end]))
|
2023-04-10 23:06:28 +00:00
|
|
|
.await?;
|
2022-07-29 22:04:14 +00:00
|
|
|
Some(Location {
|
|
|
|
buffer,
|
|
|
|
range: start..end,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
None => None,
|
|
|
|
};
|
|
|
|
|
|
|
|
let target = link.target.ok_or_else(|| anyhow!("missing target"))?;
|
|
|
|
let buffer = project
|
2022-08-17 09:10:09 +00:00
|
|
|
.update(&mut cx, |this, cx| {
|
2023-01-04 23:00:43 +00:00
|
|
|
this.wait_for_remote_buffer(target.buffer_id, cx)
|
2022-08-17 09:10:09 +00:00
|
|
|
})
|
2022-07-29 22:04:14 +00:00
|
|
|
.await?;
|
|
|
|
let start = target
|
|
|
|
.start
|
|
|
|
.and_then(deserialize_anchor)
|
|
|
|
.ok_or_else(|| anyhow!("missing target start"))?;
|
|
|
|
let end = target
|
|
|
|
.end
|
|
|
|
.and_then(deserialize_anchor)
|
|
|
|
.ok_or_else(|| anyhow!("missing target end"))?;
|
|
|
|
buffer
|
2023-04-18 23:13:18 +00:00
|
|
|
.update(&mut cx, |buffer, _| buffer.wait_for_anchors([start, end]))
|
2023-04-10 23:06:28 +00:00
|
|
|
.await?;
|
2022-07-29 22:04:14 +00:00
|
|
|
let target = Location {
|
|
|
|
buffer,
|
|
|
|
range: start..end,
|
|
|
|
};
|
|
|
|
|
|
|
|
links.push(LocationLink { origin, target })
|
|
|
|
}
|
|
|
|
|
|
|
|
Ok(links)
|
|
|
|
}
|
|
|
|
|
|
|
|
async fn location_links_from_lsp(
|
|
|
|
message: Option<lsp::GotoDefinitionResponse>,
|
|
|
|
project: ModelHandle<Project>,
|
|
|
|
buffer: ModelHandle<Buffer>,
|
2023-04-20 00:37:28 +00:00
|
|
|
server_id: LanguageServerId,
|
2022-07-29 22:04:14 +00:00
|
|
|
mut cx: AsyncAppContext,
|
|
|
|
) -> Result<Vec<LocationLink>> {
|
|
|
|
let message = match message {
|
|
|
|
Some(message) => message,
|
|
|
|
None => return Ok(Vec::new()),
|
|
|
|
};
|
|
|
|
|
|
|
|
let mut unresolved_links = Vec::new();
|
|
|
|
match message {
|
|
|
|
lsp::GotoDefinitionResponse::Scalar(loc) => {
|
|
|
|
unresolved_links.push((None, loc.uri, loc.range));
|
|
|
|
}
|
|
|
|
|
|
|
|
lsp::GotoDefinitionResponse::Array(locs) => {
|
|
|
|
unresolved_links.extend(locs.into_iter().map(|l| (None, l.uri, l.range)));
|
|
|
|
}
|
|
|
|
|
|
|
|
lsp::GotoDefinitionResponse::Link(links) => {
|
|
|
|
unresolved_links.extend(links.into_iter().map(|l| {
|
|
|
|
(
|
|
|
|
l.origin_selection_range,
|
|
|
|
l.target_uri,
|
|
|
|
l.target_selection_range,
|
|
|
|
)
|
|
|
|
}));
|
2022-07-29 15:41:08 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-04-07 15:46:05 +00:00
|
|
|
let (lsp_adapter, language_server) =
|
|
|
|
language_server_for_buffer(&project, &buffer, server_id, &mut cx)?;
|
2022-07-29 22:04:14 +00:00
|
|
|
let mut definitions = Vec::new();
|
|
|
|
for (origin_range, target_uri, target_range) in unresolved_links {
|
|
|
|
let target_buffer_handle = project
|
|
|
|
.update(&mut cx, |this, cx| {
|
|
|
|
this.open_local_buffer_via_lsp(
|
|
|
|
target_uri,
|
|
|
|
language_server.server_id(),
|
|
|
|
lsp_adapter.name.clone(),
|
|
|
|
cx,
|
|
|
|
)
|
|
|
|
})
|
|
|
|
.await?;
|
|
|
|
|
|
|
|
cx.read(|cx| {
|
|
|
|
let origin_location = origin_range.map(|origin_range| {
|
|
|
|
let origin_buffer = buffer.read(cx);
|
|
|
|
let origin_start =
|
|
|
|
origin_buffer.clip_point_utf16(point_from_lsp(origin_range.start), Bias::Left);
|
|
|
|
let origin_end =
|
|
|
|
origin_buffer.clip_point_utf16(point_from_lsp(origin_range.end), Bias::Left);
|
|
|
|
Location {
|
|
|
|
buffer: buffer.clone(),
|
2022-11-17 03:20:16 +00:00
|
|
|
range: origin_buffer.anchor_after(origin_start)
|
|
|
|
..origin_buffer.anchor_before(origin_end),
|
2022-07-29 22:04:14 +00:00
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
let target_buffer = target_buffer_handle.read(cx);
|
|
|
|
let target_start =
|
|
|
|
target_buffer.clip_point_utf16(point_from_lsp(target_range.start), Bias::Left);
|
|
|
|
let target_end =
|
|
|
|
target_buffer.clip_point_utf16(point_from_lsp(target_range.end), Bias::Left);
|
|
|
|
let target_location = Location {
|
|
|
|
buffer: target_buffer_handle,
|
2022-11-17 03:20:16 +00:00
|
|
|
range: target_buffer.anchor_after(target_start)
|
|
|
|
..target_buffer.anchor_before(target_end),
|
2022-07-29 22:04:14 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
definitions.push(LocationLink {
|
|
|
|
origin: origin_location,
|
|
|
|
target: target_location,
|
|
|
|
})
|
|
|
|
});
|
2022-07-29 15:41:08 +00:00
|
|
|
}
|
2022-07-29 22:04:14 +00:00
|
|
|
Ok(definitions)
|
|
|
|
}
|
|
|
|
|
|
|
|
fn location_links_to_proto(
|
|
|
|
links: Vec<LocationLink>,
|
|
|
|
project: &mut Project,
|
|
|
|
peer_id: PeerId,
|
2023-04-10 06:43:29 +00:00
|
|
|
cx: &mut AppContext,
|
2022-07-29 22:04:14 +00:00
|
|
|
) -> Vec<proto::LocationLink> {
|
|
|
|
links
|
|
|
|
.into_iter()
|
|
|
|
.map(|definition| {
|
|
|
|
let origin = definition.origin.map(|origin| {
|
2022-08-17 09:10:09 +00:00
|
|
|
let buffer_id = project.create_buffer_for_peer(&origin.buffer, peer_id, cx);
|
2022-07-29 22:04:14 +00:00
|
|
|
proto::Location {
|
|
|
|
start: Some(serialize_anchor(&origin.range.start)),
|
|
|
|
end: Some(serialize_anchor(&origin.range.end)),
|
2022-08-17 09:10:09 +00:00
|
|
|
buffer_id,
|
2022-07-29 22:04:14 +00:00
|
|
|
}
|
|
|
|
});
|
|
|
|
|
2022-08-17 09:10:09 +00:00
|
|
|
let buffer_id = project.create_buffer_for_peer(&definition.target.buffer, peer_id, cx);
|
2022-07-29 22:04:14 +00:00
|
|
|
let target = proto::Location {
|
|
|
|
start: Some(serialize_anchor(&definition.target.range.start)),
|
|
|
|
end: Some(serialize_anchor(&definition.target.range.end)),
|
2022-08-17 09:10:09 +00:00
|
|
|
buffer_id,
|
2022-07-29 22:04:14 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
proto::LocationLink {
|
|
|
|
origin,
|
|
|
|
target: Some(target),
|
|
|
|
}
|
|
|
|
})
|
|
|
|
.collect()
|
2022-07-29 15:41:08 +00:00
|
|
|
}
|
|
|
|
|
2022-02-22 22:27:05 +00:00
|
|
|
#[async_trait(?Send)]
|
|
|
|
impl LspCommand for GetReferences {
|
|
|
|
type Response = Vec<Location>;
|
|
|
|
type LspRequest = lsp::request::References;
|
|
|
|
type ProtoRequest = proto::GetReferences;
|
|
|
|
|
2023-04-11 13:11:30 +00:00
|
|
|
fn to_lsp(
|
|
|
|
&self,
|
|
|
|
path: &Path,
|
|
|
|
_: &Buffer,
|
|
|
|
_: &Arc<LanguageServer>,
|
|
|
|
_: &AppContext,
|
|
|
|
) -> lsp::ReferenceParams {
|
2022-02-22 22:27:05 +00:00
|
|
|
lsp::ReferenceParams {
|
|
|
|
text_document_position: lsp::TextDocumentPositionParams {
|
|
|
|
text_document: lsp::TextDocumentIdentifier {
|
|
|
|
uri: lsp::Url::from_file_path(path).unwrap(),
|
|
|
|
},
|
2022-03-31 22:39:52 +00:00
|
|
|
position: point_to_lsp(self.position),
|
2022-02-22 22:27:05 +00:00
|
|
|
},
|
|
|
|
work_done_progress_params: Default::default(),
|
|
|
|
partial_result_params: Default::default(),
|
|
|
|
context: lsp::ReferenceContext {
|
|
|
|
include_declaration: true,
|
|
|
|
},
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
async fn response_from_lsp(
|
|
|
|
self,
|
|
|
|
locations: Option<Vec<lsp::Location>>,
|
|
|
|
project: ModelHandle<Project>,
|
|
|
|
buffer: ModelHandle<Buffer>,
|
2023-04-20 00:37:28 +00:00
|
|
|
server_id: LanguageServerId,
|
2022-02-22 22:27:05 +00:00
|
|
|
mut cx: AsyncAppContext,
|
|
|
|
) -> Result<Vec<Location>> {
|
|
|
|
let mut references = Vec::new();
|
2022-07-29 22:04:14 +00:00
|
|
|
let (lsp_adapter, language_server) =
|
2023-04-07 15:46:05 +00:00
|
|
|
language_server_for_buffer(&project, &buffer, server_id, &mut cx)?;
|
2022-02-22 22:27:05 +00:00
|
|
|
|
|
|
|
if let Some(locations) = locations {
|
|
|
|
for lsp_location in locations {
|
|
|
|
let target_buffer_handle = project
|
|
|
|
.update(&mut cx, |this, cx| {
|
|
|
|
this.open_local_buffer_via_lsp(
|
|
|
|
lsp_location.uri,
|
2022-06-30 23:46:26 +00:00
|
|
|
language_server.server_id(),
|
2022-07-07 16:14:16 +00:00
|
|
|
lsp_adapter.name.clone(),
|
2022-02-22 22:27:05 +00:00
|
|
|
cx,
|
|
|
|
)
|
|
|
|
})
|
|
|
|
.await?;
|
|
|
|
|
|
|
|
cx.read(|cx| {
|
|
|
|
let target_buffer = target_buffer_handle.read(cx);
|
|
|
|
let target_start = target_buffer
|
|
|
|
.clip_point_utf16(point_from_lsp(lsp_location.range.start), Bias::Left);
|
|
|
|
let target_end = target_buffer
|
|
|
|
.clip_point_utf16(point_from_lsp(lsp_location.range.end), Bias::Left);
|
|
|
|
references.push(Location {
|
|
|
|
buffer: target_buffer_handle,
|
2022-11-17 03:20:16 +00:00
|
|
|
range: target_buffer.anchor_after(target_start)
|
|
|
|
..target_buffer.anchor_before(target_end),
|
2022-02-22 22:27:05 +00:00
|
|
|
});
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Ok(references)
|
|
|
|
}
|
|
|
|
|
|
|
|
fn to_proto(&self, project_id: u64, buffer: &Buffer) -> proto::GetReferences {
|
|
|
|
proto::GetReferences {
|
|
|
|
project_id,
|
|
|
|
buffer_id: buffer.remote_id(),
|
|
|
|
position: Some(language::proto::serialize_anchor(
|
2022-11-17 03:20:16 +00:00
|
|
|
&buffer.anchor_before(self.position),
|
2022-02-22 22:27:05 +00:00
|
|
|
)),
|
2022-03-04 21:36:23 +00:00
|
|
|
version: serialize_version(&buffer.version()),
|
2022-02-22 22:27:05 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-03-03 11:18:19 +00:00
|
|
|
async fn from_proto(
|
|
|
|
message: proto::GetReferences,
|
|
|
|
_: ModelHandle<Project>,
|
|
|
|
buffer: ModelHandle<Buffer>,
|
|
|
|
mut cx: AsyncAppContext,
|
|
|
|
) -> Result<Self> {
|
2022-02-22 22:27:05 +00:00
|
|
|
let position = message
|
|
|
|
.position
|
|
|
|
.and_then(deserialize_anchor)
|
|
|
|
.ok_or_else(|| anyhow!("invalid position"))?;
|
2022-03-03 11:18:19 +00:00
|
|
|
buffer
|
|
|
|
.update(&mut cx, |buffer, _| {
|
2023-04-10 23:06:28 +00:00
|
|
|
buffer.wait_for_version(deserialize_version(&message.version))
|
2022-03-03 11:18:19 +00:00
|
|
|
})
|
2023-04-10 23:06:28 +00:00
|
|
|
.await?;
|
2022-02-22 22:27:05 +00:00
|
|
|
Ok(Self {
|
2022-03-03 11:18:19 +00:00
|
|
|
position: buffer.read_with(&cx, |buffer, _| position.to_point_utf16(buffer)),
|
2022-02-22 22:27:05 +00:00
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
fn response_to_proto(
|
|
|
|
response: Vec<Location>,
|
|
|
|
project: &mut Project,
|
|
|
|
peer_id: PeerId,
|
|
|
|
_: &clock::Global,
|
2023-04-10 06:43:29 +00:00
|
|
|
cx: &mut AppContext,
|
2022-02-22 22:27:05 +00:00
|
|
|
) -> proto::GetReferencesResponse {
|
|
|
|
let locations = response
|
|
|
|
.into_iter()
|
|
|
|
.map(|definition| {
|
2022-08-17 09:10:09 +00:00
|
|
|
let buffer_id = project.create_buffer_for_peer(&definition.buffer, peer_id, cx);
|
2022-02-22 22:27:05 +00:00
|
|
|
proto::Location {
|
|
|
|
start: Some(serialize_anchor(&definition.range.start)),
|
|
|
|
end: Some(serialize_anchor(&definition.range.end)),
|
2022-08-17 09:10:09 +00:00
|
|
|
buffer_id,
|
2022-02-22 22:27:05 +00:00
|
|
|
}
|
|
|
|
})
|
|
|
|
.collect();
|
|
|
|
proto::GetReferencesResponse { locations }
|
|
|
|
}
|
|
|
|
|
|
|
|
async fn response_from_proto(
|
|
|
|
self,
|
|
|
|
message: proto::GetReferencesResponse,
|
|
|
|
project: ModelHandle<Project>,
|
|
|
|
_: ModelHandle<Buffer>,
|
|
|
|
mut cx: AsyncAppContext,
|
|
|
|
) -> Result<Vec<Location>> {
|
|
|
|
let mut locations = Vec::new();
|
|
|
|
for location in message.locations {
|
|
|
|
let target_buffer = project
|
2022-08-17 09:10:09 +00:00
|
|
|
.update(&mut cx, |this, cx| {
|
2023-01-04 23:00:43 +00:00
|
|
|
this.wait_for_remote_buffer(location.buffer_id, cx)
|
2022-08-17 09:10:09 +00:00
|
|
|
})
|
2022-02-22 22:27:05 +00:00
|
|
|
.await?;
|
|
|
|
let start = location
|
|
|
|
.start
|
|
|
|
.and_then(deserialize_anchor)
|
|
|
|
.ok_or_else(|| anyhow!("missing target start"))?;
|
|
|
|
let end = location
|
|
|
|
.end
|
|
|
|
.and_then(deserialize_anchor)
|
|
|
|
.ok_or_else(|| anyhow!("missing target end"))?;
|
2022-03-03 11:18:19 +00:00
|
|
|
target_buffer
|
2023-04-18 23:13:18 +00:00
|
|
|
.update(&mut cx, |buffer, _| buffer.wait_for_anchors([start, end]))
|
2023-04-10 23:06:28 +00:00
|
|
|
.await?;
|
2022-02-22 22:27:05 +00:00
|
|
|
locations.push(Location {
|
|
|
|
buffer: target_buffer,
|
|
|
|
range: start..end,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
Ok(locations)
|
|
|
|
}
|
|
|
|
|
|
|
|
fn buffer_id_from_proto(message: &proto::GetReferences) -> u64 {
|
|
|
|
message.buffer_id
|
|
|
|
}
|
|
|
|
}
|
2022-02-23 01:05:55 +00:00
|
|
|
|
|
|
|
#[async_trait(?Send)]
|
|
|
|
impl LspCommand for GetDocumentHighlights {
|
|
|
|
type Response = Vec<DocumentHighlight>;
|
|
|
|
type LspRequest = lsp::request::DocumentHighlightRequest;
|
|
|
|
type ProtoRequest = proto::GetDocumentHighlights;
|
|
|
|
|
2022-03-03 21:39:40 +00:00
|
|
|
fn check_capabilities(&self, capabilities: &ServerCapabilities) -> bool {
|
|
|
|
capabilities.document_highlight_provider.is_some()
|
|
|
|
}
|
|
|
|
|
2023-04-11 13:11:30 +00:00
|
|
|
fn to_lsp(
|
|
|
|
&self,
|
|
|
|
path: &Path,
|
|
|
|
_: &Buffer,
|
|
|
|
_: &Arc<LanguageServer>,
|
|
|
|
_: &AppContext,
|
|
|
|
) -> lsp::DocumentHighlightParams {
|
2022-02-23 01:05:55 +00:00
|
|
|
lsp::DocumentHighlightParams {
|
|
|
|
text_document_position_params: lsp::TextDocumentPositionParams {
|
|
|
|
text_document: lsp::TextDocumentIdentifier {
|
|
|
|
uri: lsp::Url::from_file_path(path).unwrap(),
|
|
|
|
},
|
2022-03-31 22:39:52 +00:00
|
|
|
position: point_to_lsp(self.position),
|
2022-02-23 01:05:55 +00:00
|
|
|
},
|
|
|
|
work_done_progress_params: Default::default(),
|
|
|
|
partial_result_params: Default::default(),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
async fn response_from_lsp(
|
|
|
|
self,
|
|
|
|
lsp_highlights: Option<Vec<lsp::DocumentHighlight>>,
|
|
|
|
_: ModelHandle<Project>,
|
|
|
|
buffer: ModelHandle<Buffer>,
|
2023-04-20 00:37:28 +00:00
|
|
|
_: LanguageServerId,
|
2022-02-23 01:05:55 +00:00
|
|
|
cx: AsyncAppContext,
|
|
|
|
) -> Result<Vec<DocumentHighlight>> {
|
|
|
|
buffer.read_with(&cx, |buffer, _| {
|
|
|
|
let mut lsp_highlights = lsp_highlights.unwrap_or_default();
|
|
|
|
lsp_highlights.sort_unstable_by_key(|h| (h.range.start, Reverse(h.range.end)));
|
|
|
|
Ok(lsp_highlights
|
|
|
|
.into_iter()
|
|
|
|
.map(|lsp_highlight| {
|
|
|
|
let start = buffer
|
|
|
|
.clip_point_utf16(point_from_lsp(lsp_highlight.range.start), Bias::Left);
|
|
|
|
let end = buffer
|
|
|
|
.clip_point_utf16(point_from_lsp(lsp_highlight.range.end), Bias::Left);
|
|
|
|
DocumentHighlight {
|
2022-11-21 16:47:46 +00:00
|
|
|
range: buffer.anchor_after(start)..buffer.anchor_before(end),
|
2022-02-23 01:05:55 +00:00
|
|
|
kind: lsp_highlight
|
|
|
|
.kind
|
|
|
|
.unwrap_or(lsp::DocumentHighlightKind::READ),
|
|
|
|
}
|
|
|
|
})
|
|
|
|
.collect())
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
fn to_proto(&self, project_id: u64, buffer: &Buffer) -> proto::GetDocumentHighlights {
|
|
|
|
proto::GetDocumentHighlights {
|
|
|
|
project_id,
|
|
|
|
buffer_id: buffer.remote_id(),
|
|
|
|
position: Some(language::proto::serialize_anchor(
|
2022-11-17 03:20:16 +00:00
|
|
|
&buffer.anchor_before(self.position),
|
2022-02-23 01:05:55 +00:00
|
|
|
)),
|
2022-03-04 21:36:23 +00:00
|
|
|
version: serialize_version(&buffer.version()),
|
2022-02-23 01:05:55 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-03-03 11:18:19 +00:00
|
|
|
async fn from_proto(
|
2022-02-23 01:05:55 +00:00
|
|
|
message: proto::GetDocumentHighlights,
|
2022-03-03 11:18:19 +00:00
|
|
|
_: ModelHandle<Project>,
|
|
|
|
buffer: ModelHandle<Buffer>,
|
|
|
|
mut cx: AsyncAppContext,
|
2022-02-23 01:05:55 +00:00
|
|
|
) -> Result<Self> {
|
|
|
|
let position = message
|
|
|
|
.position
|
|
|
|
.and_then(deserialize_anchor)
|
|
|
|
.ok_or_else(|| anyhow!("invalid position"))?;
|
2022-03-03 11:18:19 +00:00
|
|
|
buffer
|
|
|
|
.update(&mut cx, |buffer, _| {
|
2023-04-10 23:06:28 +00:00
|
|
|
buffer.wait_for_version(deserialize_version(&message.version))
|
2022-03-03 11:18:19 +00:00
|
|
|
})
|
2023-04-10 23:06:28 +00:00
|
|
|
.await?;
|
2022-02-23 01:05:55 +00:00
|
|
|
Ok(Self {
|
2022-03-03 11:18:19 +00:00
|
|
|
position: buffer.read_with(&cx, |buffer, _| position.to_point_utf16(buffer)),
|
2022-02-23 01:05:55 +00:00
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
fn response_to_proto(
|
|
|
|
response: Vec<DocumentHighlight>,
|
|
|
|
_: &mut Project,
|
|
|
|
_: PeerId,
|
|
|
|
_: &clock::Global,
|
2023-04-10 06:43:29 +00:00
|
|
|
_: &mut AppContext,
|
2022-02-23 01:05:55 +00:00
|
|
|
) -> proto::GetDocumentHighlightsResponse {
|
|
|
|
let highlights = response
|
|
|
|
.into_iter()
|
|
|
|
.map(|highlight| proto::DocumentHighlight {
|
|
|
|
start: Some(serialize_anchor(&highlight.range.start)),
|
|
|
|
end: Some(serialize_anchor(&highlight.range.end)),
|
|
|
|
kind: match highlight.kind {
|
|
|
|
DocumentHighlightKind::TEXT => proto::document_highlight::Kind::Text.into(),
|
|
|
|
DocumentHighlightKind::WRITE => proto::document_highlight::Kind::Write.into(),
|
|
|
|
DocumentHighlightKind::READ => proto::document_highlight::Kind::Read.into(),
|
|
|
|
_ => proto::document_highlight::Kind::Text.into(),
|
|
|
|
},
|
|
|
|
})
|
|
|
|
.collect();
|
|
|
|
proto::GetDocumentHighlightsResponse { highlights }
|
|
|
|
}
|
|
|
|
|
|
|
|
async fn response_from_proto(
|
|
|
|
self,
|
|
|
|
message: proto::GetDocumentHighlightsResponse,
|
|
|
|
_: ModelHandle<Project>,
|
2022-03-03 11:18:19 +00:00
|
|
|
buffer: ModelHandle<Buffer>,
|
|
|
|
mut cx: AsyncAppContext,
|
2022-02-23 01:05:55 +00:00
|
|
|
) -> Result<Vec<DocumentHighlight>> {
|
2022-03-03 11:18:19 +00:00
|
|
|
let mut highlights = Vec::new();
|
|
|
|
for highlight in message.highlights {
|
|
|
|
let start = highlight
|
|
|
|
.start
|
|
|
|
.and_then(deserialize_anchor)
|
|
|
|
.ok_or_else(|| anyhow!("missing target start"))?;
|
|
|
|
let end = highlight
|
|
|
|
.end
|
|
|
|
.and_then(deserialize_anchor)
|
|
|
|
.ok_or_else(|| anyhow!("missing target end"))?;
|
|
|
|
buffer
|
2023-04-18 23:13:18 +00:00
|
|
|
.update(&mut cx, |buffer, _| buffer.wait_for_anchors([start, end]))
|
2023-04-10 23:06:28 +00:00
|
|
|
.await?;
|
2022-03-03 11:18:19 +00:00
|
|
|
let kind = match proto::document_highlight::Kind::from_i32(highlight.kind) {
|
|
|
|
Some(proto::document_highlight::Kind::Text) => DocumentHighlightKind::TEXT,
|
|
|
|
Some(proto::document_highlight::Kind::Read) => DocumentHighlightKind::READ,
|
|
|
|
Some(proto::document_highlight::Kind::Write) => DocumentHighlightKind::WRITE,
|
|
|
|
None => DocumentHighlightKind::TEXT,
|
|
|
|
};
|
|
|
|
highlights.push(DocumentHighlight {
|
|
|
|
range: start..end,
|
|
|
|
kind,
|
|
|
|
});
|
|
|
|
}
|
|
|
|
Ok(highlights)
|
2022-02-23 01:05:55 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
fn buffer_id_from_proto(message: &proto::GetDocumentHighlights) -> u64 {
|
|
|
|
message.buffer_id
|
|
|
|
}
|
|
|
|
}
|
2022-05-30 15:00:45 +00:00
|
|
|
|
|
|
|
#[async_trait(?Send)]
|
|
|
|
impl LspCommand for GetHover {
|
2022-05-31 04:09:19 +00:00
|
|
|
type Response = Option<Hover>;
|
2022-05-30 15:00:45 +00:00
|
|
|
type LspRequest = lsp::request::HoverRequest;
|
|
|
|
type ProtoRequest = proto::GetHover;
|
|
|
|
|
2023-04-11 13:11:30 +00:00
|
|
|
fn to_lsp(
|
|
|
|
&self,
|
|
|
|
path: &Path,
|
|
|
|
_: &Buffer,
|
|
|
|
_: &Arc<LanguageServer>,
|
|
|
|
_: &AppContext,
|
|
|
|
) -> lsp::HoverParams {
|
2022-05-30 15:00:45 +00:00
|
|
|
lsp::HoverParams {
|
|
|
|
text_document_position_params: lsp::TextDocumentPositionParams {
|
|
|
|
text_document: lsp::TextDocumentIdentifier {
|
|
|
|
uri: lsp::Url::from_file_path(path).unwrap(),
|
|
|
|
},
|
|
|
|
position: point_to_lsp(self.position),
|
|
|
|
},
|
|
|
|
work_done_progress_params: Default::default(),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
async fn response_from_lsp(
|
|
|
|
self,
|
|
|
|
message: Option<lsp::Hover>,
|
2022-06-03 21:56:21 +00:00
|
|
|
_: ModelHandle<Project>,
|
2022-05-30 15:00:45 +00:00
|
|
|
buffer: ModelHandle<Buffer>,
|
2023-04-20 00:37:28 +00:00
|
|
|
_: LanguageServerId,
|
2022-06-29 15:58:11 +00:00
|
|
|
cx: AsyncAppContext,
|
2022-05-30 15:00:45 +00:00
|
|
|
) -> Result<Self::Response> {
|
2022-06-02 06:05:31 +00:00
|
|
|
Ok(message.and_then(|hover| {
|
2022-05-31 04:09:19 +00:00
|
|
|
let range = hover.range.map(|range| {
|
|
|
|
cx.read(|cx| {
|
|
|
|
let buffer = buffer.read(cx);
|
2022-05-31 15:57:51 +00:00
|
|
|
let token_start =
|
|
|
|
buffer.clip_point_utf16(point_from_lsp(range.start), Bias::Left);
|
|
|
|
let token_end = buffer.clip_point_utf16(point_from_lsp(range.end), Bias::Left);
|
2022-11-21 16:47:46 +00:00
|
|
|
buffer.anchor_after(token_start)..buffer.anchor_before(token_end)
|
2022-05-31 04:09:19 +00:00
|
|
|
})
|
|
|
|
});
|
2022-05-31 15:57:51 +00:00
|
|
|
|
2023-04-26 20:23:29 +00:00
|
|
|
fn hover_blocks_from_marked_string(
|
|
|
|
marked_string: lsp::MarkedString,
|
|
|
|
) -> Option<HoverBlock> {
|
|
|
|
let block = match marked_string {
|
|
|
|
lsp::MarkedString::String(content) => HoverBlock {
|
|
|
|
text: content,
|
|
|
|
kind: HoverBlockKind::Markdown,
|
|
|
|
},
|
|
|
|
lsp::MarkedString::LanguageString(lsp::LanguageString { language, value }) => {
|
|
|
|
HoverBlock {
|
|
|
|
text: value,
|
|
|
|
kind: HoverBlockKind::Code { language },
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
if block.text.is_empty() {
|
|
|
|
None
|
|
|
|
} else {
|
|
|
|
Some(block)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-06-03 21:56:21 +00:00
|
|
|
let contents = cx.read(|_| match hover.contents {
|
|
|
|
lsp::HoverContents::Scalar(marked_string) => {
|
2023-04-26 20:23:29 +00:00
|
|
|
hover_blocks_from_marked_string(marked_string)
|
2022-06-03 21:56:21 +00:00
|
|
|
.into_iter()
|
2023-04-26 20:23:29 +00:00
|
|
|
.collect()
|
2022-06-03 21:56:21 +00:00
|
|
|
}
|
2023-04-26 20:23:29 +00:00
|
|
|
lsp::HoverContents::Array(marked_strings) => marked_strings
|
|
|
|
.into_iter()
|
|
|
|
.filter_map(hover_blocks_from_marked_string)
|
|
|
|
.collect(),
|
|
|
|
lsp::HoverContents::Markup(markup_content) => vec![HoverBlock {
|
|
|
|
text: markup_content.value,
|
|
|
|
kind: if markup_content.kind == lsp::MarkupKind::Markdown {
|
|
|
|
HoverBlockKind::Markdown
|
2022-06-03 21:56:21 +00:00
|
|
|
} else {
|
2023-04-26 20:23:29 +00:00
|
|
|
HoverBlockKind::PlainText
|
|
|
|
},
|
|
|
|
}],
|
2022-06-01 05:49:47 +00:00
|
|
|
});
|
|
|
|
|
2023-04-26 20:23:29 +00:00
|
|
|
Some(Hover { contents, range })
|
2022-05-31 04:09:19 +00:00
|
|
|
}))
|
2022-05-30 15:00:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
fn to_proto(&self, project_id: u64, buffer: &Buffer) -> Self::ProtoRequest {
|
|
|
|
proto::GetHover {
|
|
|
|
project_id,
|
|
|
|
buffer_id: buffer.remote_id(),
|
|
|
|
position: Some(language::proto::serialize_anchor(
|
2022-11-17 03:20:16 +00:00
|
|
|
&buffer.anchor_before(self.position),
|
2022-05-30 15:00:45 +00:00
|
|
|
)),
|
|
|
|
version: serialize_version(&buffer.version),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
async fn from_proto(
|
|
|
|
message: Self::ProtoRequest,
|
2022-06-01 05:49:47 +00:00
|
|
|
_: ModelHandle<Project>,
|
2022-05-30 15:00:45 +00:00
|
|
|
buffer: ModelHandle<Buffer>,
|
|
|
|
mut cx: AsyncAppContext,
|
|
|
|
) -> Result<Self> {
|
|
|
|
let position = message
|
|
|
|
.position
|
|
|
|
.and_then(deserialize_anchor)
|
|
|
|
.ok_or_else(|| anyhow!("invalid position"))?;
|
|
|
|
buffer
|
|
|
|
.update(&mut cx, |buffer, _| {
|
2023-04-10 23:06:28 +00:00
|
|
|
buffer.wait_for_version(deserialize_version(&message.version))
|
2022-05-30 15:00:45 +00:00
|
|
|
})
|
2023-04-10 23:06:28 +00:00
|
|
|
.await?;
|
2022-05-30 15:00:45 +00:00
|
|
|
Ok(Self {
|
|
|
|
position: buffer.read_with(&cx, |buffer, _| position.to_point_utf16(buffer)),
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
fn response_to_proto(
|
|
|
|
response: Self::Response,
|
2022-06-03 21:56:21 +00:00
|
|
|
_: &mut Project,
|
|
|
|
_: PeerId,
|
|
|
|
_: &clock::Global,
|
2023-04-10 06:43:29 +00:00
|
|
|
_: &mut AppContext,
|
2022-05-30 15:00:45 +00:00
|
|
|
) -> proto::GetHoverResponse {
|
2022-06-03 21:56:21 +00:00
|
|
|
if let Some(response) = response {
|
|
|
|
let (start, end) = if let Some(range) = response.range {
|
|
|
|
(
|
|
|
|
Some(language::proto::serialize_anchor(&range.start)),
|
|
|
|
Some(language::proto::serialize_anchor(&range.end)),
|
|
|
|
)
|
|
|
|
} else {
|
|
|
|
(None, None)
|
|
|
|
};
|
|
|
|
|
|
|
|
let contents = response
|
|
|
|
.contents
|
|
|
|
.into_iter()
|
|
|
|
.map(|block| proto::HoverBlock {
|
|
|
|
text: block.text,
|
2023-04-26 20:23:29 +00:00
|
|
|
is_markdown: block.kind == HoverBlockKind::Markdown,
|
|
|
|
language: if let HoverBlockKind::Code { language } = block.kind {
|
|
|
|
Some(language)
|
|
|
|
} else {
|
|
|
|
None
|
|
|
|
},
|
2022-06-03 21:56:21 +00:00
|
|
|
})
|
|
|
|
.collect();
|
|
|
|
|
|
|
|
proto::GetHoverResponse {
|
|
|
|
start,
|
|
|
|
end,
|
|
|
|
contents,
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
proto::GetHoverResponse {
|
|
|
|
start: None,
|
|
|
|
end: None,
|
|
|
|
contents: Vec::new(),
|
|
|
|
}
|
|
|
|
}
|
2022-05-30 15:00:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
async fn response_from_proto(
|
|
|
|
self,
|
2022-06-03 21:56:21 +00:00
|
|
|
message: proto::GetHoverResponse,
|
|
|
|
_: ModelHandle<Project>,
|
|
|
|
_: ModelHandle<Buffer>,
|
|
|
|
_: AsyncAppContext,
|
2022-05-30 15:00:45 +00:00
|
|
|
) -> Result<Self::Response> {
|
2022-06-03 21:56:21 +00:00
|
|
|
let range = if let (Some(start), Some(end)) = (message.start, message.end) {
|
|
|
|
language::proto::deserialize_anchor(start)
|
|
|
|
.and_then(|start| language::proto::deserialize_anchor(end).map(|end| start..end))
|
|
|
|
} else {
|
|
|
|
None
|
|
|
|
};
|
|
|
|
|
|
|
|
let contents: Vec<_> = message
|
|
|
|
.contents
|
|
|
|
.into_iter()
|
|
|
|
.map(|block| HoverBlock {
|
|
|
|
text: block.text,
|
2023-04-26 20:23:29 +00:00
|
|
|
kind: if let Some(language) = block.language {
|
|
|
|
HoverBlockKind::Code { language }
|
|
|
|
} else if block.is_markdown {
|
|
|
|
HoverBlockKind::Markdown
|
|
|
|
} else {
|
|
|
|
HoverBlockKind::PlainText
|
|
|
|
},
|
2022-06-03 21:56:21 +00:00
|
|
|
})
|
|
|
|
.collect();
|
|
|
|
|
|
|
|
Ok(if contents.is_empty() {
|
|
|
|
None
|
|
|
|
} else {
|
|
|
|
Some(Hover { contents, range })
|
|
|
|
})
|
2022-05-30 15:00:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
fn buffer_id_from_proto(message: &Self::ProtoRequest) -> u64 {
|
|
|
|
message.buffer_id
|
|
|
|
}
|
|
|
|
}
|
2023-04-11 12:52:07 +00:00
|
|
|
|
|
|
|
#[async_trait(?Send)]
|
|
|
|
impl LspCommand for GetCompletions {
|
|
|
|
type Response = Vec<Completion>;
|
|
|
|
type LspRequest = lsp::request::Completion;
|
|
|
|
type ProtoRequest = proto::GetCompletions;
|
|
|
|
|
2023-04-11 13:11:30 +00:00
|
|
|
fn to_lsp(
|
|
|
|
&self,
|
|
|
|
path: &Path,
|
|
|
|
_: &Buffer,
|
|
|
|
_: &Arc<LanguageServer>,
|
|
|
|
_: &AppContext,
|
|
|
|
) -> lsp::CompletionParams {
|
2023-04-11 12:52:07 +00:00
|
|
|
lsp::CompletionParams {
|
|
|
|
text_document_position: lsp::TextDocumentPositionParams::new(
|
|
|
|
lsp::TextDocumentIdentifier::new(lsp::Url::from_file_path(path).unwrap()),
|
|
|
|
point_to_lsp(self.position),
|
|
|
|
),
|
|
|
|
context: Default::default(),
|
|
|
|
work_done_progress_params: Default::default(),
|
|
|
|
partial_result_params: Default::default(),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
async fn response_from_lsp(
|
|
|
|
self,
|
|
|
|
completions: Option<lsp::CompletionResponse>,
|
|
|
|
_: ModelHandle<Project>,
|
|
|
|
buffer: ModelHandle<Buffer>,
|
2023-04-20 00:37:28 +00:00
|
|
|
_: LanguageServerId,
|
2023-04-11 12:52:07 +00:00
|
|
|
cx: AsyncAppContext,
|
|
|
|
) -> Result<Vec<Completion>> {
|
|
|
|
let completions = if let Some(completions) = completions {
|
|
|
|
match completions {
|
|
|
|
lsp::CompletionResponse::Array(completions) => completions,
|
|
|
|
lsp::CompletionResponse::List(list) => list.items,
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
Default::default()
|
|
|
|
};
|
|
|
|
|
|
|
|
let completions = buffer.read_with(&cx, |buffer, _| {
|
|
|
|
let language = buffer.language().cloned();
|
|
|
|
let snapshot = buffer.snapshot();
|
|
|
|
let clipped_position = buffer.clip_point_utf16(Unclipped(self.position), Bias::Left);
|
|
|
|
let mut range_for_token = None;
|
|
|
|
completions
|
|
|
|
.into_iter()
|
|
|
|
.filter_map(move |mut lsp_completion| {
|
|
|
|
// For now, we can only handle additional edits if they are returned
|
|
|
|
// when resolving the completion, not if they are present initially.
|
|
|
|
if lsp_completion
|
|
|
|
.additional_text_edits
|
|
|
|
.as_ref()
|
|
|
|
.map_or(false, |edits| !edits.is_empty())
|
|
|
|
{
|
|
|
|
return None;
|
|
|
|
}
|
|
|
|
|
|
|
|
let (old_range, mut new_text) = match lsp_completion.text_edit.as_ref() {
|
|
|
|
// If the language server provides a range to overwrite, then
|
|
|
|
// check that the range is valid.
|
|
|
|
Some(lsp::CompletionTextEdit::Edit(edit)) => {
|
|
|
|
let range = range_from_lsp(edit.range);
|
|
|
|
let start = snapshot.clip_point_utf16(range.start, Bias::Left);
|
|
|
|
let end = snapshot.clip_point_utf16(range.end, Bias::Left);
|
|
|
|
if start != range.start.0 || end != range.end.0 {
|
|
|
|
log::info!("completion out of expected range");
|
|
|
|
return None;
|
|
|
|
}
|
|
|
|
(
|
|
|
|
snapshot.anchor_before(start)..snapshot.anchor_after(end),
|
|
|
|
edit.new_text.clone(),
|
|
|
|
)
|
|
|
|
}
|
|
|
|
// If the language server does not provide a range, then infer
|
|
|
|
// the range based on the syntax tree.
|
|
|
|
None => {
|
|
|
|
if self.position != clipped_position {
|
|
|
|
log::info!("completion out of expected range");
|
|
|
|
return None;
|
|
|
|
}
|
|
|
|
let Range { start, end } = range_for_token
|
|
|
|
.get_or_insert_with(|| {
|
|
|
|
let offset = self.position.to_offset(&snapshot);
|
|
|
|
let (range, kind) = snapshot.surrounding_word(offset);
|
|
|
|
if kind == Some(CharKind::Word) {
|
|
|
|
range
|
|
|
|
} else {
|
|
|
|
offset..offset
|
|
|
|
}
|
|
|
|
})
|
|
|
|
.clone();
|
|
|
|
let text = lsp_completion
|
|
|
|
.insert_text
|
|
|
|
.as_ref()
|
|
|
|
.unwrap_or(&lsp_completion.label)
|
|
|
|
.clone();
|
|
|
|
(
|
|
|
|
snapshot.anchor_before(start)..snapshot.anchor_after(end),
|
|
|
|
text,
|
|
|
|
)
|
|
|
|
}
|
|
|
|
Some(lsp::CompletionTextEdit::InsertAndReplace(_)) => {
|
|
|
|
log::info!("unsupported insert/replace completion");
|
|
|
|
return None;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
let language = language.clone();
|
|
|
|
LineEnding::normalize(&mut new_text);
|
|
|
|
Some(async move {
|
|
|
|
let mut label = None;
|
|
|
|
if let Some(language) = language {
|
|
|
|
language.process_completion(&mut lsp_completion).await;
|
|
|
|
label = language.label_for_completion(&lsp_completion).await;
|
|
|
|
}
|
|
|
|
Completion {
|
|
|
|
old_range,
|
|
|
|
new_text,
|
|
|
|
label: label.unwrap_or_else(|| {
|
|
|
|
language::CodeLabel::plain(
|
|
|
|
lsp_completion.label.clone(),
|
|
|
|
lsp_completion.filter_text.as_deref(),
|
|
|
|
)
|
|
|
|
}),
|
|
|
|
lsp_completion,
|
|
|
|
}
|
|
|
|
})
|
|
|
|
})
|
|
|
|
});
|
|
|
|
|
|
|
|
Ok(futures::future::join_all(completions).await)
|
|
|
|
}
|
|
|
|
|
|
|
|
fn to_proto(&self, project_id: u64, buffer: &Buffer) -> proto::GetCompletions {
|
|
|
|
let anchor = buffer.anchor_after(self.position);
|
|
|
|
proto::GetCompletions {
|
|
|
|
project_id,
|
|
|
|
buffer_id: buffer.remote_id(),
|
|
|
|
position: Some(language::proto::serialize_anchor(&anchor)),
|
|
|
|
version: serialize_version(&buffer.version()),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
async fn from_proto(
|
|
|
|
message: proto::GetCompletions,
|
2023-04-11 12:53:08 +00:00
|
|
|
_: ModelHandle<Project>,
|
2023-04-11 12:52:07 +00:00
|
|
|
buffer: ModelHandle<Buffer>,
|
|
|
|
mut cx: AsyncAppContext,
|
|
|
|
) -> Result<Self> {
|
|
|
|
let version = deserialize_version(&message.version);
|
|
|
|
buffer
|
|
|
|
.update(&mut cx, |buffer, _| buffer.wait_for_version(version))
|
|
|
|
.await?;
|
|
|
|
let position = message
|
|
|
|
.position
|
|
|
|
.and_then(language::proto::deserialize_anchor)
|
|
|
|
.map(|p| {
|
|
|
|
buffer.read_with(&cx, |buffer, _| {
|
|
|
|
buffer.clip_point_utf16(Unclipped(p.to_point_utf16(buffer)), Bias::Left)
|
|
|
|
})
|
|
|
|
})
|
|
|
|
.ok_or_else(|| anyhow!("invalid position"))?;
|
|
|
|
Ok(Self { position })
|
|
|
|
}
|
|
|
|
|
|
|
|
fn response_to_proto(
|
|
|
|
completions: Vec<Completion>,
|
|
|
|
_: &mut Project,
|
|
|
|
_: PeerId,
|
|
|
|
buffer_version: &clock::Global,
|
|
|
|
_: &mut AppContext,
|
|
|
|
) -> proto::GetCompletionsResponse {
|
|
|
|
proto::GetCompletionsResponse {
|
|
|
|
completions: completions
|
|
|
|
.iter()
|
|
|
|
.map(language::proto::serialize_completion)
|
|
|
|
.collect(),
|
|
|
|
version: serialize_version(&buffer_version),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
async fn response_from_proto(
|
|
|
|
self,
|
|
|
|
message: proto::GetCompletionsResponse,
|
|
|
|
_: ModelHandle<Project>,
|
|
|
|
buffer: ModelHandle<Buffer>,
|
|
|
|
mut cx: AsyncAppContext,
|
|
|
|
) -> Result<Vec<Completion>> {
|
|
|
|
buffer
|
|
|
|
.update(&mut cx, |buffer, _| {
|
|
|
|
buffer.wait_for_version(deserialize_version(&message.version))
|
|
|
|
})
|
|
|
|
.await?;
|
|
|
|
|
|
|
|
let language = buffer.read_with(&cx, |buffer, _| buffer.language().cloned());
|
|
|
|
let completions = message.completions.into_iter().map(|completion| {
|
|
|
|
language::proto::deserialize_completion(completion, language.clone())
|
|
|
|
});
|
|
|
|
futures::future::try_join_all(completions).await
|
|
|
|
}
|
|
|
|
|
|
|
|
fn buffer_id_from_proto(message: &proto::GetCompletions) -> u64 {
|
|
|
|
message.buffer_id
|
|
|
|
}
|
|
|
|
}
|
2023-04-11 13:11:30 +00:00
|
|
|
|
|
|
|
#[async_trait(?Send)]
|
|
|
|
impl LspCommand for GetCodeActions {
|
|
|
|
type Response = Vec<CodeAction>;
|
|
|
|
type LspRequest = lsp::request::CodeActionRequest;
|
|
|
|
type ProtoRequest = proto::GetCodeActions;
|
|
|
|
|
|
|
|
fn check_capabilities(&self, capabilities: &ServerCapabilities) -> bool {
|
|
|
|
capabilities.code_action_provider.is_some()
|
|
|
|
}
|
|
|
|
|
|
|
|
fn to_lsp(
|
|
|
|
&self,
|
|
|
|
path: &Path,
|
|
|
|
buffer: &Buffer,
|
|
|
|
language_server: &Arc<LanguageServer>,
|
|
|
|
_: &AppContext,
|
|
|
|
) -> lsp::CodeActionParams {
|
|
|
|
let relevant_diagnostics = buffer
|
|
|
|
.snapshot()
|
|
|
|
.diagnostics_in_range::<_, usize>(self.range.clone(), false)
|
|
|
|
.map(|entry| entry.to_lsp_diagnostic_stub())
|
|
|
|
.collect();
|
|
|
|
lsp::CodeActionParams {
|
|
|
|
text_document: lsp::TextDocumentIdentifier::new(
|
|
|
|
lsp::Url::from_file_path(path).unwrap(),
|
|
|
|
),
|
|
|
|
range: range_to_lsp(self.range.to_point_utf16(buffer)),
|
|
|
|
work_done_progress_params: Default::default(),
|
|
|
|
partial_result_params: Default::default(),
|
|
|
|
context: lsp::CodeActionContext {
|
|
|
|
diagnostics: relevant_diagnostics,
|
|
|
|
only: language_server.code_action_kinds(),
|
|
|
|
},
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
async fn response_from_lsp(
|
|
|
|
self,
|
|
|
|
actions: Option<lsp::CodeActionResponse>,
|
|
|
|
_: ModelHandle<Project>,
|
|
|
|
_: ModelHandle<Buffer>,
|
2023-04-20 00:37:28 +00:00
|
|
|
server_id: LanguageServerId,
|
2023-04-11 13:11:30 +00:00
|
|
|
_: AsyncAppContext,
|
|
|
|
) -> Result<Vec<CodeAction>> {
|
|
|
|
Ok(actions
|
|
|
|
.unwrap_or_default()
|
|
|
|
.into_iter()
|
|
|
|
.filter_map(|entry| {
|
|
|
|
if let lsp::CodeActionOrCommand::CodeAction(lsp_action) = entry {
|
|
|
|
Some(CodeAction {
|
2023-04-07 15:46:05 +00:00
|
|
|
server_id,
|
2023-04-11 13:11:30 +00:00
|
|
|
range: self.range.clone(),
|
|
|
|
lsp_action,
|
|
|
|
})
|
|
|
|
} else {
|
|
|
|
None
|
|
|
|
}
|
|
|
|
})
|
|
|
|
.collect())
|
|
|
|
}
|
|
|
|
|
|
|
|
fn to_proto(&self, project_id: u64, buffer: &Buffer) -> proto::GetCodeActions {
|
|
|
|
proto::GetCodeActions {
|
|
|
|
project_id,
|
|
|
|
buffer_id: buffer.remote_id(),
|
|
|
|
start: Some(language::proto::serialize_anchor(&self.range.start)),
|
|
|
|
end: Some(language::proto::serialize_anchor(&self.range.end)),
|
|
|
|
version: serialize_version(&buffer.version()),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
async fn from_proto(
|
|
|
|
message: proto::GetCodeActions,
|
|
|
|
_: ModelHandle<Project>,
|
|
|
|
buffer: ModelHandle<Buffer>,
|
|
|
|
mut cx: AsyncAppContext,
|
|
|
|
) -> Result<Self> {
|
|
|
|
let start = message
|
|
|
|
.start
|
|
|
|
.and_then(language::proto::deserialize_anchor)
|
|
|
|
.ok_or_else(|| anyhow!("invalid start"))?;
|
|
|
|
let end = message
|
|
|
|
.end
|
|
|
|
.and_then(language::proto::deserialize_anchor)
|
|
|
|
.ok_or_else(|| anyhow!("invalid end"))?;
|
|
|
|
buffer
|
|
|
|
.update(&mut cx, |buffer, _| {
|
|
|
|
buffer.wait_for_version(deserialize_version(&message.version))
|
|
|
|
})
|
|
|
|
.await?;
|
|
|
|
|
|
|
|
Ok(Self { range: start..end })
|
|
|
|
}
|
|
|
|
|
|
|
|
fn response_to_proto(
|
|
|
|
code_actions: Vec<CodeAction>,
|
|
|
|
_: &mut Project,
|
|
|
|
_: PeerId,
|
|
|
|
buffer_version: &clock::Global,
|
|
|
|
_: &mut AppContext,
|
|
|
|
) -> proto::GetCodeActionsResponse {
|
|
|
|
proto::GetCodeActionsResponse {
|
|
|
|
actions: code_actions
|
|
|
|
.iter()
|
|
|
|
.map(language::proto::serialize_code_action)
|
|
|
|
.collect(),
|
|
|
|
version: serialize_version(&buffer_version),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
async fn response_from_proto(
|
|
|
|
self,
|
|
|
|
message: proto::GetCodeActionsResponse,
|
|
|
|
_: ModelHandle<Project>,
|
|
|
|
buffer: ModelHandle<Buffer>,
|
|
|
|
mut cx: AsyncAppContext,
|
|
|
|
) -> Result<Vec<CodeAction>> {
|
|
|
|
buffer
|
|
|
|
.update(&mut cx, |buffer, _| {
|
|
|
|
buffer.wait_for_version(deserialize_version(&message.version))
|
|
|
|
})
|
|
|
|
.await?;
|
|
|
|
message
|
|
|
|
.actions
|
|
|
|
.into_iter()
|
|
|
|
.map(language::proto::deserialize_code_action)
|
|
|
|
.collect()
|
|
|
|
}
|
|
|
|
|
|
|
|
fn buffer_id_from_proto(message: &proto::GetCodeActions) -> u64 {
|
|
|
|
message.buffer_id
|
|
|
|
}
|
|
|
|
}
|
2023-05-19 10:18:50 +00:00
|
|
|
|
|
|
|
#[async_trait(?Send)]
|
|
|
|
impl LspCommand for OnTypeFormatting {
|
|
|
|
type Response = Vec<(Range<Anchor>, String)>;
|
|
|
|
type LspRequest = lsp::request::OnTypeFormatting;
|
2023-05-23 14:11:23 +00:00
|
|
|
type ProtoRequest = proto::OnTypeFormatting;
|
2023-05-19 10:18:50 +00:00
|
|
|
|
|
|
|
fn check_capabilities(&self, server_capabilities: &lsp::ServerCapabilities) -> bool {
|
|
|
|
let Some(on_type_formatting_options) = &server_capabilities.document_on_type_formatting_provider else { return false };
|
|
|
|
on_type_formatting_options
|
|
|
|
.first_trigger_character
|
2023-05-23 14:11:23 +00:00
|
|
|
.contains(&self.trigger)
|
2023-05-19 10:18:50 +00:00
|
|
|
|| on_type_formatting_options
|
|
|
|
.more_trigger_character
|
|
|
|
.iter()
|
|
|
|
.flatten()
|
2023-05-23 14:11:23 +00:00
|
|
|
.any(|chars| chars.contains(&self.trigger))
|
2023-05-19 10:18:50 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
fn to_lsp(
|
|
|
|
&self,
|
|
|
|
path: &Path,
|
|
|
|
_: &Buffer,
|
|
|
|
_: &Arc<LanguageServer>,
|
|
|
|
_: &AppContext,
|
|
|
|
) -> lsp::DocumentOnTypeFormattingParams {
|
|
|
|
lsp::DocumentOnTypeFormattingParams {
|
|
|
|
text_document_position: lsp::TextDocumentPositionParams::new(
|
|
|
|
lsp::TextDocumentIdentifier::new(lsp::Url::from_file_path(path).unwrap()),
|
|
|
|
point_to_lsp(self.position),
|
|
|
|
),
|
2023-05-23 14:11:23 +00:00
|
|
|
ch: self.trigger.clone(),
|
2023-05-23 14:38:05 +00:00
|
|
|
options: lsp_formatting_options(self.options.tab_size),
|
2023-05-19 10:18:50 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
async fn response_from_lsp(
|
|
|
|
self,
|
|
|
|
message: Option<Vec<lsp::TextEdit>>,
|
|
|
|
project: ModelHandle<Project>,
|
|
|
|
buffer: ModelHandle<Buffer>,
|
|
|
|
server_id: LanguageServerId,
|
|
|
|
mut cx: AsyncAppContext,
|
|
|
|
) -> Result<Vec<(Range<Anchor>, String)>> {
|
|
|
|
cx.update(|cx| {
|
|
|
|
project.update(cx, |project, cx| {
|
|
|
|
project.edits_from_lsp(&buffer, message.into_iter().flatten(), server_id, None, cx)
|
|
|
|
})
|
|
|
|
})
|
|
|
|
.await
|
|
|
|
.context("LSP edits conversion")
|
|
|
|
}
|
|
|
|
|
2023-05-23 14:11:23 +00:00
|
|
|
fn to_proto(&self, project_id: u64, buffer: &Buffer) -> proto::OnTypeFormatting {
|
|
|
|
proto::OnTypeFormatting {
|
|
|
|
project_id,
|
|
|
|
buffer_id: buffer.remote_id(),
|
|
|
|
position: Some(language::proto::serialize_anchor(
|
|
|
|
&buffer.anchor_before(self.position),
|
|
|
|
)),
|
|
|
|
trigger: self.trigger.clone(),
|
|
|
|
version: serialize_version(&buffer.version()),
|
|
|
|
}
|
2023-05-19 10:18:50 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
async fn from_proto(
|
2023-05-23 14:11:23 +00:00
|
|
|
message: proto::OnTypeFormatting,
|
2023-05-19 10:18:50 +00:00
|
|
|
_: ModelHandle<Project>,
|
|
|
|
buffer: ModelHandle<Buffer>,
|
|
|
|
mut cx: AsyncAppContext,
|
|
|
|
) -> Result<Self> {
|
2023-05-23 14:11:23 +00:00
|
|
|
let position = message
|
|
|
|
.position
|
|
|
|
.and_then(deserialize_anchor)
|
|
|
|
.ok_or_else(|| anyhow!("invalid position"))?;
|
|
|
|
buffer
|
|
|
|
.update(&mut cx, |buffer, _| {
|
|
|
|
buffer.wait_for_version(deserialize_version(&message.version))
|
|
|
|
})
|
|
|
|
.await?;
|
|
|
|
|
2023-05-23 19:58:40 +00:00
|
|
|
let tab_size = buffer.read_with(&cx, |buffer, cx| {
|
|
|
|
let language_name = buffer.language().map(|language| language.name());
|
|
|
|
language_settings(language_name.as_deref(), cx).tab_size
|
|
|
|
});
|
|
|
|
|
2023-05-23 14:11:23 +00:00
|
|
|
Ok(Self {
|
|
|
|
position: buffer.read_with(&cx, |buffer, _| position.to_point_utf16(buffer)),
|
|
|
|
trigger: message.trigger.clone(),
|
2023-05-23 19:58:40 +00:00
|
|
|
options: lsp_formatting_options(tab_size.get()).into(),
|
2023-05-23 14:11:23 +00:00
|
|
|
})
|
2023-05-19 10:18:50 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
fn response_to_proto(
|
|
|
|
response: Vec<(Range<Anchor>, String)>,
|
2023-05-23 14:11:23 +00:00
|
|
|
_: &mut Project,
|
|
|
|
_: PeerId,
|
|
|
|
buffer_version: &clock::Global,
|
|
|
|
_: &mut AppContext,
|
|
|
|
) -> proto::OnTypeFormattingResponse {
|
|
|
|
proto::OnTypeFormattingResponse {
|
|
|
|
entries: response
|
|
|
|
.into_iter()
|
|
|
|
.map(
|
|
|
|
|(response_range, new_text)| proto::OnTypeFormattingResponseEntry {
|
|
|
|
start: Some(language::proto::serialize_anchor(&response_range.start)),
|
|
|
|
end: Some(language::proto::serialize_anchor(&response_range.end)),
|
|
|
|
new_text,
|
|
|
|
},
|
|
|
|
)
|
|
|
|
.collect(),
|
|
|
|
version: serialize_version(&buffer_version),
|
|
|
|
}
|
2023-05-19 10:18:50 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
async fn response_from_proto(
|
|
|
|
self,
|
2023-05-23 14:11:23 +00:00
|
|
|
message: proto::OnTypeFormattingResponse,
|
|
|
|
_: ModelHandle<Project>,
|
|
|
|
buffer: ModelHandle<Buffer>,
|
2023-05-19 10:18:50 +00:00
|
|
|
mut cx: AsyncAppContext,
|
|
|
|
) -> Result<Vec<(Range<Anchor>, String)>> {
|
2023-05-23 14:11:23 +00:00
|
|
|
buffer
|
|
|
|
.update(&mut cx, |buffer, _| {
|
|
|
|
buffer.wait_for_version(deserialize_version(&message.version))
|
|
|
|
})
|
|
|
|
.await?;
|
|
|
|
message
|
|
|
|
.entries
|
|
|
|
.into_iter()
|
|
|
|
.map(|entry| {
|
|
|
|
let start = entry
|
|
|
|
.start
|
|
|
|
.and_then(language::proto::deserialize_anchor)
|
|
|
|
.ok_or_else(|| anyhow!("invalid start"))?;
|
|
|
|
let end = entry
|
|
|
|
.end
|
|
|
|
.and_then(language::proto::deserialize_anchor)
|
|
|
|
.ok_or_else(|| anyhow!("invalid end"))?;
|
|
|
|
Ok((start..end, entry.new_text))
|
|
|
|
})
|
|
|
|
.collect()
|
2023-05-19 10:18:50 +00:00
|
|
|
}
|
|
|
|
|
2023-05-23 14:11:23 +00:00
|
|
|
fn buffer_id_from_proto(message: &proto::OnTypeFormatting) -> u64 {
|
2023-05-19 10:18:50 +00:00
|
|
|
message.buffer_id
|
|
|
|
}
|
|
|
|
}
|