diff --git a/crates/project/src/buffer_store.rs b/crates/project/src/buffer_store.rs index 442cd35dc1b171a1510439f5314d3f543293350f..b9249d36e2ca8da6b17f342a8db9f3dcca113515 100644 --- a/crates/project/src/buffer_store.rs +++ b/crates/project/src/buffer_store.rs @@ -909,7 +909,14 @@ impl BufferStore { }; cx.spawn(async move |this, cx| { task.await?; - this.update(cx, |_, cx| { + this.update(cx, |this, cx| { + old_file.clone().and_then(|file| { + this.path_to_buffer_id.remove(&ProjectPath { + worktree_id: file.worktree_id(cx), + path: file.path().clone(), + }) + }); + cx.emit(BufferStoreEvent::BufferChangedFilePath { buffer, old_file }); }) }) diff --git a/crates/project/src/project_tests.rs b/crates/project/src/project_tests.rs index 859fe02cfa70d035a347c62ba7cbe93f250b674a..e3714cddf15d7623ab32403ea9cdd889c27abedc 100644 --- a/crates/project/src/project_tests.rs +++ b/crates/project/src/project_tests.rs @@ -4251,6 +4251,73 @@ async fn test_save_as(cx: &mut gpui::TestAppContext) { assert_eq!(opened_buffer, buffer); } +#[gpui::test] +async fn test_save_as_existing_file(cx: &mut gpui::TestAppContext) { + init_test(cx); + + let fs = FakeFs::new(cx.executor()); + let project = Project::test(fs.clone(), [path!("/dir").as_ref()], cx).await; + + fs.insert_tree( + path!("/dir"), + json!({ + "data_a.txt": "data about a" + }), + ) + .await; + + let buffer = project + .update(cx, |project, cx| { + project.open_local_buffer(path!("/dir/data_a.txt"), cx) + }) + .await + .unwrap(); + + buffer.update(cx, |buffer, cx| { + buffer.edit([(11..12, "b")], None, cx); + }); + + // Save buffer's contents as a new file and confirm that the buffer's now + // associated with `data_b.txt` instead of `data_a.txt`, confirming that the + // file associated with the buffer has now been updated to `data_b.txt` + project + .update(cx, |project, cx| { + let worktree_id = project.worktrees(cx).next().unwrap().read(cx).id(); + let new_path = ProjectPath { + worktree_id, + path: rel_path("data_b.txt").into(), + }; + + project.save_buffer_as(buffer.clone(), new_path, cx) + }) + .await + .unwrap(); + + buffer.update(cx, |buffer, cx| { + assert_eq!( + buffer.file().unwrap().full_path(cx), + Path::new("dir/data_b.txt") + ) + }); + + // Open the original `data_a.txt` file, confirming that its contents are + // unchanged and the resulting buffer's associated file is `data_a.txt`. + let original_buffer = project + .update(cx, |project, cx| { + project.open_local_buffer(path!("/dir/data_a.txt"), cx) + }) + .await + .unwrap(); + + original_buffer.update(cx, |buffer, cx| { + assert_eq!(buffer.text(), "data about a"); + assert_eq!( + buffer.file().unwrap().full_path(cx), + Path::new("dir/data_a.txt") + ) + }); +} + #[gpui::test(retries = 5)] async fn test_rescan_and_remote_updates(cx: &mut gpui::TestAppContext) { use worktree::WorktreeModelHandle as _;