Ensure client always responds when receiving a request

This commit is contained in:
Antonio Scandurra 2022-02-13 12:21:35 +01:00
parent a41eb5a663
commit a19735c05f
4 changed files with 519 additions and 557 deletions

View file

@ -398,29 +398,23 @@ impl Channel {
cursor cursor
} }
fn handle_message_sent( async fn handle_message_sent(
&mut self, this: ModelHandle<Self>,
message: TypedEnvelope<proto::ChannelMessageSent>, message: TypedEnvelope<proto::ChannelMessageSent>,
_: Arc<Client>, _: Arc<Client>,
cx: &mut ModelContext<Self>, mut cx: AsyncAppContext,
) -> Result<()> { ) -> Result<()> {
let user_store = self.user_store.clone(); let user_store = this.read_with(&cx, |this, _| this.user_store.clone());
let message = message let message = message
.payload .payload
.message .message
.ok_or_else(|| anyhow!("empty message"))?; .ok_or_else(|| anyhow!("empty message"))?;
cx.spawn(|this, mut cx| {
async move {
let message = ChannelMessage::from_proto(message, &user_store, &mut cx).await?; let message = ChannelMessage::from_proto(message, &user_store, &mut cx).await?;
this.update(&mut cx, |this, cx| { this.update(&mut cx, |this, cx| {
this.insert_messages(SumTree::from_item(message, &()), cx) this.insert_messages(SumTree::from_item(message, &()), cx)
}); });
Ok(())
}
.log_err()
})
.detach();
Ok(()) Ok(())
} }

View file

@ -11,8 +11,8 @@ use async_tungstenite::tungstenite::{
error::Error as WebsocketError, error::Error as WebsocketError,
http::{Request, StatusCode}, http::{Request, StatusCode},
}; };
use futures::StreamExt; use futures::{future::LocalBoxFuture, FutureExt, StreamExt};
use gpui::{action, AsyncAppContext, Entity, ModelContext, MutableAppContext, Task}; use gpui::{action, AsyncAppContext, Entity, ModelContext, ModelHandle, MutableAppContext, Task};
use http::HttpClient; use http::HttpClient;
use lazy_static::lazy_static; use lazy_static::lazy_static;
use parking_lot::RwLock; use parking_lot::RwLock;
@ -20,10 +20,11 @@ use postage::watch;
use rand::prelude::*; use rand::prelude::*;
use rpc::proto::{AnyTypedEnvelope, EntityMessage, EnvelopedMessage, RequestMessage}; use rpc::proto::{AnyTypedEnvelope, EntityMessage, EnvelopedMessage, RequestMessage};
use std::{ use std::{
any::TypeId, any::{type_name, TypeId},
collections::HashMap, collections::HashMap,
convert::TryFrom, convert::TryFrom,
fmt::Write as _, fmt::Write as _,
future::Future,
sync::{ sync::{
atomic::{AtomicUsize, Ordering}, atomic::{AtomicUsize, Ordering},
Arc, Weak, Arc, Weak,
@ -123,14 +124,17 @@ pub enum Status {
ReconnectionError { next_reconnection: Instant }, ReconnectionError { next_reconnection: Instant },
} }
type ModelHandler = Box<
dyn Send
+ Sync
+ FnMut(Box<dyn AnyTypedEnvelope>, &AsyncAppContext) -> LocalBoxFuture<'static, Result<()>>,
>;
struct ClientState { struct ClientState {
credentials: Option<Credentials>, credentials: Option<Credentials>,
status: (watch::Sender<Status>, watch::Receiver<Status>), status: (watch::Sender<Status>, watch::Receiver<Status>),
entity_id_extractors: HashMap<TypeId, Box<dyn Send + Sync + Fn(&dyn AnyTypedEnvelope) -> u64>>, entity_id_extractors: HashMap<TypeId, Box<dyn Send + Sync + Fn(&dyn AnyTypedEnvelope) -> u64>>,
model_handlers: HashMap< model_handlers: HashMap<(TypeId, Option<u64>), Option<ModelHandler>>,
(TypeId, Option<u64>),
Option<Box<dyn Send + Sync + FnMut(Box<dyn AnyTypedEnvelope>, &mut AsyncAppContext)>>,
>,
_maintain_connection: Option<Task<()>>, _maintain_connection: Option<Task<()>>,
heartbeat_interval: Duration, heartbeat_interval: Duration,
} }
@ -262,7 +266,7 @@ impl Client {
} }
} }
pub fn subscribe<T, M, F>( pub fn subscribe<T, M, F, Fut>(
self: &Arc<Self>, self: &Arc<Self>,
cx: &mut ModelContext<M>, cx: &mut ModelContext<M>,
mut handler: F, mut handler: F,
@ -273,7 +277,8 @@ impl Client {
F: 'static F: 'static
+ Send + Send
+ Sync + Sync
+ FnMut(&mut M, TypedEnvelope<T>, Arc<Self>, &mut ModelContext<M>) -> Result<()>, + FnMut(ModelHandle<M>, TypedEnvelope<T>, Arc<Self>, AsyncAppContext) -> Fut,
Fut: 'static + Future<Output = Result<()>>,
{ {
let subscription_id = (TypeId::of::<T>(), None); let subscription_id = (TypeId::of::<T>(), None);
let client = self.clone(); let client = self.clone();
@ -284,11 +289,15 @@ impl Client {
Some(Box::new(move |envelope, cx| { Some(Box::new(move |envelope, cx| {
if let Some(model) = model.upgrade(cx) { if let Some(model) = model.upgrade(cx) {
let envelope = envelope.into_any().downcast::<TypedEnvelope<T>>().unwrap(); let envelope = envelope.into_any().downcast::<TypedEnvelope<T>>().unwrap();
model.update(cx, |model, cx| { handler(model, *envelope, client.clone(), cx.clone()).boxed_local()
if let Err(error) = handler(model, *envelope, client.clone(), cx) { } else {
log::error!("error handling message: {}", error) async move {
Err(anyhow!(
"received message for {:?} but model was dropped",
type_name::<M>()
))
} }
}); .boxed_local()
} }
})), })),
); );
@ -302,7 +311,7 @@ impl Client {
} }
} }
pub fn subscribe_to_entity<T, M, F>( pub fn subscribe_to_entity<T, M, F, Fut>(
self: &Arc<Self>, self: &Arc<Self>,
remote_id: u64, remote_id: u64,
cx: &mut ModelContext<M>, cx: &mut ModelContext<M>,
@ -314,7 +323,8 @@ impl Client {
F: 'static F: 'static
+ Send + Send
+ Sync + Sync
+ FnMut(&mut M, TypedEnvelope<T>, Arc<Self>, &mut ModelContext<M>) -> Result<()>, + FnMut(ModelHandle<M>, TypedEnvelope<T>, Arc<Self>, AsyncAppContext) -> Fut,
Fut: 'static + Future<Output = Result<()>>,
{ {
let subscription_id = (TypeId::of::<T>(), Some(remote_id)); let subscription_id = (TypeId::of::<T>(), Some(remote_id));
let client = self.clone(); let client = self.clone();
@ -337,11 +347,15 @@ impl Client {
Some(Box::new(move |envelope, cx| { Some(Box::new(move |envelope, cx| {
if let Some(model) = model.upgrade(cx) { if let Some(model) = model.upgrade(cx) {
let envelope = envelope.into_any().downcast::<TypedEnvelope<T>>().unwrap(); let envelope = envelope.into_any().downcast::<TypedEnvelope<T>>().unwrap();
model.update(cx, |model, cx| { handler(model, *envelope, client.clone(), cx.clone()).boxed_local()
if let Err(error) = handler(model, *envelope, client.clone(), cx) { } else {
log::error!("error handling message: {}", error) async move {
Err(anyhow!(
"received message for {:?} but model was dropped",
type_name::<M>()
))
} }
}); .boxed_local()
} }
})), })),
); );
@ -355,6 +369,44 @@ impl Client {
} }
} }
pub fn subscribe_to_entity_request<T, M, F, Fut>(
self: &Arc<Self>,
remote_id: u64,
cx: &mut ModelContext<M>,
mut handler: F,
) -> Subscription
where
T: EntityMessage + RequestMessage,
M: Entity,
F: 'static
+ Send
+ Sync
+ FnMut(ModelHandle<M>, TypedEnvelope<T>, Arc<Self>, AsyncAppContext) -> Fut,
Fut: 'static + Future<Output = Result<T::Response>>,
{
self.subscribe_to_entity(remote_id, cx, move |model, envelope, client, cx| {
let receipt = envelope.receipt();
let response = handler(model, envelope, client.clone(), cx);
async move {
match response.await {
Ok(response) => {
client.respond(receipt, response)?;
Ok(())
}
Err(error) => {
client.respond_with_error(
receipt,
proto::Error {
message: error.to_string(),
},
)?;
Err(error)
}
}
}
})
}
pub fn has_keychain_credentials(&self, cx: &AsyncAppContext) -> bool { pub fn has_keychain_credentials(&self, cx: &AsyncAppContext) -> bool {
read_credentials_from_keychain(cx).is_some() read_credentials_from_keychain(cx).is_some()
} }
@ -442,7 +494,7 @@ impl Client {
let (connection_id, handle_io, mut incoming) = self.peer.add_connection(conn).await; let (connection_id, handle_io, mut incoming) = self.peer.add_connection(conn).await;
cx.foreground() cx.foreground()
.spawn({ .spawn({
let mut cx = cx.clone(); let cx = cx.clone();
let this = self.clone(); let this = self.clone();
async move { async move {
while let Some(message) = incoming.next().await { while let Some(message) = incoming.next().await {
@ -468,12 +520,28 @@ impl Client {
this.id, this.id,
type_name type_name
); );
(handler)(message, &mut cx);
let future = (handler)(message, &cx);
let client_id = this.id;
cx.foreground()
.spawn(async move {
match future.await {
Ok(()) => {
log::debug!( log::debug!(
"rpc message handled. client_id:{}, name:{}", "rpc message handled. client_id:{}, name:{}",
this.id, client_id,
type_name type_name
); );
}
Err(error) => {
log::error!(
"error handling rpc message. client_id:{}, name:{}, error: {}",
client_id, type_name, error
);
}
}
})
.detach();
let mut state = this.state.write(); let mut state = this.state.write();
if state.model_handlers.contains_key(&handler_key) { if state.model_handlers.contains_key(&handler_key) {
@ -715,16 +783,12 @@ impl Client {
response response
} }
pub fn respond<T: RequestMessage>( fn respond<T: RequestMessage>(&self, receipt: Receipt<T>, response: T::Response) -> Result<()> {
&self,
receipt: Receipt<T>,
response: T::Response,
) -> Result<()> {
log::debug!("rpc respond. client_id: {}. name:{}", self.id, T::NAME); log::debug!("rpc respond. client_id: {}. name:{}", self.id, T::NAME);
self.peer.respond(receipt, response) self.peer.respond(receipt, response)
} }
pub fn respond_with_error<T: RequestMessage>( fn respond_with_error<T: RequestMessage>(
&self, &self,
receipt: Receipt<T>, receipt: Receipt<T>,
error: proto::Error, error: proto::Error,
@ -866,7 +930,7 @@ mod tests {
cx, cx,
move |_, _: TypedEnvelope<proto::UnshareProject>, _, _| { move |_, _: TypedEnvelope<proto::UnshareProject>, _, _| {
postage::sink::Sink::try_send(&mut done_tx1, ()).unwrap(); postage::sink::Sink::try_send(&mut done_tx1, ()).unwrap();
Ok(()) async { Ok(()) }
}, },
) )
}); });
@ -876,7 +940,7 @@ mod tests {
cx, cx,
move |_, _: TypedEnvelope<proto::UnshareProject>, _, _| { move |_, _: TypedEnvelope<proto::UnshareProject>, _, _| {
postage::sink::Sink::try_send(&mut done_tx2, ()).unwrap(); postage::sink::Sink::try_send(&mut done_tx2, ()).unwrap();
Ok(()) async { Ok(()) }
}, },
) )
}); });
@ -887,7 +951,7 @@ mod tests {
client.subscribe_to_entity( client.subscribe_to_entity(
3, 3,
cx, cx,
move |_, _: TypedEnvelope<proto::UnshareProject>, _, _| Ok(()), |_, _: TypedEnvelope<proto::UnshareProject>, _, _| async { Ok(()) },
) )
}); });
drop(subscription3); drop(subscription3);
@ -912,14 +976,14 @@ mod tests {
let subscription1 = model.update(&mut cx, |_, cx| { let subscription1 = model.update(&mut cx, |_, cx| {
client.subscribe(cx, move |_, _: TypedEnvelope<proto::Ping>, _, _| { client.subscribe(cx, move |_, _: TypedEnvelope<proto::Ping>, _, _| {
postage::sink::Sink::try_send(&mut done_tx1, ()).unwrap(); postage::sink::Sink::try_send(&mut done_tx1, ()).unwrap();
Ok(()) async { Ok(()) }
}) })
}); });
drop(subscription1); drop(subscription1);
let _subscription2 = model.update(&mut cx, |_, cx| { let _subscription2 = model.update(&mut cx, |_, cx| {
client.subscribe(cx, move |_, _: TypedEnvelope<proto::Ping>, _, _| { client.subscribe(cx, move |_, _: TypedEnvelope<proto::Ping>, _, _| {
postage::sink::Sink::try_send(&mut done_tx2, ()).unwrap(); postage::sink::Sink::try_send(&mut done_tx2, ()).unwrap();
Ok(()) async { Ok(()) }
}) })
}); });
server.send(proto::Ping {}); server.send(proto::Ping {});
@ -939,10 +1003,10 @@ mod tests {
model.update(&mut cx, |model, cx| { model.update(&mut cx, |model, cx| {
model.subscription = Some(client.subscribe( model.subscription = Some(client.subscribe(
cx, cx,
move |model, _: TypedEnvelope<proto::Ping>, _, _| { move |model, _: TypedEnvelope<proto::Ping>, _, mut cx| {
model.subscription.take(); model.update(&mut cx, |model, _| model.subscription.take());
postage::sink::Sink::try_send(&mut done_tx, ()).unwrap(); postage::sink::Sink::try_send(&mut done_tx, ()).unwrap();
Ok(()) async { Ok(()) }
}, },
)); ));
}); });

View file

@ -60,9 +60,9 @@ impl UserStore {
watch::channel::<Option<proto::UpdateContacts>>(); watch::channel::<Option<proto::UpdateContacts>>();
let update_contacts_subscription = client.subscribe( let update_contacts_subscription = client.subscribe(
cx, cx,
move |_: &mut Self, msg: TypedEnvelope<proto::UpdateContacts>, _, _| { move |_: ModelHandle<Self>, msg: TypedEnvelope<proto::UpdateContacts>, _, _| {
let _ = update_contacts_tx.blocking_send(Some(msg.payload)); *update_contacts_tx.borrow_mut() = Some(msg.payload);
Ok(()) async move { Ok(()) }
}, },
); );
Self { Self {

View file

@ -340,24 +340,24 @@ impl Project {
if let Some(remote_id) = remote_id { if let Some(remote_id) = remote_id {
let client = &self.client; let client = &self.client;
self.subscriptions.extend([ self.subscriptions.extend([
client.subscribe_to_entity(remote_id, cx, Self::handle_open_buffer), client.subscribe_to_entity_request(remote_id, cx, Self::handle_open_buffer),
client.subscribe_to_entity(remote_id, cx, Self::handle_close_buffer), client.subscribe_to_entity(remote_id, cx, Self::handle_close_buffer),
client.subscribe_to_entity(remote_id, cx, Self::handle_add_collaborator), client.subscribe_to_entity(remote_id, cx, Self::handle_add_collaborator),
client.subscribe_to_entity(remote_id, cx, Self::handle_remove_collaborator), client.subscribe_to_entity(remote_id, cx, Self::handle_remove_collaborator),
client.subscribe_to_entity(remote_id, cx, Self::handle_update_worktree), client.subscribe_to_entity(remote_id, cx, Self::handle_update_worktree),
client.subscribe_to_entity(remote_id, cx, Self::handle_update_buffer), 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_request(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_buffer_saved),
client.subscribe_to_entity(remote_id, cx, Self::handle_format_buffers), client.subscribe_to_entity_request(remote_id, cx, Self::handle_format_buffers),
client.subscribe_to_entity(remote_id, cx, Self::handle_get_completions), client.subscribe_to_entity_request(remote_id, cx, Self::handle_get_completions),
client.subscribe_to_entity( client.subscribe_to_entity_request(
remote_id, remote_id,
cx, cx,
Self::handle_apply_additional_edits_for_completion, Self::handle_apply_additional_edits_for_completion,
), ),
client.subscribe_to_entity(remote_id, cx, Self::handle_get_code_actions), client.subscribe_to_entity_request(remote_id, cx, Self::handle_get_code_actions),
client.subscribe_to_entity(remote_id, cx, Self::handle_apply_code_action), client.subscribe_to_entity_request(remote_id, cx, Self::handle_apply_code_action),
client.subscribe_to_entity(remote_id, cx, Self::handle_get_definition), client.subscribe_to_entity_request(remote_id, cx, Self::handle_get_definition),
]); ]);
} }
} }
@ -1996,132 +1996,137 @@ impl Project {
// RPC message handlers // RPC message handlers
fn handle_unshare_project( async fn handle_unshare_project(
&mut self, this: ModelHandle<Self>,
_: TypedEnvelope<proto::UnshareProject>, _: TypedEnvelope<proto::UnshareProject>,
_: Arc<Client>, _: Arc<Client>,
cx: &mut ModelContext<Self>, mut cx: AsyncAppContext,
) -> Result<()> { ) -> Result<()> {
this.update(&mut cx, |this, cx| {
if let ProjectClientState::Remote { if let ProjectClientState::Remote {
sharing_has_stopped, sharing_has_stopped,
.. ..
} = &mut self.client_state } = &mut this.client_state
{ {
*sharing_has_stopped = true; *sharing_has_stopped = true;
self.collaborators.clear(); this.collaborators.clear();
cx.notify(); cx.notify();
Ok(())
} else { } else {
unreachable!() unreachable!()
} }
});
Ok(())
} }
fn handle_add_collaborator( async fn handle_add_collaborator(
&mut self, this: ModelHandle<Self>,
mut envelope: TypedEnvelope<proto::AddProjectCollaborator>, mut envelope: TypedEnvelope<proto::AddProjectCollaborator>,
_: Arc<Client>, _: Arc<Client>,
cx: &mut ModelContext<Self>, mut cx: AsyncAppContext,
) -> Result<()> { ) -> Result<()> {
let user_store = self.user_store.clone(); let user_store = this.read_with(&cx, |this, _| this.user_store.clone());
let collaborator = envelope let collaborator = envelope
.payload .payload
.collaborator .collaborator
.take() .take()
.ok_or_else(|| anyhow!("empty collaborator"))?; .ok_or_else(|| anyhow!("empty collaborator"))?;
cx.spawn(|this, mut cx| { let collaborator = Collaborator::from_proto(collaborator, &user_store, &mut cx).await?;
async move {
let collaborator =
Collaborator::from_proto(collaborator, &user_store, &mut cx).await?;
this.update(&mut cx, |this, cx| { this.update(&mut cx, |this, cx| {
this.collaborators this.collaborators
.insert(collaborator.peer_id, collaborator); .insert(collaborator.peer_id, collaborator);
cx.notify(); cx.notify();
}); });
Ok(())
}
.log_err()
})
.detach();
Ok(()) Ok(())
} }
fn handle_remove_collaborator( async fn handle_remove_collaborator(
&mut self, this: ModelHandle<Self>,
envelope: TypedEnvelope<proto::RemoveProjectCollaborator>, envelope: TypedEnvelope<proto::RemoveProjectCollaborator>,
_: Arc<Client>, _: Arc<Client>,
cx: &mut ModelContext<Self>, mut cx: AsyncAppContext,
) -> Result<()> { ) -> Result<()> {
this.update(&mut cx, |this, cx| {
let peer_id = PeerId(envelope.payload.peer_id); let peer_id = PeerId(envelope.payload.peer_id);
let replica_id = self let replica_id = this
.collaborators .collaborators
.remove(&peer_id) .remove(&peer_id)
.ok_or_else(|| anyhow!("unknown peer {:?}", peer_id))? .ok_or_else(|| anyhow!("unknown peer {:?}", peer_id))?
.replica_id; .replica_id;
self.shared_buffers.remove(&peer_id); this.shared_buffers.remove(&peer_id);
for (_, buffer) in &self.open_buffers { for (_, buffer) in &this.open_buffers {
if let Some(buffer) = buffer.upgrade(cx) { if let Some(buffer) = buffer.upgrade(cx) {
buffer.update(cx, |buffer, cx| buffer.remove_peer(replica_id, cx)); buffer.update(cx, |buffer, cx| buffer.remove_peer(replica_id, cx));
} }
} }
cx.notify(); cx.notify();
Ok(()) Ok(())
})
} }
fn handle_share_worktree( async fn handle_share_worktree(
&mut self, this: ModelHandle<Self>,
envelope: TypedEnvelope<proto::ShareWorktree>, envelope: TypedEnvelope<proto::ShareWorktree>,
client: Arc<Client>, client: Arc<Client>,
cx: &mut ModelContext<Self>, mut cx: AsyncAppContext,
) -> Result<()> { ) -> Result<()> {
let remote_id = self.remote_id().ok_or_else(|| anyhow!("invalid project"))?; this.update(&mut cx, |this, cx| {
let replica_id = self.replica_id(); let remote_id = this.remote_id().ok_or_else(|| anyhow!("invalid project"))?;
let replica_id = this.replica_id();
let worktree = envelope let worktree = envelope
.payload .payload
.worktree .worktree
.ok_or_else(|| anyhow!("invalid worktree"))?; .ok_or_else(|| anyhow!("invalid worktree"))?;
let (worktree, load_task) = Worktree::remote(remote_id, replica_id, worktree, client, cx); let (worktree, load_task) =
self.add_worktree(&worktree, cx); Worktree::remote(remote_id, replica_id, worktree, client, cx);
this.add_worktree(&worktree, cx);
load_task.detach(); load_task.detach();
Ok(()) Ok(())
})
} }
fn handle_unregister_worktree( async fn handle_unregister_worktree(
&mut self, this: ModelHandle<Self>,
envelope: TypedEnvelope<proto::UnregisterWorktree>, envelope: TypedEnvelope<proto::UnregisterWorktree>,
_: Arc<Client>, _: Arc<Client>,
cx: &mut ModelContext<Self>, mut cx: AsyncAppContext,
) -> Result<()> { ) -> Result<()> {
this.update(&mut cx, |this, cx| {
let worktree_id = WorktreeId::from_proto(envelope.payload.worktree_id); let worktree_id = WorktreeId::from_proto(envelope.payload.worktree_id);
self.remove_worktree(worktree_id, cx); this.remove_worktree(worktree_id, cx);
Ok(()) Ok(())
})
} }
fn handle_update_worktree( async fn handle_update_worktree(
&mut self, this: ModelHandle<Self>,
envelope: TypedEnvelope<proto::UpdateWorktree>, envelope: TypedEnvelope<proto::UpdateWorktree>,
_: Arc<Client>, _: Arc<Client>,
cx: &mut ModelContext<Self>, mut cx: AsyncAppContext,
) -> Result<()> { ) -> Result<()> {
this.update(&mut cx, |this, cx| {
let worktree_id = WorktreeId::from_proto(envelope.payload.worktree_id); let worktree_id = WorktreeId::from_proto(envelope.payload.worktree_id);
if let Some(worktree) = self.worktree_for_id(worktree_id, cx) { if let Some(worktree) = this.worktree_for_id(worktree_id, cx) {
worktree.update(cx, |worktree, cx| { worktree.update(cx, |worktree, cx| {
let worktree = worktree.as_remote_mut().unwrap(); let worktree = worktree.as_remote_mut().unwrap();
worktree.update_from_remote(envelope, cx) worktree.update_from_remote(envelope, cx)
})?; })?;
} }
Ok(()) Ok(())
})
} }
fn handle_update_diagnostic_summary( async fn handle_update_diagnostic_summary(
&mut self, this: ModelHandle<Self>,
envelope: TypedEnvelope<proto::UpdateDiagnosticSummary>, envelope: TypedEnvelope<proto::UpdateDiagnosticSummary>,
_: Arc<Client>, _: Arc<Client>,
cx: &mut ModelContext<Self>, mut cx: AsyncAppContext,
) -> Result<()> { ) -> Result<()> {
this.update(&mut cx, |this, cx| {
let worktree_id = WorktreeId::from_proto(envelope.payload.worktree_id); let worktree_id = WorktreeId::from_proto(envelope.payload.worktree_id);
if let Some(worktree) = self.worktree_for_id(worktree_id, cx) { if let Some(worktree) = this.worktree_for_id(worktree_id, cx) {
if let Some(summary) = envelope.payload.summary { if let Some(summary) = envelope.payload.summary {
let project_path = ProjectPath { let project_path = ProjectPath {
worktree_id, worktree_id,
@ -2137,34 +2142,36 @@ impl Project {
} }
} }
Ok(()) Ok(())
})
} }
fn handle_disk_based_diagnostics_updating( async fn handle_disk_based_diagnostics_updating(
&mut self, this: ModelHandle<Self>,
_: TypedEnvelope<proto::DiskBasedDiagnosticsUpdating>, _: TypedEnvelope<proto::DiskBasedDiagnosticsUpdating>,
_: Arc<Client>, _: Arc<Client>,
cx: &mut ModelContext<Self>, mut cx: AsyncAppContext,
) -> Result<()> { ) -> Result<()> {
self.disk_based_diagnostics_started(cx); this.update(&mut cx, |this, cx| this.disk_based_diagnostics_started(cx));
Ok(()) Ok(())
} }
fn handle_disk_based_diagnostics_updated( async fn handle_disk_based_diagnostics_updated(
&mut self, this: ModelHandle<Self>,
_: TypedEnvelope<proto::DiskBasedDiagnosticsUpdated>, _: TypedEnvelope<proto::DiskBasedDiagnosticsUpdated>,
_: Arc<Client>, _: Arc<Client>,
cx: &mut ModelContext<Self>, mut cx: AsyncAppContext,
) -> Result<()> { ) -> Result<()> {
self.disk_based_diagnostics_finished(cx); this.update(&mut cx, |this, cx| this.disk_based_diagnostics_finished(cx));
Ok(()) Ok(())
} }
pub fn handle_update_buffer( async fn handle_update_buffer(
&mut self, this: ModelHandle<Self>,
envelope: TypedEnvelope<proto::UpdateBuffer>, envelope: TypedEnvelope<proto::UpdateBuffer>,
_: Arc<Client>, _: Arc<Client>,
cx: &mut ModelContext<Self>, mut cx: AsyncAppContext,
) -> Result<()> { ) -> Result<()> {
this.update(&mut cx, |this, cx| {
let payload = envelope.payload.clone(); let payload = envelope.payload.clone();
let buffer_id = payload.buffer_id as usize; let buffer_id = payload.buffer_id as usize;
let ops = payload let ops = payload
@ -2172,28 +2179,30 @@ impl Project {
.into_iter() .into_iter()
.map(|op| language::proto::deserialize_operation(op)) .map(|op| language::proto::deserialize_operation(op))
.collect::<Result<Vec<_>, _>>()?; .collect::<Result<Vec<_>, _>>()?;
if let Some(buffer) = self.open_buffers.get_mut(&buffer_id) { if let Some(buffer) = this.open_buffers.get_mut(&buffer_id) {
if let Some(buffer) = buffer.upgrade(cx) { if let Some(buffer) = buffer.upgrade(cx) {
buffer.update(cx, |buffer, cx| buffer.apply_ops(ops, cx))?; buffer.update(cx, |buffer, cx| buffer.apply_ops(ops, cx))?;
} }
} }
Ok(()) Ok(())
})
} }
pub fn handle_update_buffer_file( async fn handle_update_buffer_file(
&mut self, this: ModelHandle<Self>,
envelope: TypedEnvelope<proto::UpdateBufferFile>, envelope: TypedEnvelope<proto::UpdateBufferFile>,
_: Arc<Client>, _: Arc<Client>,
cx: &mut ModelContext<Self>, mut cx: AsyncAppContext,
) -> Result<()> { ) -> Result<()> {
this.update(&mut cx, |this, cx| {
let payload = envelope.payload.clone(); let payload = envelope.payload.clone();
let buffer_id = payload.buffer_id as usize; let buffer_id = payload.buffer_id as usize;
let file = payload.file.ok_or_else(|| anyhow!("invalid file"))?; let file = payload.file.ok_or_else(|| anyhow!("invalid file"))?;
let worktree = self let worktree = this
.worktree_for_id(WorktreeId::from_proto(file.worktree_id), cx) .worktree_for_id(WorktreeId::from_proto(file.worktree_id), cx)
.ok_or_else(|| anyhow!("no such worktree"))?; .ok_or_else(|| anyhow!("no such worktree"))?;
let file = File::from_proto(file, worktree.clone(), cx)?; let file = File::from_proto(file, worktree.clone(), cx)?;
let buffer = self let buffer = this
.open_buffers .open_buffers
.get_mut(&buffer_id) .get_mut(&buffer_id)
.and_then(|b| b.upgrade(cx)) .and_then(|b| b.upgrade(cx))
@ -2201,165 +2210,109 @@ impl Project {
buffer.update(cx, |buffer, cx| { buffer.update(cx, |buffer, cx| {
buffer.file_updated(Box::new(file), cx).detach(); buffer.file_updated(Box::new(file), cx).detach();
}); });
Ok(()) Ok(())
})
} }
pub fn handle_save_buffer( async fn handle_save_buffer(
&mut self, this: ModelHandle<Self>,
envelope: TypedEnvelope<proto::SaveBuffer>, envelope: TypedEnvelope<proto::SaveBuffer>,
rpc: Arc<Client>, _: Arc<Client>,
cx: &mut ModelContext<Self>, mut cx: AsyncAppContext,
) -> Result<()> { ) -> Result<proto::BufferSaved> {
let buffer_id = envelope.payload.buffer_id;
let sender_id = envelope.original_sender_id()?; let sender_id = envelope.original_sender_id()?;
let project_id = self.remote_id().ok_or_else(|| anyhow!("not connected"))?; let (project_id, save) = this.update(&mut cx, |this, cx| {
let buffer = self let project_id = this.remote_id().ok_or_else(|| anyhow!("not connected"))?;
let buffer = this
.shared_buffers .shared_buffers
.get(&sender_id) .get(&sender_id)
.and_then(|shared_buffers| shared_buffers.get(&envelope.payload.buffer_id).cloned()) .and_then(|shared_buffers| shared_buffers.get(&buffer_id).cloned())
.ok_or_else(|| anyhow!("unknown buffer id {}", envelope.payload.buffer_id))?; .ok_or_else(|| anyhow!("unknown buffer id {}", buffer_id))?;
let receipt = envelope.receipt(); Ok::<_, anyhow::Error>((project_id, buffer.update(cx, |buffer, cx| buffer.save(cx))))
let buffer_id = envelope.payload.buffer_id; })?;
let save = cx.spawn(|_, mut cx| async move {
buffer.update(&mut cx, |buffer, cx| buffer.save(cx)).await
});
cx.background()
.spawn(
async move {
let (version, mtime) = save.await?; let (version, mtime) = save.await?;
Ok(proto::BufferSaved {
rpc.respond(
receipt,
proto::BufferSaved {
project_id, project_id,
buffer_id, buffer_id,
version: (&version).into(), version: (&version).into(),
mtime: Some(mtime.into()), mtime: Some(mtime.into()),
}, })
)?;
Ok(())
}
.log_err(),
)
.detach();
Ok(())
} }
pub fn handle_format_buffers( async fn handle_format_buffers(
&mut self, this: ModelHandle<Self>,
envelope: TypedEnvelope<proto::FormatBuffers>, envelope: TypedEnvelope<proto::FormatBuffers>,
rpc: Arc<Client>, _: Arc<Client>,
cx: &mut ModelContext<Self>, mut cx: AsyncAppContext,
) -> Result<()> { ) -> Result<proto::FormatBuffersResponse> {
let receipt = envelope.receipt();
let sender_id = envelope.original_sender_id()?; let sender_id = envelope.original_sender_id()?;
let shared_buffers = self let format = this.update(&mut cx, |this, cx| {
let shared_buffers = this
.shared_buffers .shared_buffers
.get(&sender_id) .get(&sender_id)
.ok_or_else(|| anyhow!("peer has no buffers"))?; .ok_or_else(|| anyhow!("peer has no buffers"))?;
let mut buffers = HashSet::default(); let mut buffers = HashSet::default();
for buffer_id in envelope.payload.buffer_ids { for buffer_id in &envelope.payload.buffer_ids {
buffers.insert( buffers.insert(
shared_buffers shared_buffers
.get(&buffer_id) .get(buffer_id)
.cloned() .cloned()
.ok_or_else(|| anyhow!("unknown buffer id {}", buffer_id))?, .ok_or_else(|| anyhow!("unknown buffer id {}", buffer_id))?,
); );
} }
cx.spawn(|this, mut cx| async move { Ok::<_, anyhow::Error>(this.format(buffers, false, cx))
let project_transaction = this })?;
.update(&mut cx, |this, cx| this.format(buffers, false, cx))
.await let project_transaction = format.await?;
.map(|project_transaction| { let project_transaction = this.update(&mut cx, |this, cx| {
this.update(&mut cx, |this, cx| { this.serialize_project_transaction_for_peer(project_transaction, sender_id, 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 Ok(proto::FormatBuffersResponse {
// edits associated with formatting. transaction: Some(project_transaction),
cx.spawn(|_| async move {
match project_transaction {
Ok(transaction) => rpc.respond(
receipt,
proto::FormatBuffersResponse {
transaction: Some(transaction),
},
)?,
Err(error) => rpc.respond_with_error(
receipt,
proto::Error {
message: error.to_string(),
},
)?,
}
Ok::<_, anyhow::Error>(())
}) })
.await
.log_err();
})
.detach();
Ok(())
} }
fn handle_get_completions( async fn handle_get_completions(
&mut self, this: ModelHandle<Self>,
envelope: TypedEnvelope<proto::GetCompletions>, envelope: TypedEnvelope<proto::GetCompletions>,
rpc: Arc<Client>, _: Arc<Client>,
cx: &mut ModelContext<Self>, mut cx: AsyncAppContext,
) -> Result<()> { ) -> Result<proto::GetCompletionsResponse> {
let receipt = envelope.receipt();
let sender_id = envelope.original_sender_id()?; let sender_id = envelope.original_sender_id()?;
let buffer = 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))?;
let position = envelope let position = envelope
.payload .payload
.position .position
.and_then(language::proto::deserialize_anchor) .and_then(language::proto::deserialize_anchor)
.ok_or_else(|| anyhow!("invalid position"))?; .ok_or_else(|| anyhow!("invalid position"))?;
cx.spawn(|this, mut cx| async move { let completions = this.update(&mut cx, |this, cx| {
match this let buffer = this
.update(&mut cx, |this, cx| this.completions(&buffer, position, cx)) .shared_buffers
.await .get(&sender_id)
{ .and_then(|shared_buffers| shared_buffers.get(&envelope.payload.buffer_id).cloned())
Ok(completions) => rpc.respond( .ok_or_else(|| anyhow!("unknown buffer id {}", envelope.payload.buffer_id))?;
receipt, Ok::<_, anyhow::Error>(this.completions(&buffer, position, cx))
proto::GetCompletionsResponse { })?;
Ok(proto::GetCompletionsResponse {
completions: completions completions: completions
.await?
.iter() .iter()
.map(language::proto::serialize_completion) .map(language::proto::serialize_completion)
.collect(), .collect(),
},
),
Err(error) => rpc.respond_with_error(
receipt,
proto::Error {
message: error.to_string(),
},
),
}
}) })
.detach_and_log_err(cx);
Ok(())
} }
fn handle_apply_additional_edits_for_completion( async fn handle_apply_additional_edits_for_completion(
&mut self, this: ModelHandle<Self>,
envelope: TypedEnvelope<proto::ApplyCompletionAdditionalEdits>, envelope: TypedEnvelope<proto::ApplyCompletionAdditionalEdits>,
rpc: Arc<Client>, _: Arc<Client>,
cx: &mut ModelContext<Self>, mut cx: AsyncAppContext,
) -> Result<()> { ) -> Result<proto::ApplyCompletionAdditionalEditsResponse> {
let receipt = envelope.receipt();
let sender_id = envelope.original_sender_id()?; let sender_id = envelope.original_sender_id()?;
let buffer = self let apply_additional_edits = this.update(&mut cx, |this, cx| {
let buffer = this
.shared_buffers .shared_buffers
.get(&sender_id) .get(&sender_id)
.and_then(|shared_buffers| shared_buffers.get(&envelope.payload.buffer_id).cloned()) .and_then(|shared_buffers| shared_buffers.get(&envelope.payload.buffer_id).cloned())
@ -2372,153 +2325,111 @@ impl Project {
.ok_or_else(|| anyhow!("invalid completion"))?, .ok_or_else(|| anyhow!("invalid completion"))?,
language, language,
)?; )?;
cx.spawn(|this, mut cx| async move { Ok::<_, anyhow::Error>(
match this this.apply_additional_edits_for_completion(buffer, completion, false, cx),
.update(&mut cx, |this, cx| { )
this.apply_additional_edits_for_completion(buffer, completion, false, cx) })?;
})
.await Ok(proto::ApplyCompletionAdditionalEditsResponse {
{ transaction: apply_additional_edits
Ok(transaction) => rpc.respond( .await?
receipt,
proto::ApplyCompletionAdditionalEditsResponse {
transaction: transaction
.as_ref() .as_ref()
.map(language::proto::serialize_transaction), .map(language::proto::serialize_transaction),
},
),
Err(error) => rpc.respond_with_error(
receipt,
proto::Error {
message: error.to_string(),
},
),
}
}) })
.detach_and_log_err(cx);
Ok(())
} }
fn handle_get_code_actions( async fn handle_get_code_actions(
&mut self, this: ModelHandle<Self>,
envelope: TypedEnvelope<proto::GetCodeActions>, envelope: TypedEnvelope<proto::GetCodeActions>,
rpc: Arc<Client>, _: Arc<Client>,
cx: &mut ModelContext<Self>, mut cx: AsyncAppContext,
) -> Result<()> { ) -> Result<proto::GetCodeActionsResponse> {
let receipt = envelope.receipt();
let sender_id = envelope.original_sender_id()?; let sender_id = envelope.original_sender_id()?;
let buffer = 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))?;
let position = envelope let position = envelope
.payload .payload
.position .position
.and_then(language::proto::deserialize_anchor) .and_then(language::proto::deserialize_anchor)
.ok_or_else(|| anyhow!("invalid position"))?; .ok_or_else(|| anyhow!("invalid position"))?;
cx.spawn(|this, mut cx| async move { let code_actions = this.update(&mut cx, |this, cx| {
match this let buffer = this
.update(&mut cx, |this, cx| this.code_actions(&buffer, position, cx))
.await
{
Ok(actions) => rpc.respond(
receipt,
proto::GetCodeActionsResponse {
actions: actions
.iter()
.map(language::proto::serialize_code_action)
.collect(),
},
),
Err(error) => rpc.respond_with_error(
receipt,
proto::Error {
message: error.to_string(),
},
),
}
})
.detach_and_log_err(cx);
Ok(())
}
fn handle_apply_code_action(
&mut self,
envelope: TypedEnvelope<proto::ApplyCodeAction>,
rpc: Arc<Client>,
cx: &mut ModelContext<Self>,
) -> Result<()> {
let receipt = envelope.receipt();
let sender_id = envelope.original_sender_id()?;
let buffer = self
.shared_buffers .shared_buffers
.get(&sender_id) .get(&sender_id)
.and_then(|shared_buffers| shared_buffers.get(&envelope.payload.buffer_id).cloned()) .and_then(|shared_buffers| shared_buffers.get(&envelope.payload.buffer_id).cloned())
.ok_or_else(|| anyhow!("unknown buffer id {}", envelope.payload.buffer_id))?; .ok_or_else(|| anyhow!("unknown buffer id {}", envelope.payload.buffer_id))?;
Ok::<_, anyhow::Error>(this.code_actions(&buffer, position, cx))
})?;
Ok(proto::GetCodeActionsResponse {
actions: code_actions
.await?
.iter()
.map(language::proto::serialize_code_action)
.collect(),
})
}
async fn handle_apply_code_action(
this: ModelHandle<Self>,
envelope: TypedEnvelope<proto::ApplyCodeAction>,
_: Arc<Client>,
mut cx: AsyncAppContext,
) -> Result<proto::ApplyCodeActionResponse> {
let sender_id = envelope.original_sender_id()?;
let action = language::proto::deserialize_code_action( let action = language::proto::deserialize_code_action(
envelope envelope
.payload .payload
.action .action
.ok_or_else(|| anyhow!("invalid action"))?, .ok_or_else(|| anyhow!("invalid action"))?,
)?; )?;
let apply_code_action = self.apply_code_action(buffer, action, false, cx); let apply_code_action = this.update(&mut cx, |this, cx| {
cx.spawn(|this, mut cx| async move { let buffer = this
match apply_code_action.await {
Ok(project_transaction) => this.update(&mut cx, |this, cx| {
let serialized_transaction = this.serialize_project_transaction_for_peer(
project_transaction,
sender_id,
cx,
);
rpc.respond(
receipt,
proto::ApplyCodeActionResponse {
transaction: Some(serialized_transaction),
},
)
}),
Err(error) => rpc.respond_with_error(
receipt,
proto::Error {
message: error.to_string(),
},
),
}
})
.detach_and_log_err(cx);
Ok(())
}
pub fn handle_get_definition(
&mut self,
envelope: TypedEnvelope<proto::GetDefinition>,
rpc: Arc<Client>,
cx: &mut ModelContext<Self>,
) -> Result<()> {
let receipt = envelope.receipt();
let sender_id = envelope.original_sender_id()?;
let source_buffer = self
.shared_buffers .shared_buffers
.get(&sender_id) .get(&sender_id)
.and_then(|shared_buffers| shared_buffers.get(&envelope.payload.buffer_id).cloned()) .and_then(|shared_buffers| shared_buffers.get(&envelope.payload.buffer_id).cloned())
.ok_or_else(|| anyhow!("unknown buffer id {}", envelope.payload.buffer_id))?; .ok_or_else(|| anyhow!("unknown buffer id {}", envelope.payload.buffer_id))?;
Ok::<_, anyhow::Error>(this.apply_code_action(buffer, action, false, cx))
})?;
let project_transaction = apply_code_action.await?;
let project_transaction = this.update(&mut cx, |this, cx| {
this.serialize_project_transaction_for_peer(project_transaction, sender_id, cx)
});
Ok(proto::ApplyCodeActionResponse {
transaction: Some(project_transaction),
})
}
async fn handle_get_definition(
this: ModelHandle<Self>,
envelope: TypedEnvelope<proto::GetDefinition>,
_: Arc<Client>,
mut cx: AsyncAppContext,
) -> Result<proto::GetDefinitionResponse> {
let sender_id = envelope.original_sender_id()?;
let position = envelope let position = envelope
.payload .payload
.position .position
.and_then(deserialize_anchor) .and_then(deserialize_anchor)
.ok_or_else(|| anyhow!("invalid position"))?; .ok_or_else(|| anyhow!("invalid position"))?;
if !source_buffer.read(cx).can_resolve(&position) { let definitions = this.update(&mut cx, |this, cx| {
return Err(anyhow!("cannot resolve position")); let source_buffer = this
.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))?;
if source_buffer.read(cx).can_resolve(&position) {
Ok(this.definition(&source_buffer, position, cx))
} else {
Err(anyhow!("cannot resolve position"))
} }
})?;
let definitions = self.definition(&source_buffer, position, cx);
cx.spawn(|this, mut cx| async move {
let definitions = definitions.await?; let definitions = definitions.await?;
this.update(&mut cx, |this, cx| {
let mut response = proto::GetDefinitionResponse { let mut response = proto::GetDefinitionResponse {
definitions: Default::default(), definitions: Default::default(),
}; };
this.update(&mut cx, |this, cx| {
for definition in definitions { for definition in definitions {
let buffer = let buffer =
this.serialize_buffer_for_peer(&definition.target_buffer, sender_id, cx); this.serialize_buffer_for_peer(&definition.target_buffer, sender_id, cx);
@ -2528,48 +2439,34 @@ impl Project {
buffer: Some(buffer), buffer: Some(buffer),
}); });
} }
}); Ok(response)
rpc.respond(receipt, response)?;
Ok::<_, anyhow::Error>(())
}) })
.detach_and_log_err(cx);
Ok(())
} }
pub fn handle_open_buffer( async fn handle_open_buffer(
&mut self, this: ModelHandle<Self>,
envelope: TypedEnvelope<proto::OpenBuffer>, envelope: TypedEnvelope<proto::OpenBuffer>,
rpc: Arc<Client>, _: Arc<Client>,
cx: &mut ModelContext<Self>, mut cx: AsyncAppContext,
) -> anyhow::Result<()> { ) -> anyhow::Result<proto::OpenBufferResponse> {
let receipt = envelope.receipt();
let peer_id = envelope.original_sender_id()?; let peer_id = envelope.original_sender_id()?;
let worktree_id = WorktreeId::from_proto(envelope.payload.worktree_id); let worktree_id = WorktreeId::from_proto(envelope.payload.worktree_id);
let open_buffer = self.open_buffer( let open_buffer = this.update(&mut cx, |this, cx| {
this.open_buffer(
ProjectPath { ProjectPath {
worktree_id, worktree_id,
path: PathBuf::from(envelope.payload.path).into(), path: PathBuf::from(envelope.payload.path).into(),
}, },
cx, cx,
);
cx.spawn(|this, mut cx| {
async move {
let buffer = open_buffer.await?;
let buffer = this.update(&mut cx, |this, cx| {
this.serialize_buffer_for_peer(&buffer, peer_id, cx)
});
rpc.respond(
receipt,
proto::OpenBufferResponse {
buffer: Some(buffer),
},
) )
} });
.log_err()
let buffer = open_buffer.await?;
this.update(&mut cx, |this, cx| {
Ok(proto::OpenBufferResponse {
buffer: Some(this.serialize_buffer_for_peer(&buffer, peer_id, cx)),
})
}) })
.detach();
Ok(())
} }
fn serialize_project_transaction_for_peer( fn serialize_project_transaction_for_peer(
@ -2685,67 +2582,74 @@ impl Project {
} }
} }
pub fn handle_close_buffer( async fn handle_close_buffer(
&mut self, this: ModelHandle<Self>,
envelope: TypedEnvelope<proto::CloseBuffer>, envelope: TypedEnvelope<proto::CloseBuffer>,
_: Arc<Client>, _: Arc<Client>,
cx: &mut ModelContext<Self>, mut cx: AsyncAppContext,
) -> anyhow::Result<()> { ) -> anyhow::Result<()> {
if let Some(shared_buffers) = self.shared_buffers.get_mut(&envelope.original_sender_id()?) { this.update(&mut cx, |this, cx| {
if let Some(shared_buffers) =
this.shared_buffers.get_mut(&envelope.original_sender_id()?)
{
shared_buffers.remove(&envelope.payload.buffer_id); shared_buffers.remove(&envelope.payload.buffer_id);
cx.notify(); cx.notify();
} }
Ok(()) Ok(())
})
} }
pub fn handle_buffer_saved( async fn handle_buffer_saved(
&mut self, this: ModelHandle<Self>,
envelope: TypedEnvelope<proto::BufferSaved>, envelope: TypedEnvelope<proto::BufferSaved>,
_: Arc<Client>, _: Arc<Client>,
cx: &mut ModelContext<Self>, mut cx: AsyncAppContext,
) -> Result<()> { ) -> Result<()> {
let payload = envelope.payload.clone(); let version = envelope.payload.version.try_into()?;
let buffer = self let mtime = envelope
.open_buffers .payload
.get(&(payload.buffer_id as usize))
.and_then(|buffer| buffer.upgrade(cx));
if let Some(buffer) = buffer {
buffer.update(cx, |buffer, cx| {
let version = payload.version.try_into()?;
let mtime = payload
.mtime .mtime
.ok_or_else(|| anyhow!("missing mtime"))? .ok_or_else(|| anyhow!("missing mtime"))?
.into(); .into();
this.update(&mut cx, |this, cx| {
let buffer = this
.open_buffers
.get(&(envelope.payload.buffer_id as usize))
.and_then(|buffer| buffer.upgrade(cx));
if let Some(buffer) = buffer {
buffer.update(cx, |buffer, cx| {
buffer.did_save(version, mtime, None, cx); buffer.did_save(version, mtime, None, cx);
Result::<_, anyhow::Error>::Ok(()) });
})?;
} }
Ok(()) Ok(())
})
} }
pub fn handle_buffer_reloaded( async fn handle_buffer_reloaded(
&mut self, this: ModelHandle<Self>,
envelope: TypedEnvelope<proto::BufferReloaded>, envelope: TypedEnvelope<proto::BufferReloaded>,
_: Arc<Client>, _: Arc<Client>,
cx: &mut ModelContext<Self>, mut cx: AsyncAppContext,
) -> Result<()> { ) -> Result<()> {
let payload = envelope.payload.clone(); let payload = envelope.payload.clone();
let buffer = self
.open_buffers
.get(&(payload.buffer_id as usize))
.and_then(|buffer| buffer.upgrade(cx));
if let Some(buffer) = buffer {
buffer.update(cx, |buffer, cx| {
let version = payload.version.try_into()?; let version = payload.version.try_into()?;
let mtime = payload let mtime = payload
.mtime .mtime
.ok_or_else(|| anyhow!("missing mtime"))? .ok_or_else(|| anyhow!("missing mtime"))?
.into(); .into();
this.update(&mut cx, |this, cx| {
let buffer = this
.open_buffers
.get(&(payload.buffer_id as usize))
.and_then(|buffer| buffer.upgrade(cx));
if let Some(buffer) = buffer {
buffer.update(cx, |buffer, cx| {
buffer.did_reload(version, mtime, cx); buffer.did_reload(version, mtime, cx);
Result::<_, anyhow::Error>::Ok(()) });
})?;
} }
Ok(()) Ok(())
})
} }
pub fn match_paths<'a>( pub fn match_paths<'a>(