Restructure Peer to handle connections' messages in order
This commit is contained in:
+2
-1
@@ -4015,7 +4015,8 @@ mod tests {
|
||||
let history = History::new(text.into());
|
||||
Buffer::from_history(0, history, None, lang.cloned(), cx)
|
||||
});
|
||||
let (_, view) = cx.add_window(|cx| Editor::for_buffer(buffer, app_state.settings, cx));
|
||||
let (_, view) =
|
||||
cx.add_window(|cx| Editor::for_buffer(buffer, app_state.settings.clone(), cx));
|
||||
view.condition(&cx, |view, cx| !view.buffer.read(cx).is_parsing())
|
||||
.await;
|
||||
|
||||
|
||||
@@ -719,6 +719,7 @@ impl Buffer {
|
||||
mtime: SystemTime,
|
||||
cx: &mut ModelContext<Self>,
|
||||
) {
|
||||
eprintln!("{} did_save {:?}", self.replica_id, version);
|
||||
self.saved_mtime = mtime;
|
||||
self.saved_version = version;
|
||||
cx.emit(Event::Saved);
|
||||
|
||||
@@ -479,8 +479,12 @@ mod tests {
|
||||
|
||||
let app_state = cx.read(build_app_state);
|
||||
let (window_id, workspace) = cx.add_window(|cx| {
|
||||
let mut workspace =
|
||||
Workspace::new(app_state.settings, app_state.languages, app_state.rpc, cx);
|
||||
let mut workspace = Workspace::new(
|
||||
app_state.settings.clone(),
|
||||
app_state.languages.clone(),
|
||||
app_state.rpc.clone(),
|
||||
cx,
|
||||
);
|
||||
workspace.add_worktree(tmp_dir.path(), cx);
|
||||
workspace
|
||||
});
|
||||
@@ -559,7 +563,7 @@ mod tests {
|
||||
cx.read(|cx| workspace.read(cx).worktree_scans_complete(cx))
|
||||
.await;
|
||||
let (_, finder) =
|
||||
cx.add_window(|cx| FileFinder::new(app_state.settings, workspace.clone(), cx));
|
||||
cx.add_window(|cx| FileFinder::new(app_state.settings.clone(), workspace.clone(), cx));
|
||||
|
||||
let query = "hi".to_string();
|
||||
finder
|
||||
@@ -622,7 +626,7 @@ mod tests {
|
||||
cx.read(|cx| workspace.read(cx).worktree_scans_complete(cx))
|
||||
.await;
|
||||
let (_, finder) =
|
||||
cx.add_window(|cx| FileFinder::new(app_state.settings, workspace.clone(), cx));
|
||||
cx.add_window(|cx| FileFinder::new(app_state.settings.clone(), workspace.clone(), cx));
|
||||
|
||||
// Even though there is only one worktree, that worktree's filename
|
||||
// is included in the matching, because the worktree is a single file.
|
||||
@@ -681,7 +685,7 @@ mod tests {
|
||||
.await;
|
||||
|
||||
let (_, finder) =
|
||||
cx.add_window(|cx| FileFinder::new(app_state.settings, workspace.clone(), cx));
|
||||
cx.add_window(|cx| FileFinder::new(app_state.settings.clone(), workspace.clone(), cx));
|
||||
|
||||
// Run a search that matches two files with the same relative path.
|
||||
finder
|
||||
|
||||
+3
-1
@@ -1,3 +1,5 @@
|
||||
use zed_rpc::ForegroundRouter;
|
||||
|
||||
pub mod assets;
|
||||
pub mod editor;
|
||||
pub mod file_finder;
|
||||
@@ -14,10 +16,10 @@ mod util;
|
||||
pub mod workspace;
|
||||
pub mod worktree;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct AppState {
|
||||
pub settings: postage::watch::Receiver<settings::Settings>,
|
||||
pub languages: std::sync::Arc<language::LanguageRegistry>,
|
||||
pub rpc_router: std::sync::Arc<ForegroundRouter>,
|
||||
pub rpc: rpc::Client,
|
||||
}
|
||||
|
||||
|
||||
+11
-3
@@ -10,6 +10,7 @@ use zed::{
|
||||
workspace::{self, OpenParams},
|
||||
worktree, AppState,
|
||||
};
|
||||
use zed_rpc::ForegroundRouter;
|
||||
|
||||
fn main() {
|
||||
init_logger();
|
||||
@@ -20,20 +21,27 @@ fn main() {
|
||||
let languages = Arc::new(language::LanguageRegistry::new());
|
||||
languages.set_theme(&settings.borrow().theme);
|
||||
|
||||
let app_state = AppState {
|
||||
let mut app_state = AppState {
|
||||
languages: languages.clone(),
|
||||
settings,
|
||||
rpc_router: Arc::new(ForegroundRouter::new()),
|
||||
rpc: rpc::Client::new(languages),
|
||||
};
|
||||
|
||||
app.run(move |cx| {
|
||||
cx.set_menus(menus::menus(app_state.clone()));
|
||||
worktree::init(
|
||||
cx,
|
||||
&app_state.rpc,
|
||||
Arc::get_mut(&mut app_state.rpc_router).unwrap(),
|
||||
);
|
||||
zed::init(cx);
|
||||
workspace::init(cx);
|
||||
worktree::init(cx, app_state.rpc.clone());
|
||||
editor::init(cx);
|
||||
file_finder::init(cx);
|
||||
|
||||
let app_state = Arc::new(app_state);
|
||||
cx.set_menus(menus::menus(&app_state.clone()));
|
||||
|
||||
if stdout_is_a_pty() {
|
||||
cx.platform().activate(true);
|
||||
}
|
||||
|
||||
+3
-2
@@ -1,8 +1,9 @@
|
||||
use crate::AppState;
|
||||
use gpui::{Menu, MenuItem};
|
||||
use std::sync::Arc;
|
||||
|
||||
#[cfg(target_os = "macos")]
|
||||
pub fn menus(state: AppState) -> Vec<Menu<'static>> {
|
||||
pub fn menus(state: &Arc<AppState>) -> Vec<Menu<'static>> {
|
||||
vec![
|
||||
Menu {
|
||||
name: "Zed",
|
||||
@@ -48,7 +49,7 @@ pub fn menus(state: AppState) -> Vec<Menu<'static>> {
|
||||
name: "Open…",
|
||||
keystroke: Some("cmd-o"),
|
||||
action: "workspace:open",
|
||||
arg: Some(Box::new(state)),
|
||||
arg: Some(Box::new(state.clone())),
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
+31
-24
@@ -1,10 +1,8 @@
|
||||
use crate::{language::LanguageRegistry, worktree::Worktree};
|
||||
use anyhow::{anyhow, Context, Result};
|
||||
use async_tungstenite::tungstenite::{Error as WebSocketError, Message as WebSocketMessage};
|
||||
use gpui::executor::Background;
|
||||
use gpui::{AsyncAppContext, ModelHandle, Task, WeakModelHandle};
|
||||
use lazy_static::lazy_static;
|
||||
use postage::prelude::Stream;
|
||||
use smol::lock::RwLock;
|
||||
use std::collections::HashMap;
|
||||
use std::time::Duration;
|
||||
@@ -13,7 +11,7 @@ use surf::Url;
|
||||
pub use zed_rpc::{proto, ConnectionId, PeerId, TypedEnvelope};
|
||||
use zed_rpc::{
|
||||
proto::{EnvelopedMessage, RequestMessage},
|
||||
Peer, Receipt,
|
||||
ForegroundRouter, Peer, Receipt,
|
||||
};
|
||||
|
||||
lazy_static! {
|
||||
@@ -63,24 +61,30 @@ impl Client {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn on_message<H, M>(&self, handler: H, cx: &mut gpui::MutableAppContext)
|
||||
where
|
||||
H: 'static + for<'a> MessageHandler<'a, M>,
|
||||
pub fn on_message<H, M>(
|
||||
&self,
|
||||
router: &mut ForegroundRouter,
|
||||
handler: H,
|
||||
cx: &mut gpui::MutableAppContext,
|
||||
) where
|
||||
H: 'static + Clone + for<'a> MessageHandler<'a, M>,
|
||||
M: proto::EnvelopedMessage,
|
||||
{
|
||||
let this = self.clone();
|
||||
let mut messages = smol::block_on(this.peer.add_message_handler::<M>());
|
||||
cx.spawn(|mut cx| async move {
|
||||
while let Some(message) = messages.recv().await {
|
||||
if let Err(err) = handler.handle(message, &this, &mut cx).await {
|
||||
log::error!("error handling message: {:?}", err);
|
||||
}
|
||||
}
|
||||
})
|
||||
.detach();
|
||||
let cx = cx.to_async();
|
||||
router.add_message_handler(move |message| {
|
||||
let this = this.clone();
|
||||
let mut cx = cx.clone();
|
||||
let handler = handler.clone();
|
||||
async move { handler.handle(message, &this, &mut cx).await }
|
||||
});
|
||||
}
|
||||
|
||||
pub async fn log_in_and_connect(&self, cx: &AsyncAppContext) -> surf::Result<()> {
|
||||
pub async fn log_in_and_connect(
|
||||
&self,
|
||||
router: Arc<ForegroundRouter>,
|
||||
cx: AsyncAppContext,
|
||||
) -> surf::Result<()> {
|
||||
if self.state.read().await.connection_id.is_some() {
|
||||
return Ok(());
|
||||
}
|
||||
@@ -96,14 +100,14 @@ impl Client {
|
||||
.await
|
||||
.context("websocket handshake")?;
|
||||
log::info!("connected to rpc address {}", *ZED_SERVER_URL);
|
||||
self.add_connection(stream, user_id, access_token, &cx.background())
|
||||
self.add_connection(stream, user_id, access_token, router, cx)
|
||||
.await?;
|
||||
} else if let Some(host) = ZED_SERVER_URL.strip_prefix("http://") {
|
||||
let stream = smol::net::TcpStream::connect(host).await?;
|
||||
let (stream, _) =
|
||||
async_tungstenite::client_async(format!("ws://{}/rpc", host), stream).await?;
|
||||
log::info!("connected to rpc address {}", *ZED_SERVER_URL);
|
||||
self.add_connection(stream, user_id, access_token, &cx.background())
|
||||
self.add_connection(stream, user_id, access_token, router, cx)
|
||||
.await?;
|
||||
} else {
|
||||
return Err(anyhow!("invalid server url: {}", *ZED_SERVER_URL))?;
|
||||
@@ -117,7 +121,8 @@ impl Client {
|
||||
conn: Conn,
|
||||
user_id: i32,
|
||||
access_token: String,
|
||||
executor: &Arc<Background>,
|
||||
router: Arc<ForegroundRouter>,
|
||||
cx: AsyncAppContext,
|
||||
) -> surf::Result<()>
|
||||
where
|
||||
Conn: 'static
|
||||
@@ -126,10 +131,12 @@ impl Client {
|
||||
+ Unpin
|
||||
+ Send,
|
||||
{
|
||||
let (connection_id, handler) = self.peer.add_connection(conn).await;
|
||||
executor
|
||||
let (connection_id, handle_io, handle_messages) =
|
||||
self.peer.add_connection(conn, router).await;
|
||||
cx.foreground().spawn(handle_messages).detach();
|
||||
cx.background()
|
||||
.spawn(async move {
|
||||
if let Err(error) = handler.run().await {
|
||||
if let Err(error) = handle_io.run().await {
|
||||
log::error!("connection error: {:?}", error);
|
||||
}
|
||||
})
|
||||
@@ -263,7 +270,7 @@ impl Client {
|
||||
}
|
||||
}
|
||||
|
||||
pub trait MessageHandler<'a, M: proto::EnvelopedMessage> {
|
||||
pub trait MessageHandler<'a, M: proto::EnvelopedMessage>: Clone {
|
||||
type Output: 'a + Future<Output = anyhow::Result<()>>;
|
||||
|
||||
fn handle(
|
||||
@@ -277,7 +284,7 @@ pub trait MessageHandler<'a, M: proto::EnvelopedMessage> {
|
||||
impl<'a, M, F, Fut> MessageHandler<'a, M> for F
|
||||
where
|
||||
M: proto::EnvelopedMessage,
|
||||
F: Fn(TypedEnvelope<M>, &'a Client, &'a mut gpui::AsyncAppContext) -> Fut,
|
||||
F: Clone + Fn(TypedEnvelope<M>, &'a Client, &'a mut gpui::AsyncAppContext) -> Fut,
|
||||
Fut: 'a + Future<Output = anyhow::Result<()>>,
|
||||
{
|
||||
type Output = Fut;
|
||||
|
||||
+5
-3
@@ -5,6 +5,7 @@ use std::{
|
||||
sync::Arc,
|
||||
};
|
||||
use tempdir::TempDir;
|
||||
use zed_rpc::ForegroundRouter;
|
||||
|
||||
#[cfg(feature = "test-support")]
|
||||
pub use zed_rpc::test::Channel;
|
||||
@@ -143,12 +144,13 @@ fn write_tree(path: &Path, tree: serde_json::Value) {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn build_app_state(cx: &AppContext) -> AppState {
|
||||
pub fn build_app_state(cx: &AppContext) -> Arc<AppState> {
|
||||
let settings = settings::channel(&cx.font_cache()).unwrap().1;
|
||||
let languages = Arc::new(LanguageRegistry::new());
|
||||
AppState {
|
||||
Arc::new(AppState {
|
||||
settings,
|
||||
languages: languages.clone(),
|
||||
rpc_router: Arc::new(ForegroundRouter::new()),
|
||||
rpc: rpc::Client::new(languages),
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
+33
-15
@@ -45,10 +45,10 @@ pub fn init(cx: &mut MutableAppContext) {
|
||||
|
||||
pub struct OpenParams {
|
||||
pub paths: Vec<PathBuf>,
|
||||
pub app_state: AppState,
|
||||
pub app_state: Arc<AppState>,
|
||||
}
|
||||
|
||||
fn open(app_state: &AppState, cx: &mut MutableAppContext) {
|
||||
fn open(app_state: &Arc<AppState>, cx: &mut MutableAppContext) {
|
||||
let app_state = app_state.clone();
|
||||
cx.prompt_for_paths(
|
||||
PathPromptOptions {
|
||||
@@ -101,7 +101,7 @@ fn open_paths(params: &OpenParams, cx: &mut MutableAppContext) {
|
||||
});
|
||||
}
|
||||
|
||||
fn open_new(app_state: &AppState, cx: &mut MutableAppContext) {
|
||||
fn open_new(app_state: &Arc<AppState>, cx: &mut MutableAppContext) {
|
||||
cx.add_window(|cx| {
|
||||
let mut view = Workspace::new(
|
||||
app_state.settings.clone(),
|
||||
@@ -700,12 +700,13 @@ impl Workspace {
|
||||
};
|
||||
}
|
||||
|
||||
fn share_worktree(&mut self, _: &(), cx: &mut ViewContext<Self>) {
|
||||
fn share_worktree(&mut self, app_state: &Arc<AppState>, cx: &mut ViewContext<Self>) {
|
||||
let rpc = self.rpc.clone();
|
||||
let platform = cx.platform();
|
||||
let router = app_state.rpc_router.clone();
|
||||
|
||||
let task = cx.spawn(|this, mut cx| async move {
|
||||
rpc.log_in_and_connect(&cx).await?;
|
||||
rpc.log_in_and_connect(router, cx.clone()).await?;
|
||||
|
||||
let share_task = this.update(&mut cx, |this, cx| {
|
||||
let worktree = this.worktrees.iter().next()?;
|
||||
@@ -732,12 +733,13 @@ impl Workspace {
|
||||
.detach();
|
||||
}
|
||||
|
||||
fn join_worktree(&mut self, _: &(), cx: &mut ViewContext<Self>) {
|
||||
fn join_worktree(&mut self, app_state: &Arc<AppState>, cx: &mut ViewContext<Self>) {
|
||||
let rpc = self.rpc.clone();
|
||||
let languages = self.languages.clone();
|
||||
let router = app_state.rpc_router.clone();
|
||||
|
||||
let task = cx.spawn(|this, mut cx| async move {
|
||||
rpc.log_in_and_connect(&cx).await?;
|
||||
rpc.log_in_and_connect(router, cx.clone()).await?;
|
||||
|
||||
let worktree_url = cx
|
||||
.platform()
|
||||
@@ -974,8 +976,12 @@ mod tests {
|
||||
let app_state = cx.read(build_app_state);
|
||||
|
||||
let (_, workspace) = cx.add_window(|cx| {
|
||||
let mut workspace =
|
||||
Workspace::new(app_state.settings, app_state.languages, app_state.rpc, cx);
|
||||
let mut workspace = Workspace::new(
|
||||
app_state.settings.clone(),
|
||||
app_state.languages.clone(),
|
||||
app_state.rpc.clone(),
|
||||
cx,
|
||||
);
|
||||
workspace.add_worktree(dir.path(), cx);
|
||||
workspace
|
||||
});
|
||||
@@ -1077,8 +1083,12 @@ mod tests {
|
||||
|
||||
let app_state = cx.read(build_app_state);
|
||||
let (_, workspace) = cx.add_window(|cx| {
|
||||
let mut workspace =
|
||||
Workspace::new(app_state.settings, app_state.languages, app_state.rpc, cx);
|
||||
let mut workspace = Workspace::new(
|
||||
app_state.settings.clone(),
|
||||
app_state.languages.clone(),
|
||||
app_state.rpc.clone(),
|
||||
cx,
|
||||
);
|
||||
workspace.add_worktree(dir1.path(), cx);
|
||||
workspace
|
||||
});
|
||||
@@ -1146,8 +1156,12 @@ mod tests {
|
||||
|
||||
let app_state = cx.read(build_app_state);
|
||||
let (window_id, workspace) = cx.add_window(|cx| {
|
||||
let mut workspace =
|
||||
Workspace::new(app_state.settings, app_state.languages, app_state.rpc, cx);
|
||||
let mut workspace = Workspace::new(
|
||||
app_state.settings.clone(),
|
||||
app_state.languages.clone(),
|
||||
app_state.rpc.clone(),
|
||||
cx,
|
||||
);
|
||||
workspace.add_worktree(dir.path(), cx);
|
||||
workspace
|
||||
});
|
||||
@@ -1315,8 +1329,12 @@ mod tests {
|
||||
|
||||
let app_state = cx.read(build_app_state);
|
||||
let (window_id, workspace) = cx.add_window(|cx| {
|
||||
let mut workspace =
|
||||
Workspace::new(app_state.settings, app_state.languages, app_state.rpc, cx);
|
||||
let mut workspace = Workspace::new(
|
||||
app_state.settings.clone(),
|
||||
app_state.languages.clone(),
|
||||
app_state.rpc.clone(),
|
||||
cx,
|
||||
);
|
||||
workspace.add_worktree(dir.path(), cx);
|
||||
workspace
|
||||
});
|
||||
|
||||
+19
-12
@@ -48,21 +48,21 @@ use std::{
|
||||
},
|
||||
time::{Duration, SystemTime},
|
||||
};
|
||||
use zed_rpc::{PeerId, TypedEnvelope};
|
||||
use zed_rpc::{ForegroundRouter, PeerId, TypedEnvelope};
|
||||
|
||||
lazy_static! {
|
||||
static ref GITIGNORE: &'static OsStr = OsStr::new(".gitignore");
|
||||
}
|
||||
|
||||
pub fn init(cx: &mut MutableAppContext, rpc: rpc::Client) {
|
||||
rpc.on_message(remote::add_peer, cx);
|
||||
rpc.on_message(remote::remove_peer, cx);
|
||||
rpc.on_message(remote::update_worktree, cx);
|
||||
rpc.on_message(remote::open_buffer, cx);
|
||||
rpc.on_message(remote::close_buffer, cx);
|
||||
rpc.on_message(remote::update_buffer, cx);
|
||||
rpc.on_message(remote::buffer_saved, cx);
|
||||
rpc.on_message(remote::save_buffer, cx);
|
||||
pub fn init(cx: &mut MutableAppContext, rpc: &rpc::Client, router: &mut ForegroundRouter) {
|
||||
rpc.on_message(router, remote::add_peer, cx);
|
||||
rpc.on_message(router, remote::remove_peer, cx);
|
||||
rpc.on_message(router, remote::update_worktree, cx);
|
||||
rpc.on_message(router, remote::open_buffer, cx);
|
||||
rpc.on_message(router, remote::close_buffer, cx);
|
||||
rpc.on_message(router, remote::update_buffer, cx);
|
||||
rpc.on_message(router, remote::buffer_saved, cx);
|
||||
rpc.on_message(router, remote::save_buffer, cx);
|
||||
}
|
||||
|
||||
#[async_trait::async_trait]
|
||||
@@ -2861,6 +2861,8 @@ mod remote {
|
||||
rpc: &rpc::Client,
|
||||
cx: &mut AsyncAppContext,
|
||||
) -> anyhow::Result<()> {
|
||||
eprintln!("got update buffer message {:?}", envelope.payload);
|
||||
|
||||
let message = envelope.payload;
|
||||
rpc.state
|
||||
.read()
|
||||
@@ -2875,6 +2877,8 @@ mod remote {
|
||||
rpc: &rpc::Client,
|
||||
cx: &mut AsyncAppContext,
|
||||
) -> anyhow::Result<()> {
|
||||
eprintln!("got save buffer message {:?}", envelope.payload);
|
||||
|
||||
let state = rpc.state.read().await;
|
||||
let worktree = state.shared_worktree(envelope.payload.worktree_id, cx)?;
|
||||
let sender_id = envelope.original_sender_id()?;
|
||||
@@ -2905,6 +2909,8 @@ mod remote {
|
||||
rpc: &rpc::Client,
|
||||
cx: &mut AsyncAppContext,
|
||||
) -> anyhow::Result<()> {
|
||||
eprintln!("got buffer_saved {:?}", envelope.payload);
|
||||
|
||||
rpc.state
|
||||
.read()
|
||||
.await
|
||||
@@ -2993,7 +2999,7 @@ mod tests {
|
||||
let dir = temp_tree(json!({
|
||||
"file1": "the old contents",
|
||||
}));
|
||||
let tree = cx.add_model(|cx| Worktree::local(dir.path(), app_state.languages, cx));
|
||||
let tree = cx.add_model(|cx| Worktree::local(dir.path(), app_state.languages.clone(), cx));
|
||||
let buffer = tree
|
||||
.update(&mut cx, |tree, cx| tree.open_buffer("file1", cx))
|
||||
.await
|
||||
@@ -3016,7 +3022,8 @@ mod tests {
|
||||
}));
|
||||
let file_path = dir.path().join("file1");
|
||||
|
||||
let tree = cx.add_model(|cx| Worktree::local(file_path.clone(), app_state.languages, cx));
|
||||
let tree =
|
||||
cx.add_model(|cx| Worktree::local(file_path.clone(), app_state.languages.clone(), cx));
|
||||
cx.read(|cx| tree.read(cx).as_local().unwrap().scan_complete())
|
||||
.await;
|
||||
cx.read(|cx| assert_eq!(tree.read(cx).file_count(), 1));
|
||||
|
||||
Reference in New Issue
Block a user