mirror of
https://github.com/zed-industries/zed.git
synced 2024-11-07 20:39:04 +03:00
Extract worktree, rpc_client, and util crates
Co-Authored-By: Max Brunsfeld <maxbrunsfeld@gmail.com>
This commit is contained in:
parent
154620233b
commit
c236b0828c
66
Cargo.lock
generated
66
Cargo.lock
generated
@ -4087,6 +4087,27 @@ dependencies = [
|
||||
"xmlparser",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rpc_client"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"async-recursion",
|
||||
"async-tungstenite",
|
||||
"gpui",
|
||||
"lazy_static",
|
||||
"log",
|
||||
"parking_lot",
|
||||
"postage",
|
||||
"rand 0.8.3",
|
||||
"smol",
|
||||
"surf",
|
||||
"thiserror",
|
||||
"tiny_http",
|
||||
"util",
|
||||
"zrpc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rsa"
|
||||
version = "0.4.0"
|
||||
@ -5625,6 +5646,18 @@ version = "0.7.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9"
|
||||
|
||||
[[package]]
|
||||
name = "util"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"futures",
|
||||
"log",
|
||||
"serde_json 1.0.64",
|
||||
"surf",
|
||||
"tempdir",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "uuid"
|
||||
version = "0.5.1"
|
||||
@ -5897,6 +5930,36 @@ dependencies = [
|
||||
"winapi 0.3.9",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "worktree"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"async-trait",
|
||||
"buffer",
|
||||
"clock",
|
||||
"fsevent",
|
||||
"futures",
|
||||
"fuzzy",
|
||||
"gpui",
|
||||
"ignore",
|
||||
"lazy_static",
|
||||
"libc",
|
||||
"log",
|
||||
"parking_lot",
|
||||
"postage",
|
||||
"rand 0.8.3",
|
||||
"rpc_client",
|
||||
"serde 1.0.125",
|
||||
"serde_json 1.0.64",
|
||||
"smol",
|
||||
"sum_tree",
|
||||
"tempdir",
|
||||
"toml 0.5.8",
|
||||
"util",
|
||||
"zrpc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wyz"
|
||||
version = "0.2.0"
|
||||
@ -5962,6 +6025,7 @@ dependencies = [
|
||||
"parking_lot",
|
||||
"postage",
|
||||
"rand 0.8.3",
|
||||
"rpc_client",
|
||||
"rsa",
|
||||
"rust-embed",
|
||||
"serde 1.0.125",
|
||||
@ -5981,6 +6045,8 @@ dependencies = [
|
||||
"tree-sitter-rust",
|
||||
"unindent",
|
||||
"url",
|
||||
"util",
|
||||
"worktree",
|
||||
"zrpc",
|
||||
]
|
||||
|
||||
|
@ -6,8 +6,11 @@ members = [
|
||||
"fuzzy",
|
||||
"gpui",
|
||||
"gpui_macros",
|
||||
"rpc_client",
|
||||
"server",
|
||||
"sum_tree",
|
||||
"util",
|
||||
"worktree",
|
||||
"zed",
|
||||
"zrpc"
|
||||
]
|
||||
|
@ -20,6 +20,8 @@ use lazy_static::lazy_static;
|
||||
use operation_queue::OperationQueue;
|
||||
use parking_lot::Mutex;
|
||||
pub use point::*;
|
||||
#[cfg(any(test, feature = "test-support"))]
|
||||
pub use random_char_iter::*;
|
||||
pub use rope::{Chunks, Rope, TextSummary};
|
||||
use seahash::SeaHasher;
|
||||
pub use selection::*;
|
||||
|
55
rpc_client/Cargo.toml
Normal file
55
rpc_client/Cargo.toml
Normal file
@ -0,0 +1,55 @@
|
||||
[package]
|
||||
name = "rpc_client"
|
||||
version = "0.1.0"
|
||||
edition = "2018"
|
||||
|
||||
[features]
|
||||
test-support = []
|
||||
|
||||
[dependencies]
|
||||
anyhow = "1.0.38"
|
||||
async-recursion = "0.3"
|
||||
# async-trait = "0.1"
|
||||
async-tungstenite = { version = "0.14", features = ["async-tls"] }
|
||||
# buffer = { path = "../buffer" }
|
||||
# clock = { path = "../clock" }
|
||||
# crossbeam-channel = "0.5.0"
|
||||
# ctor = "0.1.20"
|
||||
# dirs = "3.0"
|
||||
# easy-parallel = "3.1.0"
|
||||
# fsevent = { path = "../fsevent" }
|
||||
# futures = "0.3"
|
||||
# fuzzy = { path = "../fuzzy" }
|
||||
gpui = { path = "../gpui" }
|
||||
# http-auth-basic = "0.1.3"
|
||||
# ignore = "0.4"
|
||||
# image = "0.23"
|
||||
# indexmap = "1.6.2"
|
||||
lazy_static = "1.4.0"
|
||||
# libc = "0.2"
|
||||
log = "0.4"
|
||||
# log-panics = { version = "2.0", features = ["with-backtrace"] }
|
||||
# num_cpus = "1.13.0"
|
||||
parking_lot = "0.11.1"
|
||||
postage = { version = "0.4.1", features = ["futures-traits"] }
|
||||
rand = "0.8.3"
|
||||
# rsa = "0.4"
|
||||
# rust-embed = { version = "6.2", features = ["include-exclude"] }
|
||||
# serde = { version = "1", features = ["derive"] }
|
||||
# serde_json = { version = "1.0.64", features = ["preserve_order"] }
|
||||
# serde_path_to_error = "0.1.4"
|
||||
# simplelog = "0.9"
|
||||
# smallvec = { version = "1.6", features = ["union"] }
|
||||
smol = "1.2.5"
|
||||
# sum_tree = { path = "../sum_tree" }
|
||||
surf = "2.2"
|
||||
# tempdir = { version = "0.3.7", optional = true }
|
||||
thiserror = "1.0.29"
|
||||
# time = { version = "0.3" }
|
||||
tiny_http = "0.8"
|
||||
# toml = "0.5"
|
||||
# tree-sitter = "0.19.5"
|
||||
# tree-sitter-rust = "0.19.0"
|
||||
util = { path = "../util" }
|
||||
# url = "2.2"
|
||||
zrpc = { path = "../zrpc" }
|
@ -1,4 +1,6 @@
|
||||
use crate::util::ResultExt;
|
||||
#[cfg(any(test, feature = "test-support"))]
|
||||
pub mod test;
|
||||
|
||||
use anyhow::{anyhow, Context, Result};
|
||||
use async_recursion::async_recursion;
|
||||
use async_tungstenite::tungstenite::{
|
||||
@ -21,6 +23,7 @@ use std::{
|
||||
};
|
||||
use surf::Url;
|
||||
use thiserror::Error;
|
||||
use util::ResultExt;
|
||||
pub use zrpc::{proto, ConnectionId, PeerId, TypedEnvelope};
|
||||
use zrpc::{
|
||||
proto::{AnyTypedEnvelope, EntityMessage, EnvelopedMessage, RequestMessage},
|
156
rpc_client/src/test.rs
Normal file
156
rpc_client/src/test.rs
Normal file
@ -0,0 +1,156 @@
|
||||
use super::*;
|
||||
use std::sync::atomic::Ordering::SeqCst;
|
||||
|
||||
use super::Client;
|
||||
use gpui::TestAppContext;
|
||||
use parking_lot::Mutex;
|
||||
use postage::{mpsc, prelude::Stream};
|
||||
use std::sync::{
|
||||
atomic::{AtomicBool, AtomicUsize},
|
||||
Arc,
|
||||
};
|
||||
use zrpc::{proto, ConnectionId, Peer, Receipt, TypedEnvelope};
|
||||
|
||||
pub struct FakeServer {
|
||||
peer: Arc<Peer>,
|
||||
incoming: Mutex<Option<mpsc::Receiver<Box<dyn proto::AnyTypedEnvelope>>>>,
|
||||
connection_id: Mutex<Option<ConnectionId>>,
|
||||
forbid_connections: AtomicBool,
|
||||
auth_count: AtomicUsize,
|
||||
access_token: AtomicUsize,
|
||||
user_id: u64,
|
||||
}
|
||||
|
||||
impl FakeServer {
|
||||
pub async fn for_client(
|
||||
client_user_id: u64,
|
||||
client: &mut Arc<Client>,
|
||||
cx: &TestAppContext,
|
||||
) -> Arc<Self> {
|
||||
let server = Arc::new(Self {
|
||||
peer: Peer::new(),
|
||||
incoming: Default::default(),
|
||||
connection_id: Default::default(),
|
||||
forbid_connections: Default::default(),
|
||||
auth_count: Default::default(),
|
||||
access_token: Default::default(),
|
||||
user_id: client_user_id,
|
||||
});
|
||||
|
||||
Arc::get_mut(client)
|
||||
.unwrap()
|
||||
.override_authenticate({
|
||||
let server = server.clone();
|
||||
move |cx| {
|
||||
server.auth_count.fetch_add(1, SeqCst);
|
||||
let access_token = server.access_token.load(SeqCst).to_string();
|
||||
cx.spawn(move |_| async move {
|
||||
Ok(Credentials {
|
||||
user_id: client_user_id,
|
||||
access_token,
|
||||
})
|
||||
})
|
||||
}
|
||||
})
|
||||
.override_establish_connection({
|
||||
let server = server.clone();
|
||||
move |credentials, cx| {
|
||||
let credentials = credentials.clone();
|
||||
cx.spawn({
|
||||
let server = server.clone();
|
||||
move |cx| async move { server.establish_connection(&credentials, &cx).await }
|
||||
})
|
||||
}
|
||||
});
|
||||
|
||||
client
|
||||
.authenticate_and_connect(&cx.to_async())
|
||||
.await
|
||||
.unwrap();
|
||||
server
|
||||
}
|
||||
|
||||
pub async fn disconnect(&self) {
|
||||
self.peer.disconnect(self.connection_id()).await;
|
||||
self.connection_id.lock().take();
|
||||
self.incoming.lock().take();
|
||||
}
|
||||
|
||||
async fn establish_connection(
|
||||
&self,
|
||||
credentials: &Credentials,
|
||||
cx: &AsyncAppContext,
|
||||
) -> Result<Connection, EstablishConnectionError> {
|
||||
assert_eq!(credentials.user_id, self.user_id);
|
||||
|
||||
if self.forbid_connections.load(SeqCst) {
|
||||
Err(EstablishConnectionError::Other(anyhow!(
|
||||
"server is forbidding connections"
|
||||
)))?
|
||||
}
|
||||
|
||||
if credentials.access_token != self.access_token.load(SeqCst).to_string() {
|
||||
Err(EstablishConnectionError::Unauthorized)?
|
||||
}
|
||||
|
||||
let (client_conn, server_conn, _) = Connection::in_memory();
|
||||
let (connection_id, io, incoming) = self.peer.add_connection(server_conn).await;
|
||||
cx.background().spawn(io).detach();
|
||||
*self.incoming.lock() = Some(incoming);
|
||||
*self.connection_id.lock() = Some(connection_id);
|
||||
Ok(client_conn)
|
||||
}
|
||||
|
||||
pub fn auth_count(&self) -> usize {
|
||||
self.auth_count.load(SeqCst)
|
||||
}
|
||||
|
||||
pub fn roll_access_token(&self) {
|
||||
self.access_token.fetch_add(1, SeqCst);
|
||||
}
|
||||
|
||||
pub fn forbid_connections(&self) {
|
||||
self.forbid_connections.store(true, SeqCst);
|
||||
}
|
||||
|
||||
pub fn allow_connections(&self) {
|
||||
self.forbid_connections.store(false, SeqCst);
|
||||
}
|
||||
|
||||
pub async fn send<T: proto::EnvelopedMessage>(&self, message: T) {
|
||||
self.peer.send(self.connection_id(), message).await.unwrap();
|
||||
}
|
||||
|
||||
pub async fn receive<M: proto::EnvelopedMessage>(&self) -> Result<TypedEnvelope<M>> {
|
||||
let message = self
|
||||
.incoming
|
||||
.lock()
|
||||
.as_mut()
|
||||
.expect("not connected")
|
||||
.recv()
|
||||
.await
|
||||
.ok_or_else(|| anyhow!("other half hung up"))?;
|
||||
let type_name = message.payload_type_name();
|
||||
Ok(*message
|
||||
.into_any()
|
||||
.downcast::<TypedEnvelope<M>>()
|
||||
.unwrap_or_else(|_| {
|
||||
panic!(
|
||||
"fake server received unexpected message type: {:?}",
|
||||
type_name
|
||||
);
|
||||
}))
|
||||
}
|
||||
|
||||
pub async fn respond<T: proto::RequestMessage>(
|
||||
&self,
|
||||
receipt: Receipt<T>,
|
||||
response: T::Response,
|
||||
) {
|
||||
self.peer.respond(receipt, response).await.unwrap()
|
||||
}
|
||||
|
||||
fn connection_id(&self) -> ConnectionId {
|
||||
self.connection_id.lock().expect("not connected")
|
||||
}
|
||||
}
|
15
util/Cargo.toml
Normal file
15
util/Cargo.toml
Normal file
@ -0,0 +1,15 @@
|
||||
[package]
|
||||
name = "util"
|
||||
version = "0.1.0"
|
||||
edition = "2018"
|
||||
|
||||
[features]
|
||||
test-support = ["serde_json", "tempdir"]
|
||||
|
||||
[dependencies]
|
||||
anyhow = "1.0.38"
|
||||
futures = "0.3"
|
||||
log = "0.4"
|
||||
surf = "2.2"
|
||||
tempdir = { version = "0.3.7", optional = true }
|
||||
serde_json = { version = "1.0.64", features = ["preserve_order"], optional = true }
|
@ -1,11 +1,12 @@
|
||||
#[cfg(feature = "test-support")]
|
||||
pub mod test;
|
||||
|
||||
use futures::Future;
|
||||
use rand::prelude::*;
|
||||
use std::{
|
||||
cmp::Ordering,
|
||||
pin::Pin,
|
||||
task::{Context, Poll},
|
||||
};
|
||||
pub use sum_tree::Bias;
|
||||
|
||||
pub fn post_inc(value: &mut usize) -> usize {
|
||||
let prev = *value;
|
||||
@ -35,35 +36,6 @@ where
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct RandomCharIter<T: Rng>(T);
|
||||
|
||||
impl<T: Rng> RandomCharIter<T> {
|
||||
#[cfg(test)]
|
||||
pub fn new(rng: T) -> Self {
|
||||
Self(rng)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Rng> Iterator for RandomCharIter<T> {
|
||||
type Item = char;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
match self.0.gen_range(0..100) {
|
||||
// whitespace
|
||||
0..=19 => [' ', '\n', '\t'].choose(&mut self.0).copied(),
|
||||
// two-byte greek letters
|
||||
20..=32 => char::from_u32(self.0.gen_range(('α' as u32)..('ω' as u32 + 1))),
|
||||
// three-byte characters
|
||||
33..=45 => ['✋', '✅', '❌', '❎', '⭐'].choose(&mut self.0).copied(),
|
||||
// four-byte characters
|
||||
46..=58 => ['🍐', '🏀', '🍗', '🎉'].choose(&mut self.0).copied(),
|
||||
// ascii letters
|
||||
_ => Some(self.0.gen_range(b'a'..b'z' + 1).into()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub trait ResultExt {
|
||||
type Ok;
|
||||
|
37
util/src/test.rs
Normal file
37
util/src/test.rs
Normal file
@ -0,0 +1,37 @@
|
||||
use std::path::{Path, PathBuf};
|
||||
use tempdir::TempDir;
|
||||
|
||||
pub fn temp_tree(tree: serde_json::Value) -> TempDir {
|
||||
let dir = TempDir::new("").unwrap();
|
||||
write_tree(dir.path(), tree);
|
||||
dir
|
||||
}
|
||||
|
||||
fn write_tree(path: &Path, tree: serde_json::Value) {
|
||||
use serde_json::Value;
|
||||
use std::fs;
|
||||
|
||||
if let Value::Object(map) = tree {
|
||||
for (name, contents) in map {
|
||||
let mut path = PathBuf::from(path);
|
||||
path.push(name);
|
||||
match contents {
|
||||
Value::Object(_) => {
|
||||
fs::create_dir(&path).unwrap();
|
||||
write_tree(&path, contents);
|
||||
}
|
||||
Value::Null => {
|
||||
fs::create_dir(&path).unwrap();
|
||||
}
|
||||
Value::String(contents) => {
|
||||
fs::write(&path, contents).unwrap();
|
||||
}
|
||||
_ => {
|
||||
panic!("JSON object must contain only objects, strings, or null");
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
panic!("You must pass a JSON object to this helper")
|
||||
}
|
||||
}
|
61
worktree/Cargo.toml
Normal file
61
worktree/Cargo.toml
Normal file
@ -0,0 +1,61 @@
|
||||
[package]
|
||||
name = "worktree"
|
||||
version = "0.1.0"
|
||||
edition = "2018"
|
||||
|
||||
[features]
|
||||
test-support = []
|
||||
|
||||
[dependencies]
|
||||
anyhow = "1.0.38"
|
||||
# async-recursion = "0.3"
|
||||
async-trait = "0.1"
|
||||
# async-tungstenite = { version = "0.14", features = ["async-tls"] }
|
||||
buffer = { path = "../buffer" }
|
||||
clock = { path = "../clock" }
|
||||
# crossbeam-channel = "0.5.0"
|
||||
# ctor = "0.1.20"
|
||||
# dirs = "3.0"
|
||||
# easy-parallel = "3.1.0"
|
||||
fsevent = { path = "../fsevent" }
|
||||
futures = "0.3"
|
||||
fuzzy = { path = "../fuzzy" }
|
||||
gpui = { path = "../gpui" }
|
||||
# http-auth-basic = "0.1.3"
|
||||
ignore = "0.4"
|
||||
# image = "0.23"
|
||||
# indexmap = "1.6.2"
|
||||
lazy_static = "1.4.0"
|
||||
libc = "0.2"
|
||||
log = "0.4"
|
||||
# log-panics = { version = "2.0", features = ["with-backtrace"] }
|
||||
# num_cpus = "1.13.0"
|
||||
parking_lot = "0.11.1"
|
||||
postage = { version = "0.4.1", features = ["futures-traits"] }
|
||||
rpc_client = { path = "../rpc_client" }
|
||||
# rand = "0.8.3"
|
||||
# rsa = "0.4"
|
||||
# rust-embed = { version = "6.2", features = ["include-exclude"] }
|
||||
serde = { version = "1", features = ["derive"] }
|
||||
serde_json = { version = "1.0.64", features = ["preserve_order"] }
|
||||
# serde_path_to_error = "0.1.4"
|
||||
# simplelog = "0.9"
|
||||
# smallvec = { version = "1.6", features = ["union"] }
|
||||
smol = "1.2.5"
|
||||
sum_tree = { path = "../sum_tree" }
|
||||
util = { path = "../util" }
|
||||
# surf = "2.2"
|
||||
# tempdir = { version = "0.3.7", optional = true }
|
||||
# thiserror = "1.0.29"
|
||||
# time = { version = "0.3" }
|
||||
# tiny_http = "0.8"
|
||||
toml = "0.5"
|
||||
# tree-sitter = "0.19.5"
|
||||
# tree-sitter-rust = "0.19.0"
|
||||
# url = "2.2"
|
||||
zrpc = { path = "../zrpc" }
|
||||
|
||||
[dev-dependencies]
|
||||
rand = "0.8.3"
|
||||
tempdir = { version = "0.3.7" }
|
||||
util = { path = "../util", features = ["test-support"] }
|
@ -1,17 +1,14 @@
|
||||
pub mod fs;
|
||||
mod ignore;
|
||||
|
||||
use self::ignore::IgnoreStack;
|
||||
use crate::{
|
||||
fs::{self, Fs},
|
||||
fuzzy::CharBag,
|
||||
rpc::{self, proto, Status},
|
||||
util::{Bias, TryFutureExt},
|
||||
};
|
||||
use ::ignore::gitignore::{Gitignore, GitignoreBuilder};
|
||||
use anyhow::{anyhow, Result};
|
||||
use buffer::{self, Buffer, History, LanguageRegistry, Operation, Rope};
|
||||
use clock::ReplicaId;
|
||||
pub use fs::*;
|
||||
use futures::{Stream, StreamExt};
|
||||
use fuzzy::CharBag;
|
||||
use gpui::{
|
||||
executor, AppContext, AsyncAppContext, Entity, ModelContext, ModelHandle, MutableAppContext,
|
||||
Task, UpgradeModelHandle, WeakModelHandle,
|
||||
@ -22,6 +19,7 @@ use postage::{
|
||||
prelude::{Sink as _, Stream as _},
|
||||
watch,
|
||||
};
|
||||
use rpc_client as rpc;
|
||||
use serde::Deserialize;
|
||||
use smol::channel::{self, Sender};
|
||||
use std::{
|
||||
@ -40,8 +38,10 @@ use std::{
|
||||
},
|
||||
time::{Duration, SystemTime},
|
||||
};
|
||||
use sum_tree::Bias;
|
||||
use sum_tree::{self, Edit, SeekTarget, SumTree};
|
||||
use zrpc::{PeerId, TypedEnvelope};
|
||||
use util::TryFutureExt;
|
||||
use zrpc::{proto, PeerId, TypedEnvelope};
|
||||
|
||||
lazy_static! {
|
||||
static ref GITIGNORE: &'static OsStr = OsStr::new(".gitignore");
|
||||
@ -755,7 +755,7 @@ impl LocalWorktree {
|
||||
let mut status = rpc.status();
|
||||
while let Some(status) = status.recv().await {
|
||||
if let Some(this) = this.upgrade(&cx) {
|
||||
let remote_id = if let Status::Connected { .. } = status {
|
||||
let remote_id = if let rpc::Status::Connected { .. } = status {
|
||||
let collaborator_logins = this.read_with(&cx, |this, _| {
|
||||
this.as_local().unwrap().config.collaborators.clone()
|
||||
});
|
||||
@ -2832,16 +2832,19 @@ impl<'a> TryFrom<(&'a CharBag, proto::Entry)> for Entry {
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use rpc_client::test::FakeServer;
|
||||
use crate::fs::FakeFs;
|
||||
use crate::test::*;
|
||||
use anyhow::Result;
|
||||
use fs::RealFs;
|
||||
use rand::prelude::*;
|
||||
use serde_json::json;
|
||||
use std::cell::RefCell;
|
||||
use std::rc::Rc;
|
||||
use std::time::UNIX_EPOCH;
|
||||
use std::{env, fmt::Write, time::SystemTime};
|
||||
use std::{cell::RefCell, rc::Rc};
|
||||
use std::{
|
||||
env,
|
||||
fmt::Write,
|
||||
time::{SystemTime, UNIX_EPOCH},
|
||||
};
|
||||
use util::test::temp_tree;
|
||||
|
||||
#[gpui::test]
|
||||
async fn test_traversal(cx: gpui::TestAppContext) {
|
@ -17,7 +17,9 @@ path = "src/main.rs"
|
||||
test-support = [
|
||||
"buffer/test-support",
|
||||
"gpui/test-support",
|
||||
"rpc_client/test-support",
|
||||
"tempdir",
|
||||
"worktree/test-support",
|
||||
"zrpc/test-support",
|
||||
]
|
||||
|
||||
@ -48,6 +50,7 @@ num_cpus = "1.13.0"
|
||||
parking_lot = "0.11.1"
|
||||
postage = { version = "0.4.1", features = ["futures-traits"] }
|
||||
rand = "0.8.3"
|
||||
rpc_client = { path = "../rpc_client" }
|
||||
rsa = "0.4"
|
||||
rust-embed = { version = "6.2", features = ["include-exclude"] }
|
||||
serde = { version = "1", features = ["derive"] }
|
||||
@ -66,6 +69,8 @@ toml = "0.5"
|
||||
tree-sitter = "0.19.5"
|
||||
tree-sitter-rust = "0.19.0"
|
||||
url = "2.2"
|
||||
util = { path = "../util" }
|
||||
worktree = { path = "../worktree" }
|
||||
zrpc = { path = "../zrpc" }
|
||||
|
||||
[dev-dependencies]
|
||||
@ -75,8 +80,11 @@ serde_json = { version = "1.0.64", features = ["preserve_order"] }
|
||||
tempdir = { version = "0.3.7" }
|
||||
unindent = "0.1.7"
|
||||
buffer = { path = "../buffer", features = ["test-support"] }
|
||||
zrpc = { path = "../zrpc", features = ["test-support"] }
|
||||
gpui = { path = "../gpui", features = ["test-support"] }
|
||||
rpc_client = { path = "../rpc_client", features = ["test-support"] }
|
||||
util = { path = "../util", features = ["test-support"] }
|
||||
worktree = { path = "../worktree", features = ["test-support"] }
|
||||
zrpc = { path = "../zrpc", features = ["test-support"] }
|
||||
|
||||
[package.metadata.bundle]
|
||||
icon = ["app-icon@2x.png", "app-icon.png"]
|
||||
|
@ -1,14 +1,11 @@
|
||||
use crate::{
|
||||
rpc::{self, Client},
|
||||
user::{User, UserStore},
|
||||
util::{post_inc, TryFutureExt},
|
||||
};
|
||||
use crate::user::{User, UserStore};
|
||||
use anyhow::{anyhow, Context, Result};
|
||||
use gpui::{
|
||||
AsyncAppContext, Entity, ModelContext, ModelHandle, MutableAppContext, Task, WeakModelHandle,
|
||||
};
|
||||
use postage::prelude::Stream;
|
||||
use rand::prelude::*;
|
||||
use rpc_client as rpc;
|
||||
use std::{
|
||||
collections::{HashMap, HashSet},
|
||||
mem,
|
||||
@ -17,6 +14,7 @@ use std::{
|
||||
};
|
||||
use sum_tree::{self, Bias, SumTree};
|
||||
use time::OffsetDateTime;
|
||||
use util::{post_inc, TryFutureExt};
|
||||
use zrpc::{
|
||||
proto::{self, ChannelMessageSent},
|
||||
TypedEnvelope,
|
||||
@ -25,7 +23,7 @@ use zrpc::{
|
||||
pub struct ChannelList {
|
||||
available_channels: Option<Vec<ChannelDetails>>,
|
||||
channels: HashMap<u64, WeakModelHandle<Channel>>,
|
||||
rpc: Arc<Client>,
|
||||
rpc: Arc<rpc::Client>,
|
||||
user_store: ModelHandle<UserStore>,
|
||||
_task: Task<Option<()>>,
|
||||
}
|
||||
@ -42,7 +40,7 @@ pub struct Channel {
|
||||
loaded_all_messages: bool,
|
||||
next_pending_message_id: usize,
|
||||
user_store: ModelHandle<UserStore>,
|
||||
rpc: Arc<Client>,
|
||||
rpc: Arc<rpc::Client>,
|
||||
rng: StdRng,
|
||||
_subscription: rpc::Subscription,
|
||||
}
|
||||
@ -187,7 +185,7 @@ impl Channel {
|
||||
pub fn new(
|
||||
details: ChannelDetails,
|
||||
user_store: ModelHandle<UserStore>,
|
||||
rpc: Arc<Client>,
|
||||
rpc: Arc<rpc::Client>,
|
||||
cx: &mut ModelContext<Self>,
|
||||
) -> Self {
|
||||
let _subscription = rpc.subscribe_to_entity(details.id, cx, Self::handle_message_sent);
|
||||
@ -594,14 +592,15 @@ impl<'a> sum_tree::Dimension<'a, ChannelMessageSummary> for Count {
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::test::{FakeHttpClient, FakeServer};
|
||||
use crate::test::FakeHttpClient;
|
||||
use gpui::TestAppContext;
|
||||
use rpc_client::test::FakeServer;
|
||||
use surf::http::Response;
|
||||
|
||||
#[gpui::test]
|
||||
async fn test_channel_messages(mut cx: TestAppContext) {
|
||||
let user_id = 5;
|
||||
let mut client = Client::new();
|
||||
let mut client = rpc::Client::new();
|
||||
let http_client = FakeHttpClient::new(|_| async move { Ok(Response::new(404)) });
|
||||
let server = FakeServer::for_client(user_id, &mut client, &cx).await;
|
||||
let user_store = cx.add_model(|cx| UserStore::new(client.clone(), http_client, cx));
|
||||
|
@ -3,10 +3,7 @@ use std::sync::Arc;
|
||||
use crate::{
|
||||
channel::{Channel, ChannelEvent, ChannelList, ChannelMessage},
|
||||
editor::Editor,
|
||||
rpc::{self, Client},
|
||||
theme,
|
||||
util::{ResultExt, TryFutureExt},
|
||||
Settings,
|
||||
theme, Settings,
|
||||
};
|
||||
use gpui::{
|
||||
action,
|
||||
@ -18,12 +15,14 @@ use gpui::{
|
||||
ViewContext, ViewHandle,
|
||||
};
|
||||
use postage::{prelude::Stream, watch};
|
||||
use rpc_client as rpc;
|
||||
use time::{OffsetDateTime, UtcOffset};
|
||||
use util::{ResultExt, TryFutureExt};
|
||||
|
||||
const MESSAGE_LOADING_THRESHOLD: usize = 50;
|
||||
|
||||
pub struct ChatPanel {
|
||||
rpc: Arc<Client>,
|
||||
rpc: Arc<rpc::Client>,
|
||||
channel_list: ModelHandle<ChannelList>,
|
||||
active_channel: Option<(ModelHandle<Channel>, Subscription)>,
|
||||
message_list: ListState,
|
||||
@ -48,7 +47,7 @@ pub fn init(cx: &mut MutableAppContext) {
|
||||
|
||||
impl ChatPanel {
|
||||
pub fn new(
|
||||
rpc: Arc<Client>,
|
||||
rpc: Arc<rpc::Client>,
|
||||
channel_list: ModelHandle<ChannelList>,
|
||||
settings: watch::Receiver<Settings>,
|
||||
cx: &mut ViewContext<Self>,
|
||||
|
@ -2,14 +2,7 @@ pub mod display_map;
|
||||
mod element;
|
||||
pub mod movement;
|
||||
|
||||
use crate::{
|
||||
project::ProjectPath,
|
||||
settings::Settings,
|
||||
theme::Theme,
|
||||
util::{post_inc, Bias},
|
||||
workspace,
|
||||
worktree::Worktree,
|
||||
};
|
||||
use crate::{project::ProjectPath, settings::Settings, theme::Theme, workspace};
|
||||
use anyhow::Result;
|
||||
use buffer::*;
|
||||
use clock::ReplicaId;
|
||||
@ -35,6 +28,9 @@ use std::{
|
||||
sync::Arc,
|
||||
time::Duration,
|
||||
};
|
||||
use sum_tree::Bias;
|
||||
use util::post_inc;
|
||||
use worktree::Worktree;
|
||||
|
||||
const CURSOR_BLINK_INTERVAL: Duration = Duration::from_millis(500);
|
||||
const MAX_LINE_LEN: usize = 1024;
|
||||
|
@ -357,8 +357,8 @@ impl ToDisplayPoint for Anchor {
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::{editor::movement, test::*, util::RandomCharIter};
|
||||
use buffer::{History, Language, LanguageConfig, SelectionGoal, SyntaxTheme};
|
||||
use crate::{editor::movement, test::*};
|
||||
use buffer::{History, Language, LanguageConfig, RandomCharIter, SelectionGoal, SyntaxTheme};
|
||||
use gpui::{color::Color, MutableAppContext};
|
||||
use rand::{prelude::StdRng, Rng};
|
||||
use std::{env, sync::Arc};
|
||||
|
@ -1128,7 +1128,8 @@ impl FoldEdit {
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::{editor::ToPoint, test::sample_text, util::RandomCharIter};
|
||||
use crate::{editor::ToPoint, test::sample_text};
|
||||
use buffer::RandomCharIter;
|
||||
use rand::prelude::*;
|
||||
use std::{env, mem};
|
||||
use Bias::{Left, Right};
|
||||
|
@ -1,8 +1,8 @@
|
||||
use super::fold_map::{self, FoldEdit, FoldPoint, Snapshot as FoldSnapshot};
|
||||
use crate::util::Bias;
|
||||
use buffer::{rope, HighlightId};
|
||||
use parking_lot::Mutex;
|
||||
use std::{mem, ops::Range};
|
||||
use sum_tree::Bias;
|
||||
|
||||
pub struct TabMap(Mutex<Snapshot>);
|
||||
|
||||
|
@ -2,13 +2,13 @@ use super::{
|
||||
fold_map,
|
||||
tab_map::{self, Edit as TabEdit, Snapshot as TabSnapshot, TabPoint, TextSummary},
|
||||
};
|
||||
use crate::{editor::Point, util::Bias};
|
||||
use crate::editor::Point;
|
||||
use buffer::HighlightId;
|
||||
use gpui::{fonts::FontId, text_layout::LineWrapper, Entity, ModelContext, Task};
|
||||
use lazy_static::lazy_static;
|
||||
use smol::future::yield_now;
|
||||
use std::{collections::VecDeque, ops::Range, time::Duration};
|
||||
use sum_tree::{self, Cursor, SumTree};
|
||||
use sum_tree::{self, Bias, Cursor, SumTree};
|
||||
|
||||
pub struct WrapMap {
|
||||
snapshot: Snapshot,
|
||||
@ -902,8 +902,8 @@ mod tests {
|
||||
Buffer,
|
||||
},
|
||||
test::Observer,
|
||||
util::RandomCharIter,
|
||||
};
|
||||
use buffer::RandomCharIter;
|
||||
use rand::prelude::*;
|
||||
use std::env;
|
||||
|
||||
|
@ -3,7 +3,6 @@ use crate::{
|
||||
fuzzy::PathMatch,
|
||||
project::{Project, ProjectPath},
|
||||
settings::Settings,
|
||||
util,
|
||||
workspace::Workspace,
|
||||
};
|
||||
use gpui::{
|
||||
@ -26,6 +25,7 @@ use std::{
|
||||
Arc,
|
||||
},
|
||||
};
|
||||
use util::post_inc;
|
||||
|
||||
pub struct FileFinder {
|
||||
handle: WeakViewHandle<Self>,
|
||||
@ -315,7 +315,7 @@ impl FileFinder {
|
||||
editor::Event::Edited => {
|
||||
let query = self.query_editor.update(cx, |buffer, cx| buffer.text(cx));
|
||||
if query.is_empty() {
|
||||
self.latest_search_id = util::post_inc(&mut self.search_count);
|
||||
self.latest_search_id = post_inc(&mut self.search_count);
|
||||
self.matches.clear();
|
||||
cx.notify();
|
||||
} else {
|
||||
@ -422,12 +422,12 @@ mod tests {
|
||||
use super::*;
|
||||
use crate::{
|
||||
editor::{self, Insert},
|
||||
fs::FakeFs,
|
||||
test::test_app_state,
|
||||
workspace::Workspace,
|
||||
};
|
||||
use serde_json::json;
|
||||
use std::path::PathBuf;
|
||||
use worktree::fs::FakeFs;
|
||||
|
||||
#[gpui::test]
|
||||
async fn test_matching_paths(mut cx: gpui::TestAppContext) {
|
||||
|
@ -1,12 +1,10 @@
|
||||
use crate::{
|
||||
util,
|
||||
worktree::{EntryKind, Snapshot},
|
||||
};
|
||||
use gpui::executor;
|
||||
use std::{
|
||||
cmp,
|
||||
sync::{atomic::AtomicBool, Arc},
|
||||
};
|
||||
use util;
|
||||
use worktree::{EntryKind, Snapshot};
|
||||
|
||||
pub use fuzzy::*;
|
||||
|
||||
|
@ -3,7 +3,6 @@ pub mod channel;
|
||||
pub mod chat_panel;
|
||||
pub mod editor;
|
||||
pub mod file_finder;
|
||||
pub mod fs;
|
||||
mod fuzzy;
|
||||
pub mod http;
|
||||
pub mod language;
|
||||
@ -11,27 +10,25 @@ pub mod menus;
|
||||
pub mod people_panel;
|
||||
pub mod project;
|
||||
pub mod project_panel;
|
||||
pub mod rpc;
|
||||
pub mod settings;
|
||||
#[cfg(any(test, feature = "test-support"))]
|
||||
pub mod test;
|
||||
pub mod theme;
|
||||
pub mod theme_selector;
|
||||
pub mod user;
|
||||
mod util;
|
||||
pub mod workspace;
|
||||
pub mod worktree;
|
||||
|
||||
use crate::util::TryFutureExt;
|
||||
pub use buffer;
|
||||
use buffer::LanguageRegistry;
|
||||
use channel::ChannelList;
|
||||
use gpui::{action, keymap::Binding, ModelHandle};
|
||||
use parking_lot::Mutex;
|
||||
use postage::watch;
|
||||
use std::sync::Arc;
|
||||
|
||||
pub use rpc_client as rpc;
|
||||
pub use settings::Settings;
|
||||
use std::sync::Arc;
|
||||
use util::TryFutureExt;
|
||||
pub use worktree::{self, fs};
|
||||
|
||||
action!(About);
|
||||
action!(Quit);
|
||||
|
@ -1,25 +1,24 @@
|
||||
use crate::{
|
||||
fs::Fs,
|
||||
fuzzy::{self, PathMatch},
|
||||
rpc::Client,
|
||||
util::TryFutureExt as _,
|
||||
worktree::{self, Worktree},
|
||||
AppState,
|
||||
};
|
||||
use anyhow::Result;
|
||||
use buffer::LanguageRegistry;
|
||||
use futures::Future;
|
||||
use gpui::{AppContext, Entity, ModelContext, ModelHandle, Task};
|
||||
use rpc_client as rpc;
|
||||
use std::{
|
||||
path::Path,
|
||||
sync::{atomic::AtomicBool, Arc},
|
||||
};
|
||||
use util::TryFutureExt as _;
|
||||
use worktree::{fs::Fs, Worktree};
|
||||
|
||||
pub struct Project {
|
||||
worktrees: Vec<ModelHandle<Worktree>>,
|
||||
active_entry: Option<ProjectEntry>,
|
||||
languages: Arc<LanguageRegistry>,
|
||||
rpc: Arc<Client>,
|
||||
rpc: Arc<rpc::Client>,
|
||||
fs: Arc<dyn Fs>,
|
||||
}
|
||||
|
||||
@ -237,12 +236,11 @@ impl Entity for Project {
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::{
|
||||
fs::RealFs,
|
||||
test::{temp_tree, test_app_state},
|
||||
};
|
||||
use crate::test::test_app_state;
|
||||
use serde_json::json;
|
||||
use std::{os::unix, path::PathBuf};
|
||||
use util::test::temp_tree;
|
||||
use worktree::fs::RealFs;
|
||||
|
||||
#[gpui::test]
|
||||
async fn test_populate_and_search(mut cx: gpui::TestAppContext) {
|
||||
|
@ -2,7 +2,6 @@ use crate::{
|
||||
project::{self, Project, ProjectEntry, ProjectPath},
|
||||
theme,
|
||||
workspace::Workspace,
|
||||
worktree::{self, Worktree},
|
||||
Settings,
|
||||
};
|
||||
use gpui::{
|
||||
@ -26,6 +25,7 @@ use std::{
|
||||
ffi::OsStr,
|
||||
ops::Range,
|
||||
};
|
||||
use worktree::Worktree;
|
||||
|
||||
pub struct ProjectPanel {
|
||||
project: ModelHandle<Project>,
|
||||
|
200
zed/src/test.rs
200
zed/src/test.rs
@ -1,32 +1,21 @@
|
||||
use crate::{
|
||||
assets::Assets,
|
||||
channel::ChannelList,
|
||||
fs::FakeFs,
|
||||
http::{HttpClient, Request, Response, ServerResponse},
|
||||
language,
|
||||
rpc::{self, Client, Credentials, EstablishConnectionError},
|
||||
settings::{self, ThemeRegistry},
|
||||
user::UserStore,
|
||||
AppState,
|
||||
};
|
||||
use anyhow::{anyhow, Result};
|
||||
use anyhow::Result;
|
||||
use buffer::LanguageRegistry;
|
||||
use futures::{future::BoxFuture, Future};
|
||||
use gpui::{AsyncAppContext, Entity, ModelHandle, MutableAppContext, TestAppContext};
|
||||
use gpui::{Entity, ModelHandle, MutableAppContext};
|
||||
use parking_lot::Mutex;
|
||||
use postage::{mpsc, prelude::Stream as _};
|
||||
use rpc_client as rpc;
|
||||
use smol::channel;
|
||||
use std::{
|
||||
fmt,
|
||||
marker::PhantomData,
|
||||
path::{Path, PathBuf},
|
||||
sync::{
|
||||
atomic::{AtomicBool, AtomicUsize, Ordering::SeqCst},
|
||||
Arc,
|
||||
},
|
||||
};
|
||||
use tempdir::TempDir;
|
||||
use zrpc::{proto, Connection, ConnectionId, Peer, Receipt, TypedEnvelope};
|
||||
use std::{fmt, marker::PhantomData, sync::Arc};
|
||||
use worktree::fs::FakeFs;
|
||||
|
||||
#[cfg(test)]
|
||||
#[ctor::ctor]
|
||||
@ -47,41 +36,6 @@ pub fn sample_text(rows: usize, cols: usize) -> String {
|
||||
text
|
||||
}
|
||||
|
||||
pub fn temp_tree(tree: serde_json::Value) -> TempDir {
|
||||
let dir = TempDir::new("").unwrap();
|
||||
write_tree(dir.path(), tree);
|
||||
dir
|
||||
}
|
||||
|
||||
fn write_tree(path: &Path, tree: serde_json::Value) {
|
||||
use serde_json::Value;
|
||||
use std::fs;
|
||||
|
||||
if let Value::Object(map) = tree {
|
||||
for (name, contents) in map {
|
||||
let mut path = PathBuf::from(path);
|
||||
path.push(name);
|
||||
match contents {
|
||||
Value::Object(_) => {
|
||||
fs::create_dir(&path).unwrap();
|
||||
write_tree(&path, contents);
|
||||
}
|
||||
Value::Null => {
|
||||
fs::create_dir(&path).unwrap();
|
||||
}
|
||||
Value::String(contents) => {
|
||||
fs::write(&path, contents).unwrap();
|
||||
}
|
||||
_ => {
|
||||
panic!("JSON object must contain only objects, strings, or null");
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
panic!("You must pass a JSON object to this helper")
|
||||
}
|
||||
}
|
||||
|
||||
pub fn test_app_state(cx: &mut MutableAppContext) -> Arc<AppState> {
|
||||
let (settings_tx, settings) = settings::test(cx);
|
||||
let mut languages = LanguageRegistry::new();
|
||||
@ -125,150 +79,6 @@ impl<T: Entity> Observer<T> {
|
||||
}
|
||||
}
|
||||
|
||||
pub struct FakeServer {
|
||||
peer: Arc<Peer>,
|
||||
incoming: Mutex<Option<mpsc::Receiver<Box<dyn proto::AnyTypedEnvelope>>>>,
|
||||
connection_id: Mutex<Option<ConnectionId>>,
|
||||
forbid_connections: AtomicBool,
|
||||
auth_count: AtomicUsize,
|
||||
access_token: AtomicUsize,
|
||||
user_id: u64,
|
||||
}
|
||||
|
||||
impl FakeServer {
|
||||
pub async fn for_client(
|
||||
client_user_id: u64,
|
||||
client: &mut Arc<Client>,
|
||||
cx: &TestAppContext,
|
||||
) -> Arc<Self> {
|
||||
let server = Arc::new(Self {
|
||||
peer: Peer::new(),
|
||||
incoming: Default::default(),
|
||||
connection_id: Default::default(),
|
||||
forbid_connections: Default::default(),
|
||||
auth_count: Default::default(),
|
||||
access_token: Default::default(),
|
||||
user_id: client_user_id,
|
||||
});
|
||||
|
||||
Arc::get_mut(client)
|
||||
.unwrap()
|
||||
.override_authenticate({
|
||||
let server = server.clone();
|
||||
move |cx| {
|
||||
server.auth_count.fetch_add(1, SeqCst);
|
||||
let access_token = server.access_token.load(SeqCst).to_string();
|
||||
cx.spawn(move |_| async move {
|
||||
Ok(Credentials {
|
||||
user_id: client_user_id,
|
||||
access_token,
|
||||
})
|
||||
})
|
||||
}
|
||||
})
|
||||
.override_establish_connection({
|
||||
let server = server.clone();
|
||||
move |credentials, cx| {
|
||||
let credentials = credentials.clone();
|
||||
cx.spawn({
|
||||
let server = server.clone();
|
||||
move |cx| async move { server.establish_connection(&credentials, &cx).await }
|
||||
})
|
||||
}
|
||||
});
|
||||
|
||||
client
|
||||
.authenticate_and_connect(&cx.to_async())
|
||||
.await
|
||||
.unwrap();
|
||||
server
|
||||
}
|
||||
|
||||
pub async fn disconnect(&self) {
|
||||
self.peer.disconnect(self.connection_id()).await;
|
||||
self.connection_id.lock().take();
|
||||
self.incoming.lock().take();
|
||||
}
|
||||
|
||||
async fn establish_connection(
|
||||
&self,
|
||||
credentials: &Credentials,
|
||||
cx: &AsyncAppContext,
|
||||
) -> Result<Connection, EstablishConnectionError> {
|
||||
assert_eq!(credentials.user_id, self.user_id);
|
||||
|
||||
if self.forbid_connections.load(SeqCst) {
|
||||
Err(EstablishConnectionError::Other(anyhow!(
|
||||
"server is forbidding connections"
|
||||
)))?
|
||||
}
|
||||
|
||||
if credentials.access_token != self.access_token.load(SeqCst).to_string() {
|
||||
Err(EstablishConnectionError::Unauthorized)?
|
||||
}
|
||||
|
||||
let (client_conn, server_conn, _) = Connection::in_memory();
|
||||
let (connection_id, io, incoming) = self.peer.add_connection(server_conn).await;
|
||||
cx.background().spawn(io).detach();
|
||||
*self.incoming.lock() = Some(incoming);
|
||||
*self.connection_id.lock() = Some(connection_id);
|
||||
Ok(client_conn)
|
||||
}
|
||||
|
||||
pub fn auth_count(&self) -> usize {
|
||||
self.auth_count.load(SeqCst)
|
||||
}
|
||||
|
||||
pub fn roll_access_token(&self) {
|
||||
self.access_token.fetch_add(1, SeqCst);
|
||||
}
|
||||
|
||||
pub fn forbid_connections(&self) {
|
||||
self.forbid_connections.store(true, SeqCst);
|
||||
}
|
||||
|
||||
pub fn allow_connections(&self) {
|
||||
self.forbid_connections.store(false, SeqCst);
|
||||
}
|
||||
|
||||
pub async fn send<T: proto::EnvelopedMessage>(&self, message: T) {
|
||||
self.peer.send(self.connection_id(), message).await.unwrap();
|
||||
}
|
||||
|
||||
pub async fn receive<M: proto::EnvelopedMessage>(&self) -> Result<TypedEnvelope<M>> {
|
||||
let message = self
|
||||
.incoming
|
||||
.lock()
|
||||
.as_mut()
|
||||
.expect("not connected")
|
||||
.recv()
|
||||
.await
|
||||
.ok_or_else(|| anyhow!("other half hung up"))?;
|
||||
let type_name = message.payload_type_name();
|
||||
Ok(*message
|
||||
.into_any()
|
||||
.downcast::<TypedEnvelope<M>>()
|
||||
.unwrap_or_else(|_| {
|
||||
panic!(
|
||||
"fake server received unexpected message type: {:?}",
|
||||
type_name
|
||||
);
|
||||
}))
|
||||
}
|
||||
|
||||
pub async fn respond<T: proto::RequestMessage>(
|
||||
&self,
|
||||
receipt: Receipt<T>,
|
||||
response: T::Response,
|
||||
) {
|
||||
self.peer.respond(receipt, response).await.unwrap()
|
||||
}
|
||||
|
||||
fn connection_id(&self) -> ConnectionId {
|
||||
self.connection_id.lock().expect("not connected")
|
||||
}
|
||||
}
|
||||
|
||||
pub struct FakeHttpClient {
|
||||
handler:
|
||||
Box<dyn 'static + Send + Sync + Fn(Request) -> BoxFuture<'static, Result<ServerResponse>>>,
|
||||
|
@ -1,16 +1,14 @@
|
||||
use crate::{
|
||||
http::{HttpClient, Method, Request, Url},
|
||||
rpc::{Client, Status},
|
||||
util::TryFutureExt,
|
||||
};
|
||||
use crate::http::{HttpClient, Method, Request, Url};
|
||||
use anyhow::{anyhow, Context, Result};
|
||||
use futures::future;
|
||||
use gpui::{AsyncAppContext, Entity, ImageData, ModelContext, ModelHandle, Task};
|
||||
use postage::{prelude::Stream, sink::Sink, watch};
|
||||
use rpc_client as rpc;
|
||||
use std::{
|
||||
collections::{HashMap, HashSet},
|
||||
sync::Arc,
|
||||
};
|
||||
use util::TryFutureExt as _;
|
||||
use zrpc::{proto, TypedEnvelope};
|
||||
|
||||
#[derive(Debug)]
|
||||
@ -38,7 +36,7 @@ pub struct UserStore {
|
||||
users: HashMap<u64, Arc<User>>,
|
||||
current_user: watch::Receiver<Option<Arc<User>>>,
|
||||
collaborators: Arc<[Collaborator]>,
|
||||
rpc: Arc<Client>,
|
||||
rpc: Arc<rpc::Client>,
|
||||
http: Arc<dyn HttpClient>,
|
||||
_maintain_collaborators: Task<()>,
|
||||
_maintain_current_user: Task<()>,
|
||||
@ -51,7 +49,11 @@ impl Entity for UserStore {
|
||||
}
|
||||
|
||||
impl UserStore {
|
||||
pub fn new(rpc: Arc<Client>, http: Arc<dyn HttpClient>, cx: &mut ModelContext<Self>) -> Self {
|
||||
pub fn new(
|
||||
rpc: Arc<rpc::Client>,
|
||||
http: Arc<dyn HttpClient>,
|
||||
cx: &mut ModelContext<Self>,
|
||||
) -> Self {
|
||||
let (mut current_user_tx, current_user_rx) = watch::channel();
|
||||
let (mut update_collaborators_tx, mut update_collaborators_rx) =
|
||||
watch::channel::<Option<proto::UpdateCollaborators>>();
|
||||
@ -82,7 +84,7 @@ impl UserStore {
|
||||
let mut status = rpc.status();
|
||||
while let Some(status) = status.recv().await {
|
||||
match status {
|
||||
Status::Connected { .. } => {
|
||||
rpc::Status::Connected { .. } => {
|
||||
if let Some((this, user_id)) = this.upgrade(&cx).zip(rpc.user_id()) {
|
||||
let user = this
|
||||
.update(&mut cx, |this, cx| this.fetch_user(user_id, cx))
|
||||
@ -91,7 +93,7 @@ impl UserStore {
|
||||
current_user_tx.send(user).await.ok();
|
||||
}
|
||||
}
|
||||
Status::SignedOut => {
|
||||
rpc::Status::SignedOut => {
|
||||
current_user_tx.send(None).await.ok();
|
||||
}
|
||||
_ => {}
|
||||
|
@ -12,7 +12,6 @@ use crate::{
|
||||
settings::Settings,
|
||||
user,
|
||||
workspace::sidebar::{Side, Sidebar, SidebarItemId, ToggleSidebarItem, ToggleSidebarItemFocus},
|
||||
worktree::Worktree,
|
||||
AppState, Authenticate,
|
||||
};
|
||||
use anyhow::Result;
|
||||
@ -38,6 +37,7 @@ use std::{
|
||||
path::{Path, PathBuf},
|
||||
sync::Arc,
|
||||
};
|
||||
use worktree::Worktree;
|
||||
|
||||
action!(Open, Arc<AppState>);
|
||||
action!(OpenPaths, OpenParams);
|
||||
@ -1159,10 +1159,11 @@ mod tests {
|
||||
use crate::{
|
||||
editor::{Editor, Insert},
|
||||
fs::FakeFs,
|
||||
test::{temp_tree, test_app_state},
|
||||
test::test_app_state,
|
||||
};
|
||||
use serde_json::json;
|
||||
use std::collections::HashSet;
|
||||
use util::test::temp_tree;
|
||||
|
||||
#[gpui::test]
|
||||
async fn test_open_paths_action(mut cx: gpui::TestAppContext) {
|
||||
|
Loading…
Reference in New Issue
Block a user