worktree_settings.rs

 1use std::path::Path;
 2
 3use anyhow::Context;
 4use gpui::AppContext;
 5use schemars::JsonSchema;
 6use serde::{Deserialize, Serialize};
 7use settings::{Settings, SettingsSources};
 8use util::paths::PathMatcher;
 9
10#[derive(Clone, PartialEq, Eq)]
11pub struct WorktreeSettings {
12    pub file_scan_exclusions: PathMatcher,
13    pub private_files: PathMatcher,
14}
15
16impl WorktreeSettings {
17    pub fn is_path_private(&self, path: &Path) -> bool {
18        path.ancestors()
19            .any(|ancestor| self.private_files.is_match(ancestor))
20    }
21
22    pub fn is_path_excluded(&self, path: &Path) -> bool {
23        path.ancestors()
24            .any(|ancestor| self.file_scan_exclusions.is_match(ancestor))
25    }
26}
27
28#[derive(Clone, Default, Serialize, Deserialize, JsonSchema)]
29pub struct WorktreeSettingsContent {
30    /// Completely ignore files matching globs from `file_scan_exclusions`
31    ///
32    /// Default: [
33    ///   "**/.git",
34    ///   "**/.svn",
35    ///   "**/.hg",
36    ///   "**/CVS",
37    ///   "**/.DS_Store",
38    ///   "**/Thumbs.db",
39    ///   "**/.classpath",
40    ///   "**/.settings"
41    /// ]
42    #[serde(default)]
43    pub file_scan_exclusions: Option<Vec<String>>,
44
45    /// Treat the files matching these globs as `.env` files.
46    /// Default: [ "**/.env*" ]
47    pub private_files: Option<Vec<String>>,
48}
49
50impl Settings for WorktreeSettings {
51    const KEY: Option<&'static str> = None;
52
53    type FileContent = WorktreeSettingsContent;
54
55    fn load(
56        sources: SettingsSources<Self::FileContent>,
57        _: &mut AppContext,
58    ) -> anyhow::Result<Self> {
59        let result: WorktreeSettingsContent = sources.json_merge()?;
60        let mut file_scan_exclusions = result.file_scan_exclusions.unwrap_or_default();
61        let mut private_files = result.private_files.unwrap_or_default();
62        file_scan_exclusions.sort();
63        private_files.sort();
64        Ok(Self {
65            file_scan_exclusions: path_matchers(&file_scan_exclusions, "file_scan_exclusions")?,
66            private_files: path_matchers(&private_files, "private_files")?,
67        })
68    }
69}
70
71fn path_matchers(values: &[String], context: &'static str) -> anyhow::Result<PathMatcher> {
72    PathMatcher::new(values).with_context(|| format!("Failed to parse globs from {}", context))
73}