mirror of
https://github.com/zed-industries/zed.git
synced 2024-11-08 07:35:01 +03:00
Add remove channel method
Move test client fields into appstate and fix tests Co-authored-by: max <max@zed.dev>
This commit is contained in:
parent
56d4d5d1a8
commit
74437b3988
@ -51,6 +51,10 @@ impl ChannelStore {
|
|||||||
&self.channel_invitations
|
&self.channel_invitations
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn channel_for_id(&self, channel_id: u64) -> Option<Arc<Channel>> {
|
||||||
|
self.channels.iter().find(|c| c.id == channel_id).cloned()
|
||||||
|
}
|
||||||
|
|
||||||
pub fn create_channel(
|
pub fn create_channel(
|
||||||
&self,
|
&self,
|
||||||
name: &str,
|
name: &str,
|
||||||
@ -103,6 +107,14 @@ impl ChannelStore {
|
|||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn remove_channel(&self, channel_id: u64) -> impl Future<Output = Result<()>> {
|
||||||
|
let client = self.client.clone();
|
||||||
|
async move {
|
||||||
|
client.request(proto::RemoveChannel { channel_id }).await?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn remove_member(
|
pub fn remove_member(
|
||||||
&self,
|
&self,
|
||||||
channel_id: u64,
|
channel_id: u64,
|
||||||
|
@ -575,7 +575,10 @@ impl Client {
|
|||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
if prev_handler.is_some() {
|
if prev_handler.is_some() {
|
||||||
panic!("registered handler for the same message twice");
|
panic!(
|
||||||
|
"registered handler for the same message {} twice",
|
||||||
|
std::any::type_name::<M>()
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Subscription::Message {
|
Subscription::Message {
|
||||||
|
@ -44,6 +44,7 @@ use serde::{Deserialize, Serialize};
|
|||||||
pub use signup::{Invite, NewSignup, WaitlistSummary};
|
pub use signup::{Invite, NewSignup, WaitlistSummary};
|
||||||
use sqlx::migrate::{Migrate, Migration, MigrationSource};
|
use sqlx::migrate::{Migrate, Migration, MigrationSource};
|
||||||
use sqlx::Connection;
|
use sqlx::Connection;
|
||||||
|
use std::fmt::Write as _;
|
||||||
use std::ops::{Deref, DerefMut};
|
use std::ops::{Deref, DerefMut};
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
@ -3131,6 +3132,74 @@ impl Database {
|
|||||||
.await
|
.await
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub async fn remove_channel(
|
||||||
|
&self,
|
||||||
|
channel_id: ChannelId,
|
||||||
|
user_id: UserId,
|
||||||
|
) -> Result<(Vec<ChannelId>, Vec<UserId>)> {
|
||||||
|
self.transaction(move |tx| async move {
|
||||||
|
let tx = tx;
|
||||||
|
|
||||||
|
// Check if user is an admin
|
||||||
|
channel_member::Entity::find()
|
||||||
|
.filter(
|
||||||
|
channel_member::Column::ChannelId
|
||||||
|
.eq(channel_id)
|
||||||
|
.and(channel_member::Column::UserId.eq(user_id))
|
||||||
|
.and(channel_member::Column::Admin.eq(true)),
|
||||||
|
)
|
||||||
|
.one(&*tx)
|
||||||
|
.await?
|
||||||
|
.ok_or_else(|| anyhow!("user is not allowed to remove this channel"))?;
|
||||||
|
|
||||||
|
let mut descendants = self.get_channel_descendants([channel_id], &*tx).await?;
|
||||||
|
|
||||||
|
// Keep channels which have another active
|
||||||
|
let mut channels_to_keep = channel_parent::Entity::find()
|
||||||
|
.filter(
|
||||||
|
channel_parent::Column::ChildId
|
||||||
|
.is_in(descendants.keys().copied().filter(|&id| id != channel_id))
|
||||||
|
.and(
|
||||||
|
channel_parent::Column::ParentId.is_not_in(descendants.keys().copied()),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
.stream(&*tx)
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
while let Some(row) = channels_to_keep.next().await {
|
||||||
|
let row = row?;
|
||||||
|
descendants.remove(&row.child_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
drop(channels_to_keep);
|
||||||
|
|
||||||
|
let channels_to_remove = descendants.keys().copied().collect::<Vec<_>>();
|
||||||
|
|
||||||
|
#[derive(Copy, Clone, Debug, EnumIter, DeriveColumn)]
|
||||||
|
enum QueryUserIds {
|
||||||
|
UserId,
|
||||||
|
}
|
||||||
|
|
||||||
|
let members_to_notify: Vec<UserId> = channel_member::Entity::find()
|
||||||
|
.filter(channel_member::Column::ChannelId.is_in(channels_to_remove.iter().copied()))
|
||||||
|
.select_only()
|
||||||
|
.column(channel_member::Column::UserId)
|
||||||
|
.distinct()
|
||||||
|
.into_values::<_, QueryUserIds>()
|
||||||
|
.all(&*tx)
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
// Channel members and parents should delete via cascade
|
||||||
|
channel::Entity::delete_many()
|
||||||
|
.filter(channel::Column::Id.is_in(channels_to_remove.iter().copied()))
|
||||||
|
.exec(&*tx)
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
Ok((channels_to_remove, members_to_notify))
|
||||||
|
})
|
||||||
|
.await
|
||||||
|
}
|
||||||
|
|
||||||
pub async fn invite_channel_member(
|
pub async fn invite_channel_member(
|
||||||
&self,
|
&self,
|
||||||
channel_id: ChannelId,
|
channel_id: ChannelId,
|
||||||
@ -3256,50 +3325,32 @@ impl Database {
|
|||||||
self.transaction(|tx| async move {
|
self.transaction(|tx| async move {
|
||||||
let tx = tx;
|
let tx = tx;
|
||||||
|
|
||||||
// Breadth first list of all edges in this user's channels
|
#[derive(Copy, Clone, Debug, EnumIter, DeriveColumn)]
|
||||||
let sql = r#"
|
enum QueryChannelIds {
|
||||||
WITH RECURSIVE channel_tree(child_id, parent_id, depth) AS (
|
ChannelId,
|
||||||
SELECT channel_id as child_id, CAST(NULL as INTEGER) as parent_id, 0
|
|
||||||
FROM channel_members
|
|
||||||
WHERE user_id = $1 AND accepted
|
|
||||||
UNION
|
|
||||||
SELECT channel_parents.child_id, channel_parents.parent_id, channel_tree.depth + 1
|
|
||||||
FROM channel_parents, channel_tree
|
|
||||||
WHERE channel_parents.parent_id = channel_tree.child_id
|
|
||||||
)
|
|
||||||
SELECT channel_tree.child_id, channel_tree.parent_id
|
|
||||||
FROM channel_tree
|
|
||||||
ORDER BY child_id, parent_id IS NOT NULL
|
|
||||||
"#;
|
|
||||||
|
|
||||||
#[derive(FromQueryResult, Debug, PartialEq)]
|
|
||||||
pub struct ChannelParent {
|
|
||||||
pub child_id: ChannelId,
|
|
||||||
pub parent_id: Option<ChannelId>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let stmt = Statement::from_sql_and_values(
|
let starting_channel_ids: Vec<ChannelId> = channel_member::Entity::find()
|
||||||
self.pool.get_database_backend(),
|
.filter(
|
||||||
sql,
|
channel_member::Column::UserId
|
||||||
vec![user_id.into()],
|
.eq(user_id)
|
||||||
);
|
.and(channel_member::Column::Accepted.eq(true)),
|
||||||
|
)
|
||||||
|
.select_only()
|
||||||
|
.column(channel_member::Column::ChannelId)
|
||||||
|
.into_values::<_, QueryChannelIds>()
|
||||||
|
.all(&*tx)
|
||||||
|
.await?;
|
||||||
|
|
||||||
let mut parents_by_child_id = HashMap::default();
|
let parents_by_child_id = self
|
||||||
let mut parents = channel_parent::Entity::find()
|
.get_channel_descendants(starting_channel_ids, &*tx)
|
||||||
.from_raw_sql(stmt)
|
.await?;
|
||||||
.into_model::<ChannelParent>()
|
|
||||||
.stream(&*tx).await?;
|
|
||||||
while let Some(parent) = parents.next().await {
|
|
||||||
let parent = parent?;
|
|
||||||
parents_by_child_id.insert(parent.child_id, parent.parent_id);
|
|
||||||
}
|
|
||||||
|
|
||||||
drop(parents);
|
|
||||||
|
|
||||||
let mut channels = Vec::with_capacity(parents_by_child_id.len());
|
let mut channels = Vec::with_capacity(parents_by_child_id.len());
|
||||||
let mut rows = channel::Entity::find()
|
let mut rows = channel::Entity::find()
|
||||||
.filter(channel::Column::Id.is_in(parents_by_child_id.keys().copied()))
|
.filter(channel::Column::Id.is_in(parents_by_child_id.keys().copied()))
|
||||||
.stream(&*tx).await?;
|
.stream(&*tx)
|
||||||
|
.await?;
|
||||||
|
|
||||||
while let Some(row) = rows.next().await {
|
while let Some(row) = rows.next().await {
|
||||||
let row = row?;
|
let row = row?;
|
||||||
@ -3317,18 +3368,73 @@ impl Database {
|
|||||||
.await
|
.await
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn get_channel(&self, channel_id: ChannelId) -> Result<Channel> {
|
async fn get_channel_descendants(
|
||||||
|
&self,
|
||||||
|
channel_ids: impl IntoIterator<Item = ChannelId>,
|
||||||
|
tx: &DatabaseTransaction,
|
||||||
|
) -> Result<HashMap<ChannelId, Option<ChannelId>>> {
|
||||||
|
let mut values = String::new();
|
||||||
|
for id in channel_ids {
|
||||||
|
if !values.is_empty() {
|
||||||
|
values.push_str(", ");
|
||||||
|
}
|
||||||
|
write!(&mut values, "({})", id).unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
if values.is_empty() {
|
||||||
|
return Ok(HashMap::default());
|
||||||
|
}
|
||||||
|
|
||||||
|
let sql = format!(
|
||||||
|
r#"
|
||||||
|
WITH RECURSIVE channel_tree(child_id, parent_id) AS (
|
||||||
|
SELECT root_ids.column1 as child_id, CAST(NULL as INTEGER) as parent_id
|
||||||
|
FROM (VALUES {}) as root_ids
|
||||||
|
UNION
|
||||||
|
SELECT channel_parents.child_id, channel_parents.parent_id
|
||||||
|
FROM channel_parents, channel_tree
|
||||||
|
WHERE channel_parents.parent_id = channel_tree.child_id
|
||||||
|
)
|
||||||
|
SELECT channel_tree.child_id, channel_tree.parent_id
|
||||||
|
FROM channel_tree
|
||||||
|
ORDER BY child_id, parent_id IS NOT NULL
|
||||||
|
"#,
|
||||||
|
values
|
||||||
|
);
|
||||||
|
|
||||||
|
#[derive(FromQueryResult, Debug, PartialEq)]
|
||||||
|
pub struct ChannelParent {
|
||||||
|
pub child_id: ChannelId,
|
||||||
|
pub parent_id: Option<ChannelId>,
|
||||||
|
}
|
||||||
|
|
||||||
|
let stmt = Statement::from_string(self.pool.get_database_backend(), sql);
|
||||||
|
|
||||||
|
let mut parents_by_child_id = HashMap::default();
|
||||||
|
let mut parents = channel_parent::Entity::find()
|
||||||
|
.from_raw_sql(stmt)
|
||||||
|
.into_model::<ChannelParent>()
|
||||||
|
.stream(tx)
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
while let Some(parent) = parents.next().await {
|
||||||
|
let parent = parent?;
|
||||||
|
parents_by_child_id.insert(parent.child_id, parent.parent_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(parents_by_child_id)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn get_channel(&self, channel_id: ChannelId) -> Result<Option<Channel>> {
|
||||||
self.transaction(|tx| async move {
|
self.transaction(|tx| async move {
|
||||||
let tx = tx;
|
let tx = tx;
|
||||||
let channel = channel::Entity::find_by_id(channel_id)
|
let channel = channel::Entity::find_by_id(channel_id).one(&*tx).await?;
|
||||||
.one(&*tx)
|
|
||||||
.await?
|
Ok(channel.map(|channel| Channel {
|
||||||
.ok_or_else(|| anyhow!("no such channel"))?;
|
|
||||||
Ok(Channel {
|
|
||||||
id: channel.id,
|
id: channel.id,
|
||||||
name: channel.name,
|
name: channel.name,
|
||||||
parent_id: None,
|
parent_id: None,
|
||||||
})
|
}))
|
||||||
})
|
})
|
||||||
.await
|
.await
|
||||||
}
|
}
|
||||||
|
@ -918,6 +918,11 @@ test_both_dbs!(test_channels_postgres, test_channels_sqlite, db, {
|
|||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
|
let cargo_ra_id = db
|
||||||
|
.create_channel("cargo-ra", Some(cargo_id), "7", a_id)
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
let channels = db.get_channels(a_id).await.unwrap();
|
let channels = db.get_channels(a_id).await.unwrap();
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
@ -952,9 +957,28 @@ test_both_dbs!(test_channels_postgres, test_channels_sqlite, db, {
|
|||||||
id: cargo_id,
|
id: cargo_id,
|
||||||
name: "cargo".to_string(),
|
name: "cargo".to_string(),
|
||||||
parent_id: Some(rust_id),
|
parent_id: Some(rust_id),
|
||||||
|
},
|
||||||
|
Channel {
|
||||||
|
id: cargo_ra_id,
|
||||||
|
name: "cargo-ra".to_string(),
|
||||||
|
parent_id: Some(cargo_id),
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// Remove a single channel
|
||||||
|
db.remove_channel(crdb_id, a_id).await.unwrap();
|
||||||
|
assert!(db.get_channel(crdb_id).await.unwrap().is_none());
|
||||||
|
|
||||||
|
// Remove a channel tree
|
||||||
|
let (mut channel_ids, user_ids) = db.remove_channel(rust_id, a_id).await.unwrap();
|
||||||
|
channel_ids.sort();
|
||||||
|
assert_eq!(channel_ids, &[rust_id, cargo_id, cargo_ra_id]);
|
||||||
|
assert_eq!(user_ids, &[a_id]);
|
||||||
|
|
||||||
|
assert!(db.get_channel(rust_id).await.unwrap().is_none());
|
||||||
|
assert!(db.get_channel(cargo_id).await.unwrap().is_none());
|
||||||
|
assert!(db.get_channel(cargo_ra_id).await.unwrap().is_none());
|
||||||
});
|
});
|
||||||
|
|
||||||
test_both_dbs!(
|
test_both_dbs!(
|
||||||
|
@ -243,6 +243,7 @@ impl Server {
|
|||||||
.add_request_handler(remove_contact)
|
.add_request_handler(remove_contact)
|
||||||
.add_request_handler(respond_to_contact_request)
|
.add_request_handler(respond_to_contact_request)
|
||||||
.add_request_handler(create_channel)
|
.add_request_handler(create_channel)
|
||||||
|
.add_request_handler(remove_channel)
|
||||||
.add_request_handler(invite_channel_member)
|
.add_request_handler(invite_channel_member)
|
||||||
.add_request_handler(remove_channel_member)
|
.add_request_handler(remove_channel_member)
|
||||||
.add_request_handler(respond_to_channel_invite)
|
.add_request_handler(respond_to_channel_invite)
|
||||||
@ -529,7 +530,6 @@ impl Server {
|
|||||||
this.peer.send(connection_id, build_initial_contacts_update(contacts, &pool))?;
|
this.peer.send(connection_id, build_initial_contacts_update(contacts, &pool))?;
|
||||||
this.peer.send(connection_id, build_initial_channels_update(channels, channel_invites))?;
|
this.peer.send(connection_id, build_initial_channels_update(channels, channel_invites))?;
|
||||||
|
|
||||||
|
|
||||||
if let Some((code, count)) = invite_code {
|
if let Some((code, count)) = invite_code {
|
||||||
this.peer.send(connection_id, proto::UpdateInviteInfo {
|
this.peer.send(connection_id, proto::UpdateInviteInfo {
|
||||||
url: format!("{}{}", this.app_state.config.invite_link_prefix, code),
|
url: format!("{}{}", this.app_state.config.invite_link_prefix, code),
|
||||||
@ -2101,7 +2101,6 @@ async fn create_channel(
|
|||||||
response: Response<proto::CreateChannel>,
|
response: Response<proto::CreateChannel>,
|
||||||
session: Session,
|
session: Session,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
dbg!(&request);
|
|
||||||
let db = session.db().await;
|
let db = session.db().await;
|
||||||
let live_kit_room = format!("channel-{}", nanoid::nanoid!(30));
|
let live_kit_room = format!("channel-{}", nanoid::nanoid!(30));
|
||||||
|
|
||||||
@ -2132,6 +2131,35 @@ async fn create_channel(
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async fn remove_channel(
|
||||||
|
request: proto::RemoveChannel,
|
||||||
|
response: Response<proto::RemoveChannel>,
|
||||||
|
session: Session,
|
||||||
|
) -> Result<()> {
|
||||||
|
let db = session.db().await;
|
||||||
|
|
||||||
|
let channel_id = request.channel_id;
|
||||||
|
let (removed_channels, member_ids) = db
|
||||||
|
.remove_channel(ChannelId::from_proto(channel_id), session.user_id)
|
||||||
|
.await?;
|
||||||
|
response.send(proto::Ack {})?;
|
||||||
|
|
||||||
|
// Notify members of removed channels
|
||||||
|
let mut update = proto::UpdateChannels::default();
|
||||||
|
update
|
||||||
|
.remove_channels
|
||||||
|
.extend(removed_channels.into_iter().map(|id| id.to_proto()));
|
||||||
|
|
||||||
|
let connection_pool = session.connection_pool().await;
|
||||||
|
for member_id in member_ids {
|
||||||
|
for connection_id in connection_pool.user_connection_ids(member_id) {
|
||||||
|
session.peer.send(connection_id, update.clone())?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
async fn invite_channel_member(
|
async fn invite_channel_member(
|
||||||
request: proto::InviteChannelMember,
|
request: proto::InviteChannelMember,
|
||||||
response: Response<proto::InviteChannelMember>,
|
response: Response<proto::InviteChannelMember>,
|
||||||
@ -2139,7 +2167,10 @@ async fn invite_channel_member(
|
|||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
let db = session.db().await;
|
let db = session.db().await;
|
||||||
let channel_id = ChannelId::from_proto(request.channel_id);
|
let channel_id = ChannelId::from_proto(request.channel_id);
|
||||||
let channel = db.get_channel(channel_id).await?;
|
let channel = db
|
||||||
|
.get_channel(channel_id)
|
||||||
|
.await?
|
||||||
|
.ok_or_else(|| anyhow!("channel not found"))?;
|
||||||
let invitee_id = UserId::from_proto(request.user_id);
|
let invitee_id = UserId::from_proto(request.user_id);
|
||||||
db.invite_channel_member(channel_id, invitee_id, session.user_id, false)
|
db.invite_channel_member(channel_id, invitee_id, session.user_id, false)
|
||||||
.await?;
|
.await?;
|
||||||
@ -2177,7 +2208,10 @@ async fn respond_to_channel_invite(
|
|||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
let db = session.db().await;
|
let db = session.db().await;
|
||||||
let channel_id = ChannelId::from_proto(request.channel_id);
|
let channel_id = ChannelId::from_proto(request.channel_id);
|
||||||
let channel = db.get_channel(channel_id).await?;
|
let channel = db
|
||||||
|
.get_channel(channel_id)
|
||||||
|
.await?
|
||||||
|
.ok_or_else(|| anyhow!("no such channel"))?;
|
||||||
db.respond_to_channel_invite(channel_id, session.user_id, request.accept)
|
db.respond_to_channel_invite(channel_id, session.user_id, request.accept)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
|
@ -14,8 +14,8 @@ use collections::{HashMap, HashSet};
|
|||||||
use fs::FakeFs;
|
use fs::FakeFs;
|
||||||
use futures::{channel::oneshot, StreamExt as _};
|
use futures::{channel::oneshot, StreamExt as _};
|
||||||
use gpui::{
|
use gpui::{
|
||||||
elements::*, executor::Deterministic, AnyElement, Entity, ModelHandle, TestAppContext, View,
|
elements::*, executor::Deterministic, AnyElement, Entity, ModelHandle, Task, TestAppContext,
|
||||||
ViewContext, ViewHandle, WeakViewHandle,
|
View, ViewContext, ViewHandle, WeakViewHandle,
|
||||||
};
|
};
|
||||||
use language::LanguageRegistry;
|
use language::LanguageRegistry;
|
||||||
use parking_lot::Mutex;
|
use parking_lot::Mutex;
|
||||||
@ -197,7 +197,7 @@ impl TestServer {
|
|||||||
languages: Arc::new(LanguageRegistry::test()),
|
languages: Arc::new(LanguageRegistry::test()),
|
||||||
fs: fs.clone(),
|
fs: fs.clone(),
|
||||||
build_window_options: |_, _, _| Default::default(),
|
build_window_options: |_, _, _| Default::default(),
|
||||||
initialize_workspace: |_, _, _, _| unimplemented!(),
|
initialize_workspace: |_, _, _, _| Task::ready(Ok(())),
|
||||||
background_actions: || &[],
|
background_actions: || &[],
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -218,13 +218,9 @@ impl TestServer {
|
|||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let client = TestClient {
|
let client = TestClient {
|
||||||
client,
|
app_state,
|
||||||
username: name.to_string(),
|
username: name.to_string(),
|
||||||
state: Default::default(),
|
state: Default::default(),
|
||||||
user_store,
|
|
||||||
channel_store,
|
|
||||||
fs,
|
|
||||||
language_registry: Arc::new(LanguageRegistry::test()),
|
|
||||||
};
|
};
|
||||||
client.wait_for_current_user(cx).await;
|
client.wait_for_current_user(cx).await;
|
||||||
client
|
client
|
||||||
@ -252,6 +248,7 @@ impl TestServer {
|
|||||||
let (client_a, cx_a) = left.last_mut().unwrap();
|
let (client_a, cx_a) = left.last_mut().unwrap();
|
||||||
for (client_b, cx_b) in right {
|
for (client_b, cx_b) in right {
|
||||||
client_a
|
client_a
|
||||||
|
.app_state
|
||||||
.user_store
|
.user_store
|
||||||
.update(*cx_a, |store, cx| {
|
.update(*cx_a, |store, cx| {
|
||||||
store.request_contact(client_b.user_id().unwrap(), cx)
|
store.request_contact(client_b.user_id().unwrap(), cx)
|
||||||
@ -260,6 +257,7 @@ impl TestServer {
|
|||||||
.unwrap();
|
.unwrap();
|
||||||
cx_a.foreground().run_until_parked();
|
cx_a.foreground().run_until_parked();
|
||||||
client_b
|
client_b
|
||||||
|
.app_state
|
||||||
.user_store
|
.user_store
|
||||||
.update(*cx_b, |store, cx| {
|
.update(*cx_b, |store, cx| {
|
||||||
store.respond_to_contact_request(client_a.user_id().unwrap(), true, cx)
|
store.respond_to_contact_request(client_a.user_id().unwrap(), true, cx)
|
||||||
@ -278,6 +276,7 @@ impl TestServer {
|
|||||||
) -> u64 {
|
) -> u64 {
|
||||||
let (admin_client, admin_cx) = admin;
|
let (admin_client, admin_cx) = admin;
|
||||||
let channel_id = admin_client
|
let channel_id = admin_client
|
||||||
|
.app_state
|
||||||
.channel_store
|
.channel_store
|
||||||
.update(admin_cx, |channel_store, _| {
|
.update(admin_cx, |channel_store, _| {
|
||||||
channel_store.create_channel(channel, None)
|
channel_store.create_channel(channel, None)
|
||||||
@ -287,6 +286,7 @@ impl TestServer {
|
|||||||
|
|
||||||
for (member_client, member_cx) in members {
|
for (member_client, member_cx) in members {
|
||||||
admin_client
|
admin_client
|
||||||
|
.app_state
|
||||||
.channel_store
|
.channel_store
|
||||||
.update(admin_cx, |channel_store, _| {
|
.update(admin_cx, |channel_store, _| {
|
||||||
channel_store.invite_member(channel_id, member_client.user_id().unwrap(), false)
|
channel_store.invite_member(channel_id, member_client.user_id().unwrap(), false)
|
||||||
@ -297,6 +297,7 @@ impl TestServer {
|
|||||||
admin_cx.foreground().run_until_parked();
|
admin_cx.foreground().run_until_parked();
|
||||||
|
|
||||||
member_client
|
member_client
|
||||||
|
.app_state
|
||||||
.channel_store
|
.channel_store
|
||||||
.update(*member_cx, |channels, _| {
|
.update(*member_cx, |channels, _| {
|
||||||
channels.respond_to_channel_invite(channel_id, true)
|
channels.respond_to_channel_invite(channel_id, true)
|
||||||
@ -359,13 +360,9 @@ impl Drop for TestServer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
struct TestClient {
|
struct TestClient {
|
||||||
client: Arc<Client>,
|
|
||||||
username: String,
|
username: String,
|
||||||
state: RefCell<TestClientState>,
|
state: RefCell<TestClientState>,
|
||||||
pub user_store: ModelHandle<UserStore>,
|
app_state: Arc<workspace::AppState>,
|
||||||
pub channel_store: ModelHandle<ChannelStore>,
|
|
||||||
language_registry: Arc<LanguageRegistry>,
|
|
||||||
fs: Arc<FakeFs>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
@ -379,7 +376,7 @@ impl Deref for TestClient {
|
|||||||
type Target = Arc<Client>;
|
type Target = Arc<Client>;
|
||||||
|
|
||||||
fn deref(&self) -> &Self::Target {
|
fn deref(&self) -> &Self::Target {
|
||||||
&self.client
|
&self.app_state.client
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -390,22 +387,45 @@ struct ContactsSummary {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl TestClient {
|
impl TestClient {
|
||||||
|
pub fn fs(&self) -> &FakeFs {
|
||||||
|
self.app_state.fs.as_fake()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn channel_store(&self) -> &ModelHandle<ChannelStore> {
|
||||||
|
&self.app_state.channel_store
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn user_store(&self) -> &ModelHandle<UserStore> {
|
||||||
|
&self.app_state.user_store
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn language_registry(&self) -> &Arc<LanguageRegistry> {
|
||||||
|
&self.app_state.languages
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn client(&self) -> &Arc<Client> {
|
||||||
|
&self.app_state.client
|
||||||
|
}
|
||||||
|
|
||||||
pub fn current_user_id(&self, cx: &TestAppContext) -> UserId {
|
pub fn current_user_id(&self, cx: &TestAppContext) -> UserId {
|
||||||
UserId::from_proto(
|
UserId::from_proto(
|
||||||
self.user_store
|
self.app_state
|
||||||
|
.user_store
|
||||||
.read_with(cx, |user_store, _| user_store.current_user().unwrap().id),
|
.read_with(cx, |user_store, _| user_store.current_user().unwrap().id),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn wait_for_current_user(&self, cx: &TestAppContext) {
|
async fn wait_for_current_user(&self, cx: &TestAppContext) {
|
||||||
let mut authed_user = self
|
let mut authed_user = self
|
||||||
|
.app_state
|
||||||
.user_store
|
.user_store
|
||||||
.read_with(cx, |user_store, _| user_store.watch_current_user());
|
.read_with(cx, |user_store, _| user_store.watch_current_user());
|
||||||
while authed_user.next().await.unwrap().is_none() {}
|
while authed_user.next().await.unwrap().is_none() {}
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn clear_contacts(&self, cx: &mut TestAppContext) {
|
async fn clear_contacts(&self, cx: &mut TestAppContext) {
|
||||||
self.user_store
|
self.app_state
|
||||||
|
.user_store
|
||||||
.update(cx, |store, _| store.clear_contacts())
|
.update(cx, |store, _| store.clear_contacts())
|
||||||
.await;
|
.await;
|
||||||
}
|
}
|
||||||
@ -443,23 +463,25 @@ impl TestClient {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn summarize_contacts(&self, cx: &TestAppContext) -> ContactsSummary {
|
fn summarize_contacts(&self, cx: &TestAppContext) -> ContactsSummary {
|
||||||
self.user_store.read_with(cx, |store, _| ContactsSummary {
|
self.app_state
|
||||||
current: store
|
.user_store
|
||||||
.contacts()
|
.read_with(cx, |store, _| ContactsSummary {
|
||||||
.iter()
|
current: store
|
||||||
.map(|contact| contact.user.github_login.clone())
|
.contacts()
|
||||||
.collect(),
|
.iter()
|
||||||
outgoing_requests: store
|
.map(|contact| contact.user.github_login.clone())
|
||||||
.outgoing_contact_requests()
|
.collect(),
|
||||||
.iter()
|
outgoing_requests: store
|
||||||
.map(|user| user.github_login.clone())
|
.outgoing_contact_requests()
|
||||||
.collect(),
|
.iter()
|
||||||
incoming_requests: store
|
.map(|user| user.github_login.clone())
|
||||||
.incoming_contact_requests()
|
.collect(),
|
||||||
.iter()
|
incoming_requests: store
|
||||||
.map(|user| user.github_login.clone())
|
.incoming_contact_requests()
|
||||||
.collect(),
|
.iter()
|
||||||
})
|
.map(|user| user.github_login.clone())
|
||||||
|
.collect(),
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn build_local_project(
|
async fn build_local_project(
|
||||||
@ -469,10 +491,10 @@ impl TestClient {
|
|||||||
) -> (ModelHandle<Project>, WorktreeId) {
|
) -> (ModelHandle<Project>, WorktreeId) {
|
||||||
let project = cx.update(|cx| {
|
let project = cx.update(|cx| {
|
||||||
Project::local(
|
Project::local(
|
||||||
self.client.clone(),
|
self.client().clone(),
|
||||||
self.user_store.clone(),
|
self.app_state.user_store.clone(),
|
||||||
self.language_registry.clone(),
|
self.app_state.languages.clone(),
|
||||||
self.fs.clone(),
|
self.app_state.fs.clone(),
|
||||||
cx,
|
cx,
|
||||||
)
|
)
|
||||||
});
|
});
|
||||||
@ -498,8 +520,8 @@ impl TestClient {
|
|||||||
room.update(guest_cx, |room, cx| {
|
room.update(guest_cx, |room, cx| {
|
||||||
room.join_project(
|
room.join_project(
|
||||||
host_project_id,
|
host_project_id,
|
||||||
self.language_registry.clone(),
|
self.app_state.languages.clone(),
|
||||||
self.fs.clone(),
|
self.app_state.fs.clone(),
|
||||||
cx,
|
cx,
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
@ -541,7 +563,9 @@ impl TestClient {
|
|||||||
// We use a workspace container so that we don't need to remove the window in order to
|
// We use a workspace container so that we don't need to remove the window in order to
|
||||||
// drop the workspace and we can use a ViewHandle instead.
|
// drop the workspace and we can use a ViewHandle instead.
|
||||||
let (window_id, container) = cx.add_window(|_| WorkspaceContainer { workspace: None });
|
let (window_id, container) = cx.add_window(|_| WorkspaceContainer { workspace: None });
|
||||||
let workspace = cx.add_view(window_id, |cx| Workspace::test_new(project.clone(), cx));
|
let workspace = cx.add_view(window_id, |cx| {
|
||||||
|
Workspace::new(0, project.clone(), self.app_state.clone(), cx)
|
||||||
|
});
|
||||||
container.update(cx, |container, cx| {
|
container.update(cx, |container, cx| {
|
||||||
container.workspace = Some(workspace.downgrade());
|
container.workspace = Some(workspace.downgrade());
|
||||||
cx.notify();
|
cx.notify();
|
||||||
@ -552,7 +576,7 @@ impl TestClient {
|
|||||||
|
|
||||||
impl Drop for TestClient {
|
impl Drop for TestClient {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
self.client.teardown();
|
self.app_state.client.teardown();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -19,14 +19,14 @@ async fn test_basic_channels(
|
|||||||
let client_b = server.create_client(cx_b, "user_b").await;
|
let client_b = server.create_client(cx_b, "user_b").await;
|
||||||
|
|
||||||
let channel_a_id = client_a
|
let channel_a_id = client_a
|
||||||
.channel_store
|
.channel_store()
|
||||||
.update(cx_a, |channel_store, _| {
|
.update(cx_a, |channel_store, _| {
|
||||||
channel_store.create_channel("channel-a", None)
|
channel_store.create_channel("channel-a", None)
|
||||||
})
|
})
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
client_a.channel_store.read_with(cx_a, |channels, _| {
|
client_a.channel_store().read_with(cx_a, |channels, _| {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
channels.channels(),
|
channels.channels(),
|
||||||
&[Arc::new(Channel {
|
&[Arc::new(Channel {
|
||||||
@ -39,12 +39,12 @@ async fn test_basic_channels(
|
|||||||
});
|
});
|
||||||
|
|
||||||
client_b
|
client_b
|
||||||
.channel_store
|
.channel_store()
|
||||||
.read_with(cx_b, |channels, _| assert_eq!(channels.channels(), &[]));
|
.read_with(cx_b, |channels, _| assert_eq!(channels.channels(), &[]));
|
||||||
|
|
||||||
// Invite client B to channel A as client A.
|
// Invite client B to channel A as client A.
|
||||||
client_a
|
client_a
|
||||||
.channel_store
|
.channel_store()
|
||||||
.update(cx_a, |channel_store, _| {
|
.update(cx_a, |channel_store, _| {
|
||||||
channel_store.invite_member(channel_a_id, client_b.user_id().unwrap(), false)
|
channel_store.invite_member(channel_a_id, client_b.user_id().unwrap(), false)
|
||||||
})
|
})
|
||||||
@ -54,7 +54,7 @@ async fn test_basic_channels(
|
|||||||
// Wait for client b to see the invitation
|
// Wait for client b to see the invitation
|
||||||
deterministic.run_until_parked();
|
deterministic.run_until_parked();
|
||||||
|
|
||||||
client_b.channel_store.read_with(cx_b, |channels, _| {
|
client_b.channel_store().read_with(cx_b, |channels, _| {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
channels.channel_invitations(),
|
channels.channel_invitations(),
|
||||||
&[Arc::new(Channel {
|
&[Arc::new(Channel {
|
||||||
@ -68,13 +68,13 @@ async fn test_basic_channels(
|
|||||||
|
|
||||||
// Client B now sees that they are in channel A.
|
// Client B now sees that they are in channel A.
|
||||||
client_b
|
client_b
|
||||||
.channel_store
|
.channel_store()
|
||||||
.update(cx_b, |channels, _| {
|
.update(cx_b, |channels, _| {
|
||||||
channels.respond_to_channel_invite(channel_a_id, true)
|
channels.respond_to_channel_invite(channel_a_id, true)
|
||||||
})
|
})
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
client_b.channel_store.read_with(cx_b, |channels, _| {
|
client_b.channel_store().read_with(cx_b, |channels, _| {
|
||||||
assert_eq!(channels.channel_invitations(), &[]);
|
assert_eq!(channels.channel_invitations(), &[]);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
channels.channels(),
|
channels.channels(),
|
||||||
@ -86,6 +86,23 @@ async fn test_basic_channels(
|
|||||||
})]
|
})]
|
||||||
)
|
)
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Client A deletes the channel
|
||||||
|
client_a
|
||||||
|
.channel_store()
|
||||||
|
.update(cx_a, |channel_store, _| {
|
||||||
|
channel_store.remove_channel(channel_a_id)
|
||||||
|
})
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
deterministic.run_until_parked();
|
||||||
|
client_a
|
||||||
|
.channel_store()
|
||||||
|
.read_with(cx_a, |channels, _| assert_eq!(channels.channels(), &[]));
|
||||||
|
client_b
|
||||||
|
.channel_store()
|
||||||
|
.read_with(cx_b, |channels, _| assert_eq!(channels.channels(), &[]));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[gpui::test]
|
#[gpui::test]
|
||||||
|
@ -749,7 +749,7 @@ async fn test_server_restarts(
|
|||||||
let mut server = TestServer::start(&deterministic).await;
|
let mut server = TestServer::start(&deterministic).await;
|
||||||
let client_a = server.create_client(cx_a, "user_a").await;
|
let client_a = server.create_client(cx_a, "user_a").await;
|
||||||
client_a
|
client_a
|
||||||
.fs
|
.fs()
|
||||||
.insert_tree("/a", json!({ "a.txt": "a-contents" }))
|
.insert_tree("/a", json!({ "a.txt": "a-contents" }))
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
@ -1221,7 +1221,7 @@ async fn test_share_project(
|
|||||||
let active_call_c = cx_c.read(ActiveCall::global);
|
let active_call_c = cx_c.read(ActiveCall::global);
|
||||||
|
|
||||||
client_a
|
client_a
|
||||||
.fs
|
.fs()
|
||||||
.insert_tree(
|
.insert_tree(
|
||||||
"/a",
|
"/a",
|
||||||
json!({
|
json!({
|
||||||
@ -1388,7 +1388,7 @@ async fn test_unshare_project(
|
|||||||
let active_call_b = cx_b.read(ActiveCall::global);
|
let active_call_b = cx_b.read(ActiveCall::global);
|
||||||
|
|
||||||
client_a
|
client_a
|
||||||
.fs
|
.fs()
|
||||||
.insert_tree(
|
.insert_tree(
|
||||||
"/a",
|
"/a",
|
||||||
json!({
|
json!({
|
||||||
@ -1477,7 +1477,7 @@ async fn test_host_disconnect(
|
|||||||
cx_b.update(editor::init);
|
cx_b.update(editor::init);
|
||||||
|
|
||||||
client_a
|
client_a
|
||||||
.fs
|
.fs()
|
||||||
.insert_tree(
|
.insert_tree(
|
||||||
"/a",
|
"/a",
|
||||||
json!({
|
json!({
|
||||||
@ -1500,7 +1500,7 @@ async fn test_host_disconnect(
|
|||||||
assert!(worktree_a.read_with(cx_a, |tree, _| tree.as_local().unwrap().is_shared()));
|
assert!(worktree_a.read_with(cx_a, |tree, _| tree.as_local().unwrap().is_shared()));
|
||||||
|
|
||||||
let (window_id_b, workspace_b) =
|
let (window_id_b, workspace_b) =
|
||||||
cx_b.add_window(|cx| Workspace::test_new(project_b.clone(), cx));
|
cx_b.add_window(|cx| Workspace::new(0, project_b.clone(), client_b.app_state.clone(), cx));
|
||||||
let editor_b = workspace_b
|
let editor_b = workspace_b
|
||||||
.update(cx_b, |workspace, cx| {
|
.update(cx_b, |workspace, cx| {
|
||||||
workspace.open_path((worktree_id, "b.txt"), None, true, cx)
|
workspace.open_path((worktree_id, "b.txt"), None, true, cx)
|
||||||
@ -1584,7 +1584,7 @@ async fn test_project_reconnect(
|
|||||||
cx_b.update(editor::init);
|
cx_b.update(editor::init);
|
||||||
|
|
||||||
client_a
|
client_a
|
||||||
.fs
|
.fs()
|
||||||
.insert_tree(
|
.insert_tree(
|
||||||
"/root-1",
|
"/root-1",
|
||||||
json!({
|
json!({
|
||||||
@ -1612,7 +1612,7 @@ async fn test_project_reconnect(
|
|||||||
)
|
)
|
||||||
.await;
|
.await;
|
||||||
client_a
|
client_a
|
||||||
.fs
|
.fs()
|
||||||
.insert_tree(
|
.insert_tree(
|
||||||
"/root-2",
|
"/root-2",
|
||||||
json!({
|
json!({
|
||||||
@ -1621,7 +1621,7 @@ async fn test_project_reconnect(
|
|||||||
)
|
)
|
||||||
.await;
|
.await;
|
||||||
client_a
|
client_a
|
||||||
.fs
|
.fs()
|
||||||
.insert_tree(
|
.insert_tree(
|
||||||
"/root-3",
|
"/root-3",
|
||||||
json!({
|
json!({
|
||||||
@ -1701,7 +1701,7 @@ async fn test_project_reconnect(
|
|||||||
|
|
||||||
// While client A is disconnected, add and remove files from client A's project.
|
// While client A is disconnected, add and remove files from client A's project.
|
||||||
client_a
|
client_a
|
||||||
.fs
|
.fs()
|
||||||
.insert_tree(
|
.insert_tree(
|
||||||
"/root-1/dir1/subdir2",
|
"/root-1/dir1/subdir2",
|
||||||
json!({
|
json!({
|
||||||
@ -1713,7 +1713,7 @@ async fn test_project_reconnect(
|
|||||||
)
|
)
|
||||||
.await;
|
.await;
|
||||||
client_a
|
client_a
|
||||||
.fs
|
.fs()
|
||||||
.remove_dir(
|
.remove_dir(
|
||||||
"/root-1/dir1/subdir1".as_ref(),
|
"/root-1/dir1/subdir1".as_ref(),
|
||||||
RemoveOptions {
|
RemoveOptions {
|
||||||
@ -1835,11 +1835,11 @@ async fn test_project_reconnect(
|
|||||||
|
|
||||||
// While client B is disconnected, add and remove files from client A's project
|
// While client B is disconnected, add and remove files from client A's project
|
||||||
client_a
|
client_a
|
||||||
.fs
|
.fs()
|
||||||
.insert_file("/root-1/dir1/subdir2/j.txt", "j-contents".into())
|
.insert_file("/root-1/dir1/subdir2/j.txt", "j-contents".into())
|
||||||
.await;
|
.await;
|
||||||
client_a
|
client_a
|
||||||
.fs
|
.fs()
|
||||||
.remove_file("/root-1/dir1/subdir2/i.txt".as_ref(), Default::default())
|
.remove_file("/root-1/dir1/subdir2/i.txt".as_ref(), Default::default())
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
@ -1925,8 +1925,8 @@ async fn test_active_call_events(
|
|||||||
let mut server = TestServer::start(&deterministic).await;
|
let mut server = TestServer::start(&deterministic).await;
|
||||||
let client_a = server.create_client(cx_a, "user_a").await;
|
let client_a = server.create_client(cx_a, "user_a").await;
|
||||||
let client_b = server.create_client(cx_b, "user_b").await;
|
let client_b = server.create_client(cx_b, "user_b").await;
|
||||||
client_a.fs.insert_tree("/a", json!({})).await;
|
client_a.fs().insert_tree("/a", json!({})).await;
|
||||||
client_b.fs.insert_tree("/b", json!({})).await;
|
client_b.fs().insert_tree("/b", json!({})).await;
|
||||||
|
|
||||||
let (project_a, _) = client_a.build_local_project("/a", cx_a).await;
|
let (project_a, _) = client_a.build_local_project("/a", cx_a).await;
|
||||||
let (project_b, _) = client_b.build_local_project("/b", cx_b).await;
|
let (project_b, _) = client_b.build_local_project("/b", cx_b).await;
|
||||||
@ -2014,8 +2014,8 @@ async fn test_room_location(
|
|||||||
let mut server = TestServer::start(&deterministic).await;
|
let mut server = TestServer::start(&deterministic).await;
|
||||||
let client_a = server.create_client(cx_a, "user_a").await;
|
let client_a = server.create_client(cx_a, "user_a").await;
|
||||||
let client_b = server.create_client(cx_b, "user_b").await;
|
let client_b = server.create_client(cx_b, "user_b").await;
|
||||||
client_a.fs.insert_tree("/a", json!({})).await;
|
client_a.fs().insert_tree("/a", json!({})).await;
|
||||||
client_b.fs.insert_tree("/b", json!({})).await;
|
client_b.fs().insert_tree("/b", json!({})).await;
|
||||||
|
|
||||||
let active_call_a = cx_a.read(ActiveCall::global);
|
let active_call_a = cx_a.read(ActiveCall::global);
|
||||||
let active_call_b = cx_b.read(ActiveCall::global);
|
let active_call_b = cx_b.read(ActiveCall::global);
|
||||||
@ -2204,12 +2204,12 @@ async fn test_propagate_saves_and_fs_changes(
|
|||||||
Some(tree_sitter_rust::language()),
|
Some(tree_sitter_rust::language()),
|
||||||
));
|
));
|
||||||
for client in [&client_a, &client_b, &client_c] {
|
for client in [&client_a, &client_b, &client_c] {
|
||||||
client.language_registry.add(rust.clone());
|
client.language_registry().add(rust.clone());
|
||||||
client.language_registry.add(javascript.clone());
|
client.language_registry().add(javascript.clone());
|
||||||
}
|
}
|
||||||
|
|
||||||
client_a
|
client_a
|
||||||
.fs
|
.fs()
|
||||||
.insert_tree(
|
.insert_tree(
|
||||||
"/a",
|
"/a",
|
||||||
json!({
|
json!({
|
||||||
@ -2279,7 +2279,7 @@ async fn test_propagate_saves_and_fs_changes(
|
|||||||
buffer_a.update(cx_a, |buf, cx| buf.edit([(0..0, "hi-a, ")], None, cx));
|
buffer_a.update(cx_a, |buf, cx| buf.edit([(0..0, "hi-a, ")], None, cx));
|
||||||
save_b.await.unwrap();
|
save_b.await.unwrap();
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
client_a.fs.load("/a/file1.rs".as_ref()).await.unwrap(),
|
client_a.fs().load("/a/file1.rs".as_ref()).await.unwrap(),
|
||||||
"hi-a, i-am-c, i-am-b, i-am-a"
|
"hi-a, i-am-c, i-am-b, i-am-a"
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -2290,7 +2290,7 @@ async fn test_propagate_saves_and_fs_changes(
|
|||||||
|
|
||||||
// Make changes on host's file system, see those changes on guest worktrees.
|
// Make changes on host's file system, see those changes on guest worktrees.
|
||||||
client_a
|
client_a
|
||||||
.fs
|
.fs()
|
||||||
.rename(
|
.rename(
|
||||||
"/a/file1.rs".as_ref(),
|
"/a/file1.rs".as_ref(),
|
||||||
"/a/file1.js".as_ref(),
|
"/a/file1.js".as_ref(),
|
||||||
@ -2299,11 +2299,11 @@ async fn test_propagate_saves_and_fs_changes(
|
|||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
client_a
|
client_a
|
||||||
.fs
|
.fs()
|
||||||
.rename("/a/file2".as_ref(), "/a/file3".as_ref(), Default::default())
|
.rename("/a/file2".as_ref(), "/a/file3".as_ref(), Default::default())
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
client_a.fs.insert_file("/a/file4", "4".into()).await;
|
client_a.fs().insert_file("/a/file4", "4".into()).await;
|
||||||
deterministic.run_until_parked();
|
deterministic.run_until_parked();
|
||||||
|
|
||||||
worktree_a.read_with(cx_a, |tree, _| {
|
worktree_a.read_with(cx_a, |tree, _| {
|
||||||
@ -2397,7 +2397,7 @@ async fn test_git_diff_base_change(
|
|||||||
let active_call_a = cx_a.read(ActiveCall::global);
|
let active_call_a = cx_a.read(ActiveCall::global);
|
||||||
|
|
||||||
client_a
|
client_a
|
||||||
.fs
|
.fs()
|
||||||
.insert_tree(
|
.insert_tree(
|
||||||
"/dir",
|
"/dir",
|
||||||
json!({
|
json!({
|
||||||
@ -2441,7 +2441,7 @@ async fn test_git_diff_base_change(
|
|||||||
"
|
"
|
||||||
.unindent();
|
.unindent();
|
||||||
|
|
||||||
client_a.fs.as_fake().set_index_for_repo(
|
client_a.fs().set_index_for_repo(
|
||||||
Path::new("/dir/.git"),
|
Path::new("/dir/.git"),
|
||||||
&[(Path::new("a.txt"), diff_base.clone())],
|
&[(Path::new("a.txt"), diff_base.clone())],
|
||||||
);
|
);
|
||||||
@ -2486,7 +2486,7 @@ async fn test_git_diff_base_change(
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
client_a.fs.as_fake().set_index_for_repo(
|
client_a.fs().set_index_for_repo(
|
||||||
Path::new("/dir/.git"),
|
Path::new("/dir/.git"),
|
||||||
&[(Path::new("a.txt"), new_diff_base.clone())],
|
&[(Path::new("a.txt"), new_diff_base.clone())],
|
||||||
);
|
);
|
||||||
@ -2531,7 +2531,7 @@ async fn test_git_diff_base_change(
|
|||||||
"
|
"
|
||||||
.unindent();
|
.unindent();
|
||||||
|
|
||||||
client_a.fs.as_fake().set_index_for_repo(
|
client_a.fs().set_index_for_repo(
|
||||||
Path::new("/dir/sub/.git"),
|
Path::new("/dir/sub/.git"),
|
||||||
&[(Path::new("b.txt"), diff_base.clone())],
|
&[(Path::new("b.txt"), diff_base.clone())],
|
||||||
);
|
);
|
||||||
@ -2576,7 +2576,7 @@ async fn test_git_diff_base_change(
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
client_a.fs.as_fake().set_index_for_repo(
|
client_a.fs().set_index_for_repo(
|
||||||
Path::new("/dir/sub/.git"),
|
Path::new("/dir/sub/.git"),
|
||||||
&[(Path::new("b.txt"), new_diff_base.clone())],
|
&[(Path::new("b.txt"), new_diff_base.clone())],
|
||||||
);
|
);
|
||||||
@ -2635,7 +2635,7 @@ async fn test_git_branch_name(
|
|||||||
let active_call_a = cx_a.read(ActiveCall::global);
|
let active_call_a = cx_a.read(ActiveCall::global);
|
||||||
|
|
||||||
client_a
|
client_a
|
||||||
.fs
|
.fs()
|
||||||
.insert_tree(
|
.insert_tree(
|
||||||
"/dir",
|
"/dir",
|
||||||
json!({
|
json!({
|
||||||
@ -2654,8 +2654,7 @@ async fn test_git_branch_name(
|
|||||||
|
|
||||||
let project_remote = client_b.build_remote_project(project_id, cx_b).await;
|
let project_remote = client_b.build_remote_project(project_id, cx_b).await;
|
||||||
client_a
|
client_a
|
||||||
.fs
|
.fs()
|
||||||
.as_fake()
|
|
||||||
.set_branch_name(Path::new("/dir/.git"), Some("branch-1"));
|
.set_branch_name(Path::new("/dir/.git"), Some("branch-1"));
|
||||||
|
|
||||||
// Wait for it to catch up to the new branch
|
// Wait for it to catch up to the new branch
|
||||||
@ -2680,8 +2679,7 @@ async fn test_git_branch_name(
|
|||||||
});
|
});
|
||||||
|
|
||||||
client_a
|
client_a
|
||||||
.fs
|
.fs()
|
||||||
.as_fake()
|
|
||||||
.set_branch_name(Path::new("/dir/.git"), Some("branch-2"));
|
.set_branch_name(Path::new("/dir/.git"), Some("branch-2"));
|
||||||
|
|
||||||
// Wait for buffer_local_a to receive it
|
// Wait for buffer_local_a to receive it
|
||||||
@ -2720,7 +2718,7 @@ async fn test_git_status_sync(
|
|||||||
let active_call_a = cx_a.read(ActiveCall::global);
|
let active_call_a = cx_a.read(ActiveCall::global);
|
||||||
|
|
||||||
client_a
|
client_a
|
||||||
.fs
|
.fs()
|
||||||
.insert_tree(
|
.insert_tree(
|
||||||
"/dir",
|
"/dir",
|
||||||
json!({
|
json!({
|
||||||
@ -2734,7 +2732,7 @@ async fn test_git_status_sync(
|
|||||||
const A_TXT: &'static str = "a.txt";
|
const A_TXT: &'static str = "a.txt";
|
||||||
const B_TXT: &'static str = "b.txt";
|
const B_TXT: &'static str = "b.txt";
|
||||||
|
|
||||||
client_a.fs.as_fake().set_status_for_repo_via_git_operation(
|
client_a.fs().set_status_for_repo_via_git_operation(
|
||||||
Path::new("/dir/.git"),
|
Path::new("/dir/.git"),
|
||||||
&[
|
&[
|
||||||
(&Path::new(A_TXT), GitFileStatus::Added),
|
(&Path::new(A_TXT), GitFileStatus::Added),
|
||||||
@ -2780,16 +2778,13 @@ async fn test_git_status_sync(
|
|||||||
assert_status(&Path::new(B_TXT), Some(GitFileStatus::Added), project, cx);
|
assert_status(&Path::new(B_TXT), Some(GitFileStatus::Added), project, cx);
|
||||||
});
|
});
|
||||||
|
|
||||||
client_a
|
client_a.fs().set_status_for_repo_via_working_copy_change(
|
||||||
.fs
|
Path::new("/dir/.git"),
|
||||||
.as_fake()
|
&[
|
||||||
.set_status_for_repo_via_working_copy_change(
|
(&Path::new(A_TXT), GitFileStatus::Modified),
|
||||||
Path::new("/dir/.git"),
|
(&Path::new(B_TXT), GitFileStatus::Modified),
|
||||||
&[
|
],
|
||||||
(&Path::new(A_TXT), GitFileStatus::Modified),
|
);
|
||||||
(&Path::new(B_TXT), GitFileStatus::Modified),
|
|
||||||
],
|
|
||||||
);
|
|
||||||
|
|
||||||
// Wait for buffer_local_a to receive it
|
// Wait for buffer_local_a to receive it
|
||||||
deterministic.run_until_parked();
|
deterministic.run_until_parked();
|
||||||
@ -2860,7 +2855,7 @@ async fn test_fs_operations(
|
|||||||
let active_call_a = cx_a.read(ActiveCall::global);
|
let active_call_a = cx_a.read(ActiveCall::global);
|
||||||
|
|
||||||
client_a
|
client_a
|
||||||
.fs
|
.fs()
|
||||||
.insert_tree(
|
.insert_tree(
|
||||||
"/dir",
|
"/dir",
|
||||||
json!({
|
json!({
|
||||||
@ -3133,7 +3128,7 @@ async fn test_local_settings(
|
|||||||
|
|
||||||
// As client A, open a project that contains some local settings files
|
// As client A, open a project that contains some local settings files
|
||||||
client_a
|
client_a
|
||||||
.fs
|
.fs()
|
||||||
.insert_tree(
|
.insert_tree(
|
||||||
"/dir",
|
"/dir",
|
||||||
json!({
|
json!({
|
||||||
@ -3175,7 +3170,7 @@ async fn test_local_settings(
|
|||||||
|
|
||||||
// As client A, update a settings file. As Client B, see the changed settings.
|
// As client A, update a settings file. As Client B, see the changed settings.
|
||||||
client_a
|
client_a
|
||||||
.fs
|
.fs()
|
||||||
.insert_file("/dir/.zed/settings.json", r#"{}"#.into())
|
.insert_file("/dir/.zed/settings.json", r#"{}"#.into())
|
||||||
.await;
|
.await;
|
||||||
deterministic.run_until_parked();
|
deterministic.run_until_parked();
|
||||||
@ -3192,17 +3187,17 @@ async fn test_local_settings(
|
|||||||
|
|
||||||
// As client A, create and remove some settings files. As client B, see the changed settings.
|
// As client A, create and remove some settings files. As client B, see the changed settings.
|
||||||
client_a
|
client_a
|
||||||
.fs
|
.fs()
|
||||||
.remove_file("/dir/.zed/settings.json".as_ref(), Default::default())
|
.remove_file("/dir/.zed/settings.json".as_ref(), Default::default())
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
client_a
|
client_a
|
||||||
.fs
|
.fs()
|
||||||
.create_dir("/dir/b/.zed".as_ref())
|
.create_dir("/dir/b/.zed".as_ref())
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
client_a
|
client_a
|
||||||
.fs
|
.fs()
|
||||||
.insert_file("/dir/b/.zed/settings.json", r#"{"tab_size": 4}"#.into())
|
.insert_file("/dir/b/.zed/settings.json", r#"{"tab_size": 4}"#.into())
|
||||||
.await;
|
.await;
|
||||||
deterministic.run_until_parked();
|
deterministic.run_until_parked();
|
||||||
@ -3223,11 +3218,11 @@ async fn test_local_settings(
|
|||||||
|
|
||||||
// As client A, change and remove settings files while client B is disconnected.
|
// As client A, change and remove settings files while client B is disconnected.
|
||||||
client_a
|
client_a
|
||||||
.fs
|
.fs()
|
||||||
.insert_file("/dir/a/.zed/settings.json", r#"{"hard_tabs":true}"#.into())
|
.insert_file("/dir/a/.zed/settings.json", r#"{"hard_tabs":true}"#.into())
|
||||||
.await;
|
.await;
|
||||||
client_a
|
client_a
|
||||||
.fs
|
.fs()
|
||||||
.remove_file("/dir/b/.zed/settings.json".as_ref(), Default::default())
|
.remove_file("/dir/b/.zed/settings.json".as_ref(), Default::default())
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
@ -3261,7 +3256,7 @@ async fn test_buffer_conflict_after_save(
|
|||||||
let active_call_a = cx_a.read(ActiveCall::global);
|
let active_call_a = cx_a.read(ActiveCall::global);
|
||||||
|
|
||||||
client_a
|
client_a
|
||||||
.fs
|
.fs()
|
||||||
.insert_tree(
|
.insert_tree(
|
||||||
"/dir",
|
"/dir",
|
||||||
json!({
|
json!({
|
||||||
@ -3323,7 +3318,7 @@ async fn test_buffer_reloading(
|
|||||||
let active_call_a = cx_a.read(ActiveCall::global);
|
let active_call_a = cx_a.read(ActiveCall::global);
|
||||||
|
|
||||||
client_a
|
client_a
|
||||||
.fs
|
.fs()
|
||||||
.insert_tree(
|
.insert_tree(
|
||||||
"/dir",
|
"/dir",
|
||||||
json!({
|
json!({
|
||||||
@ -3351,7 +3346,7 @@ async fn test_buffer_reloading(
|
|||||||
|
|
||||||
let new_contents = Rope::from("d\ne\nf");
|
let new_contents = Rope::from("d\ne\nf");
|
||||||
client_a
|
client_a
|
||||||
.fs
|
.fs()
|
||||||
.save("/dir/a.txt".as_ref(), &new_contents, LineEnding::Windows)
|
.save("/dir/a.txt".as_ref(), &new_contents, LineEnding::Windows)
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
@ -3380,7 +3375,7 @@ async fn test_editing_while_guest_opens_buffer(
|
|||||||
let active_call_a = cx_a.read(ActiveCall::global);
|
let active_call_a = cx_a.read(ActiveCall::global);
|
||||||
|
|
||||||
client_a
|
client_a
|
||||||
.fs
|
.fs()
|
||||||
.insert_tree("/dir", json!({ "a.txt": "a-contents" }))
|
.insert_tree("/dir", json!({ "a.txt": "a-contents" }))
|
||||||
.await;
|
.await;
|
||||||
let (project_a, worktree_id) = client_a.build_local_project("/dir", cx_a).await;
|
let (project_a, worktree_id) = client_a.build_local_project("/dir", cx_a).await;
|
||||||
@ -3429,7 +3424,7 @@ async fn test_newline_above_or_below_does_not_move_guest_cursor(
|
|||||||
let active_call_a = cx_a.read(ActiveCall::global);
|
let active_call_a = cx_a.read(ActiveCall::global);
|
||||||
|
|
||||||
client_a
|
client_a
|
||||||
.fs
|
.fs()
|
||||||
.insert_tree("/dir", json!({ "a.txt": "Some text\n" }))
|
.insert_tree("/dir", json!({ "a.txt": "Some text\n" }))
|
||||||
.await;
|
.await;
|
||||||
let (project_a, worktree_id) = client_a.build_local_project("/dir", cx_a).await;
|
let (project_a, worktree_id) = client_a.build_local_project("/dir", cx_a).await;
|
||||||
@ -3527,7 +3522,7 @@ async fn test_leaving_worktree_while_opening_buffer(
|
|||||||
let active_call_a = cx_a.read(ActiveCall::global);
|
let active_call_a = cx_a.read(ActiveCall::global);
|
||||||
|
|
||||||
client_a
|
client_a
|
||||||
.fs
|
.fs()
|
||||||
.insert_tree("/dir", json!({ "a.txt": "a-contents" }))
|
.insert_tree("/dir", json!({ "a.txt": "a-contents" }))
|
||||||
.await;
|
.await;
|
||||||
let (project_a, worktree_id) = client_a.build_local_project("/dir", cx_a).await;
|
let (project_a, worktree_id) = client_a.build_local_project("/dir", cx_a).await;
|
||||||
@ -3570,7 +3565,7 @@ async fn test_canceling_buffer_opening(
|
|||||||
let active_call_a = cx_a.read(ActiveCall::global);
|
let active_call_a = cx_a.read(ActiveCall::global);
|
||||||
|
|
||||||
client_a
|
client_a
|
||||||
.fs
|
.fs()
|
||||||
.insert_tree(
|
.insert_tree(
|
||||||
"/dir",
|
"/dir",
|
||||||
json!({
|
json!({
|
||||||
@ -3626,7 +3621,7 @@ async fn test_leaving_project(
|
|||||||
let active_call_a = cx_a.read(ActiveCall::global);
|
let active_call_a = cx_a.read(ActiveCall::global);
|
||||||
|
|
||||||
client_a
|
client_a
|
||||||
.fs
|
.fs()
|
||||||
.insert_tree(
|
.insert_tree(
|
||||||
"/a",
|
"/a",
|
||||||
json!({
|
json!({
|
||||||
@ -3714,9 +3709,9 @@ async fn test_leaving_project(
|
|||||||
cx_b.spawn(|cx| {
|
cx_b.spawn(|cx| {
|
||||||
Project::remote(
|
Project::remote(
|
||||||
project_id,
|
project_id,
|
||||||
client_b.client.clone(),
|
client_b.app_state.client.clone(),
|
||||||
client_b.user_store.clone(),
|
client_b.user_store().clone(),
|
||||||
client_b.language_registry.clone(),
|
client_b.language_registry().clone(),
|
||||||
FakeFs::new(cx.background()),
|
FakeFs::new(cx.background()),
|
||||||
cx,
|
cx,
|
||||||
)
|
)
|
||||||
@ -3768,11 +3763,11 @@ async fn test_collaborating_with_diagnostics(
|
|||||||
Some(tree_sitter_rust::language()),
|
Some(tree_sitter_rust::language()),
|
||||||
);
|
);
|
||||||
let mut fake_language_servers = language.set_fake_lsp_adapter(Default::default()).await;
|
let mut fake_language_servers = language.set_fake_lsp_adapter(Default::default()).await;
|
||||||
client_a.language_registry.add(Arc::new(language));
|
client_a.language_registry().add(Arc::new(language));
|
||||||
|
|
||||||
// Share a project as client A
|
// Share a project as client A
|
||||||
client_a
|
client_a
|
||||||
.fs
|
.fs()
|
||||||
.insert_tree(
|
.insert_tree(
|
||||||
"/a",
|
"/a",
|
||||||
json!({
|
json!({
|
||||||
@ -4040,11 +4035,11 @@ async fn test_collaborating_with_lsp_progress_updates_and_diagnostics_ordering(
|
|||||||
..Default::default()
|
..Default::default()
|
||||||
}))
|
}))
|
||||||
.await;
|
.await;
|
||||||
client_a.language_registry.add(Arc::new(language));
|
client_a.language_registry().add(Arc::new(language));
|
||||||
|
|
||||||
let file_names = &["one.rs", "two.rs", "three.rs", "four.rs", "five.rs"];
|
let file_names = &["one.rs", "two.rs", "three.rs", "four.rs", "five.rs"];
|
||||||
client_a
|
client_a
|
||||||
.fs
|
.fs()
|
||||||
.insert_tree(
|
.insert_tree(
|
||||||
"/test",
|
"/test",
|
||||||
json!({
|
json!({
|
||||||
@ -4181,10 +4176,10 @@ async fn test_collaborating_with_completion(
|
|||||||
..Default::default()
|
..Default::default()
|
||||||
}))
|
}))
|
||||||
.await;
|
.await;
|
||||||
client_a.language_registry.add(Arc::new(language));
|
client_a.language_registry().add(Arc::new(language));
|
||||||
|
|
||||||
client_a
|
client_a
|
||||||
.fs
|
.fs()
|
||||||
.insert_tree(
|
.insert_tree(
|
||||||
"/a",
|
"/a",
|
||||||
json!({
|
json!({
|
||||||
@ -4342,7 +4337,7 @@ async fn test_reloading_buffer_manually(
|
|||||||
let active_call_a = cx_a.read(ActiveCall::global);
|
let active_call_a = cx_a.read(ActiveCall::global);
|
||||||
|
|
||||||
client_a
|
client_a
|
||||||
.fs
|
.fs()
|
||||||
.insert_tree("/a", json!({ "a.rs": "let one = 1;" }))
|
.insert_tree("/a", json!({ "a.rs": "let one = 1;" }))
|
||||||
.await;
|
.await;
|
||||||
let (project_a, worktree_id) = client_a.build_local_project("/a", cx_a).await;
|
let (project_a, worktree_id) = client_a.build_local_project("/a", cx_a).await;
|
||||||
@ -4373,7 +4368,7 @@ async fn test_reloading_buffer_manually(
|
|||||||
buffer_a.read_with(cx_a, |buffer, _| assert_eq!(buffer.text(), "let six = 6;"));
|
buffer_a.read_with(cx_a, |buffer, _| assert_eq!(buffer.text(), "let six = 6;"));
|
||||||
|
|
||||||
client_a
|
client_a
|
||||||
.fs
|
.fs()
|
||||||
.save(
|
.save(
|
||||||
"/a/a.rs".as_ref(),
|
"/a/a.rs".as_ref(),
|
||||||
&Rope::from("let seven = 7;"),
|
&Rope::from("let seven = 7;"),
|
||||||
@ -4444,14 +4439,14 @@ async fn test_formatting_buffer(
|
|||||||
Some(tree_sitter_rust::language()),
|
Some(tree_sitter_rust::language()),
|
||||||
);
|
);
|
||||||
let mut fake_language_servers = language.set_fake_lsp_adapter(Default::default()).await;
|
let mut fake_language_servers = language.set_fake_lsp_adapter(Default::default()).await;
|
||||||
client_a.language_registry.add(Arc::new(language));
|
client_a.language_registry().add(Arc::new(language));
|
||||||
|
|
||||||
// Here we insert a fake tree with a directory that exists on disk. This is needed
|
// Here we insert a fake tree with a directory that exists on disk. This is needed
|
||||||
// because later we'll invoke a command, which requires passing a working directory
|
// because later we'll invoke a command, which requires passing a working directory
|
||||||
// that points to a valid location on disk.
|
// that points to a valid location on disk.
|
||||||
let directory = env::current_dir().unwrap();
|
let directory = env::current_dir().unwrap();
|
||||||
client_a
|
client_a
|
||||||
.fs
|
.fs()
|
||||||
.insert_tree(&directory, json!({ "a.rs": "let one = \"two\"" }))
|
.insert_tree(&directory, json!({ "a.rs": "let one = \"two\"" }))
|
||||||
.await;
|
.await;
|
||||||
let (project_a, worktree_id) = client_a.build_local_project(&directory, cx_a).await;
|
let (project_a, worktree_id) = client_a.build_local_project(&directory, cx_a).await;
|
||||||
@ -4553,10 +4548,10 @@ async fn test_definition(
|
|||||||
Some(tree_sitter_rust::language()),
|
Some(tree_sitter_rust::language()),
|
||||||
);
|
);
|
||||||
let mut fake_language_servers = language.set_fake_lsp_adapter(Default::default()).await;
|
let mut fake_language_servers = language.set_fake_lsp_adapter(Default::default()).await;
|
||||||
client_a.language_registry.add(Arc::new(language));
|
client_a.language_registry().add(Arc::new(language));
|
||||||
|
|
||||||
client_a
|
client_a
|
||||||
.fs
|
.fs()
|
||||||
.insert_tree(
|
.insert_tree(
|
||||||
"/root",
|
"/root",
|
||||||
json!({
|
json!({
|
||||||
@ -4701,10 +4696,10 @@ async fn test_references(
|
|||||||
Some(tree_sitter_rust::language()),
|
Some(tree_sitter_rust::language()),
|
||||||
);
|
);
|
||||||
let mut fake_language_servers = language.set_fake_lsp_adapter(Default::default()).await;
|
let mut fake_language_servers = language.set_fake_lsp_adapter(Default::default()).await;
|
||||||
client_a.language_registry.add(Arc::new(language));
|
client_a.language_registry().add(Arc::new(language));
|
||||||
|
|
||||||
client_a
|
client_a
|
||||||
.fs
|
.fs()
|
||||||
.insert_tree(
|
.insert_tree(
|
||||||
"/root",
|
"/root",
|
||||||
json!({
|
json!({
|
||||||
@ -4797,7 +4792,7 @@ async fn test_project_search(
|
|||||||
let active_call_a = cx_a.read(ActiveCall::global);
|
let active_call_a = cx_a.read(ActiveCall::global);
|
||||||
|
|
||||||
client_a
|
client_a
|
||||||
.fs
|
.fs()
|
||||||
.insert_tree(
|
.insert_tree(
|
||||||
"/root",
|
"/root",
|
||||||
json!({
|
json!({
|
||||||
@ -4883,7 +4878,7 @@ async fn test_document_highlights(
|
|||||||
let active_call_a = cx_a.read(ActiveCall::global);
|
let active_call_a = cx_a.read(ActiveCall::global);
|
||||||
|
|
||||||
client_a
|
client_a
|
||||||
.fs
|
.fs()
|
||||||
.insert_tree(
|
.insert_tree(
|
||||||
"/root-1",
|
"/root-1",
|
||||||
json!({
|
json!({
|
||||||
@ -4902,7 +4897,7 @@ async fn test_document_highlights(
|
|||||||
Some(tree_sitter_rust::language()),
|
Some(tree_sitter_rust::language()),
|
||||||
);
|
);
|
||||||
let mut fake_language_servers = language.set_fake_lsp_adapter(Default::default()).await;
|
let mut fake_language_servers = language.set_fake_lsp_adapter(Default::default()).await;
|
||||||
client_a.language_registry.add(Arc::new(language));
|
client_a.language_registry().add(Arc::new(language));
|
||||||
|
|
||||||
let (project_a, worktree_id) = client_a.build_local_project("/root-1", cx_a).await;
|
let (project_a, worktree_id) = client_a.build_local_project("/root-1", cx_a).await;
|
||||||
let project_id = active_call_a
|
let project_id = active_call_a
|
||||||
@ -4989,7 +4984,7 @@ async fn test_lsp_hover(
|
|||||||
let active_call_a = cx_a.read(ActiveCall::global);
|
let active_call_a = cx_a.read(ActiveCall::global);
|
||||||
|
|
||||||
client_a
|
client_a
|
||||||
.fs
|
.fs()
|
||||||
.insert_tree(
|
.insert_tree(
|
||||||
"/root-1",
|
"/root-1",
|
||||||
json!({
|
json!({
|
||||||
@ -5008,7 +5003,7 @@ async fn test_lsp_hover(
|
|||||||
Some(tree_sitter_rust::language()),
|
Some(tree_sitter_rust::language()),
|
||||||
);
|
);
|
||||||
let mut fake_language_servers = language.set_fake_lsp_adapter(Default::default()).await;
|
let mut fake_language_servers = language.set_fake_lsp_adapter(Default::default()).await;
|
||||||
client_a.language_registry.add(Arc::new(language));
|
client_a.language_registry().add(Arc::new(language));
|
||||||
|
|
||||||
let (project_a, worktree_id) = client_a.build_local_project("/root-1", cx_a).await;
|
let (project_a, worktree_id) = client_a.build_local_project("/root-1", cx_a).await;
|
||||||
let project_id = active_call_a
|
let project_id = active_call_a
|
||||||
@ -5107,10 +5102,10 @@ async fn test_project_symbols(
|
|||||||
Some(tree_sitter_rust::language()),
|
Some(tree_sitter_rust::language()),
|
||||||
);
|
);
|
||||||
let mut fake_language_servers = language.set_fake_lsp_adapter(Default::default()).await;
|
let mut fake_language_servers = language.set_fake_lsp_adapter(Default::default()).await;
|
||||||
client_a.language_registry.add(Arc::new(language));
|
client_a.language_registry().add(Arc::new(language));
|
||||||
|
|
||||||
client_a
|
client_a
|
||||||
.fs
|
.fs()
|
||||||
.insert_tree(
|
.insert_tree(
|
||||||
"/code",
|
"/code",
|
||||||
json!({
|
json!({
|
||||||
@ -5218,10 +5213,10 @@ async fn test_open_buffer_while_getting_definition_pointing_to_it(
|
|||||||
Some(tree_sitter_rust::language()),
|
Some(tree_sitter_rust::language()),
|
||||||
);
|
);
|
||||||
let mut fake_language_servers = language.set_fake_lsp_adapter(Default::default()).await;
|
let mut fake_language_servers = language.set_fake_lsp_adapter(Default::default()).await;
|
||||||
client_a.language_registry.add(Arc::new(language));
|
client_a.language_registry().add(Arc::new(language));
|
||||||
|
|
||||||
client_a
|
client_a
|
||||||
.fs
|
.fs()
|
||||||
.insert_tree(
|
.insert_tree(
|
||||||
"/root",
|
"/root",
|
||||||
json!({
|
json!({
|
||||||
@ -5278,6 +5273,7 @@ async fn test_collaborating_with_code_actions(
|
|||||||
deterministic.forbid_parking();
|
deterministic.forbid_parking();
|
||||||
let mut server = TestServer::start(&deterministic).await;
|
let mut server = TestServer::start(&deterministic).await;
|
||||||
let client_a = server.create_client(cx_a, "user_a").await;
|
let client_a = server.create_client(cx_a, "user_a").await;
|
||||||
|
//
|
||||||
let client_b = server.create_client(cx_b, "user_b").await;
|
let client_b = server.create_client(cx_b, "user_b").await;
|
||||||
server
|
server
|
||||||
.create_room(&mut [(&client_a, cx_a), (&client_b, cx_b)])
|
.create_room(&mut [(&client_a, cx_a), (&client_b, cx_b)])
|
||||||
@ -5296,10 +5292,10 @@ async fn test_collaborating_with_code_actions(
|
|||||||
Some(tree_sitter_rust::language()),
|
Some(tree_sitter_rust::language()),
|
||||||
);
|
);
|
||||||
let mut fake_language_servers = language.set_fake_lsp_adapter(Default::default()).await;
|
let mut fake_language_servers = language.set_fake_lsp_adapter(Default::default()).await;
|
||||||
client_a.language_registry.add(Arc::new(language));
|
client_a.language_registry().add(Arc::new(language));
|
||||||
|
|
||||||
client_a
|
client_a
|
||||||
.fs
|
.fs()
|
||||||
.insert_tree(
|
.insert_tree(
|
||||||
"/a",
|
"/a",
|
||||||
json!({
|
json!({
|
||||||
@ -5316,7 +5312,8 @@ async fn test_collaborating_with_code_actions(
|
|||||||
|
|
||||||
// Join the project as client B.
|
// Join the project as client B.
|
||||||
let project_b = client_b.build_remote_project(project_id, cx_b).await;
|
let project_b = client_b.build_remote_project(project_id, cx_b).await;
|
||||||
let (_window_b, workspace_b) = cx_b.add_window(|cx| Workspace::test_new(project_b.clone(), cx));
|
let (_window_b, workspace_b) =
|
||||||
|
cx_b.add_window(|cx| Workspace::new(0, project_b.clone(), client_b.app_state.clone(), cx));
|
||||||
let editor_b = workspace_b
|
let editor_b = workspace_b
|
||||||
.update(cx_b, |workspace, cx| {
|
.update(cx_b, |workspace, cx| {
|
||||||
workspace.open_path((worktree_id, "main.rs"), None, true, cx)
|
workspace.open_path((worktree_id, "main.rs"), None, true, cx)
|
||||||
@ -5521,10 +5518,10 @@ async fn test_collaborating_with_renames(
|
|||||||
..Default::default()
|
..Default::default()
|
||||||
}))
|
}))
|
||||||
.await;
|
.await;
|
||||||
client_a.language_registry.add(Arc::new(language));
|
client_a.language_registry().add(Arc::new(language));
|
||||||
|
|
||||||
client_a
|
client_a
|
||||||
.fs
|
.fs()
|
||||||
.insert_tree(
|
.insert_tree(
|
||||||
"/dir",
|
"/dir",
|
||||||
json!({
|
json!({
|
||||||
@ -5540,7 +5537,8 @@ async fn test_collaborating_with_renames(
|
|||||||
.unwrap();
|
.unwrap();
|
||||||
let project_b = client_b.build_remote_project(project_id, cx_b).await;
|
let project_b = client_b.build_remote_project(project_id, cx_b).await;
|
||||||
|
|
||||||
let (_window_b, workspace_b) = cx_b.add_window(|cx| Workspace::test_new(project_b.clone(), cx));
|
let (_window_b, workspace_b) =
|
||||||
|
cx_b.add_window(|cx| Workspace::new(0, project_b.clone(), client_b.app_state.clone(), cx));
|
||||||
let editor_b = workspace_b
|
let editor_b = workspace_b
|
||||||
.update(cx_b, |workspace, cx| {
|
.update(cx_b, |workspace, cx| {
|
||||||
workspace.open_path((worktree_id, "one.rs"), None, true, cx)
|
workspace.open_path((worktree_id, "one.rs"), None, true, cx)
|
||||||
@ -5706,10 +5704,10 @@ async fn test_language_server_statuses(
|
|||||||
..Default::default()
|
..Default::default()
|
||||||
}))
|
}))
|
||||||
.await;
|
.await;
|
||||||
client_a.language_registry.add(Arc::new(language));
|
client_a.language_registry().add(Arc::new(language));
|
||||||
|
|
||||||
client_a
|
client_a
|
||||||
.fs
|
.fs()
|
||||||
.insert_tree(
|
.insert_tree(
|
||||||
"/dir",
|
"/dir",
|
||||||
json!({
|
json!({
|
||||||
@ -6166,7 +6164,7 @@ async fn test_contacts(
|
|||||||
|
|
||||||
// Test removing a contact
|
// Test removing a contact
|
||||||
client_b
|
client_b
|
||||||
.user_store
|
.user_store()
|
||||||
.update(cx_b, |store, cx| {
|
.update(cx_b, |store, cx| {
|
||||||
store.remove_contact(client_c.user_id().unwrap(), cx)
|
store.remove_contact(client_c.user_id().unwrap(), cx)
|
||||||
})
|
})
|
||||||
@ -6189,7 +6187,7 @@ async fn test_contacts(
|
|||||||
client: &TestClient,
|
client: &TestClient,
|
||||||
cx: &TestAppContext,
|
cx: &TestAppContext,
|
||||||
) -> Vec<(String, &'static str, &'static str)> {
|
) -> Vec<(String, &'static str, &'static str)> {
|
||||||
client.user_store.read_with(cx, |store, _| {
|
client.user_store().read_with(cx, |store, _| {
|
||||||
store
|
store
|
||||||
.contacts()
|
.contacts()
|
||||||
.iter()
|
.iter()
|
||||||
@ -6232,14 +6230,14 @@ async fn test_contact_requests(
|
|||||||
|
|
||||||
// User A and User C request that user B become their contact.
|
// User A and User C request that user B become their contact.
|
||||||
client_a
|
client_a
|
||||||
.user_store
|
.user_store()
|
||||||
.update(cx_a, |store, cx| {
|
.update(cx_a, |store, cx| {
|
||||||
store.request_contact(client_b.user_id().unwrap(), cx)
|
store.request_contact(client_b.user_id().unwrap(), cx)
|
||||||
})
|
})
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
client_c
|
client_c
|
||||||
.user_store
|
.user_store()
|
||||||
.update(cx_c, |store, cx| {
|
.update(cx_c, |store, cx| {
|
||||||
store.request_contact(client_b.user_id().unwrap(), cx)
|
store.request_contact(client_b.user_id().unwrap(), cx)
|
||||||
})
|
})
|
||||||
@ -6293,7 +6291,7 @@ async fn test_contact_requests(
|
|||||||
|
|
||||||
// User B accepts the request from user A.
|
// User B accepts the request from user A.
|
||||||
client_b
|
client_b
|
||||||
.user_store
|
.user_store()
|
||||||
.update(cx_b, |store, cx| {
|
.update(cx_b, |store, cx| {
|
||||||
store.respond_to_contact_request(client_a.user_id().unwrap(), true, cx)
|
store.respond_to_contact_request(client_a.user_id().unwrap(), true, cx)
|
||||||
})
|
})
|
||||||
@ -6337,7 +6335,7 @@ async fn test_contact_requests(
|
|||||||
|
|
||||||
// User B rejects the request from user C.
|
// User B rejects the request from user C.
|
||||||
client_b
|
client_b
|
||||||
.user_store
|
.user_store()
|
||||||
.update(cx_b, |store, cx| {
|
.update(cx_b, |store, cx| {
|
||||||
store.respond_to_contact_request(client_c.user_id().unwrap(), false, cx)
|
store.respond_to_contact_request(client_c.user_id().unwrap(), false, cx)
|
||||||
})
|
})
|
||||||
@ -6419,7 +6417,7 @@ async fn test_basic_following(
|
|||||||
cx_b.update(editor::init);
|
cx_b.update(editor::init);
|
||||||
|
|
||||||
client_a
|
client_a
|
||||||
.fs
|
.fs()
|
||||||
.insert_tree(
|
.insert_tree(
|
||||||
"/a",
|
"/a",
|
||||||
json!({
|
json!({
|
||||||
@ -6980,7 +6978,7 @@ async fn test_join_call_after_screen_was_shared(
|
|||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
client_b.user_store.update(cx_b, |user_store, _| {
|
client_b.user_store().update(cx_b, |user_store, _| {
|
||||||
user_store.clear_cache();
|
user_store.clear_cache();
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -7040,7 +7038,7 @@ async fn test_following_tab_order(
|
|||||||
cx_b.update(editor::init);
|
cx_b.update(editor::init);
|
||||||
|
|
||||||
client_a
|
client_a
|
||||||
.fs
|
.fs()
|
||||||
.insert_tree(
|
.insert_tree(
|
||||||
"/a",
|
"/a",
|
||||||
json!({
|
json!({
|
||||||
@ -7163,7 +7161,7 @@ async fn test_peers_following_each_other(
|
|||||||
|
|
||||||
// Client A shares a project.
|
// Client A shares a project.
|
||||||
client_a
|
client_a
|
||||||
.fs
|
.fs()
|
||||||
.insert_tree(
|
.insert_tree(
|
||||||
"/a",
|
"/a",
|
||||||
json!({
|
json!({
|
||||||
@ -7336,7 +7334,7 @@ async fn test_auto_unfollowing(
|
|||||||
|
|
||||||
// Client A shares a project.
|
// Client A shares a project.
|
||||||
client_a
|
client_a
|
||||||
.fs
|
.fs()
|
||||||
.insert_tree(
|
.insert_tree(
|
||||||
"/a",
|
"/a",
|
||||||
json!({
|
json!({
|
||||||
@ -7500,7 +7498,7 @@ async fn test_peers_simultaneously_following_each_other(
|
|||||||
cx_a.update(editor::init);
|
cx_a.update(editor::init);
|
||||||
cx_b.update(editor::init);
|
cx_b.update(editor::init);
|
||||||
|
|
||||||
client_a.fs.insert_tree("/a", json!({})).await;
|
client_a.fs().insert_tree("/a", json!({})).await;
|
||||||
let (project_a, _) = client_a.build_local_project("/a", cx_a).await;
|
let (project_a, _) = client_a.build_local_project("/a", cx_a).await;
|
||||||
let workspace_a = client_a.build_workspace(&project_a, cx_a);
|
let workspace_a = client_a.build_workspace(&project_a, cx_a);
|
||||||
let project_id = active_call_a
|
let project_id = active_call_a
|
||||||
@ -7577,10 +7575,10 @@ async fn test_on_input_format_from_host_to_guest(
|
|||||||
..Default::default()
|
..Default::default()
|
||||||
}))
|
}))
|
||||||
.await;
|
.await;
|
||||||
client_a.language_registry.add(Arc::new(language));
|
client_a.language_registry().add(Arc::new(language));
|
||||||
|
|
||||||
client_a
|
client_a
|
||||||
.fs
|
.fs()
|
||||||
.insert_tree(
|
.insert_tree(
|
||||||
"/a",
|
"/a",
|
||||||
json!({
|
json!({
|
||||||
@ -7706,10 +7704,10 @@ async fn test_on_input_format_from_guest_to_host(
|
|||||||
..Default::default()
|
..Default::default()
|
||||||
}))
|
}))
|
||||||
.await;
|
.await;
|
||||||
client_a.language_registry.add(Arc::new(language));
|
client_a.language_registry().add(Arc::new(language));
|
||||||
|
|
||||||
client_a
|
client_a
|
||||||
.fs
|
.fs()
|
||||||
.insert_tree(
|
.insert_tree(
|
||||||
"/a",
|
"/a",
|
||||||
json!({
|
json!({
|
||||||
@ -7862,11 +7860,11 @@ async fn test_mutual_editor_inlay_hint_cache_update(
|
|||||||
}))
|
}))
|
||||||
.await;
|
.await;
|
||||||
let language = Arc::new(language);
|
let language = Arc::new(language);
|
||||||
client_a.language_registry.add(Arc::clone(&language));
|
client_a.language_registry().add(Arc::clone(&language));
|
||||||
client_b.language_registry.add(language);
|
client_b.language_registry().add(language);
|
||||||
|
|
||||||
client_a
|
client_a
|
||||||
.fs
|
.fs()
|
||||||
.insert_tree(
|
.insert_tree(
|
||||||
"/a",
|
"/a",
|
||||||
json!({
|
json!({
|
||||||
@ -8169,11 +8167,11 @@ async fn test_inlay_hint_refresh_is_forwarded(
|
|||||||
}))
|
}))
|
||||||
.await;
|
.await;
|
||||||
let language = Arc::new(language);
|
let language = Arc::new(language);
|
||||||
client_a.language_registry.add(Arc::clone(&language));
|
client_a.language_registry().add(Arc::clone(&language));
|
||||||
client_b.language_registry.add(language);
|
client_b.language_registry().add(language);
|
||||||
|
|
||||||
client_a
|
client_a
|
||||||
.fs
|
.fs()
|
||||||
.insert_tree(
|
.insert_tree(
|
||||||
"/a",
|
"/a",
|
||||||
json!({
|
json!({
|
||||||
|
@ -396,9 +396,9 @@ async fn apply_client_operation(
|
|||||||
);
|
);
|
||||||
|
|
||||||
let root_path = Path::new("/").join(&first_root_name);
|
let root_path = Path::new("/").join(&first_root_name);
|
||||||
client.fs.create_dir(&root_path).await.unwrap();
|
client.fs().create_dir(&root_path).await.unwrap();
|
||||||
client
|
client
|
||||||
.fs
|
.fs()
|
||||||
.create_file(&root_path.join("main.rs"), Default::default())
|
.create_file(&root_path.join("main.rs"), Default::default())
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
@ -422,8 +422,8 @@ async fn apply_client_operation(
|
|||||||
);
|
);
|
||||||
|
|
||||||
ensure_project_shared(&project, client, cx).await;
|
ensure_project_shared(&project, client, cx).await;
|
||||||
if !client.fs.paths(false).contains(&new_root_path) {
|
if !client.fs().paths(false).contains(&new_root_path) {
|
||||||
client.fs.create_dir(&new_root_path).await.unwrap();
|
client.fs().create_dir(&new_root_path).await.unwrap();
|
||||||
}
|
}
|
||||||
project
|
project
|
||||||
.update(cx, |project, cx| {
|
.update(cx, |project, cx| {
|
||||||
@ -475,7 +475,7 @@ async fn apply_client_operation(
|
|||||||
Some(room.update(cx, |room, cx| {
|
Some(room.update(cx, |room, cx| {
|
||||||
room.join_project(
|
room.join_project(
|
||||||
project_id,
|
project_id,
|
||||||
client.language_registry.clone(),
|
client.language_registry().clone(),
|
||||||
FakeFs::new(cx.background().clone()),
|
FakeFs::new(cx.background().clone()),
|
||||||
cx,
|
cx,
|
||||||
)
|
)
|
||||||
@ -743,7 +743,7 @@ async fn apply_client_operation(
|
|||||||
content,
|
content,
|
||||||
} => {
|
} => {
|
||||||
if !client
|
if !client
|
||||||
.fs
|
.fs()
|
||||||
.directories(false)
|
.directories(false)
|
||||||
.contains(&path.parent().unwrap().to_owned())
|
.contains(&path.parent().unwrap().to_owned())
|
||||||
{
|
{
|
||||||
@ -752,14 +752,14 @@ async fn apply_client_operation(
|
|||||||
|
|
||||||
if is_dir {
|
if is_dir {
|
||||||
log::info!("{}: creating dir at {:?}", client.username, path);
|
log::info!("{}: creating dir at {:?}", client.username, path);
|
||||||
client.fs.create_dir(&path).await.unwrap();
|
client.fs().create_dir(&path).await.unwrap();
|
||||||
} else {
|
} else {
|
||||||
let exists = client.fs.metadata(&path).await?.is_some();
|
let exists = client.fs().metadata(&path).await?.is_some();
|
||||||
let verb = if exists { "updating" } else { "creating" };
|
let verb = if exists { "updating" } else { "creating" };
|
||||||
log::info!("{}: {} file at {:?}", verb, client.username, path);
|
log::info!("{}: {} file at {:?}", verb, client.username, path);
|
||||||
|
|
||||||
client
|
client
|
||||||
.fs
|
.fs()
|
||||||
.save(&path, &content.as_str().into(), fs::LineEnding::Unix)
|
.save(&path, &content.as_str().into(), fs::LineEnding::Unix)
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
@ -771,12 +771,12 @@ async fn apply_client_operation(
|
|||||||
repo_path,
|
repo_path,
|
||||||
contents,
|
contents,
|
||||||
} => {
|
} => {
|
||||||
if !client.fs.directories(false).contains(&repo_path) {
|
if !client.fs().directories(false).contains(&repo_path) {
|
||||||
return Err(TestError::Inapplicable);
|
return Err(TestError::Inapplicable);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (path, _) in contents.iter() {
|
for (path, _) in contents.iter() {
|
||||||
if !client.fs.files().contains(&repo_path.join(path)) {
|
if !client.fs().files().contains(&repo_path.join(path)) {
|
||||||
return Err(TestError::Inapplicable);
|
return Err(TestError::Inapplicable);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -793,16 +793,16 @@ async fn apply_client_operation(
|
|||||||
.iter()
|
.iter()
|
||||||
.map(|(path, contents)| (path.as_path(), contents.clone()))
|
.map(|(path, contents)| (path.as_path(), contents.clone()))
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
if client.fs.metadata(&dot_git_dir).await?.is_none() {
|
if client.fs().metadata(&dot_git_dir).await?.is_none() {
|
||||||
client.fs.create_dir(&dot_git_dir).await?;
|
client.fs().create_dir(&dot_git_dir).await?;
|
||||||
}
|
}
|
||||||
client.fs.set_index_for_repo(&dot_git_dir, &contents);
|
client.fs().set_index_for_repo(&dot_git_dir, &contents);
|
||||||
}
|
}
|
||||||
GitOperation::WriteGitBranch {
|
GitOperation::WriteGitBranch {
|
||||||
repo_path,
|
repo_path,
|
||||||
new_branch,
|
new_branch,
|
||||||
} => {
|
} => {
|
||||||
if !client.fs.directories(false).contains(&repo_path) {
|
if !client.fs().directories(false).contains(&repo_path) {
|
||||||
return Err(TestError::Inapplicable);
|
return Err(TestError::Inapplicable);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -814,21 +814,21 @@ async fn apply_client_operation(
|
|||||||
);
|
);
|
||||||
|
|
||||||
let dot_git_dir = repo_path.join(".git");
|
let dot_git_dir = repo_path.join(".git");
|
||||||
if client.fs.metadata(&dot_git_dir).await?.is_none() {
|
if client.fs().metadata(&dot_git_dir).await?.is_none() {
|
||||||
client.fs.create_dir(&dot_git_dir).await?;
|
client.fs().create_dir(&dot_git_dir).await?;
|
||||||
}
|
}
|
||||||
client.fs.set_branch_name(&dot_git_dir, new_branch);
|
client.fs().set_branch_name(&dot_git_dir, new_branch);
|
||||||
}
|
}
|
||||||
GitOperation::WriteGitStatuses {
|
GitOperation::WriteGitStatuses {
|
||||||
repo_path,
|
repo_path,
|
||||||
statuses,
|
statuses,
|
||||||
git_operation,
|
git_operation,
|
||||||
} => {
|
} => {
|
||||||
if !client.fs.directories(false).contains(&repo_path) {
|
if !client.fs().directories(false).contains(&repo_path) {
|
||||||
return Err(TestError::Inapplicable);
|
return Err(TestError::Inapplicable);
|
||||||
}
|
}
|
||||||
for (path, _) in statuses.iter() {
|
for (path, _) in statuses.iter() {
|
||||||
if !client.fs.files().contains(&repo_path.join(path)) {
|
if !client.fs().files().contains(&repo_path.join(path)) {
|
||||||
return Err(TestError::Inapplicable);
|
return Err(TestError::Inapplicable);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -847,16 +847,16 @@ async fn apply_client_operation(
|
|||||||
.map(|(path, val)| (path.as_path(), val.clone()))
|
.map(|(path, val)| (path.as_path(), val.clone()))
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
if client.fs.metadata(&dot_git_dir).await?.is_none() {
|
if client.fs().metadata(&dot_git_dir).await?.is_none() {
|
||||||
client.fs.create_dir(&dot_git_dir).await?;
|
client.fs().create_dir(&dot_git_dir).await?;
|
||||||
}
|
}
|
||||||
|
|
||||||
if git_operation {
|
if git_operation {
|
||||||
client
|
client
|
||||||
.fs
|
.fs()
|
||||||
.set_status_for_repo_via_git_operation(&dot_git_dir, statuses.as_slice());
|
.set_status_for_repo_via_git_operation(&dot_git_dir, statuses.as_slice());
|
||||||
} else {
|
} else {
|
||||||
client.fs.set_status_for_repo_via_working_copy_change(
|
client.fs().set_status_for_repo_via_working_copy_change(
|
||||||
&dot_git_dir,
|
&dot_git_dir,
|
||||||
statuses.as_slice(),
|
statuses.as_slice(),
|
||||||
);
|
);
|
||||||
@ -1499,7 +1499,7 @@ impl TestPlan {
|
|||||||
// Invite a contact to the current call
|
// Invite a contact to the current call
|
||||||
0..=70 => {
|
0..=70 => {
|
||||||
let available_contacts =
|
let available_contacts =
|
||||||
client.user_store.read_with(cx, |user_store, _| {
|
client.user_store().read_with(cx, |user_store, _| {
|
||||||
user_store
|
user_store
|
||||||
.contacts()
|
.contacts()
|
||||||
.iter()
|
.iter()
|
||||||
@ -1596,7 +1596,7 @@ impl TestPlan {
|
|||||||
.choose(&mut self.rng)
|
.choose(&mut self.rng)
|
||||||
.cloned() else { continue };
|
.cloned() else { continue };
|
||||||
let project_root_name = root_name_for_project(&project, cx);
|
let project_root_name = root_name_for_project(&project, cx);
|
||||||
let mut paths = client.fs.paths(false);
|
let mut paths = client.fs().paths(false);
|
||||||
paths.remove(0);
|
paths.remove(0);
|
||||||
let new_root_path = if paths.is_empty() || self.rng.gen() {
|
let new_root_path = if paths.is_empty() || self.rng.gen() {
|
||||||
Path::new("/").join(&self.next_root_dir_name(user_id))
|
Path::new("/").join(&self.next_root_dir_name(user_id))
|
||||||
@ -1776,7 +1776,7 @@ impl TestPlan {
|
|||||||
let is_dir = self.rng.gen::<bool>();
|
let is_dir = self.rng.gen::<bool>();
|
||||||
let content;
|
let content;
|
||||||
let mut path;
|
let mut path;
|
||||||
let dir_paths = client.fs.directories(false);
|
let dir_paths = client.fs().directories(false);
|
||||||
|
|
||||||
if is_dir {
|
if is_dir {
|
||||||
content = String::new();
|
content = String::new();
|
||||||
@ -1786,7 +1786,7 @@ impl TestPlan {
|
|||||||
content = Alphanumeric.sample_string(&mut self.rng, 16);
|
content = Alphanumeric.sample_string(&mut self.rng, 16);
|
||||||
|
|
||||||
// Create a new file or overwrite an existing file
|
// Create a new file or overwrite an existing file
|
||||||
let file_paths = client.fs.files();
|
let file_paths = client.fs().files();
|
||||||
if file_paths.is_empty() || self.rng.gen_bool(0.5) {
|
if file_paths.is_empty() || self.rng.gen_bool(0.5) {
|
||||||
path = dir_paths.choose(&mut self.rng).unwrap().clone();
|
path = dir_paths.choose(&mut self.rng).unwrap().clone();
|
||||||
path.push(gen_file_name(&mut self.rng));
|
path.push(gen_file_name(&mut self.rng));
|
||||||
@ -1812,7 +1812,7 @@ impl TestPlan {
|
|||||||
client: &TestClient,
|
client: &TestClient,
|
||||||
) -> Vec<PathBuf> {
|
) -> Vec<PathBuf> {
|
||||||
let mut paths = client
|
let mut paths = client
|
||||||
.fs
|
.fs()
|
||||||
.files()
|
.files()
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.filter(|path| path.starts_with(repo_path))
|
.filter(|path| path.starts_with(repo_path))
|
||||||
@ -1829,7 +1829,7 @@ impl TestPlan {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let repo_path = client
|
let repo_path = client
|
||||||
.fs
|
.fs()
|
||||||
.directories(false)
|
.directories(false)
|
||||||
.choose(&mut self.rng)
|
.choose(&mut self.rng)
|
||||||
.unwrap()
|
.unwrap()
|
||||||
@ -1928,7 +1928,7 @@ async fn simulate_client(
|
|||||||
name: "the-fake-language-server",
|
name: "the-fake-language-server",
|
||||||
capabilities: lsp::LanguageServer::full_capabilities(),
|
capabilities: lsp::LanguageServer::full_capabilities(),
|
||||||
initializer: Some(Box::new({
|
initializer: Some(Box::new({
|
||||||
let fs = client.fs.clone();
|
let fs = client.app_state.fs.clone();
|
||||||
move |fake_server: &mut FakeLanguageServer| {
|
move |fake_server: &mut FakeLanguageServer| {
|
||||||
fake_server.handle_request::<lsp::request::Completion, _, _>(
|
fake_server.handle_request::<lsp::request::Completion, _, _>(
|
||||||
|_, _| async move {
|
|_, _| async move {
|
||||||
@ -1973,7 +1973,7 @@ async fn simulate_client(
|
|||||||
let background = cx.background();
|
let background = cx.background();
|
||||||
let mut rng = background.rng();
|
let mut rng = background.rng();
|
||||||
let count = rng.gen_range::<usize, _>(1..3);
|
let count = rng.gen_range::<usize, _>(1..3);
|
||||||
let files = fs.files();
|
let files = fs.as_fake().files();
|
||||||
let files = (0..count)
|
let files = (0..count)
|
||||||
.map(|_| files.choose(&mut *rng).unwrap().clone())
|
.map(|_| files.choose(&mut *rng).unwrap().clone())
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
@ -2023,7 +2023,7 @@ async fn simulate_client(
|
|||||||
..Default::default()
|
..Default::default()
|
||||||
}))
|
}))
|
||||||
.await;
|
.await;
|
||||||
client.language_registry.add(Arc::new(language));
|
client.app_state.languages.add(Arc::new(language));
|
||||||
|
|
||||||
while let Some(batch_id) = operation_rx.next().await {
|
while let Some(batch_id) = operation_rx.next().await {
|
||||||
let Some((operation, applied)) = plan.lock().next_client_operation(&client, batch_id, &cx) else { break };
|
let Some((operation, applied)) = plan.lock().next_client_operation(&client, batch_id, &cx) else { break };
|
||||||
|
@ -3,9 +3,9 @@ mod contact_notification;
|
|||||||
mod face_pile;
|
mod face_pile;
|
||||||
mod incoming_call_notification;
|
mod incoming_call_notification;
|
||||||
mod notifications;
|
mod notifications;
|
||||||
|
pub mod panel;
|
||||||
mod project_shared_notification;
|
mod project_shared_notification;
|
||||||
mod sharing_status_indicator;
|
mod sharing_status_indicator;
|
||||||
pub mod panel;
|
|
||||||
|
|
||||||
use call::{ActiveCall, Room};
|
use call::{ActiveCall, Room};
|
||||||
pub use collab_titlebar_item::CollabTitlebarItem;
|
pub use collab_titlebar_item::CollabTitlebarItem;
|
||||||
|
@ -6,7 +6,7 @@ use anyhow::Result;
|
|||||||
use call::ActiveCall;
|
use call::ActiveCall;
|
||||||
use client::{proto::PeerId, Channel, ChannelStore, Client, Contact, User, UserStore};
|
use client::{proto::PeerId, Channel, ChannelStore, Client, Contact, User, UserStore};
|
||||||
use contact_finder::build_contact_finder;
|
use contact_finder::build_contact_finder;
|
||||||
use context_menu::ContextMenu;
|
use context_menu::{ContextMenu, ContextMenuItem};
|
||||||
use db::kvp::KEY_VALUE_STORE;
|
use db::kvp::KEY_VALUE_STORE;
|
||||||
use editor::{Cancel, Editor};
|
use editor::{Cancel, Editor};
|
||||||
use futures::StreamExt;
|
use futures::StreamExt;
|
||||||
@ -18,6 +18,7 @@ use gpui::{
|
|||||||
MouseEventHandler, Orientation, Padding, ParentElement, Stack, Svg,
|
MouseEventHandler, Orientation, Padding, ParentElement, Stack, Svg,
|
||||||
},
|
},
|
||||||
geometry::{rect::RectF, vector::vec2f},
|
geometry::{rect::RectF, vector::vec2f},
|
||||||
|
impl_actions,
|
||||||
platform::{CursorStyle, MouseButton, PromptLevel},
|
platform::{CursorStyle, MouseButton, PromptLevel},
|
||||||
serde_json, AnyElement, AppContext, AsyncAppContext, Element, Entity, ModelHandle,
|
serde_json, AnyElement, AppContext, AsyncAppContext, Element, Entity, ModelHandle,
|
||||||
Subscription, Task, View, ViewContext, ViewHandle, WeakViewHandle,
|
Subscription, Task, View, ViewContext, ViewHandle, WeakViewHandle,
|
||||||
@ -36,8 +37,15 @@ use workspace::{
|
|||||||
Workspace,
|
Workspace,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
|
||||||
|
struct RemoveChannel {
|
||||||
|
channel_id: u64,
|
||||||
|
}
|
||||||
|
|
||||||
actions!(collab_panel, [ToggleFocus]);
|
actions!(collab_panel, [ToggleFocus]);
|
||||||
|
|
||||||
|
impl_actions!(collab_panel, [RemoveChannel]);
|
||||||
|
|
||||||
const CHANNELS_PANEL_KEY: &'static str = "ChannelsPanel";
|
const CHANNELS_PANEL_KEY: &'static str = "ChannelsPanel";
|
||||||
|
|
||||||
pub fn init(_client: Arc<Client>, cx: &mut AppContext) {
|
pub fn init(_client: Arc<Client>, cx: &mut AppContext) {
|
||||||
@ -49,6 +57,7 @@ pub fn init(_client: Arc<Client>, cx: &mut AppContext) {
|
|||||||
cx.add_action(CollabPanel::select_next);
|
cx.add_action(CollabPanel::select_next);
|
||||||
cx.add_action(CollabPanel::select_prev);
|
cx.add_action(CollabPanel::select_prev);
|
||||||
cx.add_action(CollabPanel::confirm);
|
cx.add_action(CollabPanel::confirm);
|
||||||
|
cx.add_action(CollabPanel::remove_channel);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Default)]
|
#[derive(Debug, Default)]
|
||||||
@ -305,6 +314,8 @@ impl CollabPanel {
|
|||||||
let active_call = ActiveCall::global(cx);
|
let active_call = ActiveCall::global(cx);
|
||||||
this.subscriptions
|
this.subscriptions
|
||||||
.push(cx.observe(&this.user_store, |this, _, cx| this.update_entries(cx)));
|
.push(cx.observe(&this.user_store, |this, _, cx| this.update_entries(cx)));
|
||||||
|
this.subscriptions
|
||||||
|
.push(cx.observe(&this.channel_store, |this, _, cx| this.update_entries(cx)));
|
||||||
this.subscriptions
|
this.subscriptions
|
||||||
.push(cx.observe(&active_call, |this, _, cx| this.update_entries(cx)));
|
.push(cx.observe(&active_call, |this, _, cx| this.update_entries(cx)));
|
||||||
|
|
||||||
@ -1278,6 +1289,19 @@ impl CollabPanel {
|
|||||||
.on_click(MouseButton::Left, move |_, this, cx| {
|
.on_click(MouseButton::Left, move |_, this, cx| {
|
||||||
this.join_channel(channel_id, cx);
|
this.join_channel(channel_id, cx);
|
||||||
})
|
})
|
||||||
|
.on_click(MouseButton::Right, move |e, this, cx| {
|
||||||
|
this.context_menu.update(cx, |context_menu, cx| {
|
||||||
|
context_menu.show(
|
||||||
|
e.position,
|
||||||
|
gpui::elements::AnchorCorner::BottomLeft,
|
||||||
|
vec![ContextMenuItem::action(
|
||||||
|
"Remove Channel",
|
||||||
|
RemoveChannel { channel_id },
|
||||||
|
)],
|
||||||
|
cx,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
})
|
||||||
.into_any()
|
.into_any()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1564,14 +1588,13 @@ impl CollabPanel {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if let Some((_editing_state, channel_name)) = self.take_editing_state(cx) {
|
} else if let Some((_editing_state, channel_name)) = self.take_editing_state(cx) {
|
||||||
dbg!(&channel_name);
|
|
||||||
let create_channel = self.channel_store.update(cx, |channel_store, cx| {
|
let create_channel = self.channel_store.update(cx, |channel_store, cx| {
|
||||||
channel_store.create_channel(&channel_name, None)
|
channel_store.create_channel(&channel_name, None)
|
||||||
});
|
});
|
||||||
|
|
||||||
cx.foreground()
|
cx.foreground()
|
||||||
.spawn(async move {
|
.spawn(async move {
|
||||||
dbg!(create_channel.await).ok();
|
create_channel.await.ok();
|
||||||
})
|
})
|
||||||
.detach();
|
.detach();
|
||||||
}
|
}
|
||||||
@ -1600,6 +1623,36 @@ impl CollabPanel {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn remove_channel(&mut self, action: &RemoveChannel, cx: &mut ViewContext<Self>) {
|
||||||
|
let channel_id = action.channel_id;
|
||||||
|
let channel_store = self.channel_store.clone();
|
||||||
|
if let Some(channel) = channel_store.read(cx).channel_for_id(channel_id) {
|
||||||
|
let prompt_message = format!(
|
||||||
|
"Are you sure you want to remove the channel \"{}\"?",
|
||||||
|
channel.name
|
||||||
|
);
|
||||||
|
let mut answer =
|
||||||
|
cx.prompt(PromptLevel::Warning, &prompt_message, &["Remove", "Cancel"]);
|
||||||
|
let window_id = cx.window_id();
|
||||||
|
cx.spawn(|_, mut cx| async move {
|
||||||
|
if answer.next().await == Some(0) {
|
||||||
|
if let Err(e) = channel_store
|
||||||
|
.update(&mut cx, |channels, cx| channels.remove_channel(channel_id))
|
||||||
|
.await
|
||||||
|
{
|
||||||
|
cx.prompt(
|
||||||
|
window_id,
|
||||||
|
PromptLevel::Info,
|
||||||
|
&format!("Failed to remove channel: {}", e),
|
||||||
|
&["Ok"],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.detach();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn remove_contact(&mut self, user_id: u64, github_login: &str, cx: &mut ViewContext<Self>) {
|
fn remove_contact(&mut self, user_id: u64, github_login: &str, cx: &mut ViewContext<Self>) {
|
||||||
let user_store = self.user_store.clone();
|
let user_store = self.user_store.clone();
|
||||||
let prompt_message = format!(
|
let prompt_message = format!(
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
use editor::Editor;
|
use editor::Editor;
|
||||||
use gpui::{elements::*, AnyViewHandle, Entity, View, ViewContext, ViewHandle, AppContext};
|
use gpui::{elements::*, AnyViewHandle, AppContext, Entity, View, ViewContext, ViewHandle};
|
||||||
use menu::Cancel;
|
use menu::Cancel;
|
||||||
use workspace::{item::ItemHandle, Modal};
|
use workspace::{item::ItemHandle, Modal};
|
||||||
|
|
||||||
@ -62,12 +62,10 @@ impl View for ChannelModal {
|
|||||||
.constrained()
|
.constrained()
|
||||||
.with_max_width(540.)
|
.with_max_width(540.)
|
||||||
.with_max_height(420.)
|
.with_max_height(420.)
|
||||||
|
|
||||||
})
|
})
|
||||||
.on_click(gpui::platform::MouseButton::Left, |_, _, _| {}) // Capture click and down events
|
.on_click(gpui::platform::MouseButton::Left, |_, _, _| {}) // Capture click and down events
|
||||||
.on_down_out(gpui::platform::MouseButton::Left, |_, v, cx| {
|
.on_down_out(gpui::platform::MouseButton::Left, |_, v, cx| v.dismiss(cx))
|
||||||
v.dismiss(cx)
|
.into_any_named("channel modal")
|
||||||
}).into_any_named("channel modal")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn focus_in(&mut self, _: AnyViewHandle, cx: &mut ViewContext<Self>) {
|
fn focus_in(&mut self, _: AnyViewHandle, cx: &mut ViewContext<Self>) {
|
||||||
|
@ -137,6 +137,7 @@ message Envelope {
|
|||||||
RespondToChannelInvite respond_to_channel_invite = 123;
|
RespondToChannelInvite respond_to_channel_invite = 123;
|
||||||
UpdateChannels update_channels = 124;
|
UpdateChannels update_channels = 124;
|
||||||
JoinChannel join_channel = 125;
|
JoinChannel join_channel = 125;
|
||||||
|
RemoveChannel remove_channel = 126;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -875,6 +876,11 @@ message JoinChannel {
|
|||||||
uint64 channel_id = 1;
|
uint64 channel_id = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
message RemoveChannel {
|
||||||
|
uint64 channel_id = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
message CreateChannel {
|
message CreateChannel {
|
||||||
string name = 1;
|
string name = 1;
|
||||||
optional uint64 parent_id = 2;
|
optional uint64 parent_id = 2;
|
||||||
|
@ -231,6 +231,7 @@ messages!(
|
|||||||
(UpdateBuffer, Foreground),
|
(UpdateBuffer, Foreground),
|
||||||
(UpdateBufferFile, Foreground),
|
(UpdateBufferFile, Foreground),
|
||||||
(UpdateContacts, Foreground),
|
(UpdateContacts, Foreground),
|
||||||
|
(RemoveChannel, Foreground),
|
||||||
(UpdateChannels, Foreground),
|
(UpdateChannels, Foreground),
|
||||||
(UpdateDiagnosticSummary, Foreground),
|
(UpdateDiagnosticSummary, Foreground),
|
||||||
(UpdateFollowers, Foreground),
|
(UpdateFollowers, Foreground),
|
||||||
@ -296,6 +297,7 @@ request_messages!(
|
|||||||
(RespondToContactRequest, Ack),
|
(RespondToContactRequest, Ack),
|
||||||
(RespondToChannelInvite, Ack),
|
(RespondToChannelInvite, Ack),
|
||||||
(JoinChannel, JoinRoomResponse),
|
(JoinChannel, JoinRoomResponse),
|
||||||
|
(RemoveChannel, Ack),
|
||||||
(RenameProjectEntry, ProjectEntryResponse),
|
(RenameProjectEntry, ProjectEntryResponse),
|
||||||
(SaveBuffer, BufferSaved),
|
(SaveBuffer, BufferSaved),
|
||||||
(SearchProject, SearchProjectResponse),
|
(SearchProject, SearchProjectResponse),
|
||||||
|
@ -3412,6 +3412,7 @@ impl Workspace {
|
|||||||
pub fn test_new(project: ModelHandle<Project>, cx: &mut ViewContext<Self>) -> Self {
|
pub fn test_new(project: ModelHandle<Project>, cx: &mut ViewContext<Self>) -> Self {
|
||||||
let client = project.read(cx).client();
|
let client = project.read(cx).client();
|
||||||
let user_store = project.read(cx).user_store();
|
let user_store = project.read(cx).user_store();
|
||||||
|
|
||||||
let channel_store =
|
let channel_store =
|
||||||
cx.add_model(|cx| ChannelStore::new(client.clone(), user_store.clone(), cx));
|
cx.add_model(|cx| ChannelStore::new(client.clone(), user_store.clone(), cx));
|
||||||
let app_state = Arc::new(AppState {
|
let app_state = Arc::new(AppState {
|
||||||
|
Loading…
Reference in New Issue
Block a user