bacon/
config.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
use {
    crate::*,
    anyhow::*,
    lazy_regex::regex_is_match,
    serde::Deserialize,
    std::{
        collections::HashMap,
        fs,
        path::Path,
    },
};

/// A configuration item which may be stored in various places, eg as `bacon.toml`
/// along a `Cargo.toml` file or as `prefs.toml` in the xdg config directory.
///
/// Leaf values are options (and not Default) so that they don't
/// override previously set values when applied to settings.
#[derive(Debug, Clone, Deserialize)]
pub struct Config {
    pub additional_alias_args: Option<Vec<String>>,

    pub default_job: Option<ConcreteJobRef>,

    /// locations export
    #[deprecated(since = "2.22.0", note = "use exports.locations")]
    pub export: Option<ExportConfig>,

    #[deprecated(since = "2.9.0", note = "use exports.locations.auto")]
    pub export_locations: Option<bool>,

    #[serde(default)]
    pub exports: HashMap<String, ExportConfig>,

    pub help_line: Option<bool>,

    #[serde(default)]
    pub jobs: HashMap<String, Job>,

    pub keybindings: Option<KeyBindings>,

    pub on_change_strategy: Option<OnChangeStrategy>,

    pub reverse: Option<bool>,

    pub show_changes_count: Option<bool>,

    pub summary: Option<bool>,

    #[deprecated(since = "2.0.0", note = "use keybindings")]
    pub vim_keys: Option<bool>,

    pub wrap: Option<bool>,

    /// Patterns of lines which should be ignored. Patterns of
    /// the prefs or bacon.toml can be overridden at the job
    pub ignored_lines: Option<Vec<LinePattern>>,

    /// The delay between a file event and the real start of the
    /// task. Other file events occuring during this period will be
    /// ignored.
    pub grace_period: Option<Period>,
}

impl Config {
    pub fn from_path(path: &Path) -> Result<Self> {
        let conf = toml::from_str::<Self>(&fs::read_to_string(path)?)
            .with_context(|| format!("Failed to parse configuration file at {:?}", path))?;
        for (name, job) in &conf.jobs {
            if !regex_is_match!(r#"^[\w-]+$"#, name) {
                bail!("Invalid configuration : Illegal job name : {:?}", name);
            }
            if job.command.is_empty() {
                bail!("Invalid configuration : empty command for job {:?}", name);
            }
        }
        Ok(conf)
    }
    pub fn from_env(env_var_name: &str) -> Result<Option<Self>> {
        let Some(path) = std::env::var_os(env_var_name) else {
            return Ok(None);
        };
        let path = Path::new(&path);
        if !path.exists() {
            // some users may want to use an env var to point to a file that may not always exist
            // so we don't bail here
            warn!(
                "Env var {:?} points to file {:?} which does not exist",
                env_var_name, path
            );
            return Ok(None);
        }
        let config = Self::from_path(path)?;
        debug!(
            "Loaded config at {:?} as specified in env var {:?}",
            path, env_var_name
        );
        Ok(Some(config))
    }
    pub fn default_package_config() -> Self {
        toml::from_str(DEFAULT_PACKAGE_CONFIG).unwrap()
    }
    pub fn default_prefs() -> Self {
        toml::from_str(DEFAULT_PREFS).unwrap()
    }
}

#[test]
fn test_default_files() {
    let mut settings = Settings::default();
    settings.apply_config(&Config::default_prefs());
    settings.apply_config(&Config::default_package_config());
    settings.check().unwrap();
}