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:
1 parent
18960e899a
commit
2229b4e2d6
8 files changed
+279
-34
No files matched your search
@@ -7,7 +7,7 @@ use menu::{Cancel, Confirm, SelectNext, SelectPrevious};
|
|||||||
use pretty_assertions::{assert_eq, assert_matches};
|
use pretty_assertions::{assert_eq, assert_matches};
|
||||||
use project::{FS_WATCH_LATENCY, RemoveOptions};
|
use project::{FS_WATCH_LATENCY, RemoveOptions};
|
||||||
use serde_json::json;
|
use serde_json::json;
|
||||||
use settings::SettingsStore;
|
use settings::{SettingsStore, SplicingVec};
|
||||||
use util::{path, rel_path::rel_path};
|
use util::{path, rel_path::rel_path};
|
||||||
use workspace::{
|
use workspace::{
|
||||||
AppState, CloseActiveItem, Item, MultiWorkspace, OpenOptions, ToggleFileFinder, Workspace,
|
AppState, CloseActiveItem, Item, MultiWorkspace, OpenOptions, ToggleFileFinder, Workspace,
|
||||||
@@ -1003,10 +1003,10 @@ async fn test_ignored_root_with_file_inclusions(cx: &mut TestAppContext) {
|
|||||||
cx.update(|cx| {
|
cx.update(|cx| {
|
||||||
cx.update_global::<SettingsStore, _>(|store, cx| {
|
cx.update_global::<SettingsStore, _>(|store, cx| {
|
||||||
store.update_user_settings(cx, |settings| {
|
store.update_user_settings(cx, |settings| {
|
||||||
settings.project.worktree.file_scan_inclusions = Some(vec![
|
settings.project.worktree.file_scan_inclusions = Some(SplicingVec::from(vec![
|
||||||
"height_demo/**/hi_bonjour".to_string(),
|
|
||||||
"**/height_1".to_string(),
|
"**/height_1".to_string(),
|
||||||
]);
|
"height_demo/**/hi_bonjour".to_string(),
|
||||||
|
]));
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
@@ -1097,7 +1097,8 @@ async fn test_ignored_root_with_file_inclusions_repro(cx: &mut TestAppContext) {
|
|||||||
cx.update(|cx| {
|
cx.update(|cx| {
|
||||||
cx.update_global::<SettingsStore, _>(|store, cx| {
|
cx.update_global::<SettingsStore, _>(|store, cx| {
|
||||||
store.update_user_settings(cx, |settings| {
|
store.update_user_settings(cx, |settings| {
|
||||||
settings.project.worktree.file_scan_inclusions = Some(vec!["**/.env".to_string()]);
|
settings.project.worktree.file_scan_inclusions =
|
||||||
|
Some(SplicingVec::from(vec!["**/.env".to_string()]));
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -6206,8 +6206,9 @@ async fn test_gitignored_and_always_included(cx: &mut gpui::TestAppContext) {
|
|||||||
store.update_user_settings(cx, |settings| {
|
store.update_user_settings(cx, |settings| {
|
||||||
settings.project.worktree.file_scan_exclusions =
|
settings.project.worktree.file_scan_exclusions =
|
||||||
Some(SplicingVec::from(Vec::new()));
|
Some(SplicingVec::from(Vec::new()));
|
||||||
settings.project.worktree.file_scan_inclusions =
|
settings.project.worktree.file_scan_inclusions = Some(SplicingVec::from(vec![
|
||||||
Some(vec!["always_included_but_ignored_dir/*".to_string()]);
|
"always_included_but_ignored_dir/*".to_string(),
|
||||||
|
]));
|
||||||
settings
|
settings
|
||||||
.project_panel
|
.project_panel
|
||||||
.get_or_insert_default()
|
.get_or_insert_default()
|
||||||
|
|||||||
@@ -1136,15 +1136,8 @@ impl VsCodeSettings {
|
|||||||
})
|
})
|
||||||
.filter(|r| !r.is_empty())
|
.filter(|r| !r.is_empty())
|
||||||
.map(SplicingVec::from),
|
.map(SplicingVec::from),
|
||||||
file_scan_inclusions: self
|
// `files.watcherInclude` adds watch roots, not Git-ignore overrides
|
||||||
.read_value("files.watcherInclude")
|
file_scan_inclusions: None,
|
||||||
.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()),
|
|
||||||
scan_symlinks: None,
|
scan_symlinks: None,
|
||||||
private_files: None,
|
private_files: None,
|
||||||
hidden_files: None,
|
hidden_files: None,
|
||||||
@@ -1243,6 +1236,46 @@ mod tests {
|
|||||||
.reduce_motion
|
.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]
|
#[test]
|
||||||
fn test_import_read_only_files() -> Result<()> {
|
fn test_import_read_only_files() -> Result<()> {
|
||||||
let inherited = WorktreeSettingsContent {
|
let inherited = WorktreeSettingsContent {
|
||||||
|
|||||||
@@ -148,13 +148,15 @@ pub struct WorktreeSettingsContent {
|
|||||||
/// ]
|
/// ]
|
||||||
pub file_scan_exclusions: Option<SplicingVec>,
|
pub file_scan_exclusions: Option<SplicingVec>,
|
||||||
|
|
||||||
/// Always include files that match these globs when scanning for files, even if they're
|
/// Always include files that match these globs when scanning for files, even
|
||||||
/// ignored by git. This setting is overridden by `file_scan_exclusions`.
|
/// if they’re ignored by Git. This setting is overridden by
|
||||||
/// Default: [
|
/// `file_scan_exclusions`.
|
||||||
/// ".env*",
|
///
|
||||||
/// "docker-compose.*.yml",
|
/// A "..." entry expands to the value being overridden. Leave "..." out to
|
||||||
/// ]
|
/// replace the inherited globs, or use an empty list to clear them.
|
||||||
pub file_scan_inclusions: Option<Vec<String>>,
|
///
|
||||||
|
/// Default: [".env*"]
|
||||||
|
pub file_scan_inclusions: Option<SplicingVec>,
|
||||||
|
|
||||||
/// When to scan content of linked directories.
|
/// When to scan content of linked directories.
|
||||||
///
|
///
|
||||||
@@ -1044,6 +1046,74 @@ mod tests {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn inclusions(globs: &[&str]) -> WorktreeSettingsContent {
|
||||||
|
WorktreeSettingsContent {
|
||||||
|
file_scan_inclusions: Some(SplicingVec::from(
|
||||||
|
globs
|
||||||
|
.iter()
|
||||||
|
.map(|glob| glob.to_string())
|
||||||
|
.collect::<Vec<_>>(),
|
||||||
|
)),
|
||||||
|
..Default::default()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_file_scan_inclusions_splice_each_layer() {
|
||||||
|
let mut settings = inclusions(&[".env*"]);
|
||||||
|
settings.merge_from(&inclusions(&[SplicingVec::REST, "**/*.user"]));
|
||||||
|
assert_eq!(settings, inclusions(&[".env*", "**/*.user"]));
|
||||||
|
|
||||||
|
settings.merge_from(&inclusions(&["**/*.project", SplicingVec::REST]));
|
||||||
|
assert_eq!(
|
||||||
|
settings,
|
||||||
|
inclusions(&["**/*.project", ".env*", "**/*.user"])
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_file_scan_inclusions_replace_and_clear() {
|
||||||
|
let mut settings = inclusions(&[".env*"]);
|
||||||
|
settings.merge_from(&inclusions(&["**/*.user"]));
|
||||||
|
assert_eq!(settings, inclusions(&["**/*.user"]));
|
||||||
|
|
||||||
|
settings.merge_from(&inclusions(&["**/*.project"]));
|
||||||
|
assert_eq!(settings, inclusions(&["**/*.project"]));
|
||||||
|
|
||||||
|
settings.merge_from(&inclusions(&[]));
|
||||||
|
assert_eq!(settings, inclusions(&[]));
|
||||||
|
|
||||||
|
settings.merge_from(&inclusions(&[SplicingVec::REST, "**/*.next"]));
|
||||||
|
assert_eq!(settings, inclusions(&["**/*.next"]));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_file_scan_inclusions_splice_preserves_first_occurrence() {
|
||||||
|
let inherited = inclusions(&[".env*", "**/*.user"]);
|
||||||
|
let mut settings = inherited.clone();
|
||||||
|
settings.merge_from(&WorktreeSettingsContent::default());
|
||||||
|
assert_eq!(settings, inherited);
|
||||||
|
|
||||||
|
settings.merge_from(&inclusions(&[SplicingVec::REST, SplicingVec::REST]));
|
||||||
|
assert_eq!(settings, inherited);
|
||||||
|
|
||||||
|
settings.merge_from(&inclusions(&[
|
||||||
|
"**/*.user",
|
||||||
|
SplicingVec::REST,
|
||||||
|
".env*",
|
||||||
|
"**/*.project",
|
||||||
|
SplicingVec::REST,
|
||||||
|
"**/*.project",
|
||||||
|
]));
|
||||||
|
assert_eq!(
|
||||||
|
settings,
|
||||||
|
inclusions(&["**/*.user", ".env*", "**/*.project"])
|
||||||
|
);
|
||||||
|
|
||||||
|
settings.merge_from(&inclusions(&["**/*.project", "**/*.user", "**/*.project"]));
|
||||||
|
assert_eq!(settings, inclusions(&["**/*.project", "**/*.user"]));
|
||||||
|
}
|
||||||
|
|
||||||
fn read_only_files(globs: &[&str]) -> WorktreeSettingsContent {
|
fn read_only_files(globs: &[&str]) -> WorktreeSettingsContent {
|
||||||
WorktreeSettingsContent {
|
WorktreeSettingsContent {
|
||||||
read_only_files: Some(SplicingVec::from(
|
read_only_files: Some(SplicingVec::from(
|
||||||
|
|||||||
@@ -61,7 +61,7 @@ impl Settings for WorktreeSettings {
|
|||||||
fn from_settings(content: &settings::SettingsContent) -> Self {
|
fn from_settings(content: &settings::SettingsContent) -> Self {
|
||||||
let worktree = content.project.worktree.clone();
|
let worktree = content.project.worktree.clone();
|
||||||
let file_scan_exclusions = worktree.file_scan_exclusions.unwrap().0;
|
let file_scan_exclusions = worktree.file_scan_exclusions.unwrap().0;
|
||||||
let file_scan_inclusions = worktree.file_scan_inclusions.unwrap();
|
let file_scan_inclusions = worktree.file_scan_inclusions.unwrap().0;
|
||||||
let private_files = worktree.private_files.unwrap().0;
|
let private_files = worktree.private_files.unwrap().0;
|
||||||
let hidden_files = worktree.hidden_files.unwrap();
|
let hidden_files = worktree.hidden_files.unwrap();
|
||||||
let read_only_files = worktree.read_only_files.unwrap_or_default().0;
|
let read_only_files = worktree.read_only_files.unwrap_or_default().0;
|
||||||
|
|||||||
@@ -2067,10 +2067,10 @@ async fn test_file_scan_inclusions(cx: &mut TestAppContext) {
|
|||||||
cx.update_global::<SettingsStore, _>(|store, cx| {
|
cx.update_global::<SettingsStore, _>(|store, cx| {
|
||||||
store.update_user_settings(cx, |settings| {
|
store.update_user_settings(cx, |settings| {
|
||||||
settings.project.worktree.file_scan_exclusions = Some(SplicingVec::from(vec![]));
|
settings.project.worktree.file_scan_exclusions = Some(SplicingVec::from(vec![]));
|
||||||
settings.project.worktree.file_scan_inclusions = Some(vec![
|
settings.project.worktree.file_scan_inclusions = Some(SplicingVec::from(vec![
|
||||||
"node_modules/**/package.json".to_string(),
|
|
||||||
"**/.DS_Store".to_string(),
|
"**/.DS_Store".to_string(),
|
||||||
]);
|
"node_modules/**/package.json".to_string(),
|
||||||
|
]));
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -2108,6 +2108,135 @@ async fn test_file_scan_inclusions(cx: &mut TestAppContext) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[gpui::test]
|
||||||
|
async fn test_file_scan_inclusions_from_project_settings(cx: &mut TestAppContext) {
|
||||||
|
init_test(cx);
|
||||||
|
let worktree_id = WorktreeId::from_proto(0);
|
||||||
|
cx.update(|cx| {
|
||||||
|
cx.update_global::<SettingsStore, _>(|store, cx| {
|
||||||
|
store.update_user_settings(cx, |settings| {
|
||||||
|
settings.project.worktree.file_scan_exclusions = Some(SplicingVec::from(vec![
|
||||||
|
"...".to_string(),
|
||||||
|
"ignored/**/excluded.project".to_string(),
|
||||||
|
]));
|
||||||
|
settings.project.worktree.file_scan_inclusions = Some(SplicingVec::from(vec![
|
||||||
|
"...".to_string(),
|
||||||
|
"ignored/**/*.user".to_string(),
|
||||||
|
]));
|
||||||
|
});
|
||||||
|
store
|
||||||
|
.set_local_settings(
|
||||||
|
worktree_id,
|
||||||
|
LocalSettingsPath::InWorktree(Arc::from(RelPath::empty())),
|
||||||
|
LocalSettingsKind::Settings,
|
||||||
|
Some(r#"{ "file_scan_inclusions": ["...", "ignored/**/*.project"] }"#),
|
||||||
|
cx,
|
||||||
|
)
|
||||||
|
.expect("valid project settings");
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
let fs = FakeFs::new(cx.background_executor.clone());
|
||||||
|
fs.insert_tree(
|
||||||
|
path!("/root"),
|
||||||
|
json!({
|
||||||
|
".env.local": "",
|
||||||
|
".git": {},
|
||||||
|
".gitignore": ".env*\n/ignored/\nunmatched.txt\n",
|
||||||
|
"ignored": {
|
||||||
|
"nested": {
|
||||||
|
"excluded.project": "",
|
||||||
|
"included.project": "",
|
||||||
|
"included.user": "",
|
||||||
|
"unmatched.txt": ""
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"unmatched.txt": ""
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
.await;
|
||||||
|
|
||||||
|
let tree = build_worktree(fs, path!("/root"), cx).await;
|
||||||
|
tree.read_with(cx, |tree, _| {
|
||||||
|
for path in [
|
||||||
|
".env.local",
|
||||||
|
"ignored",
|
||||||
|
"ignored/nested",
|
||||||
|
"ignored/nested/included.project",
|
||||||
|
"ignored/nested/included.user",
|
||||||
|
] {
|
||||||
|
assert!(
|
||||||
|
tree.entry_for_path(rel_path(path))
|
||||||
|
.is_some_and(|entry| entry.is_ignored && entry.is_always_included),
|
||||||
|
"expected {path} to be ignored by Git and included by settings"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
for path in ["ignored/nested/unmatched.txt", "unmatched.txt"] {
|
||||||
|
assert!(
|
||||||
|
tree.entry_for_path(rel_path(path))
|
||||||
|
.is_some_and(|entry| entry.is_ignored && !entry.is_always_included),
|
||||||
|
"expected {path} to remain ignored"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
assert_eq!(
|
||||||
|
tree.entry_for_path(rel_path("ignored/nested/excluded.project")),
|
||||||
|
None
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
tree.files(false, 0)
|
||||||
|
.map(|entry| entry.path.as_ref())
|
||||||
|
.collect::<Vec<_>>(),
|
||||||
|
vec![
|
||||||
|
rel_path(".env.local"),
|
||||||
|
rel_path(".gitignore"),
|
||||||
|
rel_path("ignored/nested/included.project"),
|
||||||
|
rel_path("ignored/nested/included.user"),
|
||||||
|
]
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
for (settings, included_paths) in [
|
||||||
|
(
|
||||||
|
r#"{ "file_scan_inclusions": ["ignored/**/*.project"] }"#,
|
||||||
|
vec![
|
||||||
|
rel_path(".gitignore"),
|
||||||
|
rel_path("ignored/nested/included.project"),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
(
|
||||||
|
r#"{ "file_scan_inclusions": [] }"#,
|
||||||
|
vec![rel_path(".gitignore")],
|
||||||
|
),
|
||||||
|
] {
|
||||||
|
cx.update(|cx| {
|
||||||
|
cx.update_global::<SettingsStore, _>(|store, cx| {
|
||||||
|
store
|
||||||
|
.set_local_settings(
|
||||||
|
worktree_id,
|
||||||
|
LocalSettingsPath::InWorktree(Arc::from(RelPath::empty())),
|
||||||
|
LocalSettingsKind::Settings,
|
||||||
|
Some(settings),
|
||||||
|
cx,
|
||||||
|
)
|
||||||
|
.expect("valid project settings");
|
||||||
|
});
|
||||||
|
});
|
||||||
|
cx.run_until_parked();
|
||||||
|
tree.read_with(cx, |tree, _| {
|
||||||
|
tree.as_local().expect("local worktree").scan_complete()
|
||||||
|
})
|
||||||
|
.await;
|
||||||
|
tree.read_with(cx, |tree, _| {
|
||||||
|
assert_eq!(
|
||||||
|
tree.files(false, 0)
|
||||||
|
.map(|entry| entry.path.as_ref())
|
||||||
|
.collect::<Vec<_>>(),
|
||||||
|
included_paths
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[gpui::test]
|
#[gpui::test]
|
||||||
async fn test_file_scan_exclusions_overrules_inclusions(cx: &mut TestAppContext) {
|
async fn test_file_scan_exclusions_overrules_inclusions(cx: &mut TestAppContext) {
|
||||||
init_test(cx);
|
init_test(cx);
|
||||||
@@ -2139,7 +2268,7 @@ async fn test_file_scan_exclusions_overrules_inclusions(cx: &mut TestAppContext)
|
|||||||
settings.project.worktree.file_scan_exclusions =
|
settings.project.worktree.file_scan_exclusions =
|
||||||
Some(SplicingVec::from(vec!["**/.DS_Store".to_string()]));
|
Some(SplicingVec::from(vec!["**/.DS_Store".to_string()]));
|
||||||
settings.project.worktree.file_scan_inclusions =
|
settings.project.worktree.file_scan_inclusions =
|
||||||
Some(vec!["**/.DS_Store".to_string()]);
|
Some(SplicingVec::from(vec!["**/.DS_Store".to_string()]));
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -2202,7 +2331,7 @@ async fn test_file_scan_inclusions_reindexes_on_setting_change(cx: &mut TestAppC
|
|||||||
store.update_user_settings(cx, |settings| {
|
store.update_user_settings(cx, |settings| {
|
||||||
settings.project.worktree.file_scan_exclusions = Some(SplicingVec::from(vec![]));
|
settings.project.worktree.file_scan_exclusions = Some(SplicingVec::from(vec![]));
|
||||||
settings.project.worktree.file_scan_inclusions =
|
settings.project.worktree.file_scan_inclusions =
|
||||||
Some(vec!["node_modules/**".to_string()]);
|
Some(SplicingVec::from(vec!["node_modules/**".to_string()]));
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -2236,7 +2365,7 @@ async fn test_file_scan_inclusions_reindexes_on_setting_change(cx: &mut TestAppC
|
|||||||
cx.update_global::<SettingsStore, _>(|store, cx| {
|
cx.update_global::<SettingsStore, _>(|store, cx| {
|
||||||
store.update_user_settings(cx, |settings| {
|
store.update_user_settings(cx, |settings| {
|
||||||
settings.project.worktree.file_scan_exclusions = Some(SplicingVec::from(vec![]));
|
settings.project.worktree.file_scan_exclusions = Some(SplicingVec::from(vec![]));
|
||||||
settings.project.worktree.file_scan_inclusions = Some(vec![]);
|
settings.project.worktree.file_scan_inclusions = Some(SplicingVec::from(vec![]));
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -6818,7 +6947,7 @@ async fn test_file_scan_depth_pierced_by_inclusions(cx: &mut TestAppContext) {
|
|||||||
store.update_user_settings(cx, |settings| {
|
store.update_user_settings(cx, |settings| {
|
||||||
settings.project.worktree.file_scan_depth = Some(1);
|
settings.project.worktree.file_scan_depth = Some(1);
|
||||||
settings.project.worktree.file_scan_inclusions =
|
settings.project.worktree.file_scan_inclusions =
|
||||||
Some(vec!["junk/a/b/c/deep.txt".to_string()]);
|
Some(SplicingVec::from(vec!["junk/a/b/c/deep.txt".to_string()]));
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -84,13 +84,12 @@ The following VS Code settings are automatically imported when you use **Import
|
|||||||
|
|
||||||
| VS Code Setting | Zed Setting |
|
| VS Code Setting | Zed Setting |
|
||||||
| --------------------------- | ------------------------------ |
|
| --------------------------- | ------------------------------ |
|
||||||
|
| `files.associations` | `file_types` |
|
||||||
| `files.autoSave` | `autosave` |
|
| `files.autoSave` | `autosave` |
|
||||||
| `files.autoSaveDelay` | `autosave.milliseconds` |
|
| `files.autoSaveDelay` | `autosave.milliseconds` |
|
||||||
| `files.insertFinalNewline` | `ensure_final_newline_on_save` |
|
| `files.insertFinalNewline` | `ensure_final_newline_on_save` |
|
||||||
| `files.associations` | `file_types` |
|
|
||||||
| `files.watcherExclude` | `file_scan_exclusions` |
|
|
||||||
| `files.watcherInclude` | `file_scan_inclusions` |
|
|
||||||
| `files.simpleDialog.enable` | `use_system_path_prompts` |
|
| `files.simpleDialog.enable` | `use_system_path_prompts` |
|
||||||
|
| `files.watcherExclude` | `file_scan_exclusions` |
|
||||||
| `search.smartCase` | `use_smartcase_search` |
|
| `search.smartCase` | `use_smartcase_search` |
|
||||||
| `search.useIgnoreFiles` | `search.include_ignored` |
|
| `search.useIgnoreFiles` | `search.include_ignored` |
|
||||||
|
|
||||||
|
|||||||
@@ -2383,6 +2383,18 @@ The `"..."` entry expands to the list you are overriding, so the example above e
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Use `"..."` to extend the inherited list instead of replacing it. In your user settings, it expands to Zed’s defaults. In a project’s `.zed/settings.json`, it expands to the resolved list from your user settings, including any defaults you kept.
|
||||||
|
|
||||||
|
For example, add this to your settings.json to include generated files without repeating inherited patterns:
|
||||||
|
|
||||||
|
```json [settings]
|
||||||
|
{
|
||||||
|
"file_scan_inclusions": ["...", "generated/**"]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
With the default user settings, this keeps `.env*` and adds `generated/**`. Omit `"..."` to replace the inherited list, or use `[]` to clear it. Duplicate patterns keep their first occurrence, even if `"..."` appears more than once. `file_scan_exclusions` still takes precedence.
|
||||||
|
|
||||||
## File Scan Depth
|
## File Scan Depth
|
||||||
|
|
||||||
- Setting: `file_scan_depth`
|
- Setting: `file_scan_depth`
|
||||||
|
|||||||
Reference in new issue
Block a user