Add support for the "..." entry in file_scan_inclusions (#64440)

## Objective

Let projects add inclusion patterns without repeating defaults or
patterns inherited from user settings.

Part of #64399.

## Solution

Extend the `"..."` behavior from #62769 and #64222 to
`file_scan_inclusions` using the shared merge implementation. `"..."`
includes the resolved inherited list, omitting it replaces the list, and
`[]` clears it. Duplicate entries retain their first occurrence.

Stop importing VS Code’s `files.watcherInclude` as inclusion patterns
because it configures additional watch roots rather than overriding Git
ignores.

## Testing

Tested on macOS with settings merge, VS Code import, and worktree
integration tests. Coverage includes preservation of the `.env*`
default, layered inheritance, replacement, clearing, and deduplication.
The worktree test verifies that inherited and project-specific patterns
include Git-ignored files while exclusions still take precedence.

To check manually, configure different user and project inclusion
patterns and add ignored files matching each. Include `"..."` to retain
inherited patterns, then repeat without it and with `[]` to verify
replacement and clearing. Confirm that excluded files remain absent.

## Self-Review Checklist:

- [x] I’ve reviewed my own diff for quality, security, and reliability
- [x] Unsafe blocks (if any) have justifying comments
- [x] The content adheres to Zed’s UI standards
([UX/UI](https://github.com/zed-industries/zed/blob/main/CONTRIBUTING.md#uiux-checklist)
and
[icon](https://github.com/zed-industries/zed/blob/main/crates/icons/README.md)
guidelines)
- [x] Tests cover the new/changed behavior
- [x] Performance impact has been considered and is acceptable

---

Release Notes:

- Added support for `"..."` in `file_scan_inclusions` so project
settings can extend inherited inclusion patterns.
This commit is contained in:
Dom Porada authored and GitHub committed 2026-09-18 10:40:43 +00:00
1 parent 18960e899a
commit 2229b4e2d6
8 files changed
+279 -34

No files matched your search

+42 -9
View File
@@ -1136,15 +1136,8 @@ impl VsCodeSettings {
})
.filter(|r| !r.is_empty())
.map(SplicingVec::from),
file_scan_inclusions: self
.read_value("files.watcherInclude")
.and_then(|v| v.as_array())
.map(|v| {
v.iter()
.filter_map(|n| n.as_str().map(str::to_owned))
.collect::<Vec<_>>()
})
.filter(|r| !r.is_empty()),
// `files.watcherInclude` adds watch roots, not Git-ignore overrides
file_scan_inclusions: None,
scan_symlinks: None,
private_files: None,
hidden_files: None,
@@ -1243,6 +1236,46 @@ mod tests {
.reduce_motion
}
#[test]
fn test_import_watcher_include_preserves_file_scan_inclusions() -> Result<()> {
let inherited = WorktreeSettingsContent {
file_scan_inclusions: Some(SplicingVec::from(vec![
".env*".to_string(),
"**/*.local".to_string(),
])),
..Default::default()
};
for content in [
r#"{}"#,
r#"{"files.watcherInclude": []}"#,
r#"{"files.watcherInclude": ["linked-folder"]}"#,
r#"{"files.watcherInclude": ["..."]}"#,
r#"{"files.watcherInclude": ["linked-folder", false]}"#,
r#"{"files.watcherInclude": {"linked-folder": true}}"#,
] {
let mut content: Value = serde_json::from_str(content)?;
content["editor.tabSize"] = serde_json::json!(8);
let imported = VsCodeSettings::from_str(
&serde_json::to_string(&content)?,
VsCodeSettingsSource::VsCode,
)?
.settings_content();
assert_eq!(imported.project.worktree.file_scan_inclusions, None);
assert_eq!(
imported.project.all_languages.defaults.tab_size,
NonZeroU32::new(8)
);
let mut unchanged = inherited.clone();
unchanged.merge_from(&imported.project.worktree);
assert_eq!(
unchanged.file_scan_inclusions,
inherited.file_scan_inclusions
);
}
Ok(())
}
#[test]
fn test_import_read_only_files() -> Result<()> {
let inherited = WorktreeSettingsContent {