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}