1use std::path::Path;
2
3use anyhow::Context as _;
4use settings::Settings;
5use util::{
6 ResultExt,
7 paths::{PathMatcher, PathStyle},
8 rel_path::RelPath,
9};
10
11#[derive(Clone, PartialEq, Eq)]
12pub struct WorktreeSettings {
13 pub project_name: Option<String>,
14 /// Whether to prevent this project from being shared in public channels.
15 pub prevent_sharing_in_public_channels: bool,
16 pub file_scan_inclusions: PathMatcher,
17 pub file_scan_exclusions: PathMatcher,
18 pub private_files: PathMatcher,
19}
20
21impl WorktreeSettings {
22 pub fn is_path_private(&self, path: &RelPath) -> bool {
23 path.ancestors()
24 .any(|ancestor| self.private_files.is_match(ancestor.as_std_path()))
25 }
26
27 pub fn is_path_excluded(&self, path: &RelPath) -> bool {
28 path.ancestors()
29 .any(|ancestor| self.file_scan_exclusions.is_match(ancestor.as_std_path()))
30 }
31
32 pub fn is_path_always_included(&self, path: &RelPath) -> bool {
33 path.ancestors()
34 .any(|ancestor| self.file_scan_inclusions.is_match(ancestor.as_std_path()))
35 }
36}
37
38impl Settings for WorktreeSettings {
39 fn from_settings(content: &settings::SettingsContent) -> Self {
40 let worktree = content.project.worktree.clone();
41 let file_scan_exclusions = worktree.file_scan_exclusions.unwrap();
42 let file_scan_inclusions = worktree.file_scan_inclusions.unwrap();
43 let private_files = worktree.private_files.unwrap().0;
44 let parsed_file_scan_inclusions: Vec<String> = file_scan_inclusions
45 .iter()
46 .flat_map(|glob| {
47 Path::new(glob)
48 .ancestors()
49 .map(|a| a.to_string_lossy().into())
50 })
51 .filter(|p: &String| !p.is_empty())
52 .collect();
53
54 Self {
55 project_name: worktree.project_name.into_inner(),
56 prevent_sharing_in_public_channels: worktree.prevent_sharing_in_public_channels,
57 file_scan_exclusions: path_matchers(file_scan_exclusions, "file_scan_exclusions")
58 .log_err()
59 .unwrap_or_default(),
60 file_scan_inclusions: path_matchers(
61 parsed_file_scan_inclusions,
62 "file_scan_inclusions",
63 )
64 .unwrap(),
65 private_files: path_matchers(private_files, "private_files")
66 .log_err()
67 .unwrap_or_default(),
68 }
69 }
70}
71
72fn path_matchers(mut values: Vec<String>, context: &'static str) -> anyhow::Result<PathMatcher> {
73 values.sort();
74 PathMatcher::new(values, PathStyle::local())
75 .with_context(|| format!("Failed to parse globs from {}", context))
76}