@@ -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::<SettingsStore, _>(|store, cx| {
+ store.update_user_settings::<WorktreeSettings>(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::<ProjectPanelSettings>(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::<SettingsStore, _>(|store, cx| {
+ store.update_user_settings::<ProjectPanelSettings>(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);