Fix data loss when project settings opened with ".zed" in file_scan_exclusions
(#29578)
Closes #28640 Before creating an entry for a file opened with `open_local_file`, make sure it doesn't exist, in addition to checking that it isn't already tracked in the workspace Release Notes: - Fixed an issue where the project settings file would be truncated when opened with `zed: open project settings` if the ".zed" directory was excluded from the files scanned in a workspace (in "file_scan_exclusions")
This commit is contained in:
parent
4dc8ce8cf7
commit
3a212e72a4
1 changed files with 139 additions and 14 deletions
|
@ -1502,6 +1502,22 @@ fn open_local_file(
|
|||
if let Some(worktree) = worktree {
|
||||
let tree_id = worktree.read(cx).id();
|
||||
cx.spawn_in(window, async move |workspace, cx| {
|
||||
// Check if the file actually exists on disk (even if it's excluded from worktree)
|
||||
let file_exists = {
|
||||
let full_path =
|
||||
worktree.update(cx, |tree, _| tree.abs_path().join(settings_relative_path))?;
|
||||
|
||||
let fs = project.update(cx, |project, _| project.fs().clone())?;
|
||||
let file_exists = fs
|
||||
.metadata(&full_path)
|
||||
.await
|
||||
.ok()
|
||||
.flatten()
|
||||
.map_or(false, |metadata| !metadata.is_dir && !metadata.is_fifo);
|
||||
file_exists
|
||||
};
|
||||
|
||||
if !file_exists {
|
||||
if let Some(dir_path) = settings_relative_path.parent() {
|
||||
if worktree.update(cx, |tree, _| tree.entry_for_path(dir_path).is_none())? {
|
||||
project
|
||||
|
@ -1523,6 +1539,7 @@ fn open_local_file(
|
|||
.await
|
||||
.context("worktree was removed")?;
|
||||
}
|
||||
}
|
||||
|
||||
let editor = workspace
|
||||
.update_in(cx, |workspace, window, cx| {
|
||||
|
@ -4316,4 +4333,112 @@ mod tests {
|
|||
);
|
||||
}
|
||||
}
|
||||
|
||||
#[gpui::test]
|
||||
async fn test_opening_project_settings_when_excluded(cx: &mut gpui::TestAppContext) {
|
||||
// Use the proper initialization for runtime state
|
||||
let app_state = init_keymap_test(cx);
|
||||
|
||||
eprintln!("Running test_opening_project_settings_when_excluded");
|
||||
|
||||
// 1. Set up a project with some project settings
|
||||
let settings_init =
|
||||
r#"{ "UNIQUEVALUE": true, "git": { "inline_blame": { "enabled": false } } }"#;
|
||||
app_state
|
||||
.fs
|
||||
.as_fake()
|
||||
.insert_tree(
|
||||
Path::new("/root"),
|
||||
json!({
|
||||
".zed": {
|
||||
"settings.json": settings_init
|
||||
}
|
||||
}),
|
||||
)
|
||||
.await;
|
||||
|
||||
eprintln!("Created project with .zed/settings.json containing UNIQUEVALUE");
|
||||
|
||||
// 2. Create a project with the file system and load it
|
||||
let project = Project::test(app_state.fs.clone(), [Path::new("/root")], cx).await;
|
||||
|
||||
// Save original settings content for comparison
|
||||
let original_settings = app_state
|
||||
.fs
|
||||
.load(Path::new("/root/.zed/settings.json"))
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let original_settings_str = original_settings.clone();
|
||||
|
||||
// Verify settings exist on disk and have expected content
|
||||
eprintln!("Original settings content: {}", original_settings_str);
|
||||
assert!(
|
||||
original_settings_str.contains("UNIQUEVALUE"),
|
||||
"Test setup failed - settings file doesn't contain our marker"
|
||||
);
|
||||
|
||||
// 3. Add .zed to file scan exclusions in user settings
|
||||
cx.update_global::<SettingsStore, _>(|store, cx| {
|
||||
store.update_user_settings::<WorktreeSettings>(cx, |worktree_settings| {
|
||||
worktree_settings.file_scan_exclusions = Some(vec![".zed".to_string()]);
|
||||
});
|
||||
});
|
||||
|
||||
eprintln!("Added .zed to file_scan_exclusions in settings");
|
||||
|
||||
// 4. Run tasks to apply settings
|
||||
cx.background_executor.run_until_parked();
|
||||
|
||||
// 5. Critical: Verify .zed is actually excluded from worktree
|
||||
let worktree = cx.update(|cx| project.read(cx).worktrees(cx).next().unwrap().clone());
|
||||
|
||||
let has_zed_entry = cx.update(|cx| worktree.read(cx).entry_for_path(".zed").is_some());
|
||||
|
||||
eprintln!(
|
||||
"Is .zed directory visible in worktree after exclusion: {}",
|
||||
has_zed_entry
|
||||
);
|
||||
|
||||
// This assertion verifies the test is set up correctly to show the bug
|
||||
// If .zed is not excluded, the test will fail here
|
||||
assert!(
|
||||
!has_zed_entry,
|
||||
"Test precondition failed: .zed directory should be excluded but was found in worktree"
|
||||
);
|
||||
|
||||
// 6. Create workspace and trigger the actual function that causes the bug
|
||||
let window = cx.add_window(|window, cx| Workspace::test_new(project.clone(), window, cx));
|
||||
window
|
||||
.update(cx, |workspace, window, cx| {
|
||||
// Call the exact function that contains the bug
|
||||
eprintln!("About to call open_project_settings_file");
|
||||
open_project_settings_file(workspace, &OpenProjectSettings, window, cx);
|
||||
})
|
||||
.unwrap();
|
||||
|
||||
// 7. Run background tasks until completion
|
||||
cx.background_executor.run_until_parked();
|
||||
|
||||
// 8. Verify file contents after calling function
|
||||
let new_content = app_state
|
||||
.fs
|
||||
.load(Path::new("/root/.zed/settings.json"))
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let new_content_str = new_content.clone();
|
||||
eprintln!("New settings content: {}", new_content_str);
|
||||
|
||||
// The bug causes the settings to be overwritten with empty settings
|
||||
// So if the unique value is no longer present, the bug has been reproduced
|
||||
let bug_exists = !new_content_str.contains("UNIQUEVALUE");
|
||||
eprintln!("Bug reproduced: {}", bug_exists);
|
||||
|
||||
// This assertion should fail if the bug exists - showing the bug is real
|
||||
assert!(
|
||||
new_content_str.contains("UNIQUEVALUE"),
|
||||
"BUG FOUND: Project settings were overwritten when opening via command - original custom content was lost"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue