file_finder: Respect .gitignore and file_scan_inclusions with ** in glob (#40654)

Closes #39037 

Previously, the code split the `**/.env` glob in `file_scan_inclusions`
into two sources for the `PathMatcher`: `["**", "**/.env"]`. This
approach works for directories, but including `**` will match all
directories and their files. To address this, I now select the
appropriate `PathMatcher` using only `**/.env` when specifically
targeting a file to determine whether to include it in the file finder.

Release Notes:

- Fixed: respect `.gitignore` and `file_scan_inclusions` settings with
`**` in glob for file finder

---------

Signed-off-by: Benjamin <5719034+bnjjj@users.noreply.github.com>
Co-authored-by: Julia Ryan <juliaryan3.14@gmail.com>
This commit is contained in:
Coenen Benjamin
2025-11-04 12:11:17 +00:00
committed by GitHub
co-authored by Julia Ryan
parent cc6208b17f
commit a827f25d00
5 changed files with 183 additions and 11 deletions
+11 -6
View File
@@ -505,7 +505,7 @@ impl Worktree {
project_id,
replica_id,
snapshot,
file_scan_inclusions: settings.file_scan_inclusions.clone(),
file_scan_inclusions: settings.parent_dir_scan_inclusions.clone(),
background_snapshot: background_snapshot.clone(),
updates_tx: Some(background_updates_tx),
update_observer: None,
@@ -520,8 +520,10 @@ impl Worktree {
while let Some(update) = background_updates_rx.next().await {
{
let mut lock = background_snapshot.lock();
lock.0
.apply_remote_update(update.clone(), &settings.file_scan_inclusions);
lock.0.apply_remote_update(
update.clone(),
&settings.parent_dir_scan_inclusions,
);
lock.1.push(update);
}
snapshot_updated_tx.send(()).await.ok();
@@ -4290,7 +4292,8 @@ impl BackgroundScanner {
if child_entry.is_dir() {
child_entry.is_ignored = ignore_stack.is_abs_path_ignored(&child_abs_path, true);
child_entry.is_always_included = self.settings.is_path_always_included(&child_path);
child_entry.is_always_included =
self.settings.is_path_always_included(&child_path, true);
// Avoid recursing until crash in the case of a recursive symlink
if job.ancestor_inodes.contains(&child_entry.inode) {
@@ -4315,7 +4318,8 @@ impl BackgroundScanner {
}
} else {
child_entry.is_ignored = ignore_stack.is_abs_path_ignored(&child_abs_path, false);
child_entry.is_always_included = self.settings.is_path_always_included(&child_path);
child_entry.is_always_included =
self.settings.is_path_always_included(&child_path, false);
}
{
@@ -4450,7 +4454,8 @@ impl BackgroundScanner {
fs_entry.is_ignored = ignore_stack.is_abs_path_ignored(&abs_path, is_dir);
fs_entry.is_external = is_external;
fs_entry.is_private = self.is_path_private(path);
fs_entry.is_always_included = self.settings.is_path_always_included(path);
fs_entry.is_always_included =
self.settings.is_path_always_included(path, is_dir);
let parent_is_hidden = path
.parent()
+14 -5
View File
@@ -13,8 +13,11 @@ pub struct WorktreeSettings {
pub project_name: Option<String>,
/// Whether to prevent this project from being shared in public channels.
pub prevent_sharing_in_public_channels: bool,
pub file_scan_inclusions: PathMatcher,
pub file_scan_exclusions: PathMatcher,
pub file_scan_inclusions: PathMatcher,
/// This field contains all ancestors of the `file_scan_inclusions`. It's used to
/// determine whether to terminate worktree scanning for a given dir.
pub parent_dir_scan_inclusions: PathMatcher,
pub private_files: PathMatcher,
}
@@ -29,9 +32,12 @@ impl WorktreeSettings {
.any(|ancestor| self.file_scan_exclusions.is_match(ancestor.as_std_path()))
}
pub fn is_path_always_included(&self, path: &RelPath) -> bool {
path.ancestors()
.any(|ancestor| self.file_scan_inclusions.is_match(ancestor.as_std_path()))
pub fn is_path_always_included(&self, path: &RelPath, is_dir: bool) -> bool {
if is_dir {
self.parent_dir_scan_inclusions.is_match(path.as_std_path())
} else {
self.file_scan_inclusions.is_match(path.as_std_path())
}
}
}
@@ -46,6 +52,7 @@ impl Settings for WorktreeSettings {
.flat_map(|glob| {
Path::new(glob)
.ancestors()
.skip(1)
.map(|a| a.to_string_lossy().into())
})
.filter(|p: &String| !p.is_empty())
@@ -57,11 +64,13 @@ impl Settings for WorktreeSettings {
file_scan_exclusions: path_matchers(file_scan_exclusions, "file_scan_exclusions")
.log_err()
.unwrap_or_default(),
file_scan_inclusions: path_matchers(
parent_dir_scan_inclusions: path_matchers(
parsed_file_scan_inclusions,
"file_scan_inclusions",
)
.unwrap(),
file_scan_inclusions: path_matchers(file_scan_inclusions, "file_scan_inclusions")
.unwrap(),
private_files: path_matchers(private_files, "private_files")
.log_err()
.unwrap_or_default(),
+1
View File
@@ -760,6 +760,7 @@ async fn test_file_scan_inclusions(cx: &mut TestAppContext) {
"prettier": {
"package.json": "{}",
},
"package.json": "//package.json"
},
"src": {
".DS_Store": "",