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, Serialize, Deserialize, JsonSchema)]
 29#[serde(default)]
 30pub struct WorktreeSettingsContent {
 31    /// Completely ignore files matching globs from `file_scan_exclusions`
 32    ///
 33    /// Default: [
 34    ///   "**/.git",
 35    ///   "**/.svn",
 36    ///   "**/.hg",
 37    ///   "**/CVS",
 38    ///   "**/.DS_Store",
 39    ///   "**/Thumbs.db",
 40    ///   "**/.classpath",
 41    ///   "**/.settings"
 42    /// ]
 43    pub file_scan_exclusions: Vec<String>,
 44
 45    /// Treat the files matching these globs as `.env` files.
 46    /// Default: [ "**/.env*" ]
 47    pub private_files: Vec<String>,
 48}
 49
 50impl Default for WorktreeSettingsContent {
 51    fn default() -> Self {
 52        Self {
 53            private_files: [
 54                "**/.env*",
 55                "**/*.pem",
 56                "**/*.key",
 57                "**/*.cert",
 58                "**/*.crt",
 59                "**/secrets.yml",
 60            ]
 61            .into_iter()
 62            .map(str::to_owned)
 63            .collect(),
 64            file_scan_exclusions: [
 65                "**/.git",
 66                "**/.svn",
 67                "**/.hg",
 68                "**/CVS",
 69                "**/.DS_Store",
 70                "**/Thumbs.db",
 71                "**/.classpath",
 72                "**/.settings",
 73            ]
 74            .into_iter()
 75            .map(str::to_owned)
 76            .collect(),
 77        }
 78    }
 79}
 80
 81impl Settings for WorktreeSettings {
 82    const KEY: Option<&'static str> = None;
 83
 84    type FileContent = WorktreeSettingsContent;
 85
 86    fn load(
 87        sources: SettingsSources<Self::FileContent>,
 88        _: &mut AppContext,
 89    ) -> anyhow::Result<Self> {
 90        let result: WorktreeSettingsContent = sources.json_merge()?;
 91        let mut file_scan_exclusions = result.file_scan_exclusions;
 92        let mut private_files = result.private_files;
 93        file_scan_exclusions.sort();
 94        private_files.sort();
 95        Ok(Self {
 96            file_scan_exclusions: path_matchers(&file_scan_exclusions, "file_scan_exclusions")?,
 97            private_files: path_matchers(&private_files, "private_files")?,
 98        })
 99    }
100}
101
102fn path_matchers(values: &[String], context: &'static str) -> anyhow::Result<PathMatcher> {
103    PathMatcher::new(values).with_context(|| format!("Failed to parse globs from {}", context))
104}