feat(config): add backend option
This commit is contained in:
parent
8257e9f400
commit
65fd76c5b9
|
@ -30,6 +30,7 @@ pub(crate) mod store;
|
|||
pub trait Config {
|
||||
fn label(&self) -> &str;
|
||||
fn match_paths(&self) -> &[String];
|
||||
fn backend(&self) -> Backend;
|
||||
|
||||
fn is_match(&self, app: &AppProperties) -> bool;
|
||||
}
|
||||
|
@ -47,6 +48,13 @@ pub struct AppProperties<'a> {
|
|||
pub exec: Option<&'a str>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub enum Backend {
|
||||
Inject,
|
||||
Clipboard,
|
||||
Auto,
|
||||
}
|
||||
|
||||
pub fn load_store(config_dir: &Path) -> Result<impl ConfigStore> {
|
||||
store::DefaultConfigStore::load(config_dir)
|
||||
}
|
||||
|
|
|
@ -27,6 +27,8 @@ mod yaml;
|
|||
pub(crate) struct ParsedConfig {
|
||||
pub label: Option<String>,
|
||||
|
||||
pub backend: Option<String>,
|
||||
|
||||
// Includes
|
||||
pub includes: Option<Vec<String>>,
|
||||
pub excludes: Option<Vec<String>>,
|
||||
|
|
|
@ -30,6 +30,9 @@ pub(crate) struct YAMLConfig {
|
|||
#[serde(default)]
|
||||
pub label: Option<String>,
|
||||
|
||||
#[serde(default)]
|
||||
pub backend: Option<String>,
|
||||
|
||||
#[serde(default)]
|
||||
pub includes: Option<Vec<String>>,
|
||||
|
||||
|
@ -78,7 +81,7 @@ impl TryFrom<YAMLConfig> for ParsedConfig {
|
|||
fn try_from(yaml_config: YAMLConfig) -> Result<Self, Self::Error> {
|
||||
Ok(Self {
|
||||
label: yaml_config.label,
|
||||
|
||||
backend: yaml_config.backend,
|
||||
use_standard_includes: yaml_config.use_standard_includes,
|
||||
includes: yaml_config.includes,
|
||||
extra_includes: yaml_config.extra_includes,
|
||||
|
@ -103,6 +106,7 @@ mod tests {
|
|||
let config = YAMLConfig::parse_from_str(
|
||||
r#"
|
||||
label: "test"
|
||||
backend: clipboard
|
||||
|
||||
use_standard_includes: true
|
||||
includes: ["test1"]
|
||||
|
@ -123,6 +127,9 @@ mod tests {
|
|||
parsed_config,
|
||||
ParsedConfig {
|
||||
label: Some("test".to_string()),
|
||||
|
||||
backend: Some("clipboard".to_string()),
|
||||
|
||||
use_standard_includes: Some(true),
|
||||
includes: Some(vec!["test1".to_string()]),
|
||||
extra_includes: Some(vec!["test2".to_string()]),
|
||||
|
|
|
@ -17,9 +17,10 @@
|
|||
* along with espanso. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
use super::{parse::ParsedConfig, path::calculate_paths, util::os_matches, AppProperties, Config};
|
||||
use super::{AppProperties, Backend, Config, parse::ParsedConfig, path::calculate_paths, util::os_matches};
|
||||
use crate::merge;
|
||||
use anyhow::Result;
|
||||
use log::error;
|
||||
use regex::Regex;
|
||||
use std::iter::FromIterator;
|
||||
use std::{collections::HashSet, path::Path};
|
||||
|
@ -109,6 +110,18 @@ impl Config for ResolvedConfig {
|
|||
// All the filters that have been specified must be true to define a match
|
||||
is_os_match && is_exec_match && is_title_match && is_class_match
|
||||
}
|
||||
|
||||
fn backend(&self) -> Backend {
|
||||
match self.parsed.backend.as_deref().map(|b| b.to_lowercase()).as_deref() {
|
||||
Some("clipboard") => Backend::Clipboard,
|
||||
Some("inject") => Backend::Inject,
|
||||
Some("auto") => Backend::Auto,
|
||||
err => {
|
||||
error!("invalid backend specified {:?}, falling back to Auto", err);
|
||||
Backend::Auto
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ResolvedConfig {
|
||||
|
@ -164,6 +177,7 @@ impl ResolvedConfig {
|
|||
parent,
|
||||
// Fields
|
||||
label,
|
||||
backend,
|
||||
includes,
|
||||
excludes,
|
||||
extra_includes,
|
||||
|
|
|
@ -145,6 +145,10 @@ mod tests {
|
|||
fn is_match(&self, _: &crate::config::AppProperties) -> bool {
|
||||
self.is_match
|
||||
}
|
||||
|
||||
fn backend(&self) -> crate::config::Backend {
|
||||
unimplemented!()
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
|
@ -509,7 +509,7 @@ impl LegacyConfig {
|
|||
|
||||
fn triggers_for_match(m: &Value) -> Vec<String> {
|
||||
if let Some(triggers) = m.get("triggers").and_then(|v| v.as_sequence()) {
|
||||
triggers.into_iter().filter_map(|v| v.as_str().map(|s| s.to_string())).collect()
|
||||
triggers.iter().filter_map(|v| v.as_str().map(|s| s.to_string())).collect()
|
||||
} else if let Some(trigger) = m.get("trigger").and_then(|v| v.as_str()) {
|
||||
vec![trigger.to_string()]
|
||||
} else {
|
||||
|
@ -517,6 +517,7 @@ fn triggers_for_match(m: &Value) -> Vec<String> {
|
|||
}
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
fn replace_for_match(m: &Value) -> String {
|
||||
m.get("replace").and_then(|v| v.as_str()).expect("match is missing replace field").to_string()
|
||||
}
|
||||
|
@ -752,6 +753,7 @@ impl LegacyConfigSet {
|
|||
|
||||
// Error handling
|
||||
#[derive(Debug, PartialEq)]
|
||||
#[allow(dead_code)]
|
||||
pub enum ConfigLoadError {
|
||||
FileNotFound,
|
||||
UnableToReadFile,
|
||||
|
|
|
@ -92,9 +92,10 @@ fn split_config(config: LegacyConfig) -> (LegacyInteropConfig, LegacyMatchGroup)
|
|||
|
||||
struct LegacyInteropConfig {
|
||||
pub name: String,
|
||||
|
||||
match_paths: Vec<String>,
|
||||
|
||||
config: LegacyConfig,
|
||||
|
||||
filter_title: Option<Regex>,
|
||||
filter_class: Option<Regex>,
|
||||
filter_exec: Option<Regex>,
|
||||
|
@ -103,6 +104,7 @@ struct LegacyInteropConfig {
|
|||
impl From<config::LegacyConfig> for LegacyInteropConfig {
|
||||
fn from(config: config::LegacyConfig) -> Self {
|
||||
Self {
|
||||
config: config.clone(),
|
||||
name: config.name.clone(),
|
||||
match_paths: vec![config.name],
|
||||
filter_title: if !config.filter_title.is_empty() {
|
||||
|
@ -126,7 +128,15 @@ impl From<config::LegacyConfig> for LegacyInteropConfig {
|
|||
|
||||
impl Config for LegacyInteropConfig {
|
||||
fn label(&self) -> &str {
|
||||
&self.name
|
||||
&self.config.name
|
||||
}
|
||||
|
||||
fn backend(&self) -> crate::config::Backend {
|
||||
match self.config.backend {
|
||||
config::BackendType::Inject => crate::config::Backend::Inject,
|
||||
config::BackendType::Clipboard => crate::config::Backend::Clipboard,
|
||||
config::BackendType::Auto => crate::config::Backend::Auto,
|
||||
}
|
||||
}
|
||||
|
||||
fn match_paths(&self) -> &[String] {
|
||||
|
@ -237,7 +247,9 @@ mod tests {
|
|||
#[test]
|
||||
fn load_legacy_works_correctly() {
|
||||
use_test_directory(|base, user, packages| {
|
||||
std::fs::write(base.join("default.yml"), r#"
|
||||
std::fs::write(
|
||||
base.join("default.yml"),
|
||||
r#"
|
||||
backend: Clipboard
|
||||
|
||||
global_vars:
|
||||
|
@ -247,25 +259,35 @@ mod tests {
|
|||
matches:
|
||||
- trigger: "hello"
|
||||
replace: "world"
|
||||
"#).unwrap();
|
||||
"#,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
std::fs::write(user.join("specific.yml"), r#"
|
||||
std::fs::write(
|
||||
user.join("specific.yml"),
|
||||
r#"
|
||||
name: specific
|
||||
parent: default
|
||||
|
||||
matches:
|
||||
- trigger: "foo"
|
||||
replace: "bar"
|
||||
"#).unwrap();
|
||||
"#,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
std::fs::write(user.join("separate.yml"), r#"
|
||||
std::fs::write(
|
||||
user.join("separate.yml"),
|
||||
r#"
|
||||
name: separate
|
||||
filter_title: "Google"
|
||||
|
||||
matches:
|
||||
- trigger: "eren"
|
||||
replace: "mikasa"
|
||||
"#).unwrap();
|
||||
"#,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let (config_store, match_store) = load(base, packages).unwrap();
|
||||
|
||||
|
@ -286,44 +308,91 @@ mod tests {
|
|||
});
|
||||
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_config.match_paths())
|
||||
.matches
|
||||
.len(),
|
||||
2
|
||||
);
|
||||
assert_eq!(
|
||||
match_store
|
||||
.query(default_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);
|
||||
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#"
|
||||
use_test_directory(|base, _, packages| {
|
||||
std::fs::write(
|
||||
base.join("default.yml"),
|
||||
r#"
|
||||
backend: Clipboard
|
||||
|
||||
matches:
|
||||
- trigger: "hello"
|
||||
replace: "world"
|
||||
"#).unwrap();
|
||||
"#,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
create_dir_all(packages.join("test-package")).unwrap();
|
||||
std::fs::write(packages.join("test-package").join("package.yml"), r#"
|
||||
std::fs::write(
|
||||
packages.join("test-package").join("package.yml"),
|
||||
r#"
|
||||
name: test-package
|
||||
parent: default
|
||||
|
||||
matches:
|
||||
- trigger: "foo"
|
||||
replace: "bar"
|
||||
"#).unwrap();
|
||||
"#,
|
||||
)
|
||||
.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);
|
||||
assert_eq!(
|
||||
match_store
|
||||
.query(default_config.match_paths())
|
||||
.matches
|
||||
.len(),
|
||||
2
|
||||
);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user