worktree: Create parent directories on rename (#37437)

Closes https://github.com/zed-industries/zed/issues/37357

Release Notes:

- Allow creating sub-directories when renaming a file in file finder

---------

Co-authored-by: Kirill Bulatov <kirill@zed.dev>
This commit is contained in:
Mitch (a.k.a Voz)
2025-09-04 08:25:47 +00:00
committed by GitHub
co-authored by Kirill Bulatov
parent aa1629b544
commit b7ad20773c
2 changed files with 138 additions and 20 deletions
+95
View File
@@ -1924,6 +1924,101 @@ fn random_filename(rng: &mut impl Rng) -> String {
.collect()
}
#[gpui::test]
async fn test_rename_file_to_new_directory(cx: &mut TestAppContext) {
init_test(cx);
let fs = FakeFs::new(cx.background_executor.clone());
let expected_contents = "content";
fs.as_fake()
.insert_tree(
"/root",
json!({
"test.txt": expected_contents
}),
)
.await;
let worktree = Worktree::local(
Path::new("/root"),
true,
fs.clone(),
Arc::default(),
&mut cx.to_async(),
)
.await
.unwrap();
cx.read(|cx| worktree.read(cx).as_local().unwrap().scan_complete())
.await;
let entry_id = worktree.read_with(cx, |worktree, _| {
worktree.entry_for_path("test.txt").unwrap().id
});
let _result = worktree
.update(cx, |worktree, cx| {
worktree.rename_entry(entry_id, Path::new("dir1/dir2/dir3/test.txt"), cx)
})
.await
.unwrap();
worktree.read_with(cx, |worktree, _| {
assert!(
worktree.entry_for_path("test.txt").is_none(),
"Old file should have been removed"
);
assert!(
worktree.entry_for_path("dir1/dir2/dir3/test.txt").is_some(),
"Whole directory hierarchy and the new file should have been created"
);
});
assert_eq!(
worktree
.update(cx, |worktree, cx| {
worktree.load_file("dir1/dir2/dir3/test.txt".as_ref(), cx)
})
.await
.unwrap()
.text,
expected_contents,
"Moved file's contents should be preserved"
);
let entry_id = worktree.read_with(cx, |worktree, _| {
worktree
.entry_for_path("dir1/dir2/dir3/test.txt")
.unwrap()
.id
});
let _result = worktree
.update(cx, |worktree, cx| {
worktree.rename_entry(entry_id, Path::new("dir1/dir2/test.txt"), cx)
})
.await
.unwrap();
worktree.read_with(cx, |worktree, _| {
assert!(
worktree.entry_for_path("test.txt").is_none(),
"First file should not reappear"
);
assert!(
worktree.entry_for_path("dir1/dir2/dir3/test.txt").is_none(),
"Old file should have been removed"
);
assert!(
worktree.entry_for_path("dir1/dir2/test.txt").is_some(),
"No error should have occurred after moving into existing directory"
);
});
assert_eq!(
worktree
.update(cx, |worktree, cx| {
worktree.load_file("dir1/dir2/test.txt".as_ref(), cx)
})
.await
.unwrap()
.text,
expected_contents,
"Moved file's contents should be preserved"
);
}
#[gpui::test]
async fn test_private_single_file_worktree(cx: &mut TestAppContext) {
init_test(cx);