feat(config): implement legacy loader
This commit is contained in:
parent
1e015eb891
commit
9098d5ac2a
|
@ -24,8 +24,8 @@ use thiserror::Error;
|
|||
mod parse;
|
||||
mod path;
|
||||
mod resolve;
|
||||
mod store;
|
||||
mod util;
|
||||
pub(crate) mod store;
|
||||
|
||||
pub trait Config {
|
||||
fn label(&self) -> &str;
|
||||
|
|
|
@ -106,6 +106,13 @@ impl DefaultConfigStore {
|
|||
customs,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn from_configs(default: Box<dyn Config>, customs: Vec<Box<dyn Config>>) -> Result<Self> {
|
||||
Ok(Self {
|
||||
default,
|
||||
customs,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
|
|
@ -153,13 +153,12 @@ fn default_modulo_path() -> Option<String> {
|
|||
fn default_post_inject_delay() -> u64 {
|
||||
100
|
||||
}
|
||||
|
||||
fn default_wait_for_modifiers_release() -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
pub struct Configs {
|
||||
pub struct LegacyConfig {
|
||||
#[serde(default = "default_name")]
|
||||
pub name: String,
|
||||
|
||||
|
@ -302,7 +301,7 @@ macro_rules! validate_field {
|
|||
};
|
||||
}
|
||||
|
||||
impl Configs {
|
||||
impl LegacyConfig {
|
||||
/*
|
||||
* Validate the Config instance.
|
||||
* It makes sure that user defined config instances do not define
|
||||
|
@ -412,8 +411,8 @@ impl Default for BackendType {
|
|||
}
|
||||
}
|
||||
|
||||
impl Configs {
|
||||
fn load_config(path: &Path) -> Result<Configs, ConfigLoadError> {
|
||||
impl LegacyConfig {
|
||||
fn load_config(path: &Path) -> Result<LegacyConfig, ConfigLoadError> {
|
||||
let file_res = File::open(path);
|
||||
if let Ok(mut file) = file_res {
|
||||
let mut contents = String::new();
|
||||
|
@ -435,7 +434,7 @@ impl Configs {
|
|||
}
|
||||
}
|
||||
|
||||
fn merge_overwrite(&mut self, new_config: Configs) {
|
||||
fn merge_overwrite(&mut self, new_config: LegacyConfig) {
|
||||
// Merge matches
|
||||
let mut merged_matches = new_config.matches;
|
||||
let mut match_trigger_set = HashSet::new();
|
||||
|
@ -473,7 +472,7 @@ impl Configs {
|
|||
self.global_vars = merged_global_vars;
|
||||
}
|
||||
|
||||
fn merge_no_overwrite(&mut self, default: &Configs) {
|
||||
fn merge_no_overwrite(&mut self, default: &LegacyConfig) {
|
||||
// Merge matches
|
||||
let mut match_trigger_set = HashSet::new();
|
||||
self.matches.iter().for_each(|m| {
|
||||
|
@ -527,20 +526,20 @@ fn name_for_global_var(v: &Value) -> String {
|
|||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
pub struct ConfigSet {
|
||||
pub default: Configs,
|
||||
pub specific: Vec<Configs>,
|
||||
pub struct LegacyConfigSet {
|
||||
pub default: LegacyConfig,
|
||||
pub specific: Vec<LegacyConfig>,
|
||||
}
|
||||
|
||||
impl ConfigSet {
|
||||
pub fn load(config_dir: &Path, package_dir: &Path) -> Result<ConfigSet, ConfigLoadError> {
|
||||
impl LegacyConfigSet {
|
||||
pub fn load(config_dir: &Path, package_dir: &Path) -> Result<LegacyConfigSet, ConfigLoadError> {
|
||||
if !config_dir.is_dir() {
|
||||
return Err(ConfigLoadError::InvalidConfigDirectory);
|
||||
}
|
||||
|
||||
// Load default configuration
|
||||
let default_file = config_dir.join(DEFAULT_CONFIG_FILE_NAME);
|
||||
let default = Configs::load_config(default_file.as_path())?;
|
||||
let default = LegacyConfig::load_config(default_file.as_path())?;
|
||||
|
||||
// Check that a compatible backend is used, otherwise warn the user
|
||||
if cfg!(not(target_os = "linux")) && default.backend == BackendType::Auto {
|
||||
|
@ -569,13 +568,13 @@ impl ConfigSet {
|
|||
// Load the user defined config files
|
||||
|
||||
let mut name_set = HashSet::new();
|
||||
let mut children_map: HashMap<String, Vec<Configs>> = HashMap::new();
|
||||
let mut package_map: HashMap<String, Vec<Configs>> = HashMap::new();
|
||||
let mut children_map: HashMap<String, Vec<LegacyConfig>> = HashMap::new();
|
||||
let mut package_map: HashMap<String, Vec<LegacyConfig>> = HashMap::new();
|
||||
let mut root_configs = Vec::new();
|
||||
root_configs.push(default);
|
||||
|
||||
let mut file_loader = |entry: walkdir::Result<DirEntry>,
|
||||
dest_map: &mut HashMap<String, Vec<Configs>>|
|
||||
dest_map: &mut HashMap<String, Vec<LegacyConfig>>|
|
||||
-> Result<(), ConfigLoadError> {
|
||||
match entry {
|
||||
Ok(entry) => {
|
||||
|
@ -598,12 +597,12 @@ impl ConfigSet {
|
|||
.unwrap_or_default()
|
||||
.to_str()
|
||||
.unwrap_or_default()
|
||||
.starts_with(".")
|
||||
.starts_with('.')
|
||||
{
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
let mut config = Configs::load_config(&path)?;
|
||||
let mut config = LegacyConfig::load_config(&path)?;
|
||||
|
||||
// Make sure the config does not contain reserved fields
|
||||
if !config.validate_user_defined_config() {
|
||||
|
@ -651,7 +650,7 @@ impl ConfigSet {
|
|||
// Merge the children config files
|
||||
let mut configs_without_packages = Vec::new();
|
||||
for root_config in root_configs {
|
||||
let config = ConfigSet::reduce_configs(root_config, &children_map, true);
|
||||
let config = LegacyConfigSet::reduce_configs(root_config, &children_map, true);
|
||||
configs_without_packages.push(config);
|
||||
}
|
||||
|
||||
|
@ -660,13 +659,13 @@ impl ConfigSet {
|
|||
// than configs.
|
||||
let mut configs = Vec::new();
|
||||
for root_config in configs_without_packages {
|
||||
let config = ConfigSet::reduce_configs(root_config, &package_map, false);
|
||||
let config = LegacyConfigSet::reduce_configs(root_config, &package_map, false);
|
||||
configs.push(config);
|
||||
}
|
||||
|
||||
// Separate default from specific
|
||||
let default = configs.get(0).unwrap().clone();
|
||||
let mut specific = (&configs[1..]).to_vec().clone();
|
||||
let mut specific = (&configs[1..]).to_vec();
|
||||
|
||||
// Add default entries to specific configs when needed
|
||||
for config in specific.iter_mut() {
|
||||
|
@ -685,14 +684,14 @@ impl ConfigSet {
|
|||
}
|
||||
}
|
||||
|
||||
Ok(ConfigSet { default, specific })
|
||||
Ok(LegacyConfigSet { default, specific })
|
||||
}
|
||||
|
||||
fn reduce_configs(
|
||||
target: Configs,
|
||||
children_map: &HashMap<String, Vec<Configs>>,
|
||||
target: LegacyConfig,
|
||||
children_map: &HashMap<String, Vec<LegacyConfig>>,
|
||||
higher_priority: bool,
|
||||
) -> Configs {
|
||||
) -> LegacyConfig {
|
||||
if children_map.contains_key(&target.name) {
|
||||
let mut target = target;
|
||||
for children in children_map.get(&target.name).unwrap() {
|
||||
|
@ -709,7 +708,7 @@ impl ConfigSet {
|
|||
}
|
||||
}
|
||||
|
||||
fn has_conflicts(default: &Configs, specific: &Vec<Configs>) -> bool {
|
||||
fn has_conflicts(default: &LegacyConfig, specific: &[LegacyConfig]) -> bool {
|
||||
let mut sorted_triggers: Vec<String> = default
|
||||
.matches
|
||||
.iter()
|
||||
|
@ -729,7 +728,7 @@ impl ConfigSet {
|
|||
has_conflicts
|
||||
}
|
||||
|
||||
fn list_has_conflicts(sorted_list: &Vec<String>) -> bool {
|
||||
fn list_has_conflicts(sorted_list: &[String]) -> bool {
|
||||
if sorted_list.len() <= 1 {
|
||||
return false;
|
||||
}
|
||||
|
@ -817,7 +816,7 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn test_config_file_not_found() {
|
||||
let config = Configs::load_config(Path::new("invalid/path"));
|
||||
let config = LegacyConfig::load_config(Path::new("invalid/path"));
|
||||
assert_eq!(config.is_err(), true);
|
||||
assert_eq!(config.unwrap_err(), ConfigLoadError::FileNotFound);
|
||||
}
|
||||
|
@ -825,15 +824,14 @@ mod tests {
|
|||
#[test]
|
||||
fn test_config_file_with_bad_yaml_syntax() {
|
||||
let broken_config_file = create_tmp_file(TEST_CONFIG_FILE_WITH_BAD_YAML);
|
||||
let config = Configs::load_config(broken_config_file.path());
|
||||
let config = LegacyConfig::load_config(broken_config_file.path());
|
||||
match config {
|
||||
Ok(_) => assert!(false),
|
||||
Ok(_) => unreachable!(),
|
||||
Err(e) => {
|
||||
match e {
|
||||
ConfigLoadError::InvalidYAML(p, _) => assert_eq!(p, broken_config_file.path().to_owned()),
|
||||
_ => assert!(false),
|
||||
_ => unreachable!(),
|
||||
}
|
||||
assert!(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -861,7 +859,7 @@ mod tests {
|
|||
|
||||
"###,
|
||||
);
|
||||
let config = Configs::load_config(working_config_file.path());
|
||||
let config = LegacyConfig::load_config(working_config_file.path());
|
||||
assert_eq!(config.unwrap().validate_user_defined_config(), true);
|
||||
}
|
||||
|
||||
|
@ -875,7 +873,7 @@ mod tests {
|
|||
|
||||
"###,
|
||||
);
|
||||
let config = Configs::load_config(working_config_file.path());
|
||||
let config = LegacyConfig::load_config(working_config_file.path());
|
||||
assert_eq!(config.unwrap().validate_user_defined_config(), false);
|
||||
}
|
||||
|
||||
|
@ -889,7 +887,7 @@ mod tests {
|
|||
|
||||
"###,
|
||||
);
|
||||
let config = Configs::load_config(working_config_file.path());
|
||||
let config = LegacyConfig::load_config(working_config_file.path());
|
||||
assert_eq!(config.unwrap().validate_user_defined_config(), false);
|
||||
}
|
||||
|
||||
|
@ -903,7 +901,7 @@ mod tests {
|
|||
|
||||
"###,
|
||||
);
|
||||
let config = Configs::load_config(working_config_file.path());
|
||||
let config = LegacyConfig::load_config(working_config_file.path());
|
||||
assert_eq!(config.unwrap().validate_user_defined_config(), false);
|
||||
}
|
||||
|
||||
|
@ -917,14 +915,14 @@ mod tests {
|
|||
|
||||
"###,
|
||||
);
|
||||
let config = Configs::load_config(working_config_file.path());
|
||||
let config = LegacyConfig::load_config(working_config_file.path());
|
||||
assert_eq!(config.unwrap().validate_user_defined_config(), false);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_config_loaded_correctly() {
|
||||
let working_config_file = create_tmp_file(TEST_WORKING_CONFIG_FILE);
|
||||
let config = Configs::load_config(working_config_file.path());
|
||||
let config = LegacyConfig::load_config(working_config_file.path());
|
||||
assert_eq!(config.is_ok(), true);
|
||||
}
|
||||
|
||||
|
@ -981,13 +979,13 @@ mod tests {
|
|||
fn test_config_set_default_content_should_work_correctly() {
|
||||
let (data_dir, package_dir) = create_temp_espanso_directories();
|
||||
|
||||
let config_set = ConfigSet::load(data_dir.path(), package_dir.path());
|
||||
let config_set = LegacyConfigSet::load(data_dir.path(), package_dir.path());
|
||||
assert!(config_set.is_ok());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_config_set_load_fail_bad_directory() {
|
||||
let config_set = ConfigSet::load(Path::new("invalid/path"), Path::new("invalid/path"));
|
||||
let config_set = LegacyConfigSet::load(Path::new("invalid/path"), Path::new("invalid/path"));
|
||||
assert_eq!(config_set.is_err(), true);
|
||||
assert_eq!(
|
||||
config_set.unwrap_err(),
|
||||
|
@ -1000,7 +998,7 @@ mod tests {
|
|||
let data_dir = TempDir::new().expect("unable to create temp directory");
|
||||
let package_dir = TempDir::new().expect("unable to create package directory");
|
||||
|
||||
let config_set = ConfigSet::load(data_dir.path(), package_dir.path());
|
||||
let config_set = LegacyConfigSet::load(data_dir.path(), package_dir.path());
|
||||
assert_eq!(config_set.is_err(), true);
|
||||
assert_eq!(config_set.unwrap_err(), ConfigLoadError::FileNotFound);
|
||||
}
|
||||
|
@ -1011,15 +1009,14 @@ mod tests {
|
|||
create_temp_espanso_directories_with_default_content(TEST_CONFIG_FILE_WITH_BAD_YAML);
|
||||
let default_path = data_dir.path().join(DEFAULT_CONFIG_FILE_NAME);
|
||||
|
||||
let config_set = ConfigSet::load(data_dir.path(), package_dir.path());
|
||||
let config_set = LegacyConfigSet::load(data_dir.path(), package_dir.path());
|
||||
match config_set {
|
||||
Ok(_) => assert!(false),
|
||||
Ok(_) => unreachable!(),
|
||||
Err(e) => {
|
||||
match e {
|
||||
ConfigLoadError::InvalidYAML(p, _) => assert_eq!(p, default_path),
|
||||
_ => assert!(false),
|
||||
_ => unreachable!(),
|
||||
}
|
||||
assert!(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1035,13 +1032,11 @@ mod tests {
|
|||
config_caching_interval: 10000
|
||||
"###,
|
||||
);
|
||||
let user_defined_path_copy = user_defined_path.clone();
|
||||
|
||||
let config_set = ConfigSet::load(data_dir.path(), package_dir.path());
|
||||
let config_set = LegacyConfigSet::load(data_dir.path(), package_dir.path());
|
||||
assert!(config_set.is_err());
|
||||
assert_eq!(
|
||||
config_set.unwrap_err(),
|
||||
ConfigLoadError::InvalidParameter(user_defined_path_copy)
|
||||
ConfigLoadError::InvalidParameter(user_defined_path)
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -1056,13 +1051,12 @@ mod tests {
|
|||
backend: Clipboard
|
||||
"###,
|
||||
);
|
||||
let user_defined_path_copy = user_defined_path.clone();
|
||||
|
||||
let config_set = ConfigSet::load(data_dir.path(), package_dir.path());
|
||||
let config_set = LegacyConfigSet::load(data_dir.path(), package_dir.path());
|
||||
assert!(config_set.is_ok());
|
||||
assert_eq!(
|
||||
config_set.unwrap().specific[0].name,
|
||||
user_defined_path_copy.to_str().unwrap_or_default()
|
||||
user_defined_path.to_str().unwrap_or_default()
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -1086,7 +1080,7 @@ mod tests {
|
|||
"###,
|
||||
);
|
||||
|
||||
let config_set = ConfigSet::load(data_dir.path(), package_dir.path());
|
||||
let config_set = LegacyConfigSet::load(data_dir.path(), package_dir.path());
|
||||
assert!(config_set.is_err());
|
||||
assert!(matches!(
|
||||
&config_set.unwrap_err(),
|
||||
|
@ -1118,25 +1112,22 @@ mod tests {
|
|||
"###,
|
||||
);
|
||||
|
||||
let config_set = ConfigSet::load(data_dir.path(), package_dir.path()).unwrap();
|
||||
let config_set = LegacyConfigSet::load(data_dir.path(), package_dir.path()).unwrap();
|
||||
assert_eq!(config_set.default.matches.len(), 2);
|
||||
assert_eq!(config_set.specific[0].matches.len(), 3);
|
||||
|
||||
assert!(config_set.specific[0]
|
||||
.matches
|
||||
.iter()
|
||||
.find(|x| triggers_for_match(x)[0] == "hello")
|
||||
.is_some());
|
||||
.any(|x| triggers_for_match(x)[0] == "hello"));
|
||||
assert!(config_set.specific[0]
|
||||
.matches
|
||||
.iter()
|
||||
.find(|x| triggers_for_match(x)[0] == ":lol")
|
||||
.is_some());
|
||||
.any(|x| triggers_for_match(x)[0] == ":lol"));
|
||||
assert!(config_set.specific[0]
|
||||
.matches
|
||||
.iter()
|
||||
.find(|x| triggers_for_match(x)[0] == ":yess")
|
||||
.is_some());
|
||||
.any(|x| triggers_for_match(x)[0] == ":yess"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -1163,22 +1154,20 @@ mod tests {
|
|||
"###,
|
||||
);
|
||||
|
||||
let config_set = ConfigSet::load(data_dir.path(), package_dir.path()).unwrap();
|
||||
let config_set = LegacyConfigSet::load(data_dir.path(), package_dir.path()).unwrap();
|
||||
assert_eq!(config_set.default.matches.len(), 2);
|
||||
assert_eq!(config_set.specific[0].matches.len(), 2);
|
||||
|
||||
assert!(config_set.specific[0]
|
||||
.matches
|
||||
.iter()
|
||||
.find(|x| {
|
||||
.any(|x| {
|
||||
triggers_for_match(x)[0] == ":lol" && replace_for_match(x) == "newstring"
|
||||
})
|
||||
.is_some());
|
||||
}));
|
||||
assert!(config_set.specific[0]
|
||||
.matches
|
||||
.iter()
|
||||
.find(|x| triggers_for_match(x)[0] == ":yess")
|
||||
.is_some());
|
||||
.any(|x| triggers_for_match(x)[0] == ":yess"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -1207,17 +1196,16 @@ mod tests {
|
|||
"###,
|
||||
);
|
||||
|
||||
let config_set = ConfigSet::load(data_dir.path(), package_dir.path()).unwrap();
|
||||
let config_set = LegacyConfigSet::load(data_dir.path(), package_dir.path()).unwrap();
|
||||
assert_eq!(config_set.default.matches.len(), 2);
|
||||
assert_eq!(config_set.specific[0].matches.len(), 1);
|
||||
|
||||
assert!(config_set.specific[0]
|
||||
.matches
|
||||
.iter()
|
||||
.find(|x| {
|
||||
.any(|x| {
|
||||
triggers_for_match(x)[0] == "hello" && replace_for_match(x) == "newstring"
|
||||
})
|
||||
.is_some());
|
||||
}));
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -1246,7 +1234,7 @@ mod tests {
|
|||
"###,
|
||||
);
|
||||
|
||||
let config_set = ConfigSet::load(data_dir.path(), package_dir.path()).unwrap();
|
||||
let config_set = LegacyConfigSet::load(data_dir.path(), package_dir.path()).unwrap();
|
||||
assert_eq!(config_set.specific.len(), 0);
|
||||
}
|
||||
|
||||
|
@ -1276,7 +1264,7 @@ mod tests {
|
|||
"###,
|
||||
);
|
||||
|
||||
let config_set = ConfigSet::load(data_dir.path(), package_dir.path()).unwrap();
|
||||
let config_set = LegacyConfigSet::load(data_dir.path(), package_dir.path()).unwrap();
|
||||
assert_eq!(config_set.specific.len(), 0);
|
||||
}
|
||||
|
||||
|
@ -1300,7 +1288,7 @@ mod tests {
|
|||
"###,
|
||||
);
|
||||
|
||||
let config_set = ConfigSet::load(data_dir.path(), package_dir.path()).unwrap();
|
||||
let config_set = LegacyConfigSet::load(data_dir.path(), package_dir.path()).unwrap();
|
||||
assert_eq!(config_set.specific.len(), 2);
|
||||
}
|
||||
|
||||
|
@ -1326,7 +1314,7 @@ mod tests {
|
|||
"###,
|
||||
);
|
||||
|
||||
let config_set = ConfigSet::load(data_dir.path(), package_dir.path()).unwrap();
|
||||
let config_set = LegacyConfigSet::load(data_dir.path(), package_dir.path()).unwrap();
|
||||
assert_eq!(config_set.specific.len(), 0);
|
||||
assert_eq!(config_set.default.matches.len(), 2);
|
||||
assert!(config_set
|
||||
|
@ -1361,7 +1349,7 @@ mod tests {
|
|||
"###,
|
||||
);
|
||||
|
||||
let config_set = ConfigSet::load(data_dir.path(), package_dir.path()).unwrap();
|
||||
let config_set = LegacyConfigSet::load(data_dir.path(), package_dir.path()).unwrap();
|
||||
assert_eq!(config_set.specific.len(), 1);
|
||||
assert_eq!(config_set.default.matches.len(), 1);
|
||||
assert!(config_set
|
||||
|
@ -1415,7 +1403,7 @@ mod tests {
|
|||
"###,
|
||||
);
|
||||
|
||||
let config_set = ConfigSet::load(data_dir.path(), package_dir.path()).unwrap();
|
||||
let config_set = LegacyConfigSet::load(data_dir.path(), package_dir.path()).unwrap();
|
||||
assert_eq!(config_set.specific.len(), 0);
|
||||
assert_eq!(config_set.default.matches.len(), 3);
|
||||
assert!(config_set
|
||||
|
@ -1457,7 +1445,7 @@ mod tests {
|
|||
"###,
|
||||
);
|
||||
|
||||
let config_set = ConfigSet::load(data_dir.path(), package_dir.path()).unwrap();
|
||||
let config_set = LegacyConfigSet::load(data_dir.path(), package_dir.path()).unwrap();
|
||||
assert_eq!(config_set.specific.len(), 0);
|
||||
assert_eq!(config_set.default.matches.len(), 1);
|
||||
assert!(config_set.default.matches.iter().any(|m| {
|
||||
|
@ -1488,7 +1476,7 @@ mod tests {
|
|||
"###,
|
||||
);
|
||||
|
||||
let config_set = ConfigSet::load(data_dir.path(), package_dir.path()).unwrap();
|
||||
let config_set = LegacyConfigSet::load(data_dir.path(), package_dir.path()).unwrap();
|
||||
assert_eq!(config_set.specific.len(), 0);
|
||||
assert_eq!(config_set.default.matches.len(), 2);
|
||||
assert!(config_set
|
||||
|
@ -1526,7 +1514,7 @@ mod tests {
|
|||
"###,
|
||||
);
|
||||
|
||||
let config_set = ConfigSet::load(data_dir.path(), package_dir.path()).unwrap();
|
||||
let config_set = LegacyConfigSet::load(data_dir.path(), package_dir.path()).unwrap();
|
||||
assert_eq!(config_set.specific.len(), 0);
|
||||
assert_eq!(config_set.default.matches.len(), 1);
|
||||
assert_eq!(triggers_for_match(&config_set.default.matches[0])[0], "hasta");
|
||||
|
@ -1554,7 +1542,7 @@ mod tests {
|
|||
"###,
|
||||
);
|
||||
|
||||
let config_set = ConfigSet::load(data_dir.path(), package_dir.path()).unwrap();
|
||||
let config_set = LegacyConfigSet::load(data_dir.path(), package_dir.path()).unwrap();
|
||||
assert_eq!(config_set.specific.len(), 1);
|
||||
assert_eq!(config_set.default.matches.len(), 1);
|
||||
assert!(config_set
|
||||
|
@ -1604,7 +1592,7 @@ mod tests {
|
|||
"###,
|
||||
);
|
||||
|
||||
let config_set = ConfigSet::load(data_dir.path(), package_dir.path()).unwrap();
|
||||
let config_set = LegacyConfigSet::load(data_dir.path(), package_dir.path()).unwrap();
|
||||
assert_eq!(config_set.specific.len(), 1);
|
||||
assert_eq!(config_set.default.matches.len(), 1);
|
||||
assert!(config_set
|
||||
|
@ -1625,7 +1613,7 @@ mod tests {
|
|||
#[test]
|
||||
fn test_list_has_conflict_no_conflict() {
|
||||
assert_eq!(
|
||||
ConfigSet::list_has_conflicts(&vec!(":ab".to_owned(), ":bc".to_owned())),
|
||||
LegacyConfigSet::list_has_conflicts(&[":ab".to_owned(), ":bc".to_owned()]),
|
||||
false
|
||||
);
|
||||
}
|
||||
|
@ -1634,7 +1622,7 @@ mod tests {
|
|||
fn test_list_has_conflict_conflict() {
|
||||
let mut list = vec!["ac".to_owned(), "ab".to_owned(), "abc".to_owned()];
|
||||
list.sort();
|
||||
assert_eq!(ConfigSet::list_has_conflicts(&list), true);
|
||||
assert_eq!(LegacyConfigSet::list_has_conflicts(&list), true);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -1661,9 +1649,9 @@ mod tests {
|
|||
"###,
|
||||
);
|
||||
|
||||
let config_set = ConfigSet::load(data_dir.path(), package_dir.path()).unwrap();
|
||||
let config_set = LegacyConfigSet::load(data_dir.path(), package_dir.path()).unwrap();
|
||||
assert_eq!(
|
||||
ConfigSet::has_conflicts(&config_set.default, &config_set.specific),
|
||||
LegacyConfigSet::has_conflicts(&config_set.default, &config_set.specific),
|
||||
false
|
||||
);
|
||||
}
|
||||
|
@ -1694,9 +1682,9 @@ mod tests {
|
|||
"###,
|
||||
);
|
||||
|
||||
let config_set = ConfigSet::load(data_dir.path(), package_dir.path()).unwrap();
|
||||
let config_set = LegacyConfigSet::load(data_dir.path(), package_dir.path()).unwrap();
|
||||
assert_eq!(
|
||||
ConfigSet::has_conflicts(&config_set.default, &config_set.specific),
|
||||
LegacyConfigSet::has_conflicts(&config_set.default, &config_set.specific),
|
||||
true
|
||||
);
|
||||
}
|
||||
|
@ -1725,9 +1713,9 @@ mod tests {
|
|||
"###,
|
||||
);
|
||||
|
||||
let config_set = ConfigSet::load(data_dir.path(), package_dir.path()).unwrap();
|
||||
let config_set = LegacyConfigSet::load(data_dir.path(), package_dir.path()).unwrap();
|
||||
assert_eq!(
|
||||
ConfigSet::has_conflicts(&config_set.default, &config_set.specific),
|
||||
LegacyConfigSet::has_conflicts(&config_set.default, &config_set.specific),
|
||||
true
|
||||
);
|
||||
}
|
||||
|
@ -1767,9 +1755,9 @@ mod tests {
|
|||
"###,
|
||||
);
|
||||
|
||||
let config_set = ConfigSet::load(data_dir.path(), package_dir.path()).unwrap();
|
||||
let config_set = LegacyConfigSet::load(data_dir.path(), package_dir.path()).unwrap();
|
||||
assert_eq!(
|
||||
ConfigSet::has_conflicts(&config_set.default, &config_set.specific),
|
||||
LegacyConfigSet::has_conflicts(&config_set.default, &config_set.specific),
|
||||
false
|
||||
);
|
||||
}
|
||||
|
@ -1798,7 +1786,7 @@ mod tests {
|
|||
"###,
|
||||
);
|
||||
|
||||
let config_set = ConfigSet::load(data_dir.path(), package_dir.path()).unwrap();
|
||||
let config_set = LegacyConfigSet::load(data_dir.path(), package_dir.path()).unwrap();
|
||||
assert_eq!(config_set.specific.len(), 1);
|
||||
assert_eq!(config_set.default.global_vars.len(), 1);
|
||||
assert_eq!(config_set.specific[0].global_vars.len(), 2);
|
||||
|
@ -1837,7 +1825,7 @@ mod tests {
|
|||
"###,
|
||||
);
|
||||
|
||||
let config_set = ConfigSet::load(data_dir.path(), package_dir.path()).unwrap();
|
||||
let config_set = LegacyConfigSet::load(data_dir.path(), package_dir.path()).unwrap();
|
||||
assert_eq!(config_set.specific.len(), 0);
|
||||
assert_eq!(config_set.default.global_vars.len(), 2);
|
||||
assert!(config_set
|
||||
|
@ -1878,7 +1866,7 @@ mod tests {
|
|||
"###,
|
||||
);
|
||||
|
||||
let config_set = ConfigSet::load(data_dir.path(), package_dir.path()).unwrap();
|
||||
let config_set = LegacyConfigSet::load(data_dir.path(), package_dir.path()).unwrap();
|
||||
assert_eq!(config_set.specific.len(), 1);
|
||||
assert_eq!(config_set.default.global_vars.len(), 1);
|
||||
assert_eq!(config_set.specific[0].global_vars.len(), 1);
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
* This file is part of espanso.
|
||||
*
|
||||
* Copyright (C) 2019-2021 Federico Terzi
|
||||
* C title: (), class: (), exec: ()opyright (C) 2019-2021 Federico Terzi
|
||||
*
|
||||
* espanso is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
@ -17,16 +17,313 @@
|
|||
* along with espanso. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
use std::path::Path;
|
||||
use anyhow::Result;
|
||||
use regex::Regex;
|
||||
use std::{collections::HashMap, path::Path};
|
||||
|
||||
use crate::{config::ConfigStore, matches::store::MatchStore};
|
||||
use self::config::LegacyConfig;
|
||||
use crate::config::store::DefaultConfigStore;
|
||||
use crate::matches::group::loader::yaml::parse::{YAMLMatch, YAMLVariable};
|
||||
use crate::{
|
||||
config::Config,
|
||||
config::{AppProperties, ConfigStore},
|
||||
matches::{
|
||||
store::{MatchSet, MatchStore},
|
||||
Match, Variable,
|
||||
},
|
||||
};
|
||||
use std::convert::TryInto;
|
||||
|
||||
mod config;
|
||||
mod model;
|
||||
|
||||
pub fn load(base_dir: &Path) -> Result<(Box<dyn ConfigStore>, Box<dyn MatchStore>)> {
|
||||
// TODO: load legacy config set and then convert it to the new format
|
||||
pub fn load(
|
||||
base_dir: &Path,
|
||||
package_dir: &Path,
|
||||
) -> Result<(Box<dyn ConfigStore>, Box<dyn MatchStore>)> {
|
||||
let config_set = config::LegacyConfigSet::load(base_dir, package_dir)?;
|
||||
|
||||
todo!()
|
||||
}
|
||||
let (default_config, default_match_group) = split_config(config_set.default);
|
||||
let mut match_groups = HashMap::new();
|
||||
match_groups.insert("default".to_string(), default_match_group);
|
||||
|
||||
let mut custom_configs: Vec<Box<dyn Config>> = Vec::new();
|
||||
for custom in config_set.specific {
|
||||
let (custom_config, custom_match_group) = split_config(custom);
|
||||
match_groups.insert(custom_config.name.clone(), custom_match_group);
|
||||
custom_configs.push(Box::new(custom_config));
|
||||
}
|
||||
|
||||
let config_store = DefaultConfigStore::from_configs(Box::new(default_config), custom_configs)?;
|
||||
let match_store = LegacyMatchStore::new(match_groups);
|
||||
|
||||
Ok((Box::new(config_store), Box::new(match_store)))
|
||||
}
|
||||
|
||||
fn split_config(config: LegacyConfig) -> (LegacyInteropConfig, LegacyMatchGroup) {
|
||||
let global_vars = config
|
||||
.global_vars
|
||||
.iter()
|
||||
.filter_map(|var| {
|
||||
let var: YAMLVariable = serde_yaml::from_value(var.clone()).ok()?;
|
||||
let var: Variable = var.try_into().ok()?;
|
||||
Some(var)
|
||||
})
|
||||
.collect();
|
||||
|
||||
let matches = config
|
||||
.matches
|
||||
.iter()
|
||||
.filter_map(|var| {
|
||||
let m: YAMLMatch = serde_yaml::from_value(var.clone()).ok()?;
|
||||
let m: Match = m.try_into().ok()?;
|
||||
Some(m)
|
||||
})
|
||||
.collect();
|
||||
|
||||
let match_group = LegacyMatchGroup {
|
||||
global_vars,
|
||||
matches,
|
||||
};
|
||||
|
||||
let config: LegacyInteropConfig = config.into();
|
||||
(config, match_group)
|
||||
}
|
||||
|
||||
struct LegacyInteropConfig {
|
||||
pub name: String,
|
||||
|
||||
match_paths: Vec<String>,
|
||||
|
||||
filter_title: Option<Regex>,
|
||||
filter_class: Option<Regex>,
|
||||
filter_exec: Option<Regex>,
|
||||
}
|
||||
|
||||
impl From<config::LegacyConfig> for LegacyInteropConfig {
|
||||
fn from(config: config::LegacyConfig) -> Self {
|
||||
Self {
|
||||
name: config.name.clone(),
|
||||
match_paths: vec![config.name],
|
||||
filter_title: if !config.filter_title.is_empty() {
|
||||
Regex::new(&config.filter_title).ok()
|
||||
} else {
|
||||
None
|
||||
},
|
||||
filter_class: if !config.filter_class.is_empty() {
|
||||
Regex::new(&config.filter_class).ok()
|
||||
} else {
|
||||
None
|
||||
},
|
||||
filter_exec: if !config.filter_exec.is_empty() {
|
||||
Regex::new(&config.filter_exec).ok()
|
||||
} else {
|
||||
None
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Config for LegacyInteropConfig {
|
||||
fn label(&self) -> &str {
|
||||
&self.name
|
||||
}
|
||||
|
||||
fn match_paths(&self) -> &[String] {
|
||||
&self.match_paths
|
||||
}
|
||||
|
||||
fn is_match(&self, app: &AppProperties) -> bool {
|
||||
if self.filter_title.is_none() && self.filter_exec.is_none() && self.filter_class.is_none() {
|
||||
return false;
|
||||
}
|
||||
|
||||
let is_title_match = if let Some(title_regex) = self.filter_title.as_ref() {
|
||||
if let Some(title) = app.title {
|
||||
title_regex.is_match(title)
|
||||
} else {
|
||||
false
|
||||
}
|
||||
} else {
|
||||
true
|
||||
};
|
||||
|
||||
let is_exec_match = if let Some(exec_regex) = self.filter_exec.as_ref() {
|
||||
if let Some(exec) = app.exec {
|
||||
exec_regex.is_match(exec)
|
||||
} else {
|
||||
false
|
||||
}
|
||||
} else {
|
||||
true
|
||||
};
|
||||
|
||||
let is_class_match = if let Some(class_regex) = self.filter_class.as_ref() {
|
||||
if let Some(class) = app.class {
|
||||
class_regex.is_match(class)
|
||||
} else {
|
||||
false
|
||||
}
|
||||
} else {
|
||||
true
|
||||
};
|
||||
|
||||
// All the filters that have been specified must be true to define a match
|
||||
is_exec_match && is_title_match && is_class_match
|
||||
}
|
||||
}
|
||||
|
||||
struct LegacyMatchGroup {
|
||||
matches: Vec<Match>,
|
||||
global_vars: Vec<Variable>,
|
||||
}
|
||||
|
||||
struct LegacyMatchStore {
|
||||
groups: HashMap<String, LegacyMatchGroup>,
|
||||
}
|
||||
|
||||
impl LegacyMatchStore {
|
||||
pub fn new(groups: HashMap<String, LegacyMatchGroup>) -> Self {
|
||||
Self { groups }
|
||||
}
|
||||
}
|
||||
|
||||
impl MatchStore for LegacyMatchStore {
|
||||
fn query(&self, paths: &[String]) -> MatchSet {
|
||||
let group = if !paths.is_empty() {
|
||||
if let Some(group) = self.groups.get(&paths[0]) {
|
||||
Some(group)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
if let Some(group) = group {
|
||||
MatchSet {
|
||||
matches: group.matches.iter().collect(),
|
||||
global_vars: group.global_vars.iter().collect(),
|
||||
}
|
||||
} else {
|
||||
MatchSet {
|
||||
matches: Vec::new(),
|
||||
global_vars: Vec::new(),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use std::{fs::create_dir_all, path::Path};
|
||||
use tempdir::TempDir;
|
||||
|
||||
pub fn use_test_directory(callback: impl FnOnce(&Path, &Path, &Path)) {
|
||||
let dir = TempDir::new("tempconfig").unwrap();
|
||||
let user_dir = dir.path().join("user");
|
||||
create_dir_all(&user_dir).unwrap();
|
||||
|
||||
let package_dir = TempDir::new("tempconfig").unwrap();
|
||||
|
||||
callback(
|
||||
&dunce::canonicalize(&dir.path()).unwrap(),
|
||||
&dunce::canonicalize(&user_dir).unwrap(),
|
||||
&dunce::canonicalize(&package_dir.path()).unwrap(),
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn load_legacy_works_correctly() {
|
||||
use_test_directory(|base, user, packages| {
|
||||
std::fs::write(base.join("default.yml"), r#"
|
||||
backend: Clipboard
|
||||
|
||||
global_vars:
|
||||
- name: var1
|
||||
type: test
|
||||
|
||||
matches:
|
||||
- trigger: "hello"
|
||||
replace: "world"
|
||||
"#).unwrap();
|
||||
|
||||
std::fs::write(user.join("specific.yml"), r#"
|
||||
name: specific
|
||||
parent: default
|
||||
|
||||
matches:
|
||||
- trigger: "foo"
|
||||
replace: "bar"
|
||||
"#).unwrap();
|
||||
|
||||
std::fs::write(user.join("separate.yml"), r#"
|
||||
name: separate
|
||||
filter_title: "Google"
|
||||
|
||||
matches:
|
||||
- trigger: "eren"
|
||||
replace: "mikasa"
|
||||
"#).unwrap();
|
||||
|
||||
let (config_store, match_store) = load(base, packages).unwrap();
|
||||
|
||||
let default_config = config_store.default();
|
||||
assert_eq!(default_config.match_paths().len(), 1);
|
||||
|
||||
let active_config = config_store.active(&AppProperties {
|
||||
title: Some("Google"),
|
||||
class: None,
|
||||
exec: None,
|
||||
});
|
||||
assert_eq!(active_config.match_paths().len(), 1);
|
||||
|
||||
let default_fallback = config_store.active(&AppProperties {
|
||||
title: Some("Yahoo"),
|
||||
class: None,
|
||||
exec: None,
|
||||
});
|
||||
assert_eq!(default_fallback.match_paths().len(), 1);
|
||||
|
||||
assert_eq!(match_store.query(default_config.match_paths()).matches.len(), 2);
|
||||
assert_eq!(match_store.query(default_config.match_paths()).global_vars.len(), 1);
|
||||
|
||||
assert_eq!(match_store.query(active_config.match_paths()).matches.len(), 3);
|
||||
assert_eq!(match_store.query(active_config.match_paths()).global_vars.len(), 1);
|
||||
|
||||
assert_eq!(match_store.query(default_fallback.match_paths()).matches.len(), 2);
|
||||
assert_eq!(match_store.query(default_fallback.match_paths()).global_vars.len(), 1);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn load_legacy_with_packages() {
|
||||
use_test_directory(|base, user, packages| {
|
||||
std::fs::write(base.join("default.yml"), r#"
|
||||
backend: Clipboard
|
||||
|
||||
matches:
|
||||
- trigger: "hello"
|
||||
replace: "world"
|
||||
"#).unwrap();
|
||||
|
||||
create_dir_all(packages.join("test-package")).unwrap();
|
||||
std::fs::write(packages.join("test-package").join("package.yml"), r#"
|
||||
name: test-package
|
||||
parent: default
|
||||
|
||||
matches:
|
||||
- trigger: "foo"
|
||||
replace: "bar"
|
||||
"#).unwrap();
|
||||
|
||||
let (config_store, match_store) = load(base, packages).unwrap();
|
||||
|
||||
let default_config = config_store.default();
|
||||
assert_eq!(default_config.match_paths().len(), 1);
|
||||
|
||||
assert_eq!(match_store.query(default_config.match_paths()).matches.len(), 2);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -25,7 +25,7 @@ use self::yaml::YAMLImporter;
|
|||
|
||||
use super::MatchGroup;
|
||||
|
||||
mod yaml;
|
||||
pub(crate) mod yaml;
|
||||
|
||||
trait Importer {
|
||||
fn is_supported(&self, extension: &str) -> bool;
|
||||
|
|
|
@ -31,7 +31,7 @@ use crate::matches::{MatchCause, MatchEffect, TextEffect, TriggerCause};
|
|||
|
||||
use super::Importer;
|
||||
|
||||
mod parse;
|
||||
pub(crate) mod parse;
|
||||
|
||||
pub(crate) struct YAMLImporter {}
|
||||
|
||||
|
|
|
@ -22,7 +22,7 @@ use std::path::Path;
|
|||
|
||||
use super::{Match, Variable};
|
||||
|
||||
mod loader;
|
||||
pub(crate) mod loader;
|
||||
mod path;
|
||||
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
|
|
|
@ -21,7 +21,7 @@ use serde_yaml::Mapping;
|
|||
|
||||
use crate::counter::{next_id, StructId};
|
||||
|
||||
mod group;
|
||||
pub(crate) mod group;
|
||||
pub mod store;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
|
|
Loading…
Reference in New Issue
Block a user