diff --git a/crates/project_panel/src/project_panel.rs b/crates/project_panel/src/project_panel.rs index 29f8f6459e..0095e4ab79 100644 --- a/crates/project_panel/src/project_panel.rs +++ b/crates/project_panel/src/project_panel.rs @@ -4246,7 +4246,7 @@ impl ProjectPanel { if skip_ignored && worktree .entry_for_id(entry_id) - .map_or(true, |entry| entry.is_ignored) + .map_or(true, |entry| entry.is_ignored && !entry.is_always_included) { return; } @@ -7871,6 +7871,123 @@ mod tests { ); } + #[gpui::test] + async fn test_gitignored_and_always_included(cx: &mut gpui::TestAppContext) { + init_test_with_editor(cx); + cx.update(|cx| { + cx.update_global::(|store, cx| { + store.update_user_settings::(cx, |worktree_settings| { + worktree_settings.file_scan_exclusions = Some(Vec::new()); + worktree_settings.file_scan_inclusions = + Some(vec!["always_included_but_ignored_dir/*".to_string()]); + }); + store.update_user_settings::(cx, |project_panel_settings| { + project_panel_settings.auto_reveal_entries = Some(false) + }); + }) + }); + + let fs = FakeFs::new(cx.background_executor.clone()); + fs.insert_tree( + "/project_root", + json!({ + ".git": {}, + ".gitignore": "**/gitignored_dir\n/always_included_but_ignored_dir", + "dir_1": { + "file_1.py": "# File 1_1 contents", + "file_2.py": "# File 1_2 contents", + "file_3.py": "# File 1_3 contents", + "gitignored_dir": { + "file_a.py": "# File contents", + "file_b.py": "# File contents", + "file_c.py": "# File contents", + }, + }, + "dir_2": { + "file_1.py": "# File 2_1 contents", + "file_2.py": "# File 2_2 contents", + "file_3.py": "# File 2_3 contents", + }, + "always_included_but_ignored_dir": { + "file_a.py": "# File contents", + "file_b.py": "# File contents", + "file_c.py": "# File contents", + }, + }), + ) + .await; + + let project = Project::test(fs.clone(), ["/project_root".as_ref()], cx).await; + let workspace = + cx.add_window(|window, cx| Workspace::test_new(project.clone(), window, cx)); + let cx = &mut VisualTestContext::from_window(*workspace, cx); + let panel = workspace.update(cx, ProjectPanel::new).unwrap(); + + assert_eq!( + visible_entries_as_strings(&panel, 0..20, cx), + &[ + "v project_root", + " > .git", + " > always_included_but_ignored_dir", + " > dir_1", + " > dir_2", + " .gitignore", + ] + ); + + let gitignored_dir_file = + find_project_entry(&panel, "project_root/dir_1/gitignored_dir/file_a.py", cx); + let always_included_but_ignored_dir_file = find_project_entry( + &panel, + "project_root/always_included_but_ignored_dir/file_a.py", + cx, + ) + .expect("file that is .gitignored but set to always be included should have an entry"); + assert_eq!( + gitignored_dir_file, None, + "File in the gitignored dir should not have an entry unless its directory is toggled" + ); + + toggle_expand_dir(&panel, "project_root/dir_1", cx); + cx.run_until_parked(); + cx.update(|_, cx| { + cx.update_global::(|store, cx| { + store.update_user_settings::(cx, |project_panel_settings| { + project_panel_settings.auto_reveal_entries = Some(true) + }); + }) + }); + + panel.update(cx, |panel, cx| { + panel.project.update(cx, |_, cx| { + cx.emit(project::Event::ActiveEntryChanged(Some( + always_included_but_ignored_dir_file, + ))) + }) + }); + cx.run_until_parked(); + + assert_eq!( + visible_entries_as_strings(&panel, 0..20, cx), + &[ + "v project_root", + " > .git", + " v always_included_but_ignored_dir", + " file_a.py <== selected <== marked", + " file_b.py", + " file_c.py", + " v dir_1", + " > gitignored_dir", + " file_1.py", + " file_2.py", + " file_3.py", + " > dir_2", + " .gitignore", + ], + "When auto reveal is enabled, a gitignored but always included selected entry should be revealed in the project panel" + ); + } + #[gpui::test] async fn test_explicit_reveal(cx: &mut gpui::TestAppContext) { init_test_with_editor(cx);