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 pub file_scan_inclusions: PathMatcher,
15 pub file_scan_exclusions: PathMatcher,
16 pub private_files: PathMatcher,
17}
18
19impl WorktreeSettings {
20 pub fn is_path_private(&self, path: &RelPath) -> bool {
21 path.ancestors()
22 .any(|ancestor| self.private_files.is_match(ancestor.as_std_path()))
23 }
24
25 pub fn is_path_excluded(&self, path: &RelPath) -> bool {
26 path.ancestors()
27 .any(|ancestor| self.file_scan_exclusions.is_match(ancestor.as_std_path()))
28 }
29
30 pub fn is_path_always_included(&self, path: &RelPath) -> bool {
31 path.ancestors()
32 .any(|ancestor| self.file_scan_inclusions.is_match(ancestor.as_std_path()))
33 }
34}
35
36impl Settings for WorktreeSettings {
37 fn from_settings(content: &settings::SettingsContent) -> Self {
38 let worktree = content.project.worktree.clone();
39 let file_scan_exclusions = worktree.file_scan_exclusions.unwrap();
40 let file_scan_inclusions = worktree.file_scan_inclusions.unwrap();
41 let private_files = worktree.private_files.unwrap().0;
42 let parsed_file_scan_inclusions: Vec<String> = file_scan_inclusions
43 .iter()
44 .flat_map(|glob| {
45 Path::new(glob)
46 .ancestors()
47 .map(|a| a.to_string_lossy().into())
48 })
49 .filter(|p: &String| !p.is_empty())
50 .collect();
51
52 Self {
53 project_name: worktree.project_name.into_inner(),
54 file_scan_exclusions: path_matchers(file_scan_exclusions, "file_scan_exclusions")
55 .log_err()
56 .unwrap_or_default(),
57 file_scan_inclusions: path_matchers(
58 parsed_file_scan_inclusions,
59 "file_scan_inclusions",
60 )
61 .unwrap(),
62 private_files: path_matchers(private_files, "private_files")
63 .log_err()
64 .unwrap_or_default(),
65 }
66 }
67}
68
69fn path_matchers(mut values: Vec<String>, context: &'static str) -> anyhow::Result<PathMatcher> {
70 values.sort();
71 PathMatcher::new(values, PathStyle::local())
72 .with_context(|| format!("Failed to parse globs from {}", context))
73}