mod signature_help; use crate::{ buffer_store::BufferStore, lsp_store::LspStore, CodeAction, CoreCompletion, DocumentHighlight, Hover, HoverBlock, HoverBlockKind, InlayHint, InlayHintLabel, InlayHintLabelPart, InlayHintLabelPartTooltip, InlayHintTooltip, Location, LocationLink, MarkupContent, ProjectTransaction, ResolveState,};use anyhow::{anyhow, Context, Result};use async_trait::async_trait;use client::proto::{self, PeerId};use clock::Global;use collections::HashSet;use futures::future;use gpui::{AppContext, AsyncAppContext, Entity, Model};use language::{ language_settings::{language_settings, InlayHintKind, LanguageSettings}, point_from_lsp, point_to_lsp, proto::{deserialize_anchor, deserialize_version, serialize_anchor, serialize_version}, range_from_lsp, range_to_lsp, Anchor, Bias, Buffer, BufferSnapshot, CachedLspAdapter, CharKind, OffsetRangeExt, PointUtf16, ToOffset, ToPointUtf16, Transaction, Unclipped,};use lsp::{ AdapterServerCapabilities, CodeActionKind, CodeActionOptions, CompletionContext, CompletionListItemDefaultsEditRange, CompletionTriggerKind, DocumentHighlightKind, LanguageServer, LanguageServerId, LinkedEditingRangeServerCapabilities, OneOf, ServerCapabilities,};use signature_help::{lsp_to_proto_signature, proto_to_lsp_signature};use std::{cmp::Reverse, ops::Range, path::Path, sync::Arc};use text::{BufferId, LineEnding}; pub use signature_help::{ SignatureHelp, SIGNATURE_HELP_HIGHLIGHT_CURRENT, SIGNATURE_HELP_HIGHLIGHT_OVERLOAD,}; pub fn lsp_formatting_options(settings: &LanguageSettings) -> lsp::FormattingOptions { lsp::FormattingOptions { tab_size: settings.tab_size.into(), insert_spaces: !settings.hard_tabs, trim_trailing_whitespace: Some(settings.remove_trailing_whitespace_on_save), trim_final_newlines: Some(settings.ensure_final_newline_on_save), insert_final_newline: Some(settings.ensure_final_newline_on_save), ..lsp::FormattingOptions::default() }} #[async_trait(?Send)]pub trait LspCommand: 'static + Sized + Send { type Response: 'static + Default + Send; type LspRequest: 'static + Send + lsp::request::Request; type ProtoRequest: 'static + Send + proto::RequestMessage; fn check_capabilities(&self, _: AdapterServerCapabilities) -> bool { true } fn status(&self) -> Option<String> { None } fn to_lsp( &self, path: &Path, buffer: &Buffer, language_server: &Arc<LanguageServer>, cx: &AppContext, ) -> <Self::LspRequest as lsp::request::Request>::Params; async fn response_from_lsp( self, message: <Self::LspRequest as lsp::request::Request>::Result, lsp_store: Model<LspStore>, buffer: Model<Buffer>, server_id: LanguageServerId, cx: AsyncAppContext, ) -> Result<Self::Response>; fn to_proto(&self, project_id: u64, buffer: &Buffer) -> Self::ProtoRequest; async fn from_proto( message: Self::ProtoRequest, lsp_store: Model<LspStore>, buffer: Model<Buffer>, cx: AsyncAppContext, ) -> Result<Self>; fn response_to_proto( response: Self::Response, lsp_store: &mut LspStore, peer_id: PeerId, buffer_version: &clock::Global, cx: &mut AppContext, ) -> <Self::ProtoRequest as proto::RequestMessage>::Response; async fn response_from_proto( self, message: <Self::ProtoRequest as proto::RequestMessage>::Response, lsp_store: Model<LspStore>, buffer: Model<Buffer>, cx: AsyncAppContext, ) -> Result<Self::Response>; fn buffer_id_from_proto(message: &Self::ProtoRequest) -> Result<BufferId>;} pub(crate) struct PrepareRename { pub position: PointUtf16,} pub(crate) struct PerformRename { pub position: PointUtf16, pub new_name: String, pub push_to_history: bool,} pub struct GetDefinition { pub position: PointUtf16,} pub(crate) struct GetDeclaration { pub position: PointUtf16,} pub(crate) struct GetTypeDefinition { pub position: PointUtf16,} pub(crate) struct GetImplementation { pub position: PointUtf16,} pub(crate) struct GetReferences { pub position: PointUtf16,} pub(crate) struct GetDocumentHighlights { pub position: PointUtf16,} #[derive(Clone)]pub(crate) struct GetSignatureHelp { pub position: PointUtf16,} #[derive(Clone)]pub(crate) struct GetHover { pub position: PointUtf16,} pub(crate) struct GetCompletions { pub position: PointUtf16, pub context: CompletionContext,} #[derive(Clone)]pub(crate) struct GetCodeActions { pub range: Range<Anchor>, pub kinds: Option<Vec<lsp::CodeActionKind>>,} pub(crate) struct OnTypeFormatting { pub position: PointUtf16, pub trigger: String, pub options: lsp::FormattingOptions, pub push_to_history: bool,} pub(crate) struct InlayHints { pub range: Range<Anchor>,} pub(crate) struct LinkedEditingRange { pub position: Anchor,} #[async_trait(?Send)]impl LspCommand for PrepareRename { type Response = Option<Range<Anchor>>; type LspRequest = lsp::request::PrepareRenameRequest; type ProtoRequest = proto::PrepareRename; fn check_capabilities(&self, capabilities: AdapterServerCapabilities) -> bool { if let Some(lsp::OneOf::Right(rename)) = &capabilities.server_capabilities.rename_provider { rename.prepare_provider == Some(true) } else { false } } fn to_lsp( &self, path: &Path, _: &Buffer, _: &Arc<LanguageServer>, _: &AppContext, ) -> lsp::TextDocumentPositionParams { lsp::TextDocumentPositionParams { text_document: lsp::TextDocumentIdentifier { uri: lsp::Url::from_file_path(path).unwrap(), }, position: point_to_lsp(self.position), } } async fn response_from_lsp( self, message: Option<lsp::PrepareRenameResponse>, _: Model<LspStore>, buffer: Model<Buffer>, _: LanguageServerId, mut cx: AsyncAppContext, ) -> Result<Option<Range<Anchor>>> { buffer.update(&mut cx, |buffer, _| { if let Some( lsp::PrepareRenameResponse::Range(range) | lsp::PrepareRenameResponse::RangeWithPlaceholder { range, .. }, ) = message { let Range { start, end } = range_from_lsp(range); if buffer.clip_point_utf16(start, Bias::Left) == start.0 && buffer.clip_point_utf16(end, Bias::Left) == end.0 { return Ok(Some(buffer.anchor_after(start)..buffer.anchor_before(end))); } } Ok(None) })? } fn to_proto(&self, project_id: u64, buffer: &Buffer) -> proto::PrepareRename { proto::PrepareRename { project_id, buffer_id: buffer.remote_id().into(), position: Some(language::proto::serialize_anchor( &buffer.anchor_before(self.position), )), version: serialize_version(&buffer.version()), } } async fn from_proto( message: proto::PrepareRename, _: Model<LspStore>, buffer: Model<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, _| { buffer.wait_for_version(deserialize_version(&message.version)) })? .await?; Ok(Self { position: buffer.update(&mut cx, |buffer, _| position.to_point_utf16(buffer))?, }) } fn response_to_proto( range: Option<Range<Anchor>>, _: &mut LspStore, _: PeerId, buffer_version: &clock::Global, _: &mut AppContext, ) -> 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)), version: serialize_version(buffer_version), } } async fn response_from_proto( self, message: proto::PrepareRenameResponse, _: Model<LspStore>, buffer: Model<Buffer>, mut cx: AsyncAppContext, ) -> Result<Option<Range<Anchor>>> { if message.can_rename { buffer .update(&mut cx, |buffer, _| { buffer.wait_for_version(deserialize_version(&message.version)) })? .await?; 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) } } fn buffer_id_from_proto(message: &proto::PrepareRename) -> Result<BufferId> { BufferId::new(message.buffer_id) }} #[async_trait(?Send)]impl LspCommand for PerformRename { type Response = ProjectTransaction; type LspRequest = lsp::request::Rename; type ProtoRequest = proto::PerformRename; fn to_lsp( &self, path: &Path, _: &Buffer, _: &Arc<LanguageServer>, _: &AppContext, ) -> lsp::RenameParams { lsp::RenameParams { text_document_position: lsp::TextDocumentPositionParams { text_document: lsp::TextDocumentIdentifier { uri: lsp::Url::from_file_path(path).unwrap(), }, position: point_to_lsp(self.position), }, new_name: self.new_name.clone(), work_done_progress_params: Default::default(), } } async fn response_from_lsp( self, message: Option<lsp::WorkspaceEdit>, lsp_store: Model<LspStore>, buffer: Model<Buffer>, server_id: LanguageServerId, mut cx: AsyncAppContext, ) -> Result<ProjectTransaction> { if let Some(edit) = message { let (lsp_adapter, lsp_server) = language_server_for_buffer(&lsp_store, &buffer, server_id, &mut cx)?; LspStore::deserialize_workspace_edit( lsp_store, edit, self.push_to_history, lsp_adapter, lsp_server, &mut cx, ) .await } else { Ok(ProjectTransaction::default()) } } fn to_proto(&self, project_id: u64, buffer: &Buffer) -> proto::PerformRename { proto::PerformRename { project_id, buffer_id: buffer.remote_id().into(), position: Some(language::proto::serialize_anchor( &buffer.anchor_before(self.position), )), new_name: self.new_name.clone(), version: serialize_version(&buffer.version()), } } async fn from_proto( message: proto::PerformRename, _: Model<LspStore>, buffer: Model<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, _| { buffer.wait_for_version(deserialize_version(&message.version)) })? .await?; Ok(Self { position: buffer.update(&mut cx, |buffer, _| position.to_point_utf16(buffer))?, new_name: message.new_name, push_to_history: false, }) } fn response_to_proto( response: ProjectTransaction, lsp_store: &mut LspStore, peer_id: PeerId, _: &clock::Global, cx: &mut AppContext, ) -> proto::PerformRenameResponse { let transaction = lsp_store.buffer_store().update(cx, |buffer_store, cx| { buffer_store.serialize_project_transaction_for_peer(response, peer_id, cx) }); proto::PerformRenameResponse { transaction: Some(transaction), } } async fn response_from_proto( self, message: proto::PerformRenameResponse, lsp_store: Model<LspStore>, _: Model<Buffer>, cx: AsyncAppContext, ) -> Result<ProjectTransaction> { let message = message .transaction .ok_or_else(|| anyhow!("missing transaction"))?; BufferStore::deserialize_project_transaction( lsp_store.read_with(&cx, |lsp_store, _| lsp_store.buffer_store().downgrade())?, message, self.push_to_history, cx, ) .await } fn buffer_id_from_proto(message: &proto::PerformRename) -> Result<BufferId> { BufferId::new(message.buffer_id) }} #[async_trait(?Send)]impl LspCommand for GetDefinition { type Response = Vec<LocationLink>; type LspRequest = lsp::request::GotoDefinition; type ProtoRequest = proto::GetDefinition; fn check_capabilities(&self, capabilities: AdapterServerCapabilities) -> bool { capabilities .server_capabilities .definition_provider .is_some() } fn to_lsp( &self, path: &Path, _: &Buffer, _: &Arc<LanguageServer>, _: &AppContext, ) -> lsp::GotoDefinitionParams { lsp::GotoDefinitionParams { 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::GotoDefinitionResponse>, lsp_store: Model<LspStore>, buffer: Model<Buffer>, server_id: LanguageServerId, cx: AsyncAppContext, ) -> Result<Vec<LocationLink>> { location_links_from_lsp(message, lsp_store, buffer, server_id, cx).await } fn to_proto(&self, project_id: u64, buffer: &Buffer) -> proto::GetDefinition { proto::GetDefinition { project_id, buffer_id: buffer.remote_id().into(), position: Some(language::proto::serialize_anchor( &buffer.anchor_before(self.position), )), version: serialize_version(&buffer.version()), } } async fn from_proto( message: proto::GetDefinition, _: Model<LspStore>, buffer: Model<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, _| { buffer.wait_for_version(deserialize_version(&message.version)) })? .await?; Ok(Self {Lines 1–500 of 3015. Load more
mod signature_help; use crate::{ buffer_store::BufferStore, lsp_store::LspStore, CodeAction, CoreCompletion, DocumentHighlight, Hover, HoverBlock, HoverBlockKind, InlayHint, InlayHintLabel, InlayHintLabelPart, InlayHintLabelPartTooltip, InlayHintTooltip, Location, LocationLink, MarkupContent, ProjectTransaction, ResolveState, }; use anyhow::{anyhow, Context, Result}; use async_trait::async_trait; use client::proto::{self, PeerId}; use clock::Global; use collections::HashSet; use futures::future; use gpui::{AppContext, AsyncAppContext, Entity, Model}; use language::{ language_settings::{language_settings, InlayHintKind, LanguageSettings}, point_from_lsp, point_to_lsp, proto::{deserialize_anchor, deserialize_version, serialize_anchor, serialize_version}, range_from_lsp, range_to_lsp, Anchor, Bias, Buffer, BufferSnapshot, CachedLspAdapter, CharKind, OffsetRangeExt, PointUtf16, ToOffset, ToPointUtf16, Transaction, Unclipped, }; use lsp::{ AdapterServerCapabilities, CodeActionKind, CodeActionOptions, CompletionContext, CompletionListItemDefaultsEditRange, CompletionTriggerKind, DocumentHighlightKind, LanguageServer, LanguageServerId, LinkedEditingRangeServerCapabilities, OneOf, ServerCapabilities, }; use signature_help::{lsp_to_proto_signature, proto_to_lsp_signature}; use std::{cmp::Reverse, ops::Range, path::Path, sync::Arc}; use text::{BufferId, LineEnding}; pub use signature_help::{ SignatureHelp, SIGNATURE_HELP_HIGHLIGHT_CURRENT, SIGNATURE_HELP_HIGHLIGHT_OVERLOAD, }; pub fn lsp_formatting_options(settings: &LanguageSettings) -> lsp::FormattingOptions { lsp::FormattingOptions { tab_size: settings.tab_size.into(), insert_spaces: !settings.hard_tabs, trim_trailing_whitespace: Some(settings.remove_trailing_whitespace_on_save), trim_final_newlines: Some(settings.ensure_final_newline_on_save), insert_final_newline: Some(settings.ensure_final_newline_on_save), ..lsp::FormattingOptions::default() } } #[async_trait(?Send)] pub trait LspCommand: 'static + Sized + Send { type Response: 'static + Default + Send; type LspRequest: 'static + Send + lsp::request::Request; type ProtoRequest: 'static + Send + proto::RequestMessage; fn check_capabilities(&self, _: AdapterServerCapabilities) -> bool { true } fn status(&self) -> Option<String> { None } fn to_lsp( &self, path: &Path, buffer: &Buffer, language_server: &Arc<LanguageServer>, cx: &AppContext, ) -> <Self::LspRequest as lsp::request::Request>::Params; async fn response_from_lsp( self, message: <Self::LspRequest as lsp::request::Request>::Result, lsp_store: Model<LspStore>, buffer: Model<Buffer>, server_id: LanguageServerId, cx: AsyncAppContext, ) -> Result<Self::Response>; fn to_proto(&self, project_id: u64, buffer: &Buffer) -> Self::ProtoRequest; async fn from_proto( message: Self::ProtoRequest, lsp_store: Model<LspStore>, buffer: Model<Buffer>, cx: AsyncAppContext, ) -> Result<Self>; fn response_to_proto( response: Self::Response, lsp_store: &mut LspStore, peer_id: PeerId, buffer_version: &clock::Global, cx: &mut AppContext, ) -> <Self::ProtoRequest as proto::RequestMessage>::Response; async fn response_from_proto( self, message: <Self::ProtoRequest as proto::RequestMessage>::Response, lsp_store: Model<LspStore>, buffer: Model<Buffer>, cx: AsyncAppContext, ) -> Result<Self::Response>; fn buffer_id_from_proto(message: &Self::ProtoRequest) -> Result<BufferId>; } pub(crate) struct PrepareRename { pub position: PointUtf16, } pub(crate) struct PerformRename { pub position: PointUtf16, pub new_name: String, pub push_to_history: bool, } pub struct GetDefinition { pub position: PointUtf16, } pub(crate) struct GetDeclaration { pub position: PointUtf16, } pub(crate) struct GetTypeDefinition { pub position: PointUtf16, } pub(crate) struct GetImplementation { pub position: PointUtf16, } pub(crate) struct GetReferences { pub position: PointUtf16, } pub(crate) struct GetDocumentHighlights { pub position: PointUtf16, } #[derive(Clone)] pub(crate) struct GetSignatureHelp { pub position: PointUtf16, } #[derive(Clone)] pub(crate) struct GetHover { pub position: PointUtf16, } pub(crate) struct GetCompletions { pub position: PointUtf16, pub context: CompletionContext, } #[derive(Clone)] pub(crate) struct GetCodeActions { pub range: Range<Anchor>, pub kinds: Option<Vec<lsp::CodeActionKind>>, } pub(crate) struct OnTypeFormatting { pub position: PointUtf16, pub trigger: String, pub options: lsp::FormattingOptions, pub push_to_history: bool, } pub(crate) struct InlayHints { pub range: Range<Anchor>, } pub(crate) struct LinkedEditingRange { pub position: Anchor, } #[async_trait(?Send)] impl LspCommand for PrepareRename { type Response = Option<Range<Anchor>>; type LspRequest = lsp::request::PrepareRenameRequest; type ProtoRequest = proto::PrepareRename; fn check_capabilities(&self, capabilities: AdapterServerCapabilities) -> bool { if let Some(lsp::OneOf::Right(rename)) = &capabilities.server_capabilities.rename_provider { rename.prepare_provider == Some(true) } else { false } } fn to_lsp( &self, path: &Path, _: &Buffer, _: &Arc<LanguageServer>, _: &AppContext, ) -> lsp::TextDocumentPositionParams { lsp::TextDocumentPositionParams { text_document: lsp::TextDocumentIdentifier { uri: lsp::Url::from_file_path(path).unwrap(), }, position: point_to_lsp(self.position), } } async fn response_from_lsp( self, message: Option<lsp::PrepareRenameResponse>, _: Model<LspStore>, buffer: Model<Buffer>, _: LanguageServerId, mut cx: AsyncAppContext, ) -> Result<Option<Range<Anchor>>> { buffer.update(&mut cx, |buffer, _| { if let Some( lsp::PrepareRenameResponse::Range(range) | lsp::PrepareRenameResponse::RangeWithPlaceholder { range, .. }, ) = message { let Range { start, end } = range_from_lsp(range); if buffer.clip_point_utf16(start, Bias::Left) == start.0 && buffer.clip_point_utf16(end, Bias::Left) == end.0 { return Ok(Some(buffer.anchor_after(start)..buffer.anchor_before(end))); } } Ok(None) })? } fn to_proto(&self, project_id: u64, buffer: &Buffer) -> proto::PrepareRename { proto::PrepareRename { project_id, buffer_id: buffer.remote_id().into(), position: Some(language::proto::serialize_anchor( &buffer.anchor_before(self.position), )), version: serialize_version(&buffer.version()), } } async fn from_proto( message: proto::PrepareRename, _: Model<LspStore>, buffer: Model<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, _| { buffer.wait_for_version(deserialize_version(&message.version)) })? .await?; Ok(Self { position: buffer.update(&mut cx, |buffer, _| position.to_point_utf16(buffer))?, }) } fn response_to_proto( range: Option<Range<Anchor>>, _: &mut LspStore, _: PeerId, buffer_version: &clock::Global, _: &mut AppContext, ) -> 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)), version: serialize_version(buffer_version), } } async fn response_from_proto( self, message: proto::PrepareRenameResponse, _: Model<LspStore>, buffer: Model<Buffer>, mut cx: AsyncAppContext, ) -> Result<Option<Range<Anchor>>> { if message.can_rename { buffer .update(&mut cx, |buffer, _| { buffer.wait_for_version(deserialize_version(&message.version)) })? .await?; 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) } } fn buffer_id_from_proto(message: &proto::PrepareRename) -> Result<BufferId> { BufferId::new(message.buffer_id) } } #[async_trait(?Send)] impl LspCommand for PerformRename { type Response = ProjectTransaction; type LspRequest = lsp::request::Rename; type ProtoRequest = proto::PerformRename; fn to_lsp( &self, path: &Path, _: &Buffer, _: &Arc<LanguageServer>, _: &AppContext, ) -> lsp::RenameParams { lsp::RenameParams { text_document_position: lsp::TextDocumentPositionParams { text_document: lsp::TextDocumentIdentifier { uri: lsp::Url::from_file_path(path).unwrap(), }, position: point_to_lsp(self.position), }, new_name: self.new_name.clone(), work_done_progress_params: Default::default(), } } async fn response_from_lsp( self, message: Option<lsp::WorkspaceEdit>, lsp_store: Model<LspStore>, buffer: Model<Buffer>, server_id: LanguageServerId, mut cx: AsyncAppContext, ) -> Result<ProjectTransaction> { if let Some(edit) = message { let (lsp_adapter, lsp_server) = language_server_for_buffer(&lsp_store, &buffer, server_id, &mut cx)?; LspStore::deserialize_workspace_edit( lsp_store, edit, self.push_to_history, lsp_adapter, lsp_server, &mut cx, ) .await } else { Ok(ProjectTransaction::default()) } } fn to_proto(&self, project_id: u64, buffer: &Buffer) -> proto::PerformRename { proto::PerformRename { project_id, buffer_id: buffer.remote_id().into(), position: Some(language::proto::serialize_anchor( &buffer.anchor_before(self.position), )), new_name: self.new_name.clone(), version: serialize_version(&buffer.version()), } } async fn from_proto( message: proto::PerformRename, _: Model<LspStore>, buffer: Model<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, _| { buffer.wait_for_version(deserialize_version(&message.version)) })? .await?; Ok(Self { position: buffer.update(&mut cx, |buffer, _| position.to_point_utf16(buffer))?, new_name: message.new_name, push_to_history: false, }) } fn response_to_proto( response: ProjectTransaction, lsp_store: &mut LspStore, peer_id: PeerId, _: &clock::Global, cx: &mut AppContext, ) -> proto::PerformRenameResponse { let transaction = lsp_store.buffer_store().update(cx, |buffer_store, cx| { buffer_store.serialize_project_transaction_for_peer(response, peer_id, cx) }); proto::PerformRenameResponse { transaction: Some(transaction), } } async fn response_from_proto( self, message: proto::PerformRenameResponse, lsp_store: Model<LspStore>, _: Model<Buffer>, cx: AsyncAppContext, ) -> Result<ProjectTransaction> { let message = message .transaction .ok_or_else(|| anyhow!("missing transaction"))?; BufferStore::deserialize_project_transaction( lsp_store.read_with(&cx, |lsp_store, _| lsp_store.buffer_store().downgrade())?, message, self.push_to_history, cx, ) .await } fn buffer_id_from_proto(message: &proto::PerformRename) -> Result<BufferId> { BufferId::new(message.buffer_id) } } #[async_trait(?Send)] impl LspCommand for GetDefinition { type Response = Vec<LocationLink>; type LspRequest = lsp::request::GotoDefinition; type ProtoRequest = proto::GetDefinition; fn check_capabilities(&self, capabilities: AdapterServerCapabilities) -> bool { capabilities .server_capabilities .definition_provider .is_some() } fn to_lsp( &self, path: &Path, _: &Buffer, _: &Arc<LanguageServer>, _: &AppContext, ) -> lsp::GotoDefinitionParams { lsp::GotoDefinitionParams { 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::GotoDefinitionResponse>, lsp_store: Model<LspStore>, buffer: Model<Buffer>, server_id: LanguageServerId, cx: AsyncAppContext, ) -> Result<Vec<LocationLink>> { location_links_from_lsp(message, lsp_store, buffer, server_id, cx).await } fn to_proto(&self, project_id: u64, buffer: &Buffer) -> proto::GetDefinition { proto::GetDefinition { project_id, buffer_id: buffer.remote_id().into(), position: Some(language::proto::serialize_anchor( &buffer.anchor_before(self.position), )), version: serialize_version(&buffer.version()), } } async fn from_proto( message: proto::GetDefinition, _: Model<LspStore>, buffer: Model<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, _| { buffer.wait_for_version(deserialize_version(&message.version)) })? .await?; Ok(Self {