Redesign Worktree save API and make test_rescan_simple pass
This commit does too much. The first goal was to change our approach to saving new buffers so that we don't need to construct a File for an entry that doesn't exist. Rather than doing that, we call `Worktree::save_buffer_as` with the buffer handle, the path, and the contents. This then saves the buffer and returns a handle to a `File` that references an entry that actually exists. I needed to do this so that we can store an entry id on `File`. In the process, I noticed intermittent test failures on `test_rescan_simple`, so I made some changes required to fix those related to our reuse of existing ids. Our previous approach of removing a path when inserting a new entry was broken, because of the recursive nature of `remove_path`. Instead, I simply recycle the id of an existing worktree entry with the same path if one is present, then allow it to be replaced.
This commit is contained in:
+53
-15
@@ -127,7 +127,13 @@ pub trait ItemView: View {
|
||||
fn has_conflict(&self, _: &AppContext) -> bool {
|
||||
false
|
||||
}
|
||||
fn save(&mut self, _: Option<File>, _: &mut ViewContext<Self>) -> Task<anyhow::Result<()>>;
|
||||
fn save(&mut self, cx: &mut ViewContext<Self>) -> Result<Task<Result<()>>>;
|
||||
fn save_as(
|
||||
&mut self,
|
||||
worktree: &ModelHandle<Worktree>,
|
||||
path: &Path,
|
||||
cx: &mut ViewContext<Self>,
|
||||
) -> Task<anyhow::Result<()>>;
|
||||
fn should_activate_item_on_event(_: &Self::Event) -> bool {
|
||||
false
|
||||
}
|
||||
@@ -162,7 +168,13 @@ pub trait ItemViewHandle: Send + Sync {
|
||||
fn to_any(&self) -> AnyViewHandle;
|
||||
fn is_dirty(&self, cx: &AppContext) -> bool;
|
||||
fn has_conflict(&self, cx: &AppContext) -> bool;
|
||||
fn save(&self, file: Option<File>, cx: &mut MutableAppContext) -> Task<anyhow::Result<()>>;
|
||||
fn save(&self, cx: &mut MutableAppContext) -> Result<Task<Result<()>>>;
|
||||
fn save_as(
|
||||
&self,
|
||||
worktree: &ModelHandle<Worktree>,
|
||||
path: &Path,
|
||||
cx: &mut MutableAppContext,
|
||||
) -> Task<anyhow::Result<()>>;
|
||||
}
|
||||
|
||||
impl<T: Item> ItemHandle for ModelHandle<T> {
|
||||
@@ -236,8 +248,17 @@ impl<T: ItemView> ItemViewHandle for ViewHandle<T> {
|
||||
})
|
||||
}
|
||||
|
||||
fn save(&self, file: Option<File>, cx: &mut MutableAppContext) -> Task<anyhow::Result<()>> {
|
||||
self.update(cx, |item, cx| item.save(file, cx))
|
||||
fn save(&self, cx: &mut MutableAppContext) -> Result<Task<Result<()>>> {
|
||||
self.update(cx, |item, cx| item.save(cx))
|
||||
}
|
||||
|
||||
fn save_as(
|
||||
&self,
|
||||
worktree: &ModelHandle<Worktree>,
|
||||
path: &Path,
|
||||
cx: &mut MutableAppContext,
|
||||
) -> Task<anyhow::Result<()>> {
|
||||
self.update(cx, |item, cx| item.save_as(worktree, path, cx))
|
||||
}
|
||||
|
||||
fn is_dirty(&self, cx: &AppContext) -> bool {
|
||||
@@ -388,6 +409,23 @@ impl Workspace {
|
||||
}
|
||||
}
|
||||
|
||||
fn worktree_for_abs_path(
|
||||
&mut self,
|
||||
abs_path: &Path,
|
||||
cx: &mut ViewContext<Self>,
|
||||
) -> (ModelHandle<Worktree>, PathBuf) {
|
||||
for tree in self.worktrees.iter() {
|
||||
if let Some(path) = tree
|
||||
.read(cx)
|
||||
.as_local()
|
||||
.and_then(|tree| abs_path.strip_prefix(&tree.abs_path()).ok())
|
||||
{
|
||||
return (tree.clone(), path.to_path_buf());
|
||||
}
|
||||
}
|
||||
(self.add_worktree(abs_path, cx), PathBuf::new())
|
||||
}
|
||||
|
||||
fn file_for_path(&mut self, abs_path: &Path, cx: &mut ViewContext<Self>) -> File {
|
||||
for tree in self.worktrees.iter() {
|
||||
if let Some(relative_path) = tree
|
||||
@@ -559,19 +597,19 @@ impl Workspace {
|
||||
let handle = cx.handle();
|
||||
if item.entry_id(cx.as_ref()).is_none() {
|
||||
let worktree = self.worktrees.iter().next();
|
||||
let start_path = worktree
|
||||
let start_abs_path = worktree
|
||||
.and_then(|w| w.read(cx).as_local())
|
||||
.map_or(Path::new(""), |w| w.abs_path())
|
||||
.to_path_buf();
|
||||
cx.prompt_for_new_path(&start_path, move |path, cx| {
|
||||
if let Some(path) = path {
|
||||
cx.prompt_for_new_path(&start_abs_path, move |abs_path, cx| {
|
||||
if let Some(abs_path) = abs_path {
|
||||
cx.spawn(|mut cx| async move {
|
||||
let result = async move {
|
||||
let file =
|
||||
handle.update(&mut cx, |me, cx| me.file_for_path(&path, cx));
|
||||
cx.update(|cx| item.save(Some(file), cx)).await
|
||||
}
|
||||
.await;
|
||||
let result = handle
|
||||
.update(&mut cx, |me, cx| {
|
||||
let (worktree, path) = me.worktree_for_abs_path(&abs_path, cx);
|
||||
item.save_as(&worktree, &path, cx.as_mut())
|
||||
})
|
||||
.await;
|
||||
if let Err(error) = result {
|
||||
error!("failed to save item: {:?}, ", error);
|
||||
}
|
||||
@@ -590,7 +628,7 @@ impl Workspace {
|
||||
move |answer, cx| {
|
||||
if answer == 0 {
|
||||
cx.spawn(|mut cx| async move {
|
||||
if let Err(error) = cx.update(|cx| item.save(None, cx)).await {
|
||||
if let Err(error) = cx.update(|cx| item.save(cx)).unwrap().await {
|
||||
error!("failed to save item: {:?}, ", error);
|
||||
}
|
||||
})
|
||||
@@ -600,7 +638,7 @@ impl Workspace {
|
||||
);
|
||||
} else {
|
||||
cx.spawn(|_, mut cx| async move {
|
||||
if let Err(error) = cx.update(|cx| item.save(None, cx)).await {
|
||||
if let Err(error) = cx.update(|cx| item.save(cx)).unwrap().await {
|
||||
error!("failed to save item: {:?}, ", error);
|
||||
}
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user