mirror of
https://github.com/zed-industries/zed.git
synced 2024-12-25 01:34:02 +00:00
Move Buffer::format
to Project::format
This commit is contained in:
parent
645df73a37
commit
4929b8c525
10 changed files with 290 additions and 177 deletions
|
@ -572,8 +572,12 @@ impl workspace::ItemView for ProjectDiagnosticsEditor {
|
|||
true
|
||||
}
|
||||
|
||||
fn save(&mut self, cx: &mut ViewContext<Self>) -> Task<Result<()>> {
|
||||
self.editor.save(cx)
|
||||
fn save(
|
||||
&mut self,
|
||||
project: ModelHandle<Project>,
|
||||
cx: &mut ViewContext<Self>,
|
||||
) -> Task<Result<()>> {
|
||||
self.editor.save(project, cx)
|
||||
}
|
||||
|
||||
fn can_save_as(&self, _: &AppContext) -> bool {
|
||||
|
|
|
@ -220,11 +220,15 @@ impl ItemView for Editor {
|
|||
!self.buffer().read(cx).is_singleton() || self.project_path(cx).is_some()
|
||||
}
|
||||
|
||||
fn save(&mut self, cx: &mut ViewContext<Self>) -> Task<Result<()>> {
|
||||
fn save(
|
||||
&mut self,
|
||||
project: ModelHandle<Project>,
|
||||
cx: &mut ViewContext<Self>,
|
||||
) -> Task<Result<()>> {
|
||||
let buffer = self.buffer().clone();
|
||||
cx.spawn(|editor, mut cx| async move {
|
||||
buffer
|
||||
.update(&mut cx, |buffer, cx| buffer.format(cx).log_err())
|
||||
.update(&mut cx, |buffer, cx| buffer.format(project, cx).log_err())
|
||||
.await;
|
||||
editor.update(&mut cx, |editor, cx| {
|
||||
editor.request_autoscroll(Autoscroll::Fit, cx)
|
||||
|
|
|
@ -10,6 +10,7 @@ use language::{
|
|||
Buffer, BufferChunks, BufferSnapshot, Chunk, DiagnosticEntry, Event, File, Language, Outline,
|
||||
OutlineItem, Selection, ToOffset as _, ToPoint as _, ToPointUtf16 as _, TransactionId,
|
||||
};
|
||||
use project::Project;
|
||||
use std::{
|
||||
cell::{Ref, RefCell},
|
||||
cmp, fmt, io,
|
||||
|
@ -930,16 +931,25 @@ impl MultiBuffer {
|
|||
cx.emit(event.clone());
|
||||
}
|
||||
|
||||
pub fn format(&mut self, cx: &mut ModelContext<Self>) -> Task<Result<()>> {
|
||||
let mut format_tasks = Vec::new();
|
||||
for BufferState { buffer, .. } in self.buffers.borrow().values() {
|
||||
format_tasks.push(buffer.update(cx, |buffer, cx| buffer.format(cx)));
|
||||
}
|
||||
|
||||
cx.spawn(|_, _| async move {
|
||||
for format in format_tasks {
|
||||
format.await?;
|
||||
}
|
||||
pub fn format(
|
||||
&mut self,
|
||||
project: ModelHandle<Project>,
|
||||
cx: &mut ModelContext<Self>,
|
||||
) -> Task<Result<()>> {
|
||||
let buffers = self
|
||||
.buffers
|
||||
.borrow()
|
||||
.values()
|
||||
.map(|state| state.buffer.clone())
|
||||
.collect();
|
||||
let transaction = project.update(cx, |project, cx| project.format(buffers, true, cx));
|
||||
cx.spawn(|this, mut cx| async move {
|
||||
let transaction = transaction.await?;
|
||||
this.update(&mut cx, |this, _| {
|
||||
if !this.singleton {
|
||||
this.push_transaction(&transaction.0);
|
||||
}
|
||||
});
|
||||
Ok(())
|
||||
})
|
||||
}
|
||||
|
|
|
@ -201,9 +201,6 @@ pub trait File {
|
|||
cx: &mut MutableAppContext,
|
||||
) -> Task<Result<(clock::Global, SystemTime)>>;
|
||||
|
||||
fn format_remote(&self, buffer_id: u64, cx: &mut MutableAppContext)
|
||||
-> Option<Task<Result<()>>>;
|
||||
|
||||
fn buffer_updated(&self, buffer_id: u64, operation: Operation, cx: &mut MutableAppContext);
|
||||
|
||||
fn buffer_removed(&self, buffer_id: u64, cx: &mut MutableAppContext);
|
||||
|
@ -278,10 +275,6 @@ impl File for FakeFile {
|
|||
cx.spawn(|_| async move { Ok((Default::default(), SystemTime::UNIX_EPOCH)) })
|
||||
}
|
||||
|
||||
fn format_remote(&self, _: u64, _: &mut MutableAppContext) -> Option<Task<Result<()>>> {
|
||||
None
|
||||
}
|
||||
|
||||
fn buffer_updated(&self, _: u64, _: Operation, _: &mut MutableAppContext) {}
|
||||
|
||||
fn buffer_removed(&self, _: u64, _: &mut MutableAppContext) {}
|
||||
|
@ -540,52 +533,6 @@ impl Buffer {
|
|||
self.file.as_deref()
|
||||
}
|
||||
|
||||
pub fn format(&mut self, cx: &mut ModelContext<Self>) -> Task<Result<()>> {
|
||||
let file = if let Some(file) = self.file.as_ref() {
|
||||
file
|
||||
} else {
|
||||
return Task::ready(Err(anyhow!("buffer has no file")));
|
||||
};
|
||||
|
||||
if let Some(LanguageServerState { server, .. }) = self.language_server.as_ref() {
|
||||
let server = server.clone();
|
||||
let abs_path = file.as_local().unwrap().abs_path(cx);
|
||||
let version = self.version();
|
||||
cx.spawn(|this, mut cx| async move {
|
||||
let edits = server
|
||||
.request::<lsp::request::Formatting>(lsp::DocumentFormattingParams {
|
||||
text_document: lsp::TextDocumentIdentifier::new(
|
||||
lsp::Url::from_file_path(&abs_path).unwrap(),
|
||||
),
|
||||
options: Default::default(),
|
||||
work_done_progress_params: Default::default(),
|
||||
})
|
||||
.await?;
|
||||
|
||||
if let Some(edits) = edits {
|
||||
this.update(&mut cx, |this, cx| {
|
||||
if this.version == version {
|
||||
this.apply_lsp_edits(edits, None, cx)?;
|
||||
Ok(())
|
||||
} else {
|
||||
Err(anyhow!("buffer edited since starting to format"))
|
||||
}
|
||||
})
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
})
|
||||
} else {
|
||||
let format = file.format_remote(self.remote_id(), cx.as_mut());
|
||||
cx.spawn(|_, _| async move {
|
||||
if let Some(format) = format {
|
||||
format.await?;
|
||||
}
|
||||
Ok(())
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
pub fn save(
|
||||
&mut self,
|
||||
cx: &mut ModelContext<Self>,
|
||||
|
|
|
@ -348,7 +348,7 @@ impl Project {
|
|||
client.subscribe_to_entity(remote_id, cx, Self::handle_update_buffer),
|
||||
client.subscribe_to_entity(remote_id, cx, Self::handle_save_buffer),
|
||||
client.subscribe_to_entity(remote_id, cx, Self::handle_buffer_saved),
|
||||
client.subscribe_to_entity(remote_id, cx, Self::handle_format_buffer),
|
||||
client.subscribe_to_entity(remote_id, cx, Self::handle_format_buffers),
|
||||
client.subscribe_to_entity(remote_id, cx, Self::handle_get_completions),
|
||||
client.subscribe_to_entity(
|
||||
remote_id,
|
||||
|
@ -613,9 +613,7 @@ impl Project {
|
|||
})
|
||||
.await?;
|
||||
let buffer = response.buffer.ok_or_else(|| anyhow!("missing buffer"))?;
|
||||
this.update(&mut cx, |this, cx| {
|
||||
this.deserialize_remote_buffer(buffer, cx)
|
||||
})
|
||||
this.update(&mut cx, |this, cx| this.deserialize_buffer(buffer, cx))
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -1045,6 +1043,112 @@ impl Project {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
pub fn format(
|
||||
&self,
|
||||
buffers: HashSet<ModelHandle<Buffer>>,
|
||||
push_to_history: bool,
|
||||
cx: &mut ModelContext<Project>,
|
||||
) -> Task<Result<ProjectTransaction>> {
|
||||
let mut local_buffers = Vec::new();
|
||||
let mut remote_buffers = None;
|
||||
for buffer_handle in buffers {
|
||||
let buffer = buffer_handle.read(cx);
|
||||
let worktree;
|
||||
if let Some(file) = File::from_dyn(buffer.file()) {
|
||||
worktree = file.worktree.clone();
|
||||
if let Some(buffer_abs_path) = file.as_local().map(|f| f.abs_path(cx)) {
|
||||
let lang_server;
|
||||
if let Some(lang) = buffer.language() {
|
||||
if let Some(server) = self
|
||||
.language_servers
|
||||
.get(&(worktree.read(cx).id(), lang.name().to_string()))
|
||||
{
|
||||
lang_server = server.clone();
|
||||
} else {
|
||||
return Task::ready(Err(anyhow!(
|
||||
"buffer {} does not have a language server",
|
||||
buffer.remote_id()
|
||||
)));
|
||||
};
|
||||
} else {
|
||||
return Task::ready(Err(anyhow!("buffer does not have a language")));
|
||||
}
|
||||
|
||||
local_buffers.push((buffer_handle, buffer_abs_path, lang_server));
|
||||
} else {
|
||||
remote_buffers.get_or_insert(Vec::new()).push(buffer_handle);
|
||||
}
|
||||
} else {
|
||||
return Task::ready(Err(anyhow!(
|
||||
"buffer {} does not belong to any worktree",
|
||||
buffer.remote_id()
|
||||
)));
|
||||
}
|
||||
}
|
||||
|
||||
let remote_buffers = self.remote_id().zip(remote_buffers);
|
||||
let client = self.client.clone();
|
||||
|
||||
cx.spawn(|this, mut cx| async move {
|
||||
let mut project_transaction = ProjectTransaction::default();
|
||||
|
||||
if let Some((project_id, remote_buffers)) = remote_buffers {
|
||||
let response = client
|
||||
.request(proto::FormatBuffers {
|
||||
project_id,
|
||||
buffer_ids: remote_buffers
|
||||
.iter()
|
||||
.map(|buffer| buffer.read_with(&cx, |buffer, _| buffer.remote_id()))
|
||||
.collect(),
|
||||
})
|
||||
.await?
|
||||
.transaction
|
||||
.ok_or_else(|| anyhow!("missing transaction"))?;
|
||||
project_transaction = this
|
||||
.update(&mut cx, |this, cx| {
|
||||
this.deserialize_project_transaction(response, push_to_history, cx)
|
||||
})
|
||||
.await?;
|
||||
}
|
||||
|
||||
for (buffer, buffer_abs_path, lang_server) in local_buffers {
|
||||
let lsp_edits = lang_server
|
||||
.request::<lsp::request::Formatting>(lsp::DocumentFormattingParams {
|
||||
text_document: lsp::TextDocumentIdentifier::new(
|
||||
lsp::Url::from_file_path(&buffer_abs_path).unwrap(),
|
||||
),
|
||||
options: Default::default(),
|
||||
work_done_progress_params: Default::default(),
|
||||
})
|
||||
.await?;
|
||||
|
||||
if let Some(lsp_edits) = lsp_edits {
|
||||
let edits = buffer
|
||||
.update(&mut cx, |buffer, cx| {
|
||||
buffer.edits_from_lsp(lsp_edits, None, cx)
|
||||
})
|
||||
.await?;
|
||||
buffer.update(&mut cx, |buffer, cx| {
|
||||
buffer.finalize_last_transaction();
|
||||
buffer.start_transaction();
|
||||
for (range, text) in edits {
|
||||
buffer.edit([range], text, cx);
|
||||
}
|
||||
if buffer.end_transaction(cx).is_some() {
|
||||
let transaction = buffer.finalize_last_transaction().unwrap().clone();
|
||||
if !push_to_history {
|
||||
buffer.forget_transaction(transaction.id);
|
||||
}
|
||||
project_transaction.0.insert(cx.handle(), transaction);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
Ok(project_transaction)
|
||||
})
|
||||
}
|
||||
|
||||
pub fn definition<T: ToPointUtf16>(
|
||||
&self,
|
||||
source_buffer_handle: &ModelHandle<Buffer>,
|
||||
|
@ -1156,7 +1260,7 @@ impl Project {
|
|||
this.update(&mut cx, |this, cx| {
|
||||
let mut definitions = Vec::new();
|
||||
for definition in response.definitions {
|
||||
let target_buffer = this.deserialize_remote_buffer(
|
||||
let target_buffer = this.deserialize_buffer(
|
||||
definition.buffer.ok_or_else(|| anyhow!("missing buffer"))?,
|
||||
cx,
|
||||
)?;
|
||||
|
@ -1637,29 +1741,10 @@ impl Project {
|
|||
.await?
|
||||
.transaction
|
||||
.ok_or_else(|| anyhow!("missing transaction"))?;
|
||||
let mut project_transaction = ProjectTransaction::default();
|
||||
for (buffer, transaction) in response.buffers.into_iter().zip(response.transactions)
|
||||
{
|
||||
let buffer = this.update(&mut cx, |this, cx| {
|
||||
this.deserialize_remote_buffer(buffer, cx)
|
||||
})?;
|
||||
let transaction = language::proto::deserialize_transaction(transaction)?;
|
||||
|
||||
buffer
|
||||
.update(&mut cx, |buffer, _| {
|
||||
buffer.wait_for_edits(transaction.edit_ids.iter().copied())
|
||||
})
|
||||
.await;
|
||||
|
||||
if push_to_history {
|
||||
buffer.update(&mut cx, |buffer, _| {
|
||||
buffer.push_transaction(transaction.clone(), Instant::now());
|
||||
});
|
||||
}
|
||||
|
||||
project_transaction.0.insert(buffer, transaction);
|
||||
}
|
||||
Ok(project_transaction)
|
||||
this.update(&mut cx, |this, cx| {
|
||||
this.deserialize_project_transaction(response, push_to_history, cx)
|
||||
})
|
||||
.await
|
||||
})
|
||||
} else {
|
||||
Task::ready(Err(anyhow!("project does not have a remote id")))
|
||||
|
@ -2163,26 +2248,51 @@ impl Project {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
pub fn handle_format_buffer(
|
||||
pub fn handle_format_buffers(
|
||||
&mut self,
|
||||
envelope: TypedEnvelope<proto::FormatBuffer>,
|
||||
envelope: TypedEnvelope<proto::FormatBuffers>,
|
||||
rpc: Arc<Client>,
|
||||
cx: &mut ModelContext<Self>,
|
||||
) -> Result<()> {
|
||||
let receipt = envelope.receipt();
|
||||
let sender_id = envelope.original_sender_id()?;
|
||||
let buffer = self
|
||||
let shared_buffers = self
|
||||
.shared_buffers
|
||||
.get(&sender_id)
|
||||
.and_then(|shared_buffers| shared_buffers.get(&envelope.payload.buffer_id).cloned())
|
||||
.ok_or_else(|| anyhow!("unknown buffer id {}", envelope.payload.buffer_id))?;
|
||||
cx.spawn(|_, mut cx| async move {
|
||||
let format = buffer.update(&mut cx, |buffer, cx| buffer.format(cx)).await;
|
||||
// We spawn here in order to enqueue the sending of `Ack` *after* transmission of edits
|
||||
// associated with formatting.
|
||||
.ok_or_else(|| anyhow!("peer has no buffers"))?;
|
||||
let mut buffers = HashSet::default();
|
||||
for buffer_id in envelope.payload.buffer_ids {
|
||||
buffers.insert(
|
||||
shared_buffers
|
||||
.get(&buffer_id)
|
||||
.cloned()
|
||||
.ok_or_else(|| anyhow!("unknown buffer id {}", buffer_id))?,
|
||||
);
|
||||
}
|
||||
cx.spawn(|this, mut cx| async move {
|
||||
dbg!("here!");
|
||||
let project_transaction = this
|
||||
.update(&mut cx, |this, cx| this.format(buffers, false, cx))
|
||||
.await
|
||||
.map(|project_transaction| {
|
||||
this.update(&mut cx, |this, cx| {
|
||||
this.serialize_project_transaction_for_peer(
|
||||
project_transaction,
|
||||
sender_id,
|
||||
cx,
|
||||
)
|
||||
})
|
||||
});
|
||||
// We spawn here in order to enqueue the sending of the response *after* transmission of
|
||||
// edits associated with formatting.
|
||||
cx.spawn(|_| async move {
|
||||
match format {
|
||||
Ok(()) => rpc.respond(receipt, proto::Ack {})?,
|
||||
match project_transaction {
|
||||
Ok(transaction) => rpc.respond(
|
||||
receipt,
|
||||
proto::FormatBuffersResponse {
|
||||
transaction: Some(transaction),
|
||||
},
|
||||
)?,
|
||||
Err(error) => rpc.respond_with_error(
|
||||
receipt,
|
||||
proto::Error {
|
||||
|
@ -2358,18 +2468,11 @@ impl Project {
|
|||
cx.spawn(|this, mut cx| async move {
|
||||
match apply_code_action.await {
|
||||
Ok(project_transaction) => this.update(&mut cx, |this, cx| {
|
||||
let mut serialized_transaction = proto::ProjectTransaction {
|
||||
buffers: Default::default(),
|
||||
transactions: Default::default(),
|
||||
};
|
||||
for (buffer, transaction) in project_transaction.0 {
|
||||
serialized_transaction
|
||||
.buffers
|
||||
.push(this.serialize_buffer_for_peer(&buffer, sender_id, cx));
|
||||
serialized_transaction
|
||||
.transactions
|
||||
.push(language::proto::serialize_transaction(&transaction));
|
||||
}
|
||||
let serialized_transaction = this.serialize_project_transaction_for_peer(
|
||||
project_transaction,
|
||||
sender_id,
|
||||
cx,
|
||||
);
|
||||
rpc.respond(
|
||||
receipt,
|
||||
proto::ApplyCodeActionResponse {
|
||||
|
@ -2471,6 +2574,58 @@ impl Project {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
fn serialize_project_transaction_for_peer(
|
||||
&mut self,
|
||||
project_transaction: ProjectTransaction,
|
||||
peer_id: PeerId,
|
||||
cx: &AppContext,
|
||||
) -> proto::ProjectTransaction {
|
||||
let mut serialized_transaction = proto::ProjectTransaction {
|
||||
buffers: Default::default(),
|
||||
transactions: Default::default(),
|
||||
};
|
||||
for (buffer, transaction) in project_transaction.0 {
|
||||
serialized_transaction
|
||||
.buffers
|
||||
.push(self.serialize_buffer_for_peer(&buffer, peer_id, cx));
|
||||
serialized_transaction
|
||||
.transactions
|
||||
.push(language::proto::serialize_transaction(&transaction));
|
||||
}
|
||||
serialized_transaction
|
||||
}
|
||||
|
||||
fn deserialize_project_transaction(
|
||||
&self,
|
||||
message: proto::ProjectTransaction,
|
||||
push_to_history: bool,
|
||||
cx: &mut ModelContext<Self>,
|
||||
) -> Task<Result<ProjectTransaction>> {
|
||||
cx.spawn(|this, mut cx| async move {
|
||||
let mut project_transaction = ProjectTransaction::default();
|
||||
for (buffer, transaction) in message.buffers.into_iter().zip(message.transactions) {
|
||||
let buffer =
|
||||
this.update(&mut cx, |this, cx| this.deserialize_buffer(buffer, cx))?;
|
||||
let transaction = language::proto::deserialize_transaction(transaction)?;
|
||||
|
||||
buffer
|
||||
.update(&mut cx, |buffer, _| {
|
||||
buffer.wait_for_edits(transaction.edit_ids.iter().copied())
|
||||
})
|
||||
.await;
|
||||
|
||||
if push_to_history {
|
||||
buffer.update(&mut cx, |buffer, _| {
|
||||
buffer.push_transaction(transaction.clone(), Instant::now());
|
||||
});
|
||||
}
|
||||
|
||||
project_transaction.0.insert(buffer, transaction);
|
||||
}
|
||||
Ok(project_transaction)
|
||||
})
|
||||
}
|
||||
|
||||
fn serialize_buffer_for_peer(
|
||||
&mut self,
|
||||
buffer: &ModelHandle<Buffer>,
|
||||
|
@ -2492,7 +2647,7 @@ impl Project {
|
|||
}
|
||||
}
|
||||
|
||||
fn deserialize_remote_buffer(
|
||||
fn deserialize_buffer(
|
||||
&mut self,
|
||||
buffer: proto::Buffer,
|
||||
cx: &mut ModelContext<Self>,
|
||||
|
|
|
@ -1385,25 +1385,6 @@ impl language::File for File {
|
|||
})
|
||||
}
|
||||
|
||||
fn format_remote(
|
||||
&self,
|
||||
buffer_id: u64,
|
||||
cx: &mut MutableAppContext,
|
||||
) -> Option<Task<Result<()>>> {
|
||||
let worktree = self.worktree.read(cx);
|
||||
let worktree = worktree.as_remote()?;
|
||||
let rpc = worktree.client.clone();
|
||||
let project_id = worktree.project_id;
|
||||
Some(cx.foreground().spawn(async move {
|
||||
rpc.request(proto::FormatBuffer {
|
||||
project_id,
|
||||
buffer_id,
|
||||
})
|
||||
.await?;
|
||||
Ok(())
|
||||
}))
|
||||
}
|
||||
|
||||
fn buffer_updated(&self, buffer_id: u64, operation: Operation, cx: &mut MutableAppContext) {
|
||||
self.worktree.update(cx, |worktree, cx| {
|
||||
worktree.send_buffer_update(buffer_id, operation, cx);
|
||||
|
|
|
@ -39,31 +39,32 @@ message Envelope {
|
|||
SaveBuffer save_buffer = 31;
|
||||
BufferSaved buffer_saved = 32;
|
||||
BufferReloaded buffer_reloaded = 33;
|
||||
FormatBuffer format_buffer = 34;
|
||||
GetCompletions get_completions = 35;
|
||||
GetCompletionsResponse get_completions_response = 36;
|
||||
ApplyCompletionAdditionalEdits apply_completion_additional_edits = 37;
|
||||
ApplyCompletionAdditionalEditsResponse apply_completion_additional_edits_response = 38;
|
||||
GetCodeActions get_code_actions = 39;
|
||||
GetCodeActionsResponse get_code_actions_response = 40;
|
||||
ApplyCodeAction apply_code_action = 41;
|
||||
ApplyCodeActionResponse apply_code_action_response = 42;
|
||||
FormatBuffers format_buffers = 34;
|
||||
FormatBuffersResponse format_buffers_response = 35;
|
||||
GetCompletions get_completions = 36;
|
||||
GetCompletionsResponse get_completions_response = 37;
|
||||
ApplyCompletionAdditionalEdits apply_completion_additional_edits = 38;
|
||||
ApplyCompletionAdditionalEditsResponse apply_completion_additional_edits_response = 39;
|
||||
GetCodeActions get_code_actions = 40;
|
||||
GetCodeActionsResponse get_code_actions_response = 41;
|
||||
ApplyCodeAction apply_code_action = 42;
|
||||
ApplyCodeActionResponse apply_code_action_response = 43;
|
||||
|
||||
GetChannels get_channels = 43;
|
||||
GetChannelsResponse get_channels_response = 44;
|
||||
JoinChannel join_channel = 45;
|
||||
JoinChannelResponse join_channel_response = 46;
|
||||
LeaveChannel leave_channel = 47;
|
||||
SendChannelMessage send_channel_message = 48;
|
||||
SendChannelMessageResponse send_channel_message_response = 49;
|
||||
ChannelMessageSent channel_message_sent = 50;
|
||||
GetChannelMessages get_channel_messages = 51;
|
||||
GetChannelMessagesResponse get_channel_messages_response = 52;
|
||||
GetChannels get_channels = 44;
|
||||
GetChannelsResponse get_channels_response = 45;
|
||||
JoinChannel join_channel = 46;
|
||||
JoinChannelResponse join_channel_response = 47;
|
||||
LeaveChannel leave_channel = 48;
|
||||
SendChannelMessage send_channel_message = 49;
|
||||
SendChannelMessageResponse send_channel_message_response = 50;
|
||||
ChannelMessageSent channel_message_sent = 51;
|
||||
GetChannelMessages get_channel_messages = 52;
|
||||
GetChannelMessagesResponse get_channel_messages_response = 53;
|
||||
|
||||
UpdateContacts update_contacts = 53;
|
||||
UpdateContacts update_contacts = 54;
|
||||
|
||||
GetUsers get_users = 54;
|
||||
GetUsersResponse get_users_response = 55;
|
||||
GetUsers get_users = 55;
|
||||
GetUsersResponse get_users_response = 56;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -206,9 +207,13 @@ message BufferReloaded {
|
|||
Timestamp mtime = 4;
|
||||
}
|
||||
|
||||
message FormatBuffer {
|
||||
message FormatBuffers {
|
||||
uint64 project_id = 1;
|
||||
uint64 buffer_id = 2;
|
||||
repeated uint64 buffer_ids = 2;
|
||||
}
|
||||
|
||||
message FormatBuffersResponse {
|
||||
ProjectTransaction transaction = 1;
|
||||
}
|
||||
|
||||
message GetCompletions {
|
||||
|
|
|
@ -133,7 +133,8 @@ messages!(
|
|||
DiskBasedDiagnosticsUpdated,
|
||||
DiskBasedDiagnosticsUpdating,
|
||||
Error,
|
||||
FormatBuffer,
|
||||
FormatBuffers,
|
||||
FormatBuffersResponse,
|
||||
GetChannelMessages,
|
||||
GetChannelMessagesResponse,
|
||||
GetChannels,
|
||||
|
@ -180,7 +181,7 @@ request_messages!(
|
|||
ApplyCompletionAdditionalEdits,
|
||||
ApplyCompletionAdditionalEditsResponse
|
||||
),
|
||||
(FormatBuffer, Ack),
|
||||
(FormatBuffers, FormatBuffersResponse),
|
||||
(GetChannelMessages, GetChannelMessagesResponse),
|
||||
(GetChannels, GetChannelsResponse),
|
||||
(GetCodeActions, GetCodeActionsResponse),
|
||||
|
@ -210,7 +211,7 @@ entity_messages!(
|
|||
CloseBuffer,
|
||||
DiskBasedDiagnosticsUpdated,
|
||||
DiskBasedDiagnosticsUpdating,
|
||||
FormatBuffer,
|
||||
FormatBuffers,
|
||||
GetCodeActions,
|
||||
GetCompletions,
|
||||
GetDefinition,
|
||||
|
|
|
@ -82,7 +82,7 @@ impl Server {
|
|||
.add_handler(Server::buffer_reloaded)
|
||||
.add_handler(Server::buffer_saved)
|
||||
.add_handler(Server::save_buffer)
|
||||
.add_handler(Server::format_buffer)
|
||||
.add_handler(Server::format_buffers)
|
||||
.add_handler(Server::get_completions)
|
||||
.add_handler(Server::apply_additional_edits_for_completion)
|
||||
.add_handler(Server::get_code_actions)
|
||||
|
@ -669,9 +669,9 @@ impl Server {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
async fn format_buffer(
|
||||
async fn format_buffers(
|
||||
self: Arc<Server>,
|
||||
request: TypedEnvelope<proto::FormatBuffer>,
|
||||
request: TypedEnvelope<proto::FormatBuffers>,
|
||||
) -> tide::Result<()> {
|
||||
let host;
|
||||
{
|
||||
|
@ -2607,7 +2607,9 @@ mod tests {
|
|||
.await
|
||||
.unwrap();
|
||||
|
||||
let format = buffer_b.update(&mut cx_b, |buffer, cx| buffer.format(cx));
|
||||
let format = project_b.update(&mut cx_b, |project, cx| {
|
||||
project.format(HashSet::from_iter([buffer_b.clone()]), true, cx)
|
||||
});
|
||||
let (request_id, _) = fake_language_server
|
||||
.receive_request::<lsp::request::Formatting>()
|
||||
.await;
|
||||
|
|
|
@ -168,7 +168,11 @@ pub trait ItemView: View {
|
|||
false
|
||||
}
|
||||
fn can_save(&self, cx: &AppContext) -> bool;
|
||||
fn save(&mut self, cx: &mut ViewContext<Self>) -> Task<Result<()>>;
|
||||
fn save(
|
||||
&mut self,
|
||||
project: ModelHandle<Project>,
|
||||
cx: &mut ViewContext<Self>,
|
||||
) -> Task<Result<()>>;
|
||||
fn can_save_as(&self, cx: &AppContext) -> bool;
|
||||
fn save_as(
|
||||
&mut self,
|
||||
|
@ -234,7 +238,7 @@ pub trait ItemViewHandle: 'static {
|
|||
fn has_conflict(&self, cx: &AppContext) -> bool;
|
||||
fn can_save(&self, cx: &AppContext) -> bool;
|
||||
fn can_save_as(&self, cx: &AppContext) -> bool;
|
||||
fn save(&self, cx: &mut MutableAppContext) -> Task<Result<()>>;
|
||||
fn save(&self, project: ModelHandle<Project>, cx: &mut MutableAppContext) -> Task<Result<()>>;
|
||||
fn save_as(
|
||||
&self,
|
||||
project: ModelHandle<Project>,
|
||||
|
@ -402,8 +406,8 @@ impl<T: ItemView> ItemViewHandle for ViewHandle<T> {
|
|||
self.update(cx, |this, cx| this.navigate(data, cx));
|
||||
}
|
||||
|
||||
fn save(&self, cx: &mut MutableAppContext) -> Task<Result<()>> {
|
||||
self.update(cx, |item, cx| item.save(cx))
|
||||
fn save(&self, project: ModelHandle<Project>, cx: &mut MutableAppContext) -> Task<Result<()>> {
|
||||
self.update(cx, |item, cx| item.save(project, cx))
|
||||
}
|
||||
|
||||
fn save_as(
|
||||
|
@ -820,6 +824,7 @@ impl Workspace {
|
|||
}
|
||||
|
||||
pub fn save_active_item(&mut self, cx: &mut ViewContext<Self>) -> Task<Result<()>> {
|
||||
let project = self.project.clone();
|
||||
if let Some(item) = self.active_item(cx) {
|
||||
if item.can_save(cx) {
|
||||
if item.has_conflict(cx.as_ref()) {
|
||||
|
@ -833,12 +838,12 @@ impl Workspace {
|
|||
cx.spawn(|_, mut cx| async move {
|
||||
let answer = answer.recv().await;
|
||||
if answer == Some(0) {
|
||||
cx.update(|cx| item.save(cx)).await?;
|
||||
cx.update(|cx| item.save(project, cx)).await?;
|
||||
}
|
||||
Ok(())
|
||||
})
|
||||
} else {
|
||||
item.save(cx)
|
||||
item.save(project, cx)
|
||||
}
|
||||
} else if item.can_save_as(cx) {
|
||||
let worktree = self.worktrees(cx).next();
|
||||
|
@ -847,9 +852,8 @@ impl Workspace {
|
|||
.map_or(Path::new(""), |w| w.abs_path())
|
||||
.to_path_buf();
|
||||
let mut abs_path = cx.prompt_for_new_path(&start_abs_path);
|
||||
cx.spawn(|this, mut cx| async move {
|
||||
cx.spawn(|_, mut cx| async move {
|
||||
if let Some(abs_path) = abs_path.recv().await.flatten() {
|
||||
let project = this.read_with(&cx, |this, _| this.project().clone());
|
||||
cx.update(|cx| item.save_as(project, abs_path, cx)).await?;
|
||||
}
|
||||
Ok(())
|
||||
|
|
Loading…
Reference in a new issue