diff --git a/crates/project/src/lsp_command.rs b/crates/project/src/lsp_command.rs index 523011c76a..01aba89aa7 100644 --- a/crates/project/src/lsp_command.rs +++ b/crates/project/src/lsp_command.rs @@ -111,7 +111,7 @@ pub(crate) struct GetCodeActions { pub(crate) struct OnTypeFormatting { pub position: PointUtf16, - pub new_char: char, + pub trigger: String, // TODO kb formatting options? } @@ -1607,18 +1607,18 @@ impl LspCommand for GetCodeActions { impl LspCommand for OnTypeFormatting { type Response = Vec<(Range, String)>; type LspRequest = lsp::request::OnTypeFormatting; - type ProtoRequest = proto::PerformRename; + type ProtoRequest = proto::OnTypeFormatting; 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 - .contains(self.new_char) + .contains(&self.trigger) || on_type_formatting_options .more_trigger_character .iter() .flatten() - .any(|chars| chars.contains(self.new_char)) + .any(|chars| chars.contains(&self.trigger)) } fn to_lsp( @@ -1633,7 +1633,7 @@ impl LspCommand for OnTypeFormatting { lsp::TextDocumentIdentifier::new(lsp::Url::from_file_path(path).unwrap()), point_to_lsp(self.position), ), - ch: self.new_char.to_string(), + ch: self.trigger.clone(), // TODO kb pass current editor ones options: lsp::FormattingOptions::default(), } @@ -1656,44 +1656,92 @@ impl LspCommand for OnTypeFormatting { .context("LSP edits conversion") } - fn to_proto(&self, project_id: u64, buffer: &Buffer) -> proto::PerformRename { - todo!("TODO kb") + 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()), + } } async fn from_proto( - message: proto::PerformRename, + message: proto::OnTypeFormatting, _: ModelHandle, buffer: ModelHandle, mut cx: AsyncAppContext, ) -> Result { - todo!("TODO kb") + 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.read_with(&cx, |buffer, _| position.to_point_utf16(buffer)), + trigger: message.trigger.clone(), + }) } fn response_to_proto( response: Vec<(Range, String)>, - project: &mut Project, - peer_id: PeerId, - _: &clock::Global, - cx: &mut AppContext, - ) -> proto::PerformRenameResponse { - // let transaction = project.serialize_project_transaction_for_peer(response, peer_id, cx); - // proto::PerformRenameResponse { - // transaction: Some(transaction), - // } - todo!("TODO kb") + _: &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), + } } async fn response_from_proto( self, - message: proto::PerformRenameResponse, - project: ModelHandle, - _: ModelHandle, + message: proto::OnTypeFormattingResponse, + _: ModelHandle, + buffer: ModelHandle, mut cx: AsyncAppContext, ) -> Result, String)>> { - todo!("TODO kb") + 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() } - fn buffer_id_from_proto(message: &proto::PerformRename) -> u64 { + fn buffer_id_from_proto(message: &proto::OnTypeFormatting) -> u64 { message.buffer_id } } diff --git a/crates/project/src/project.rs b/crates/project/src/project.rs index d8d29cbadd..1047ca1d52 100644 --- a/crates/project/src/project.rs +++ b/crates/project/src/project.rs @@ -4221,7 +4221,7 @@ impl Project { buffer.clone(), OnTypeFormatting { position, - new_char: input, + trigger: input.to_string(), }, cx, ); diff --git a/crates/rpc/proto/zed.proto b/crates/rpc/proto/zed.proto index eca5fda306..fe0d18f422 100644 --- a/crates/rpc/proto/zed.proto +++ b/crates/rpc/proto/zed.proto @@ -129,6 +129,9 @@ message Envelope { GetPrivateUserInfo get_private_user_info = 105; GetPrivateUserInfoResponse get_private_user_info_response = 106; UpdateDiffBase update_diff_base = 107; + + OnTypeFormatting on_type_formatting = 111; + OnTypeFormattingResponse on_type_formatting_response = 112; } } @@ -670,6 +673,25 @@ message PerformRename { repeated VectorClockEntry version = 5; } +message OnTypeFormatting { + uint64 project_id = 1; + uint64 buffer_id = 2; + Anchor position = 3; + string trigger = 4; + repeated VectorClockEntry version = 5; +} + +message OnTypeFormattingResponse { + repeated OnTypeFormattingResponseEntry entries = 1; + repeated VectorClockEntry version = 2; +} + +message OnTypeFormattingResponseEntry { + Anchor start = 1; + Anchor end = 2; + string new_text = 3; +} + message PerformRenameResponse { ProjectTransaction transaction = 2; } diff --git a/crates/rpc/src/proto.rs b/crates/rpc/src/proto.rs index cef4e6867c..07925a0486 100644 --- a/crates/rpc/src/proto.rs +++ b/crates/rpc/src/proto.rs @@ -195,6 +195,8 @@ messages!( (OpenBufferResponse, Background), (PerformRename, Background), (PerformRenameResponse, Background), + (OnTypeFormatting, Background), + (OnTypeFormattingResponse, Background), (Ping, Foreground), (PrepareRename, Background), (PrepareRenameResponse, Background), @@ -279,6 +281,7 @@ request_messages!( (Ping, Ack), (PerformRename, PerformRenameResponse), (PrepareRename, PrepareRenameResponse), + (OnTypeFormatting, OnTypeFormattingResponse), (ReloadBuffers, ReloadBuffersResponse), (RequestContact, Ack), (RemoveContact, Ack), @@ -323,6 +326,7 @@ entity_messages!( OpenBufferByPath, OpenBufferForSymbol, PerformRename, + OnTypeFormatting, PrepareRename, ReloadBuffers, RemoveProjectCollaborator,