mirror of
https://github.com/zed-industries/zed.git
synced 2025-01-26 12:21:50 +00:00
Merge pull request #1746 from zed-industries/maintain-buffer-identity-across-renames
Preserve buffer identity when underlying entry temporarily disappears
This commit is contained in:
commit
ad975da8bd
4 changed files with 77 additions and 14 deletions
|
@ -4298,34 +4298,35 @@ impl Project {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let new_file = if let Some(entry) = old_file
|
let new_file = if let Some(entry) = snapshot.entry_for_id(old_file.entry_id)
|
||||||
.entry_id
|
|
||||||
.and_then(|entry_id| snapshot.entry_for_id(entry_id))
|
|
||||||
{
|
{
|
||||||
File {
|
File {
|
||||||
is_local: true,
|
is_local: true,
|
||||||
entry_id: Some(entry.id),
|
entry_id: entry.id,
|
||||||
mtime: entry.mtime,
|
mtime: entry.mtime,
|
||||||
path: entry.path.clone(),
|
path: entry.path.clone(),
|
||||||
worktree: worktree_handle.clone(),
|
worktree: worktree_handle.clone(),
|
||||||
|
is_deleted: false,
|
||||||
}
|
}
|
||||||
} else if let Some(entry) =
|
} else if let Some(entry) =
|
||||||
snapshot.entry_for_path(old_file.path().as_ref())
|
snapshot.entry_for_path(old_file.path().as_ref())
|
||||||
{
|
{
|
||||||
File {
|
File {
|
||||||
is_local: true,
|
is_local: true,
|
||||||
entry_id: Some(entry.id),
|
entry_id: entry.id,
|
||||||
mtime: entry.mtime,
|
mtime: entry.mtime,
|
||||||
path: entry.path.clone(),
|
path: entry.path.clone(),
|
||||||
worktree: worktree_handle.clone(),
|
worktree: worktree_handle.clone(),
|
||||||
|
is_deleted: false,
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
File {
|
File {
|
||||||
is_local: true,
|
is_local: true,
|
||||||
entry_id: None,
|
entry_id: old_file.entry_id,
|
||||||
path: old_file.path().clone(),
|
path: old_file.path().clone(),
|
||||||
mtime: old_file.mtime(),
|
mtime: old_file.mtime(),
|
||||||
worktree: worktree_handle.clone(),
|
worktree: worktree_handle.clone(),
|
||||||
|
is_deleted: true,
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -2260,6 +2260,57 @@ async fn test_rescan_and_remote_updates(
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[gpui::test(iterations = 10)]
|
||||||
|
async fn test_buffer_identity_across_renames(
|
||||||
|
deterministic: Arc<Deterministic>,
|
||||||
|
cx: &mut gpui::TestAppContext,
|
||||||
|
) {
|
||||||
|
let fs = FakeFs::new(cx.background());
|
||||||
|
fs.insert_tree(
|
||||||
|
"/dir",
|
||||||
|
json!({
|
||||||
|
"a": {
|
||||||
|
"file1": "",
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
.await;
|
||||||
|
|
||||||
|
let project = Project::test(fs, [Path::new("/dir")], cx).await;
|
||||||
|
let tree = project.read_with(cx, |project, cx| project.worktrees(cx).next().unwrap());
|
||||||
|
let tree_id = tree.read_with(cx, |tree, _| tree.id());
|
||||||
|
|
||||||
|
let id_for_path = |path: &'static str, cx: &gpui::TestAppContext| {
|
||||||
|
project.read_with(cx, |project, cx| {
|
||||||
|
let tree = project.worktrees(cx).next().unwrap();
|
||||||
|
tree.read(cx)
|
||||||
|
.entry_for_path(path)
|
||||||
|
.unwrap_or_else(|| panic!("no entry for path {}", path))
|
||||||
|
.id
|
||||||
|
})
|
||||||
|
};
|
||||||
|
|
||||||
|
let dir_id = id_for_path("a", cx);
|
||||||
|
let file_id = id_for_path("a/file1", cx);
|
||||||
|
let buffer = project
|
||||||
|
.update(cx, |p, cx| p.open_buffer((tree_id, "a/file1"), cx))
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
buffer.read_with(cx, |buffer, _| assert!(!buffer.is_dirty()));
|
||||||
|
|
||||||
|
project
|
||||||
|
.update(cx, |project, cx| {
|
||||||
|
project.rename_entry(dir_id, Path::new("b"), cx)
|
||||||
|
})
|
||||||
|
.unwrap()
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
deterministic.run_until_parked();
|
||||||
|
assert_eq!(id_for_path("b", cx), dir_id);
|
||||||
|
assert_eq!(id_for_path("b/file1", cx), file_id);
|
||||||
|
buffer.read_with(cx, |buffer, _| assert!(!buffer.is_dirty()));
|
||||||
|
}
|
||||||
|
|
||||||
#[gpui::test]
|
#[gpui::test]
|
||||||
async fn test_buffer_deduping(cx: &mut gpui::TestAppContext) {
|
async fn test_buffer_deduping(cx: &mut gpui::TestAppContext) {
|
||||||
let fs = FakeFs::new(cx.background());
|
let fs = FakeFs::new(cx.background());
|
||||||
|
@ -2414,6 +2465,7 @@ async fn test_buffer_is_dirty(cx: &mut gpui::TestAppContext) {
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
cx.foreground().run_until_parked();
|
cx.foreground().run_until_parked();
|
||||||
|
buffer2.read_with(cx, |buffer, _| assert!(buffer.is_dirty()));
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
*events.borrow(),
|
*events.borrow(),
|
||||||
&[
|
&[
|
||||||
|
|
|
@ -688,11 +688,12 @@ impl LocalWorktree {
|
||||||
|
|
||||||
Ok((
|
Ok((
|
||||||
File {
|
File {
|
||||||
entry_id: Some(entry.id),
|
entry_id: entry.id,
|
||||||
worktree: handle,
|
worktree: handle,
|
||||||
path: entry.path,
|
path: entry.path,
|
||||||
mtime: entry.mtime,
|
mtime: entry.mtime,
|
||||||
is_local: true,
|
is_local: true,
|
||||||
|
is_deleted: false,
|
||||||
},
|
},
|
||||||
text,
|
text,
|
||||||
diff_base,
|
diff_base,
|
||||||
|
@ -715,11 +716,12 @@ impl LocalWorktree {
|
||||||
cx.as_mut().spawn(|mut cx| async move {
|
cx.as_mut().spawn(|mut cx| async move {
|
||||||
let entry = save.await?;
|
let entry = save.await?;
|
||||||
let file = File {
|
let file = File {
|
||||||
entry_id: Some(entry.id),
|
entry_id: entry.id,
|
||||||
worktree: handle,
|
worktree: handle,
|
||||||
path: entry.path,
|
path: entry.path,
|
||||||
mtime: entry.mtime,
|
mtime: entry.mtime,
|
||||||
is_local: true,
|
is_local: true,
|
||||||
|
is_deleted: false,
|
||||||
};
|
};
|
||||||
|
|
||||||
buffer_handle.update(&mut cx, |buffer, cx| {
|
buffer_handle.update(&mut cx, |buffer, cx| {
|
||||||
|
@ -1813,8 +1815,9 @@ pub struct File {
|
||||||
pub worktree: ModelHandle<Worktree>,
|
pub worktree: ModelHandle<Worktree>,
|
||||||
pub path: Arc<Path>,
|
pub path: Arc<Path>,
|
||||||
pub mtime: SystemTime,
|
pub mtime: SystemTime,
|
||||||
pub(crate) entry_id: Option<ProjectEntryId>,
|
pub(crate) entry_id: ProjectEntryId,
|
||||||
pub(crate) is_local: bool,
|
pub(crate) is_local: bool,
|
||||||
|
pub(crate) is_deleted: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl language::File for File {
|
impl language::File for File {
|
||||||
|
@ -1852,7 +1855,7 @@ impl language::File for File {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_deleted(&self) -> bool {
|
fn is_deleted(&self) -> bool {
|
||||||
self.entry_id.is_none()
|
self.is_deleted
|
||||||
}
|
}
|
||||||
|
|
||||||
fn save(
|
fn save(
|
||||||
|
@ -1912,9 +1915,10 @@ impl language::File for File {
|
||||||
fn to_proto(&self) -> rpc::proto::File {
|
fn to_proto(&self) -> rpc::proto::File {
|
||||||
rpc::proto::File {
|
rpc::proto::File {
|
||||||
worktree_id: self.worktree.id() as u64,
|
worktree_id: self.worktree.id() as u64,
|
||||||
entry_id: self.entry_id.map(|entry_id| entry_id.to_proto()),
|
entry_id: self.entry_id.to_proto(),
|
||||||
path: self.path.to_string_lossy().into(),
|
path: self.path.to_string_lossy().into(),
|
||||||
mtime: Some(self.mtime.into()),
|
mtime: Some(self.mtime.into()),
|
||||||
|
is_deleted: self.is_deleted,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1983,8 +1987,9 @@ impl File {
|
||||||
worktree,
|
worktree,
|
||||||
path: Path::new(&proto.path).into(),
|
path: Path::new(&proto.path).into(),
|
||||||
mtime: proto.mtime.ok_or_else(|| anyhow!("no timestamp"))?.into(),
|
mtime: proto.mtime.ok_or_else(|| anyhow!("no timestamp"))?.into(),
|
||||||
entry_id: proto.entry_id.map(ProjectEntryId::from_proto),
|
entry_id: ProjectEntryId::from_proto(proto.entry_id),
|
||||||
is_local: false,
|
is_local: false,
|
||||||
|
is_deleted: proto.is_deleted,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1997,7 +2002,11 @@ impl File {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn project_entry_id(&self, _: &AppContext) -> Option<ProjectEntryId> {
|
pub fn project_entry_id(&self, _: &AppContext) -> Option<ProjectEntryId> {
|
||||||
self.entry_id
|
if self.is_deleted {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
Some(self.entry_id)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -868,9 +868,10 @@ message User {
|
||||||
|
|
||||||
message File {
|
message File {
|
||||||
uint64 worktree_id = 1;
|
uint64 worktree_id = 1;
|
||||||
optional uint64 entry_id = 2;
|
uint64 entry_id = 2;
|
||||||
string path = 3;
|
string path = 3;
|
||||||
Timestamp mtime = 4;
|
Timestamp mtime = 4;
|
||||||
|
bool is_deleted = 5;
|
||||||
}
|
}
|
||||||
|
|
||||||
message Entry {
|
message Entry {
|
||||||
|
|
Loading…
Reference in a new issue