mirror of
https://github.com/zed-industries/zed.git
synced 2025-01-24 02:46:43 +00:00
Remove weak worktrees from project when nobody references them
Also, avoid showing them in the project panel as well as in the contacts panel.
This commit is contained in:
parent
ee95775b1c
commit
6e7e86e491
10 changed files with 261 additions and 170 deletions
|
@ -764,9 +764,9 @@ mod tests {
|
||||||
)
|
)
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
let worktree = project
|
let (worktree, _) = project
|
||||||
.update(&mut cx, |project, cx| {
|
.update(&mut cx, |project, cx| {
|
||||||
project.add_local_worktree("/test", cx)
|
project.find_or_create_worktree_for_abs_path("/test", false, cx)
|
||||||
})
|
})
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
|
@ -454,9 +454,10 @@ mod tests {
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
let (window_id, workspace) = cx.add_window(|cx| Workspace::new(¶ms, cx));
|
let (window_id, workspace) = cx.add_window(|cx| Workspace::new(¶ms, cx));
|
||||||
workspace
|
params
|
||||||
.update(&mut cx, |workspace, cx| {
|
.project
|
||||||
workspace.add_worktree(Path::new("/root"), cx)
|
.update(&mut cx, |project, cx| {
|
||||||
|
project.find_or_create_worktree_for_abs_path(Path::new("/root"), false, cx)
|
||||||
})
|
})
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
@ -514,9 +515,10 @@ mod tests {
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
let (_, workspace) = cx.add_window(|cx| Workspace::new(¶ms, cx));
|
let (_, workspace) = cx.add_window(|cx| Workspace::new(¶ms, cx));
|
||||||
workspace
|
params
|
||||||
.update(&mut cx, |workspace, cx| {
|
.project
|
||||||
workspace.add_worktree("/dir".as_ref(), cx)
|
.update(&mut cx, |project, cx| {
|
||||||
|
project.find_or_create_worktree_for_abs_path(Path::new("/dir"), false, cx)
|
||||||
})
|
})
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
@ -579,9 +581,14 @@ mod tests {
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
let (_, workspace) = cx.add_window(|cx| Workspace::new(¶ms, cx));
|
let (_, workspace) = cx.add_window(|cx| Workspace::new(¶ms, cx));
|
||||||
workspace
|
params
|
||||||
.update(&mut cx, |workspace, cx| {
|
.project
|
||||||
workspace.add_worktree(Path::new("/root/the-parent-dir/the-file"), cx)
|
.update(&mut cx, |project, cx| {
|
||||||
|
project.find_or_create_worktree_for_abs_path(
|
||||||
|
Path::new("/root/the-parent-dir/the-file"),
|
||||||
|
false,
|
||||||
|
cx,
|
||||||
|
)
|
||||||
})
|
})
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
|
@ -10,6 +10,7 @@ use futures::Future;
|
||||||
use fuzzy::{PathMatch, PathMatchCandidate, PathMatchCandidateSet};
|
use fuzzy::{PathMatch, PathMatchCandidate, PathMatchCandidateSet};
|
||||||
use gpui::{
|
use gpui::{
|
||||||
AppContext, AsyncAppContext, Entity, ModelContext, ModelHandle, MutableAppContext, Task,
|
AppContext, AsyncAppContext, Entity, ModelContext, ModelHandle, MutableAppContext, Task,
|
||||||
|
WeakModelHandle,
|
||||||
};
|
};
|
||||||
use language::{
|
use language::{
|
||||||
Bias, Buffer, DiagnosticEntry, File as _, Language, LanguageRegistry, ToOffset, ToPointUtf16,
|
Bias, Buffer, DiagnosticEntry, File as _, Language, LanguageRegistry, ToOffset, ToPointUtf16,
|
||||||
|
@ -28,7 +29,7 @@ pub use fs::*;
|
||||||
pub use worktree::*;
|
pub use worktree::*;
|
||||||
|
|
||||||
pub struct Project {
|
pub struct Project {
|
||||||
worktrees: Vec<ModelHandle<Worktree>>,
|
worktrees: Vec<WorktreeHandle>,
|
||||||
active_entry: Option<ProjectEntry>,
|
active_entry: Option<ProjectEntry>,
|
||||||
languages: Arc<LanguageRegistry>,
|
languages: Arc<LanguageRegistry>,
|
||||||
language_servers: HashMap<(WorktreeId, String), Arc<LanguageServer>>,
|
language_servers: HashMap<(WorktreeId, String), Arc<LanguageServer>>,
|
||||||
|
@ -41,6 +42,11 @@ pub struct Project {
|
||||||
language_servers_with_diagnostics_running: isize,
|
language_servers_with_diagnostics_running: isize,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enum WorktreeHandle {
|
||||||
|
Strong(ModelHandle<Worktree>),
|
||||||
|
Weak(WeakModelHandle<Worktree>),
|
||||||
|
}
|
||||||
|
|
||||||
enum ProjectClientState {
|
enum ProjectClientState {
|
||||||
Local {
|
Local {
|
||||||
is_shared: bool,
|
is_shared: bool,
|
||||||
|
@ -161,7 +167,7 @@ impl Project {
|
||||||
if let Some(project_id) = remote_id {
|
if let Some(project_id) = remote_id {
|
||||||
let mut registrations = Vec::new();
|
let mut registrations = Vec::new();
|
||||||
this.update(&mut cx, |this, cx| {
|
this.update(&mut cx, |this, cx| {
|
||||||
for worktree in &this.worktrees {
|
for worktree in this.worktrees(cx).collect::<Vec<_>>() {
|
||||||
registrations.push(worktree.update(
|
registrations.push(worktree.update(
|
||||||
cx,
|
cx,
|
||||||
|worktree, cx| {
|
|worktree, cx| {
|
||||||
|
@ -295,7 +301,7 @@ impl Project {
|
||||||
language_servers: Default::default(),
|
language_servers: Default::default(),
|
||||||
};
|
};
|
||||||
for worktree in worktrees {
|
for worktree in worktrees {
|
||||||
this.add_worktree(worktree, cx);
|
this.add_worktree(&worktree, false, cx);
|
||||||
}
|
}
|
||||||
this
|
this
|
||||||
}))
|
}))
|
||||||
|
@ -364,8 +370,13 @@ impl Project {
|
||||||
&self.collaborators
|
&self.collaborators
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn worktrees(&self) -> &[ModelHandle<Worktree>] {
|
pub fn worktrees<'a>(
|
||||||
&self.worktrees
|
&'a self,
|
||||||
|
cx: &'a AppContext,
|
||||||
|
) -> impl 'a + Iterator<Item = ModelHandle<Worktree>> {
|
||||||
|
self.worktrees
|
||||||
|
.iter()
|
||||||
|
.filter_map(move |worktree| worktree.upgrade(cx))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn worktree_for_id(
|
pub fn worktree_for_id(
|
||||||
|
@ -373,10 +384,8 @@ impl Project {
|
||||||
id: WorktreeId,
|
id: WorktreeId,
|
||||||
cx: &AppContext,
|
cx: &AppContext,
|
||||||
) -> Option<ModelHandle<Worktree>> {
|
) -> Option<ModelHandle<Worktree>> {
|
||||||
self.worktrees
|
self.worktrees(cx)
|
||||||
.iter()
|
|
||||||
.find(|worktree| worktree.read(cx).id() == id)
|
.find(|worktree| worktree.read(cx).id() == id)
|
||||||
.cloned()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn share(&self, cx: &mut ModelContext<Self>) -> Task<anyhow::Result<()>> {
|
pub fn share(&self, cx: &mut ModelContext<Self>) -> Task<anyhow::Result<()>> {
|
||||||
|
@ -401,7 +410,7 @@ impl Project {
|
||||||
rpc.request(proto::ShareProject { project_id }).await?;
|
rpc.request(proto::ShareProject { project_id }).await?;
|
||||||
let mut tasks = Vec::new();
|
let mut tasks = Vec::new();
|
||||||
this.update(&mut cx, |this, cx| {
|
this.update(&mut cx, |this, cx| {
|
||||||
for worktree in &this.worktrees {
|
for worktree in this.worktrees(cx).collect::<Vec<_>>() {
|
||||||
worktree.update(cx, |worktree, cx| {
|
worktree.update(cx, |worktree, cx| {
|
||||||
let worktree = worktree.as_local_mut().unwrap();
|
let worktree = worktree.as_local_mut().unwrap();
|
||||||
tasks.push(worktree.share(cx));
|
tasks.push(worktree.share(cx));
|
||||||
|
@ -438,7 +447,7 @@ impl Project {
|
||||||
rpc.send(proto::UnshareProject { project_id }).await?;
|
rpc.send(proto::UnshareProject { project_id }).await?;
|
||||||
this.update(&mut cx, |this, cx| {
|
this.update(&mut cx, |this, cx| {
|
||||||
this.collaborators.clear();
|
this.collaborators.clear();
|
||||||
for worktree in &this.worktrees {
|
for worktree in this.worktrees(cx).collect::<Vec<_>>() {
|
||||||
worktree.update(cx, |worktree, _| {
|
worktree.update(cx, |worktree, _| {
|
||||||
worktree.as_local_mut().unwrap().unshare();
|
worktree.as_local_mut().unwrap().unshare();
|
||||||
});
|
});
|
||||||
|
@ -494,7 +503,7 @@ impl Project {
|
||||||
abs_path: PathBuf,
|
abs_path: PathBuf,
|
||||||
cx: &mut ModelContext<Project>,
|
cx: &mut ModelContext<Project>,
|
||||||
) -> Task<Result<()>> {
|
) -> Task<Result<()>> {
|
||||||
let worktree_task = self.find_or_create_worktree_for_abs_path(&abs_path, cx);
|
let worktree_task = self.find_or_create_worktree_for_abs_path(&abs_path, false, cx);
|
||||||
cx.spawn(|this, mut cx| async move {
|
cx.spawn(|this, mut cx| async move {
|
||||||
let (worktree, path) = worktree_task.await?;
|
let (worktree, path) = worktree_task.await?;
|
||||||
worktree
|
worktree
|
||||||
|
@ -777,7 +786,7 @@ impl Project {
|
||||||
} else {
|
} else {
|
||||||
let (worktree, relative_path) = this
|
let (worktree, relative_path) = this
|
||||||
.update(&mut cx, |this, cx| {
|
.update(&mut cx, |this, cx| {
|
||||||
this.create_worktree_for_abs_path(&abs_path, cx)
|
this.create_worktree_for_abs_path(&abs_path, true, cx)
|
||||||
})
|
})
|
||||||
.await?;
|
.await?;
|
||||||
this.update(&mut cx, |this, cx| {
|
this.update(&mut cx, |this, cx| {
|
||||||
|
@ -829,22 +838,25 @@ impl Project {
|
||||||
|
|
||||||
pub fn find_or_create_worktree_for_abs_path(
|
pub fn find_or_create_worktree_for_abs_path(
|
||||||
&self,
|
&self,
|
||||||
abs_path: &Path,
|
abs_path: impl AsRef<Path>,
|
||||||
|
weak: bool,
|
||||||
cx: &mut ModelContext<Self>,
|
cx: &mut ModelContext<Self>,
|
||||||
) -> Task<Result<(ModelHandle<Worktree>, PathBuf)>> {
|
) -> Task<Result<(ModelHandle<Worktree>, PathBuf)>> {
|
||||||
|
let abs_path = abs_path.as_ref();
|
||||||
if let Some((tree, relative_path)) = self.find_worktree_for_abs_path(abs_path, cx) {
|
if let Some((tree, relative_path)) = self.find_worktree_for_abs_path(abs_path, cx) {
|
||||||
Task::ready(Ok((tree.clone(), relative_path.into())))
|
Task::ready(Ok((tree.clone(), relative_path.into())))
|
||||||
} else {
|
} else {
|
||||||
self.create_worktree_for_abs_path(abs_path, cx)
|
self.create_worktree_for_abs_path(abs_path, weak, cx)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn create_worktree_for_abs_path(
|
fn create_worktree_for_abs_path(
|
||||||
&self,
|
&self,
|
||||||
abs_path: &Path,
|
abs_path: &Path,
|
||||||
|
weak: bool,
|
||||||
cx: &mut ModelContext<Self>,
|
cx: &mut ModelContext<Self>,
|
||||||
) -> Task<Result<(ModelHandle<Worktree>, PathBuf)>> {
|
) -> Task<Result<(ModelHandle<Worktree>, PathBuf)>> {
|
||||||
let worktree = self.add_local_worktree(abs_path, cx);
|
let worktree = self.add_local_worktree(abs_path, weak, cx);
|
||||||
cx.background().spawn(async move {
|
cx.background().spawn(async move {
|
||||||
let worktree = worktree.await?;
|
let worktree = worktree.await?;
|
||||||
Ok((worktree, PathBuf::new()))
|
Ok((worktree, PathBuf::new()))
|
||||||
|
@ -856,7 +868,7 @@ impl Project {
|
||||||
abs_path: &Path,
|
abs_path: &Path,
|
||||||
cx: &AppContext,
|
cx: &AppContext,
|
||||||
) -> Option<(ModelHandle<Worktree>, PathBuf)> {
|
) -> Option<(ModelHandle<Worktree>, PathBuf)> {
|
||||||
for tree in &self.worktrees {
|
for tree in self.worktrees(cx) {
|
||||||
if let Some(relative_path) = tree
|
if let Some(relative_path) = tree
|
||||||
.read(cx)
|
.read(cx)
|
||||||
.as_local()
|
.as_local()
|
||||||
|
@ -875,9 +887,10 @@ impl Project {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn add_local_worktree(
|
fn add_local_worktree(
|
||||||
&self,
|
&self,
|
||||||
abs_path: impl AsRef<Path>,
|
abs_path: impl AsRef<Path>,
|
||||||
|
weak: bool,
|
||||||
cx: &mut ModelContext<Self>,
|
cx: &mut ModelContext<Self>,
|
||||||
) -> Task<Result<ModelHandle<Worktree>>> {
|
) -> Task<Result<ModelHandle<Worktree>>> {
|
||||||
let fs = self.fs.clone();
|
let fs = self.fs.clone();
|
||||||
|
@ -886,10 +899,10 @@ impl Project {
|
||||||
let path = Arc::from(abs_path.as_ref());
|
let path = Arc::from(abs_path.as_ref());
|
||||||
cx.spawn(|project, mut cx| async move {
|
cx.spawn(|project, mut cx| async move {
|
||||||
let worktree =
|
let worktree =
|
||||||
Worktree::open_local(client.clone(), user_store, path, fs, &mut cx).await?;
|
Worktree::open_local(client.clone(), user_store, path, weak, fs, &mut cx).await?;
|
||||||
|
|
||||||
let (remote_project_id, is_shared) = project.update(&mut cx, |project, cx| {
|
let (remote_project_id, is_shared) = project.update(&mut cx, |project, cx| {
|
||||||
project.add_worktree(worktree.clone(), cx);
|
project.add_worktree(&worktree, weak, cx);
|
||||||
(project.remote_id(), project.is_shared())
|
(project.remote_id(), project.is_shared())
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -913,14 +926,28 @@ impl Project {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn remove_worktree(&mut self, id: WorktreeId, cx: &mut ModelContext<Self>) {
|
pub fn remove_worktree(&mut self, id: WorktreeId, cx: &mut ModelContext<Self>) {
|
||||||
self.worktrees
|
self.worktrees.retain(|worktree| {
|
||||||
.retain(|worktree| worktree.read(cx).id() != id);
|
worktree
|
||||||
|
.upgrade(cx)
|
||||||
|
.map_or(false, |w| w.read(cx).id() != id)
|
||||||
|
});
|
||||||
cx.notify();
|
cx.notify();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn add_worktree(&mut self, worktree: ModelHandle<Worktree>, cx: &mut ModelContext<Self>) {
|
fn add_worktree(
|
||||||
|
&mut self,
|
||||||
|
worktree: &ModelHandle<Worktree>,
|
||||||
|
weak: bool,
|
||||||
|
cx: &mut ModelContext<Self>,
|
||||||
|
) {
|
||||||
cx.observe(&worktree, |_, _, cx| cx.notify()).detach();
|
cx.observe(&worktree, |_, _, cx| cx.notify()).detach();
|
||||||
self.worktrees.push(worktree);
|
if weak {
|
||||||
|
self.worktrees
|
||||||
|
.push(WorktreeHandle::Weak(worktree.downgrade()));
|
||||||
|
} else {
|
||||||
|
self.worktrees
|
||||||
|
.push(WorktreeHandle::Strong(worktree.clone()));
|
||||||
|
}
|
||||||
cx.notify();
|
cx.notify();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -966,7 +993,7 @@ impl Project {
|
||||||
&'a self,
|
&'a self,
|
||||||
cx: &'a AppContext,
|
cx: &'a AppContext,
|
||||||
) -> impl Iterator<Item = (ProjectPath, DiagnosticSummary)> + 'a {
|
) -> impl Iterator<Item = (ProjectPath, DiagnosticSummary)> + 'a {
|
||||||
self.worktrees.iter().flat_map(move |worktree| {
|
self.worktrees(cx).flat_map(move |worktree| {
|
||||||
let worktree = worktree.read(cx);
|
let worktree = worktree.read(cx);
|
||||||
let worktree_id = worktree.id();
|
let worktree_id = worktree.id();
|
||||||
worktree
|
worktree
|
||||||
|
@ -1059,7 +1086,7 @@ impl Project {
|
||||||
.remove(&peer_id)
|
.remove(&peer_id)
|
||||||
.ok_or_else(|| anyhow!("unknown peer {:?}", peer_id))?
|
.ok_or_else(|| anyhow!("unknown peer {:?}", peer_id))?
|
||||||
.replica_id;
|
.replica_id;
|
||||||
for worktree in &self.worktrees {
|
for worktree in self.worktrees(cx).collect::<Vec<_>>() {
|
||||||
worktree.update(cx, |worktree, cx| {
|
worktree.update(cx, |worktree, cx| {
|
||||||
worktree.remove_collaborator(peer_id, replica_id, cx);
|
worktree.remove_collaborator(peer_id, replica_id, cx);
|
||||||
})
|
})
|
||||||
|
@ -1085,7 +1112,7 @@ impl Project {
|
||||||
let worktree =
|
let worktree =
|
||||||
Worktree::remote(remote_id, replica_id, worktree, client, user_store, &mut cx)
|
Worktree::remote(remote_id, replica_id, worktree, client, user_store, &mut cx)
|
||||||
.await?;
|
.await?;
|
||||||
this.update(&mut cx, |this, cx| this.add_worktree(worktree, cx));
|
this.update(&mut cx, |this, cx| this.add_worktree(&worktree, false, cx));
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
.log_err()
|
.log_err()
|
||||||
|
@ -1293,8 +1320,7 @@ impl Project {
|
||||||
) -> impl 'a + Future<Output = Vec<PathMatch>> {
|
) -> impl 'a + Future<Output = Vec<PathMatch>> {
|
||||||
let include_root_name = self.worktrees.len() > 1;
|
let include_root_name = self.worktrees.len() > 1;
|
||||||
let candidate_sets = self
|
let candidate_sets = self
|
||||||
.worktrees
|
.worktrees(cx)
|
||||||
.iter()
|
|
||||||
.map(|worktree| CandidateSet {
|
.map(|worktree| CandidateSet {
|
||||||
snapshot: worktree.read(cx).snapshot(),
|
snapshot: worktree.read(cx).snapshot(),
|
||||||
include_ignored,
|
include_ignored,
|
||||||
|
@ -1317,6 +1343,15 @@ impl Project {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl WorktreeHandle {
|
||||||
|
pub fn upgrade(&self, cx: &AppContext) -> Option<ModelHandle<Worktree>> {
|
||||||
|
match self {
|
||||||
|
WorktreeHandle::Strong(handle) => Some(handle.clone()),
|
||||||
|
WorktreeHandle::Weak(handle) => handle.upgrade(cx),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
struct CandidateSet {
|
struct CandidateSet {
|
||||||
snapshot: Snapshot,
|
snapshot: Snapshot,
|
||||||
include_ignored: bool,
|
include_ignored: bool,
|
||||||
|
@ -1489,7 +1524,7 @@ mod tests {
|
||||||
|
|
||||||
let tree = project
|
let tree = project
|
||||||
.update(&mut cx, |project, cx| {
|
.update(&mut cx, |project, cx| {
|
||||||
project.add_local_worktree(&root_link_path, cx)
|
project.add_local_worktree(&root_link_path, false, cx)
|
||||||
})
|
})
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
@ -1564,7 +1599,7 @@ mod tests {
|
||||||
|
|
||||||
let tree = project
|
let tree = project
|
||||||
.update(&mut cx, |project, cx| {
|
.update(&mut cx, |project, cx| {
|
||||||
project.add_local_worktree(dir.path(), cx)
|
project.add_local_worktree(dir.path(), false, cx)
|
||||||
})
|
})
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
@ -1670,7 +1705,7 @@ mod tests {
|
||||||
let project = build_project(&mut cx);
|
let project = build_project(&mut cx);
|
||||||
let tree = project
|
let tree = project
|
||||||
.update(&mut cx, |project, cx| {
|
.update(&mut cx, |project, cx| {
|
||||||
project.add_local_worktree(&dir.path(), cx)
|
project.add_local_worktree(&dir.path(), false, cx)
|
||||||
})
|
})
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
|
@ -91,11 +91,12 @@ impl Worktree {
|
||||||
client: Arc<Client>,
|
client: Arc<Client>,
|
||||||
user_store: ModelHandle<UserStore>,
|
user_store: ModelHandle<UserStore>,
|
||||||
path: impl Into<Arc<Path>>,
|
path: impl Into<Arc<Path>>,
|
||||||
|
weak: bool,
|
||||||
fs: Arc<dyn Fs>,
|
fs: Arc<dyn Fs>,
|
||||||
cx: &mut AsyncAppContext,
|
cx: &mut AsyncAppContext,
|
||||||
) -> Result<ModelHandle<Self>> {
|
) -> Result<ModelHandle<Self>> {
|
||||||
let (tree, scan_states_tx) =
|
let (tree, scan_states_tx) =
|
||||||
LocalWorktree::new(client, user_store, path, fs.clone(), cx).await?;
|
LocalWorktree::new(client, user_store, path, weak, fs.clone(), cx).await?;
|
||||||
tree.update(cx, |tree, cx| {
|
tree.update(cx, |tree, cx| {
|
||||||
let tree = tree.as_local_mut().unwrap();
|
let tree = tree.as_local_mut().unwrap();
|
||||||
let abs_path = tree.snapshot.abs_path.clone();
|
let abs_path = tree.snapshot.abs_path.clone();
|
||||||
|
@ -126,6 +127,7 @@ impl Worktree {
|
||||||
.map(|c| c.to_ascii_lowercase())
|
.map(|c| c.to_ascii_lowercase())
|
||||||
.collect();
|
.collect();
|
||||||
let root_name = worktree.root_name.clone();
|
let root_name = worktree.root_name.clone();
|
||||||
|
let weak = worktree.weak;
|
||||||
let (entries_by_path, entries_by_id, diagnostic_summaries) = cx
|
let (entries_by_path, entries_by_id, diagnostic_summaries) = cx
|
||||||
.background()
|
.background()
|
||||||
.spawn(async move {
|
.spawn(async move {
|
||||||
|
@ -225,6 +227,7 @@ impl Worktree {
|
||||||
queued_operations: Default::default(),
|
queued_operations: Default::default(),
|
||||||
user_store,
|
user_store,
|
||||||
diagnostic_summaries,
|
diagnostic_summaries,
|
||||||
|
weak,
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
|
@ -271,6 +274,13 @@ impl Worktree {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn is_weak(&self) -> bool {
|
||||||
|
match self {
|
||||||
|
Worktree::Local(worktree) => worktree.weak,
|
||||||
|
Worktree::Remote(worktree) => worktree.weak,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn replica_id(&self) -> ReplicaId {
|
pub fn replica_id(&self) -> ReplicaId {
|
||||||
match self {
|
match self {
|
||||||
Worktree::Local(_) => 0,
|
Worktree::Local(_) => 0,
|
||||||
|
@ -776,6 +786,7 @@ pub struct LocalWorktree {
|
||||||
client: Arc<Client>,
|
client: Arc<Client>,
|
||||||
user_store: ModelHandle<UserStore>,
|
user_store: ModelHandle<UserStore>,
|
||||||
fs: Arc<dyn Fs>,
|
fs: Arc<dyn Fs>,
|
||||||
|
weak: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Eq, PartialEq)]
|
#[derive(Debug, Eq, PartialEq)]
|
||||||
|
@ -803,6 +814,7 @@ pub struct RemoteWorktree {
|
||||||
user_store: ModelHandle<UserStore>,
|
user_store: ModelHandle<UserStore>,
|
||||||
queued_operations: Vec<(u64, Operation)>,
|
queued_operations: Vec<(u64, Operation)>,
|
||||||
diagnostic_summaries: TreeMap<PathKey, DiagnosticSummary>,
|
diagnostic_summaries: TreeMap<PathKey, DiagnosticSummary>,
|
||||||
|
weak: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
type LoadingBuffers = HashMap<
|
type LoadingBuffers = HashMap<
|
||||||
|
@ -822,6 +834,7 @@ impl LocalWorktree {
|
||||||
client: Arc<Client>,
|
client: Arc<Client>,
|
||||||
user_store: ModelHandle<UserStore>,
|
user_store: ModelHandle<UserStore>,
|
||||||
path: impl Into<Arc<Path>>,
|
path: impl Into<Arc<Path>>,
|
||||||
|
weak: bool,
|
||||||
fs: Arc<dyn Fs>,
|
fs: Arc<dyn Fs>,
|
||||||
cx: &mut AsyncAppContext,
|
cx: &mut AsyncAppContext,
|
||||||
) -> Result<(ModelHandle<Worktree>, Sender<ScanState>)> {
|
) -> Result<(ModelHandle<Worktree>, Sender<ScanState>)> {
|
||||||
|
@ -889,6 +902,7 @@ impl LocalWorktree {
|
||||||
client,
|
client,
|
||||||
user_store,
|
user_store,
|
||||||
fs,
|
fs,
|
||||||
|
weak,
|
||||||
};
|
};
|
||||||
|
|
||||||
cx.spawn_weak(|this, mut cx| async move {
|
cx.spawn_weak(|this, mut cx| async move {
|
||||||
|
@ -1415,10 +1429,11 @@ impl LocalWorktree {
|
||||||
});
|
});
|
||||||
|
|
||||||
let diagnostic_summaries = self.diagnostic_summaries.clone();
|
let diagnostic_summaries = self.diagnostic_summaries.clone();
|
||||||
|
let weak = self.weak;
|
||||||
let share_message = cx.background().spawn(async move {
|
let share_message = cx.background().spawn(async move {
|
||||||
proto::ShareWorktree {
|
proto::ShareWorktree {
|
||||||
project_id,
|
project_id,
|
||||||
worktree: Some(snapshot.to_proto(&diagnostic_summaries)),
|
worktree: Some(snapshot.to_proto(&diagnostic_summaries, weak)),
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -1636,6 +1651,7 @@ impl Snapshot {
|
||||||
pub fn to_proto(
|
pub fn to_proto(
|
||||||
&self,
|
&self,
|
||||||
diagnostic_summaries: &TreeMap<PathKey, DiagnosticSummary>,
|
diagnostic_summaries: &TreeMap<PathKey, DiagnosticSummary>,
|
||||||
|
weak: bool,
|
||||||
) -> proto::Worktree {
|
) -> proto::Worktree {
|
||||||
let root_name = self.root_name.clone();
|
let root_name = self.root_name.clone();
|
||||||
proto::Worktree {
|
proto::Worktree {
|
||||||
|
@ -1651,6 +1667,7 @@ impl Snapshot {
|
||||||
.iter()
|
.iter()
|
||||||
.map(|(path, summary)| summary.to_proto(path.0.clone()))
|
.map(|(path, summary)| summary.to_proto(path.0.clone()))
|
||||||
.collect(),
|
.collect(),
|
||||||
|
weak,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3110,6 +3127,7 @@ mod tests {
|
||||||
client,
|
client,
|
||||||
user_store,
|
user_store,
|
||||||
Arc::from(Path::new("/root")),
|
Arc::from(Path::new("/root")),
|
||||||
|
false,
|
||||||
Arc::new(fs),
|
Arc::new(fs),
|
||||||
&mut cx.to_async(),
|
&mut cx.to_async(),
|
||||||
)
|
)
|
||||||
|
@ -3147,6 +3165,7 @@ mod tests {
|
||||||
client,
|
client,
|
||||||
user_store,
|
user_store,
|
||||||
dir.path(),
|
dir.path(),
|
||||||
|
false,
|
||||||
Arc::new(RealFs),
|
Arc::new(RealFs),
|
||||||
&mut cx.to_async(),
|
&mut cx.to_async(),
|
||||||
)
|
)
|
||||||
|
@ -3181,6 +3200,7 @@ mod tests {
|
||||||
client,
|
client,
|
||||||
user_store,
|
user_store,
|
||||||
file_path.clone(),
|
file_path.clone(),
|
||||||
|
false,
|
||||||
Arc::new(RealFs),
|
Arc::new(RealFs),
|
||||||
&mut cx.to_async(),
|
&mut cx.to_async(),
|
||||||
)
|
)
|
||||||
|
@ -3229,6 +3249,7 @@ mod tests {
|
||||||
client,
|
client,
|
||||||
user_store.clone(),
|
user_store.clone(),
|
||||||
dir.path(),
|
dir.path(),
|
||||||
|
false,
|
||||||
Arc::new(RealFs),
|
Arc::new(RealFs),
|
||||||
&mut cx.to_async(),
|
&mut cx.to_async(),
|
||||||
)
|
)
|
||||||
|
@ -3265,7 +3286,7 @@ mod tests {
|
||||||
let remote = Worktree::remote(
|
let remote = Worktree::remote(
|
||||||
1,
|
1,
|
||||||
1,
|
1,
|
||||||
initial_snapshot.to_proto(&Default::default()),
|
initial_snapshot.to_proto(&Default::default(), Default::default()),
|
||||||
Client::new(http_client.clone()),
|
Client::new(http_client.clone()),
|
||||||
user_store,
|
user_store,
|
||||||
&mut cx.to_async(),
|
&mut cx.to_async(),
|
||||||
|
@ -3379,6 +3400,7 @@ mod tests {
|
||||||
client,
|
client,
|
||||||
user_store,
|
user_store,
|
||||||
dir.path(),
|
dir.path(),
|
||||||
|
false,
|
||||||
Arc::new(RealFs),
|
Arc::new(RealFs),
|
||||||
&mut cx.to_async(),
|
&mut cx.to_async(),
|
||||||
)
|
)
|
||||||
|
@ -3431,6 +3453,7 @@ mod tests {
|
||||||
client.clone(),
|
client.clone(),
|
||||||
user_store,
|
user_store,
|
||||||
"/the-dir".as_ref(),
|
"/the-dir".as_ref(),
|
||||||
|
false,
|
||||||
fs,
|
fs,
|
||||||
&mut cx.to_async(),
|
&mut cx.to_async(),
|
||||||
)
|
)
|
||||||
|
@ -3485,6 +3508,7 @@ mod tests {
|
||||||
client,
|
client,
|
||||||
user_store,
|
user_store,
|
||||||
dir.path(),
|
dir.path(),
|
||||||
|
false,
|
||||||
Arc::new(RealFs),
|
Arc::new(RealFs),
|
||||||
&mut cx.to_async(),
|
&mut cx.to_async(),
|
||||||
)
|
)
|
||||||
|
@ -3621,6 +3645,7 @@ mod tests {
|
||||||
client,
|
client,
|
||||||
user_store,
|
user_store,
|
||||||
dir.path(),
|
dir.path(),
|
||||||
|
false,
|
||||||
Arc::new(RealFs),
|
Arc::new(RealFs),
|
||||||
&mut cx.to_async(),
|
&mut cx.to_async(),
|
||||||
)
|
)
|
||||||
|
@ -3735,6 +3760,7 @@ mod tests {
|
||||||
client.clone(),
|
client.clone(),
|
||||||
user_store,
|
user_store,
|
||||||
"/the-dir".as_ref(),
|
"/the-dir".as_ref(),
|
||||||
|
false,
|
||||||
fs,
|
fs,
|
||||||
&mut cx.to_async(),
|
&mut cx.to_async(),
|
||||||
)
|
)
|
||||||
|
|
|
@ -6,8 +6,8 @@ use gpui::{
|
||||||
},
|
},
|
||||||
keymap::{self, Binding},
|
keymap::{self, Binding},
|
||||||
platform::CursorStyle,
|
platform::CursorStyle,
|
||||||
AppContext, Element, ElementBox, Entity, ModelHandle, MutableAppContext, ReadModel, View,
|
AppContext, Element, ElementBox, Entity, ModelHandle, MutableAppContext, View, ViewContext,
|
||||||
ViewContext, ViewHandle, WeakViewHandle,
|
ViewHandle, WeakViewHandle,
|
||||||
};
|
};
|
||||||
use postage::watch;
|
use postage::watch;
|
||||||
use project::{Project, ProjectEntry, ProjectPath, Worktree, WorktreeId};
|
use project::{Project, ProjectEntry, ProjectPath, Worktree, WorktreeId};
|
||||||
|
@ -24,7 +24,7 @@ use workspace::{
|
||||||
pub struct ProjectPanel {
|
pub struct ProjectPanel {
|
||||||
project: ModelHandle<Project>,
|
project: ModelHandle<Project>,
|
||||||
list: UniformListState,
|
list: UniformListState,
|
||||||
visible_entries: Vec<Vec<usize>>,
|
visible_entries: Vec<(WorktreeId, Vec<usize>)>,
|
||||||
expanded_dir_ids: HashMap<WorktreeId, Vec<usize>>,
|
expanded_dir_ids: HashMap<WorktreeId, Vec<usize>>,
|
||||||
selection: Option<Selection>,
|
selection: Option<Selection>,
|
||||||
settings: watch::Receiver<Settings>,
|
settings: watch::Receiver<Settings>,
|
||||||
|
@ -260,7 +260,11 @@ impl ProjectPanel {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn select_first(&mut self, cx: &mut ViewContext<Self>) {
|
fn select_first(&mut self, cx: &mut ViewContext<Self>) {
|
||||||
if let Some(worktree) = self.project.read(cx).worktrees().first() {
|
let worktree = self
|
||||||
|
.visible_entries
|
||||||
|
.first()
|
||||||
|
.and_then(|(worktree_id, _)| self.project.read(cx).worktree_for_id(*worktree_id, cx));
|
||||||
|
if let Some(worktree) = worktree {
|
||||||
let worktree = worktree.read(cx);
|
let worktree = worktree.read(cx);
|
||||||
let worktree_id = worktree.id();
|
let worktree_id = worktree.id();
|
||||||
if let Some(root_entry) = worktree.root_entry() {
|
if let Some(root_entry) = worktree.root_entry() {
|
||||||
|
@ -289,10 +293,11 @@ impl ProjectPanel {
|
||||||
let project = self.project.read(cx);
|
let project = self.project.read(cx);
|
||||||
let mut offset = None;
|
let mut offset = None;
|
||||||
let mut ix = 0;
|
let mut ix = 0;
|
||||||
for (worktree_ix, visible_entries) in self.visible_entries.iter().enumerate() {
|
for (worktree_id, visible_entries) in &self.visible_entries {
|
||||||
if target_ix < ix + visible_entries.len() {
|
if target_ix < ix + visible_entries.len() {
|
||||||
let worktree = project.worktrees()[worktree_ix].read(cx);
|
offset = project
|
||||||
offset = Some((worktree, visible_entries[target_ix - ix]));
|
.worktree_for_id(*worktree_id, cx)
|
||||||
|
.map(|w| (w.read(cx), visible_entries[target_ix - ix]));
|
||||||
break;
|
break;
|
||||||
} else {
|
} else {
|
||||||
ix += visible_entries.len();
|
ix += visible_entries.len();
|
||||||
|
@ -318,7 +323,11 @@ impl ProjectPanel {
|
||||||
new_selected_entry: Option<(WorktreeId, usize)>,
|
new_selected_entry: Option<(WorktreeId, usize)>,
|
||||||
cx: &mut ViewContext<Self>,
|
cx: &mut ViewContext<Self>,
|
||||||
) {
|
) {
|
||||||
let worktrees = self.project.read(cx).worktrees();
|
let worktrees = self
|
||||||
|
.project
|
||||||
|
.read(cx)
|
||||||
|
.worktrees(cx)
|
||||||
|
.filter(|worktree| !worktree.read(cx).is_weak());
|
||||||
self.visible_entries.clear();
|
self.visible_entries.clear();
|
||||||
|
|
||||||
let mut entry_ix = 0;
|
let mut entry_ix = 0;
|
||||||
|
@ -369,7 +378,8 @@ impl ProjectPanel {
|
||||||
}
|
}
|
||||||
entry_iter.advance();
|
entry_iter.advance();
|
||||||
}
|
}
|
||||||
self.visible_entries.push(visible_worktree_entries);
|
self.visible_entries
|
||||||
|
.push((worktree_id, visible_worktree_entries));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -404,16 +414,14 @@ impl ProjectPanel {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn for_each_visible_entry<C: ReadModel>(
|
fn for_each_visible_entry(
|
||||||
&self,
|
&self,
|
||||||
range: Range<usize>,
|
range: Range<usize>,
|
||||||
cx: &mut C,
|
cx: &mut ViewContext<ProjectPanel>,
|
||||||
mut callback: impl FnMut(ProjectEntry, EntryDetails, &mut C),
|
mut callback: impl FnMut(ProjectEntry, EntryDetails, &mut ViewContext<ProjectPanel>),
|
||||||
) {
|
) {
|
||||||
let project = self.project.read(cx);
|
|
||||||
let worktrees = project.worktrees().to_vec();
|
|
||||||
let mut ix = 0;
|
let mut ix = 0;
|
||||||
for (worktree_ix, visible_worktree_entries) in self.visible_entries.iter().enumerate() {
|
for (worktree_id, visible_worktree_entries) in &self.visible_entries {
|
||||||
if ix >= range.end {
|
if ix >= range.end {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -423,7 +431,7 @@ impl ProjectPanel {
|
||||||
}
|
}
|
||||||
|
|
||||||
let end_ix = range.end.min(ix + visible_worktree_entries.len());
|
let end_ix = range.end.min(ix + visible_worktree_entries.len());
|
||||||
let worktree = &worktrees[worktree_ix];
|
if let Some(worktree) = self.project.read(cx).worktree_for_id(*worktree_id, cx) {
|
||||||
let snapshot = worktree.read(cx).snapshot();
|
let snapshot = worktree.read(cx).snapshot();
|
||||||
let expanded_entry_ids = self
|
let expanded_entry_ids = self
|
||||||
.expanded_dir_ids
|
.expanded_dir_ids
|
||||||
|
@ -456,6 +464,7 @@ impl ProjectPanel {
|
||||||
callback(entry, details, cx);
|
callback(entry, details, cx);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
ix = end_ix;
|
ix = end_ix;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -545,7 +554,7 @@ impl View for ProjectPanel {
|
||||||
self.list.clone(),
|
self.list.clone(),
|
||||||
self.visible_entries
|
self.visible_entries
|
||||||
.iter()
|
.iter()
|
||||||
.map(|worktree_entries| worktree_entries.len())
|
.map(|(_, worktree_entries)| worktree_entries.len())
|
||||||
.sum(),
|
.sum(),
|
||||||
move |range, items, cx| {
|
move |range, items, cx| {
|
||||||
let theme = &settings.borrow().theme.project_panel;
|
let theme = &settings.borrow().theme.project_panel;
|
||||||
|
@ -633,18 +642,18 @@ mod tests {
|
||||||
cx,
|
cx,
|
||||||
)
|
)
|
||||||
});
|
});
|
||||||
let root1 = project
|
let (root1, _) = project
|
||||||
.update(&mut cx, |project, cx| {
|
.update(&mut cx, |project, cx| {
|
||||||
project.add_local_worktree("/root1", cx)
|
project.find_or_create_worktree_for_abs_path("/root1", false, cx)
|
||||||
})
|
})
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
root1
|
root1
|
||||||
.read_with(&cx, |t, _| t.as_local().unwrap().scan_complete())
|
.read_with(&cx, |t, _| t.as_local().unwrap().scan_complete())
|
||||||
.await;
|
.await;
|
||||||
let root2 = project
|
let (root2, _) = project
|
||||||
.update(&mut cx, |project, cx| {
|
.update(&mut cx, |project, cx| {
|
||||||
project.add_local_worktree("/root2", cx)
|
project.find_or_create_worktree_for_abs_path("/root2", false, cx)
|
||||||
})
|
})
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
@ -827,7 +836,7 @@ mod tests {
|
||||||
) {
|
) {
|
||||||
let path = path.as_ref();
|
let path = path.as_ref();
|
||||||
panel.update(cx, |panel, cx| {
|
panel.update(cx, |panel, cx| {
|
||||||
for worktree in panel.project.read(cx).worktrees() {
|
for worktree in panel.project.read(cx).worktrees(cx).collect::<Vec<_>>() {
|
||||||
let worktree = worktree.read(cx);
|
let worktree = worktree.read(cx);
|
||||||
if let Ok(relative_path) = path.strip_prefix(worktree.root_name()) {
|
if let Ok(relative_path) = path.strip_prefix(worktree.root_name()) {
|
||||||
let entry_id = worktree.entry_for_path(relative_path).unwrap().id;
|
let entry_id = worktree.entry_for_path(relative_path).unwrap().id;
|
||||||
|
|
|
@ -272,6 +272,7 @@ message Worktree {
|
||||||
string root_name = 2;
|
string root_name = 2;
|
||||||
repeated Entry entries = 3;
|
repeated Entry entries = 3;
|
||||||
repeated DiagnosticSummary diagnostic_summaries = 4;
|
repeated DiagnosticSummary diagnostic_summaries = 4;
|
||||||
|
bool weak = 5;
|
||||||
}
|
}
|
||||||
|
|
||||||
message Entry {
|
message Entry {
|
||||||
|
|
|
@ -309,6 +309,7 @@ impl Server {
|
||||||
.values()
|
.values()
|
||||||
.cloned()
|
.cloned()
|
||||||
.collect(),
|
.collect(),
|
||||||
|
weak: worktree.weak,
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
|
@ -421,6 +422,7 @@ impl Server {
|
||||||
authorized_user_ids: contact_user_ids.clone(),
|
authorized_user_ids: contact_user_ids.clone(),
|
||||||
root_name: request.payload.root_name,
|
root_name: request.payload.root_name,
|
||||||
share: None,
|
share: None,
|
||||||
|
weak: false,
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -1158,8 +1160,10 @@ mod tests {
|
||||||
cx,
|
cx,
|
||||||
)
|
)
|
||||||
});
|
});
|
||||||
let worktree_a = project_a
|
let (worktree_a, _) = project_a
|
||||||
.update(&mut cx_a, |p, cx| p.add_local_worktree("/a", cx))
|
.update(&mut cx_a, |p, cx| {
|
||||||
|
p.find_or_create_worktree_for_abs_path("/a", false, cx)
|
||||||
|
})
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
worktree_a
|
worktree_a
|
||||||
|
@ -1184,7 +1188,7 @@ mod tests {
|
||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let worktree_b = project_b.update(&mut cx_b, |p, _| p.worktrees()[0].clone());
|
let worktree_b = project_b.update(&mut cx_b, |p, cx| p.worktrees(cx).next().unwrap());
|
||||||
|
|
||||||
let replica_id_b = project_b.read_with(&cx_b, |project, _| {
|
let replica_id_b = project_b.read_with(&cx_b, |project, _| {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
|
@ -1293,8 +1297,10 @@ mod tests {
|
||||||
cx,
|
cx,
|
||||||
)
|
)
|
||||||
});
|
});
|
||||||
let worktree_a = project_a
|
let (worktree_a, _) = project_a
|
||||||
.update(&mut cx_a, |p, cx| p.add_local_worktree("/a", cx))
|
.update(&mut cx_a, |p, cx| {
|
||||||
|
p.find_or_create_worktree_for_abs_path("/a", false, cx)
|
||||||
|
})
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
worktree_a
|
worktree_a
|
||||||
|
@ -1321,7 +1327,7 @@ mod tests {
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let worktree_b = project_b.read_with(&cx_b, |p, _| p.worktrees()[0].clone());
|
let worktree_b = project_b.read_with(&cx_b, |p, cx| p.worktrees(cx).next().unwrap());
|
||||||
worktree_b
|
worktree_b
|
||||||
.update(&mut cx_b, |tree, cx| tree.open_buffer("a.txt", cx))
|
.update(&mut cx_b, |tree, cx| tree.open_buffer("a.txt", cx))
|
||||||
.await
|
.await
|
||||||
|
@ -1353,7 +1359,7 @@ mod tests {
|
||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let worktree_c = project_c.read_with(&cx_b, |p, _| p.worktrees()[0].clone());
|
let worktree_c = project_c.read_with(&cx_b, |p, cx| p.worktrees(cx).next().unwrap());
|
||||||
worktree_c
|
worktree_c
|
||||||
.update(&mut cx_b, |tree, cx| tree.open_buffer("a.txt", cx))
|
.update(&mut cx_b, |tree, cx| tree.open_buffer("a.txt", cx))
|
||||||
.await
|
.await
|
||||||
|
@ -1395,8 +1401,10 @@ mod tests {
|
||||||
cx,
|
cx,
|
||||||
)
|
)
|
||||||
});
|
});
|
||||||
let worktree_a = project_a
|
let (worktree_a, _) = project_a
|
||||||
.update(&mut cx_a, |p, cx| p.add_local_worktree("/a", cx))
|
.update(&mut cx_a, |p, cx| {
|
||||||
|
p.find_or_create_worktree_for_abs_path("/a", false, cx)
|
||||||
|
})
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
worktree_a
|
worktree_a
|
||||||
|
@ -1433,8 +1441,8 @@ mod tests {
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
// Open and edit a buffer as both guests B and C.
|
// Open and edit a buffer as both guests B and C.
|
||||||
let worktree_b = project_b.read_with(&cx_b, |p, _| p.worktrees()[0].clone());
|
let worktree_b = project_b.read_with(&cx_b, |p, cx| p.worktrees(cx).next().unwrap());
|
||||||
let worktree_c = project_c.read_with(&cx_c, |p, _| p.worktrees()[0].clone());
|
let worktree_c = project_c.read_with(&cx_c, |p, cx| p.worktrees(cx).next().unwrap());
|
||||||
let buffer_b = worktree_b
|
let buffer_b = worktree_b
|
||||||
.update(&mut cx_b, |tree, cx| tree.open_buffer("file1", cx))
|
.update(&mut cx_b, |tree, cx| tree.open_buffer("file1", cx))
|
||||||
.await
|
.await
|
||||||
|
@ -1547,8 +1555,10 @@ mod tests {
|
||||||
cx,
|
cx,
|
||||||
)
|
)
|
||||||
});
|
});
|
||||||
let worktree_a = project_a
|
let (worktree_a, _) = project_a
|
||||||
.update(&mut cx_a, |p, cx| p.add_local_worktree("/dir", cx))
|
.update(&mut cx_a, |p, cx| {
|
||||||
|
p.find_or_create_worktree_for_abs_path("/dir", false, cx)
|
||||||
|
})
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
worktree_a
|
worktree_a
|
||||||
|
@ -1573,7 +1583,7 @@ mod tests {
|
||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let worktree_b = project_b.update(&mut cx_b, |p, _| p.worktrees()[0].clone());
|
let worktree_b = project_b.update(&mut cx_b, |p, cx| p.worktrees(cx).next().unwrap());
|
||||||
|
|
||||||
// Open a buffer as client B
|
// Open a buffer as client B
|
||||||
let buffer_b = worktree_b
|
let buffer_b = worktree_b
|
||||||
|
@ -1642,8 +1652,10 @@ mod tests {
|
||||||
cx,
|
cx,
|
||||||
)
|
)
|
||||||
});
|
});
|
||||||
let worktree_a = project_a
|
let (worktree_a, _) = project_a
|
||||||
.update(&mut cx_a, |p, cx| p.add_local_worktree("/dir", cx))
|
.update(&mut cx_a, |p, cx| {
|
||||||
|
p.find_or_create_worktree_for_abs_path("/dir", false, cx)
|
||||||
|
})
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
worktree_a
|
worktree_a
|
||||||
|
@ -1668,7 +1680,7 @@ mod tests {
|
||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let worktree_b = project_b.update(&mut cx_b, |p, _| p.worktrees()[0].clone());
|
let worktree_b = project_b.update(&mut cx_b, |p, cx| p.worktrees(cx).next().unwrap());
|
||||||
|
|
||||||
// Open a buffer as client A
|
// Open a buffer as client A
|
||||||
let buffer_a = worktree_a
|
let buffer_a = worktree_a
|
||||||
|
@ -1723,8 +1735,10 @@ mod tests {
|
||||||
cx,
|
cx,
|
||||||
)
|
)
|
||||||
});
|
});
|
||||||
let worktree_a = project_a
|
let (worktree_a, _) = project_a
|
||||||
.update(&mut cx_a, |p, cx| p.add_local_worktree("/dir", cx))
|
.update(&mut cx_a, |p, cx| {
|
||||||
|
p.find_or_create_worktree_for_abs_path("/dir", false, cx)
|
||||||
|
})
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
worktree_a
|
worktree_a
|
||||||
|
@ -1749,7 +1763,7 @@ mod tests {
|
||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let worktree_b = project_b.update(&mut cx_b, |p, _| p.worktrees()[0].clone());
|
let worktree_b = project_b.update(&mut cx_b, |p, cx| p.worktrees(cx).next().unwrap());
|
||||||
|
|
||||||
// See that a guest has joined as client A.
|
// See that a guest has joined as client A.
|
||||||
project_a
|
project_a
|
||||||
|
@ -1799,8 +1813,10 @@ mod tests {
|
||||||
cx,
|
cx,
|
||||||
)
|
)
|
||||||
});
|
});
|
||||||
let worktree_a = project_a
|
let (worktree_a, _) = project_a
|
||||||
.update(&mut cx_a, |p, cx| p.add_local_worktree("/a", cx))
|
.update(&mut cx_a, |p, cx| {
|
||||||
|
p.find_or_create_worktree_for_abs_path("/a", false, cx)
|
||||||
|
})
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
worktree_a
|
worktree_a
|
||||||
|
@ -1886,8 +1902,10 @@ mod tests {
|
||||||
cx,
|
cx,
|
||||||
)
|
)
|
||||||
});
|
});
|
||||||
let worktree_a = project_a
|
let (worktree_a, _) = project_a
|
||||||
.update(&mut cx_a, |p, cx| p.add_local_worktree("/a", cx))
|
.update(&mut cx_a, |p, cx| {
|
||||||
|
p.find_or_create_worktree_for_abs_path("/a", false, cx)
|
||||||
|
})
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
worktree_a
|
worktree_a
|
||||||
|
@ -2023,7 +2041,7 @@ mod tests {
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
// Open the file with the errors on client B. They should be present.
|
// Open the file with the errors on client B. They should be present.
|
||||||
let worktree_b = project_b.update(&mut cx_b, |p, _| p.worktrees()[0].clone());
|
let worktree_b = project_b.update(&mut cx_b, |p, cx| p.worktrees(cx).next().unwrap());
|
||||||
let buffer_b = cx_b
|
let buffer_b = cx_b
|
||||||
.background()
|
.background()
|
||||||
.spawn(worktree_b.update(&mut cx_b, |worktree, cx| worktree.open_buffer("a.rs", cx)))
|
.spawn(worktree_b.update(&mut cx_b, |worktree, cx| worktree.open_buffer("a.rs", cx)))
|
||||||
|
@ -2108,8 +2126,10 @@ mod tests {
|
||||||
cx,
|
cx,
|
||||||
)
|
)
|
||||||
});
|
});
|
||||||
let worktree_a = project_a
|
let (worktree_a, _) = project_a
|
||||||
.update(&mut cx_a, |p, cx| p.add_local_worktree("/a", cx))
|
.update(&mut cx_a, |p, cx| {
|
||||||
|
p.find_or_create_worktree_for_abs_path("/a", false, cx)
|
||||||
|
})
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
worktree_a
|
worktree_a
|
||||||
|
@ -2136,7 +2156,7 @@ mod tests {
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
// Open the file to be formatted on client B.
|
// Open the file to be formatted on client B.
|
||||||
let worktree_b = project_b.update(&mut cx_b, |p, _| p.worktrees()[0].clone());
|
let worktree_b = project_b.update(&mut cx_b, |p, cx| p.worktrees(cx).next().unwrap());
|
||||||
let buffer_b = cx_b
|
let buffer_b = cx_b
|
||||||
.background()
|
.background()
|
||||||
.spawn(worktree_b.update(&mut cx_b, |worktree, cx| worktree.open_buffer("a.rs", cx)))
|
.spawn(worktree_b.update(&mut cx_b, |worktree, cx| worktree.open_buffer("a.rs", cx)))
|
||||||
|
@ -2616,8 +2636,10 @@ mod tests {
|
||||||
cx,
|
cx,
|
||||||
)
|
)
|
||||||
});
|
});
|
||||||
let worktree_a = project_a
|
let (worktree_a, _) = project_a
|
||||||
.update(&mut cx_a, |p, cx| p.add_local_worktree("/a", cx))
|
.update(&mut cx_a, |p, cx| {
|
||||||
|
p.find_or_create_worktree_for_abs_path("/a", false, cx)
|
||||||
|
})
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
worktree_a
|
worktree_a
|
||||||
|
|
|
@ -31,6 +31,7 @@ pub struct Worktree {
|
||||||
pub authorized_user_ids: Vec<UserId>,
|
pub authorized_user_ids: Vec<UserId>,
|
||||||
pub root_name: String,
|
pub root_name: String,
|
||||||
pub share: Option<WorktreeShare>,
|
pub share: Option<WorktreeShare>,
|
||||||
|
pub weak: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
|
@ -202,6 +203,7 @@ impl Store {
|
||||||
let mut worktree_root_names = project
|
let mut worktree_root_names = project
|
||||||
.worktrees
|
.worktrees
|
||||||
.values()
|
.values()
|
||||||
|
.filter(|worktree| !worktree.weak)
|
||||||
.map(|worktree| worktree.root_name.clone())
|
.map(|worktree| worktree.root_name.clone())
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
worktree_root_names.sort_unstable();
|
worktree_root_names.sort_unstable();
|
||||||
|
|
|
@ -639,8 +639,11 @@ impl Workspace {
|
||||||
&self.project
|
&self.project
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn worktrees<'a>(&self, cx: &'a AppContext) -> &'a [ModelHandle<Worktree>] {
|
pub fn worktrees<'a>(
|
||||||
&self.project.read(cx).worktrees()
|
&self,
|
||||||
|
cx: &'a AppContext,
|
||||||
|
) -> impl 'a + Iterator<Item = ModelHandle<Worktree>> {
|
||||||
|
self.project.read(cx).worktrees(cx)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn contains_paths(&self, paths: &[PathBuf], cx: &AppContext) -> bool {
|
pub fn contains_paths(&self, paths: &[PathBuf], cx: &AppContext) -> bool {
|
||||||
|
@ -660,7 +663,6 @@ impl Workspace {
|
||||||
pub fn worktree_scans_complete(&self, cx: &AppContext) -> impl Future<Output = ()> + 'static {
|
pub fn worktree_scans_complete(&self, cx: &AppContext) -> impl Future<Output = ()> + 'static {
|
||||||
let futures = self
|
let futures = self
|
||||||
.worktrees(cx)
|
.worktrees(cx)
|
||||||
.iter()
|
|
||||||
.filter_map(|worktree| worktree.read(cx).as_local())
|
.filter_map(|worktree| worktree.read(cx).as_local())
|
||||||
.map(|worktree| worktree.scan_complete())
|
.map(|worktree| worktree.scan_complete())
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
|
@ -720,7 +722,7 @@ impl Workspace {
|
||||||
cx: &mut ViewContext<Self>,
|
cx: &mut ViewContext<Self>,
|
||||||
) -> Task<Result<ProjectPath>> {
|
) -> Task<Result<ProjectPath>> {
|
||||||
let entry = self.project().update(cx, |project, cx| {
|
let entry = self.project().update(cx, |project, cx| {
|
||||||
project.find_or_create_worktree_for_abs_path(abs_path, cx)
|
project.find_or_create_worktree_for_abs_path(abs_path, false, cx)
|
||||||
});
|
});
|
||||||
cx.spawn(|_, cx| async move {
|
cx.spawn(|_, cx| async move {
|
||||||
let (worktree, path) = entry.await?;
|
let (worktree, path) = entry.await?;
|
||||||
|
@ -731,15 +733,6 @@ impl Workspace {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn add_worktree(
|
|
||||||
&self,
|
|
||||||
path: &Path,
|
|
||||||
cx: &mut ViewContext<Self>,
|
|
||||||
) -> Task<Result<ModelHandle<Worktree>>> {
|
|
||||||
self.project
|
|
||||||
.update(cx, |project, cx| project.add_local_worktree(path, cx))
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn toggle_modal<V, F>(&mut self, cx: &mut ViewContext<Self>, add_view: F)
|
pub fn toggle_modal<V, F>(&mut self, cx: &mut ViewContext<Self>, add_view: F)
|
||||||
where
|
where
|
||||||
V: 'static + View,
|
V: 'static + View,
|
||||||
|
@ -866,7 +859,7 @@ impl Workspace {
|
||||||
item.save(cx)
|
item.save(cx)
|
||||||
}
|
}
|
||||||
} else if item.can_save_as(cx) {
|
} else if item.can_save_as(cx) {
|
||||||
let worktree = self.worktrees(cx).first();
|
let worktree = self.worktrees(cx).next();
|
||||||
let start_abs_path = worktree
|
let start_abs_path = worktree
|
||||||
.and_then(|w| w.read(cx).as_local())
|
.and_then(|w| w.read(cx).as_local())
|
||||||
.map_or(Path::new(""), |w| w.abs_path())
|
.map_or(Path::new(""), |w| w.abs_path())
|
||||||
|
@ -1343,7 +1336,6 @@ impl WorkspaceHandle for ViewHandle<Workspace> {
|
||||||
fn file_project_paths(&self, cx: &AppContext) -> Vec<ProjectPath> {
|
fn file_project_paths(&self, cx: &AppContext) -> Vec<ProjectPath> {
|
||||||
self.read(cx)
|
self.read(cx)
|
||||||
.worktrees(cx)
|
.worktrees(cx)
|
||||||
.iter()
|
|
||||||
.flat_map(|worktree| {
|
.flat_map(|worktree| {
|
||||||
let worktree_id = worktree.read(cx).id();
|
let worktree_id = worktree.read(cx).id();
|
||||||
worktree.read(cx).files(true, 0).map(move |f| ProjectPath {
|
worktree.read(cx).files(true, 0).map(move |f| ProjectPath {
|
||||||
|
|
|
@ -175,7 +175,7 @@ mod tests {
|
||||||
assert_eq!(cx.window_ids().len(), 1);
|
assert_eq!(cx.window_ids().len(), 1);
|
||||||
let workspace_1 = cx.root_view::<Workspace>(cx.window_ids()[0]).unwrap();
|
let workspace_1 = cx.root_view::<Workspace>(cx.window_ids()[0]).unwrap();
|
||||||
workspace_1.read_with(&cx, |workspace, cx| {
|
workspace_1.read_with(&cx, |workspace, cx| {
|
||||||
assert_eq!(workspace.worktrees(cx).len(), 2)
|
assert_eq!(workspace.worktrees(cx).count(), 2)
|
||||||
});
|
});
|
||||||
|
|
||||||
cx.update(|cx| {
|
cx.update(|cx| {
|
||||||
|
@ -242,9 +242,10 @@ mod tests {
|
||||||
.await;
|
.await;
|
||||||
let params = cx.update(|cx| WorkspaceParams::local(&app_state, cx));
|
let params = cx.update(|cx| WorkspaceParams::local(&app_state, cx));
|
||||||
let (_, workspace) = cx.add_window(|cx| Workspace::new(¶ms, cx));
|
let (_, workspace) = cx.add_window(|cx| Workspace::new(¶ms, cx));
|
||||||
workspace
|
params
|
||||||
.update(&mut cx, |workspace, cx| {
|
.project
|
||||||
workspace.add_worktree(Path::new("/root"), cx)
|
.update(&mut cx, |project, cx| {
|
||||||
|
project.find_or_create_worktree_for_abs_path(Path::new("/root"), false, cx)
|
||||||
})
|
})
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
@ -366,9 +367,10 @@ mod tests {
|
||||||
|
|
||||||
let params = cx.update(|cx| WorkspaceParams::local(&app_state, cx));
|
let params = cx.update(|cx| WorkspaceParams::local(&app_state, cx));
|
||||||
let (_, workspace) = cx.add_window(|cx| Workspace::new(¶ms, cx));
|
let (_, workspace) = cx.add_window(|cx| Workspace::new(¶ms, cx));
|
||||||
workspace
|
params
|
||||||
.update(&mut cx, |workspace, cx| {
|
.project
|
||||||
workspace.add_worktree("/dir1".as_ref(), cx)
|
.update(&mut cx, |project, cx| {
|
||||||
|
project.find_or_create_worktree_for_abs_path(Path::new("/dir1"), false, cx)
|
||||||
})
|
})
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
@ -402,7 +404,6 @@ mod tests {
|
||||||
let worktree_roots = workspace
|
let worktree_roots = workspace
|
||||||
.read(cx)
|
.read(cx)
|
||||||
.worktrees(cx)
|
.worktrees(cx)
|
||||||
.iter()
|
|
||||||
.map(|w| w.read(cx).as_local().unwrap().abs_path().as_ref())
|
.map(|w| w.read(cx).as_local().unwrap().abs_path().as_ref())
|
||||||
.collect::<HashSet<_>>();
|
.collect::<HashSet<_>>();
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
|
@ -433,9 +434,10 @@ mod tests {
|
||||||
|
|
||||||
let params = cx.update(|cx| WorkspaceParams::local(&app_state, cx));
|
let params = cx.update(|cx| WorkspaceParams::local(&app_state, cx));
|
||||||
let (window_id, workspace) = cx.add_window(|cx| Workspace::new(¶ms, cx));
|
let (window_id, workspace) = cx.add_window(|cx| Workspace::new(¶ms, cx));
|
||||||
workspace
|
params
|
||||||
.update(&mut cx, |workspace, cx| {
|
.project
|
||||||
workspace.add_worktree(Path::new("/root"), cx)
|
.update(&mut cx, |project, cx| {
|
||||||
|
project.find_or_create_worktree_for_abs_path(Path::new("/root"), false, cx)
|
||||||
})
|
})
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
@ -481,21 +483,14 @@ mod tests {
|
||||||
app_state.fs.as_fake().insert_dir("/root").await.unwrap();
|
app_state.fs.as_fake().insert_dir("/root").await.unwrap();
|
||||||
let params = cx.update(|cx| WorkspaceParams::local(&app_state, cx));
|
let params = cx.update(|cx| WorkspaceParams::local(&app_state, cx));
|
||||||
let (window_id, workspace) = cx.add_window(|cx| Workspace::new(¶ms, cx));
|
let (window_id, workspace) = cx.add_window(|cx| Workspace::new(¶ms, cx));
|
||||||
workspace
|
params
|
||||||
.update(&mut cx, |workspace, cx| {
|
.project
|
||||||
workspace.add_worktree(Path::new("/root"), cx)
|
.update(&mut cx, |project, cx| {
|
||||||
|
project.find_or_create_worktree_for_abs_path(Path::new("/root"), false, cx)
|
||||||
})
|
})
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let worktree = cx.read(|cx| {
|
let worktree = cx.read(|cx| workspace.read(cx).worktrees(cx).next().unwrap());
|
||||||
workspace
|
|
||||||
.read(cx)
|
|
||||||
.worktrees(cx)
|
|
||||||
.iter()
|
|
||||||
.next()
|
|
||||||
.unwrap()
|
|
||||||
.clone()
|
|
||||||
});
|
|
||||||
|
|
||||||
// Create a new untitled buffer
|
// Create a new untitled buffer
|
||||||
cx.dispatch_action(window_id, vec![workspace.id()], OpenNew(app_state.clone()));
|
cx.dispatch_action(window_id, vec![workspace.id()], OpenNew(app_state.clone()));
|
||||||
|
@ -640,9 +635,10 @@ mod tests {
|
||||||
|
|
||||||
let params = cx.update(|cx| WorkspaceParams::local(&app_state, cx));
|
let params = cx.update(|cx| WorkspaceParams::local(&app_state, cx));
|
||||||
let (window_id, workspace) = cx.add_window(|cx| Workspace::new(¶ms, cx));
|
let (window_id, workspace) = cx.add_window(|cx| Workspace::new(¶ms, cx));
|
||||||
workspace
|
params
|
||||||
.update(&mut cx, |workspace, cx| {
|
.project
|
||||||
workspace.add_worktree(Path::new("/root"), cx)
|
.update(&mut cx, |project, cx| {
|
||||||
|
project.find_or_create_worktree_for_abs_path(Path::new("/root"), false, cx)
|
||||||
})
|
})
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
@ -717,9 +713,10 @@ mod tests {
|
||||||
.await;
|
.await;
|
||||||
let params = cx.update(|cx| WorkspaceParams::local(&app_state, cx));
|
let params = cx.update(|cx| WorkspaceParams::local(&app_state, cx));
|
||||||
let (_, workspace) = cx.add_window(|cx| Workspace::new(¶ms, cx));
|
let (_, workspace) = cx.add_window(|cx| Workspace::new(¶ms, cx));
|
||||||
workspace
|
params
|
||||||
.update(&mut cx, |workspace, cx| {
|
.project
|
||||||
workspace.add_worktree(Path::new("/root"), cx)
|
.update(&mut cx, |project, cx| {
|
||||||
|
project.find_or_create_worktree_for_abs_path(Path::new("/root"), false, cx)
|
||||||
})
|
})
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
Loading…
Reference in a new issue