Detailed changes
@@ -132,7 +132,7 @@ pub enum BaseKeymapContent {
None,
}
-#[derive(Debug, Clone, Default, Serialize, Deserialize, JsonSchema)]
+#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize, JsonSchema)]
pub struct ProjectSettingsContent {
#[serde(flatten)]
pub all_languages: AllLanguageSettingsContent,
@@ -229,7 +229,7 @@ pub enum GitHostingProviderKind {
Bitbucket,
}
-#[derive(Clone, Debug, Default, Serialize, Deserialize, JsonSchema)]
+#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize, JsonSchema)]
pub struct WorktreeSettingsContent {
/// The displayed name of this project. If not set, the root directory name
/// will be displayed.
@@ -765,6 +765,7 @@ impl SettingsStore {
self.extension_settings = Some(SettingsContent {
project: ProjectSettingsContent {
all_languages: content.all_languages,
+ ..Default::default()
},
..Default::default()
});
@@ -2,10 +2,8 @@ use std::path::Path;
use anyhow::Context as _;
use gpui::App;
-use schemars::JsonSchema;
-use serde::{Deserialize, Serialize};
-use settings::{Settings, SettingsKey, SettingsUi};
-use util::paths::PathMatcher;
+use settings::{Settings, SettingsContent};
+use util::{ResultExt, paths::PathMatcher};
#[derive(Clone, PartialEq, Eq)]
pub struct WorktreeSettings {
@@ -34,19 +32,11 @@ impl WorktreeSettings {
impl Settings for WorktreeSettings {
fn from_defaults(content: &settings::SettingsContent, _cx: &mut App) -> Self {
- Self {
- project_name: None,
- file_scan_exclusions: content.project.worktree.file_scan_exclusions.unwrap(),
- file_scan_inclusions: PathMatcher::default(),
- }
- }
- fn load(sources: SettingsSources<Self::FileContent>, _: &mut App) -> anyhow::Result<Self> {
- let result: WorktreeSettingsContent = sources.json_merge()?;
- let mut file_scan_exclusions = result.file_scan_exclusions.unwrap_or_default();
- let mut private_files = result.private_files.unwrap_or_default();
- let mut parsed_file_scan_inclusions: Vec<String> = result
- .file_scan_inclusions
- .unwrap_or_default()
+ let worktree = content.project.worktree.clone();
+ let file_scan_exclusions = worktree.file_scan_exclusions.unwrap();
+ let file_scan_inclusions = worktree.file_scan_inclusions.unwrap();
+ let private_files = worktree.private_files.unwrap();
+ let parsed_file_scan_inclusions: Vec<String> = file_scan_inclusions
.iter()
.flat_map(|glob| {
Path::new(glob)
@@ -55,30 +45,71 @@ impl Settings for WorktreeSettings {
})
.filter(|p: &String| !p.is_empty())
.collect();
- file_scan_exclusions.sort();
- private_files.sort();
- parsed_file_scan_inclusions.sort();
- Ok(Self {
- file_scan_exclusions: path_matchers(&file_scan_exclusions, "file_scan_exclusions")?,
- private_files: path_matchers(&private_files, "private_files")?,
+
+ Self {
+ project_name: None,
+ file_scan_exclusions: path_matchers(file_scan_exclusions, "file_scan_exclusions")
+ .unwrap(),
file_scan_inclusions: path_matchers(
- &parsed_file_scan_inclusions,
+ parsed_file_scan_inclusions,
"file_scan_inclusions",
- )?,
- project_name: result.project_name,
- })
+ )
+ .unwrap(),
+ private_files: path_matchers(private_files, "private_files").unwrap(),
+ }
+ }
+
+ fn refine(&mut self, content: &SettingsContent, _cx: &mut App) {
+ let worktree = &content.project.worktree;
+
+ if let Some(project_name) = worktree.project_name.clone() {
+ self.project_name = Some(project_name);
+ }
+
+ // todo!() test this. Did it used to extend the arrays, or overwrite them?
+
+ if let Some(private_files) = worktree.private_files.clone() {
+ if let Some(matchers) = path_matchers(private_files, "private_files").log_err() {
+ self.private_files = matchers
+ }
+ }
+
+ if let Some(file_scan_exclusions) = worktree.file_scan_exclusions.clone() {
+ if let Some(matchers) =
+ path_matchers(file_scan_exclusions, "file_scan_exclusions").log_err()
+ {
+ self.file_scan_exclusions = matchers
+ }
+ }
+
+ if let Some(file_scan_inclusions) = worktree.file_scan_inclusions.clone() {
+ let parsed_file_scan_inclusions: Vec<String> = file_scan_inclusions
+ .iter()
+ .flat_map(|glob| {
+ Path::new(glob)
+ .ancestors()
+ .map(|a| a.to_string_lossy().into())
+ })
+ .filter(|p: &String| !p.is_empty())
+ .collect();
+ if let Some(matchers) =
+ path_matchers(parsed_file_scan_inclusions, "file_scan_inclusions").log_err()
+ {
+ self.file_scan_inclusions = matchers
+ }
+ }
}
- fn import_from_vscode(vscode: &settings::VsCodeSettings, current: &mut Self::FileContent) {
+ fn import_from_vscode(vscode: &settings::VsCodeSettings, current: &mut SettingsContent) {
if let Some(inclusions) = vscode
.read_value("files.watcherInclude")
.and_then(|v| v.as_array())
.and_then(|v| v.iter().map(|n| n.as_str().map(str::to_owned)).collect())
{
- if let Some(old) = current.file_scan_inclusions.as_mut() {
+ if let Some(old) = current.project.worktree.file_scan_inclusions.as_mut() {
old.extend(inclusions)
} else {
- current.file_scan_inclusions = Some(inclusions)
+ current.project.worktree.file_scan_inclusions = Some(inclusions)
}
}
if let Some(exclusions) = vscode
@@ -86,15 +117,16 @@ impl Settings for WorktreeSettings {
.and_then(|v| v.as_array())
.and_then(|v| v.iter().map(|n| n.as_str().map(str::to_owned)).collect())
{
- if let Some(old) = current.file_scan_exclusions.as_mut() {
+ if let Some(old) = current.project.worktree.file_scan_exclusions.as_mut() {
old.extend(exclusions)
} else {
- current.file_scan_exclusions = Some(exclusions)
+ current.project.worktree.file_scan_exclusions = Some(exclusions)
}
}
}
}
-fn path_matchers(values: &[String], context: &'static str) -> anyhow::Result<PathMatcher> {
+fn path_matchers(mut values: Vec<String>, context: &'static str) -> anyhow::Result<PathMatcher> {
+ values.sort();
PathMatcher::new(values).with_context(|| format!("Failed to parse globs from {}", context))
}
@@ -770,9 +770,9 @@ async fn test_file_scan_inclusions(cx: &mut TestAppContext) {
}));
cx.update(|cx| {
cx.update_global::<SettingsStore, _>(|store, cx| {
- store.update_user_settings::<WorktreeSettings>(cx, |project_settings| {
- project_settings.file_scan_exclusions = Some(vec![]);
- project_settings.file_scan_inclusions = Some(vec![
+ store.update_user_settings(cx, |settings| {
+ settings.project.worktree.file_scan_exclusions = Some(vec![]);
+ settings.project.worktree.file_scan_inclusions = Some(vec![
"node_modules/**/package.json".to_string(),
"**/.DS_Store".to_string(),
]);
@@ -836,9 +836,11 @@ async fn test_file_scan_exclusions_overrules_inclusions(cx: &mut TestAppContext)
cx.update(|cx| {
cx.update_global::<SettingsStore, _>(|store, cx| {
- store.update_user_settings::<WorktreeSettings>(cx, |project_settings| {
- project_settings.file_scan_exclusions = Some(vec!["**/.DS_Store".to_string()]);
- project_settings.file_scan_inclusions = Some(vec!["**/.DS_Store".to_string()]);
+ store.update_user_settings(cx, |settings| {
+ settings.project.worktree.file_scan_exclusions =
+ Some(vec!["**/.DS_Store".to_string()]);
+ settings.project.worktree.file_scan_inclusions =
+ Some(vec!["**/.DS_Store".to_string()]);
});
});
});
@@ -894,9 +896,10 @@ async fn test_file_scan_inclusions_reindexes_on_setting_change(cx: &mut TestAppC
cx.update(|cx| {
cx.update_global::<SettingsStore, _>(|store, cx| {
- store.update_user_settings::<WorktreeSettings>(cx, |project_settings| {
- project_settings.file_scan_exclusions = Some(vec![]);
- project_settings.file_scan_inclusions = Some(vec!["node_modules/**".to_string()]);
+ store.update_user_settings(cx, |settings| {
+ settings.project.worktree.file_scan_exclusions = Some(vec![]);
+ settings.project.worktree.file_scan_inclusions =
+ Some(vec!["node_modules/**".to_string()]);
});
});
});
@@ -926,9 +929,9 @@ async fn test_file_scan_inclusions_reindexes_on_setting_change(cx: &mut TestAppC
cx.update(|cx| {
cx.update_global::<SettingsStore, _>(|store, cx| {
- store.update_user_settings::<WorktreeSettings>(cx, |project_settings| {
- project_settings.file_scan_exclusions = Some(vec![]);
- project_settings.file_scan_inclusions = Some(vec![]);
+ store.update_user_settings(cx, |settings| {
+ settings.project.worktree.file_scan_exclusions = Some(vec![]);
+ settings.project.worktree.file_scan_inclusions = Some(vec![]);
});
});
});
@@ -978,8 +981,8 @@ async fn test_file_scan_exclusions(cx: &mut TestAppContext) {
}));
cx.update(|cx| {
cx.update_global::<SettingsStore, _>(|store, cx| {
- store.update_user_settings::<WorktreeSettings>(cx, |project_settings| {
- project_settings.file_scan_exclusions =
+ store.update_user_settings(cx, |settings| {
+ settings.project.worktree.file_scan_exclusions =
Some(vec!["**/foo/**".to_string(), "**/.DS_Store".to_string()]);
});
});
@@ -1015,8 +1018,8 @@ async fn test_file_scan_exclusions(cx: &mut TestAppContext) {
cx.update(|cx| {
cx.update_global::<SettingsStore, _>(|store, cx| {
- store.update_user_settings::<WorktreeSettings>(cx, |project_settings| {
- project_settings.file_scan_exclusions =
+ store.update_user_settings(cx, |settings| {
+ settings.project.worktree.file_scan_exclusions =
Some(vec!["**/node_modules/**".to_string()]);
});
});
@@ -1080,8 +1083,8 @@ async fn test_fs_events_in_exclusions(cx: &mut TestAppContext) {
}));
cx.update(|cx| {
cx.update_global::<SettingsStore, _>(|store, cx| {
- store.update_user_settings::<WorktreeSettings>(cx, |project_settings| {
- project_settings.file_scan_exclusions = Some(vec![
+ store.update_user_settings(cx, |settings| {
+ settings.project.worktree.file_scan_exclusions = Some(vec![
"**/.git".to_string(),
"node_modules/".to_string(),
"build_output".to_string(),