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 {
|
pub trait Config {
|
||||||
fn label(&self) -> &str;
|
fn label(&self) -> &str;
|
||||||
fn match_paths(&self) -> &[String];
|
fn match_paths(&self) -> &[String];
|
||||||
|
fn backend(&self) -> Backend;
|
||||||
|
|
||||||
fn is_match(&self, app: &AppProperties) -> bool;
|
fn is_match(&self, app: &AppProperties) -> bool;
|
||||||
}
|
}
|
||||||
|
@ -47,6 +48,13 @@ pub struct AppProperties<'a> {
|
||||||
pub exec: Option<&'a str>,
|
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> {
|
pub fn load_store(config_dir: &Path) -> Result<impl ConfigStore> {
|
||||||
store::DefaultConfigStore::load(config_dir)
|
store::DefaultConfigStore::load(config_dir)
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,6 +27,8 @@ mod yaml;
|
||||||
pub(crate) struct ParsedConfig {
|
pub(crate) struct ParsedConfig {
|
||||||
pub label: Option<String>,
|
pub label: Option<String>,
|
||||||
|
|
||||||
|
pub backend: Option<String>,
|
||||||
|
|
||||||
// Includes
|
// Includes
|
||||||
pub includes: Option<Vec<String>>,
|
pub includes: Option<Vec<String>>,
|
||||||
pub excludes: Option<Vec<String>>,
|
pub excludes: Option<Vec<String>>,
|
||||||
|
|
|
@ -30,6 +30,9 @@ pub(crate) struct YAMLConfig {
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub label: Option<String>,
|
pub label: Option<String>,
|
||||||
|
|
||||||
|
#[serde(default)]
|
||||||
|
pub backend: Option<String>,
|
||||||
|
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub includes: Option<Vec<String>>,
|
pub includes: Option<Vec<String>>,
|
||||||
|
|
||||||
|
@ -78,7 +81,7 @@ impl TryFrom<YAMLConfig> for ParsedConfig {
|
||||||
fn try_from(yaml_config: YAMLConfig) -> Result<Self, Self::Error> {
|
fn try_from(yaml_config: YAMLConfig) -> Result<Self, Self::Error> {
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
label: yaml_config.label,
|
label: yaml_config.label,
|
||||||
|
backend: yaml_config.backend,
|
||||||
use_standard_includes: yaml_config.use_standard_includes,
|
use_standard_includes: yaml_config.use_standard_includes,
|
||||||
includes: yaml_config.includes,
|
includes: yaml_config.includes,
|
||||||
extra_includes: yaml_config.extra_includes,
|
extra_includes: yaml_config.extra_includes,
|
||||||
|
@ -103,6 +106,7 @@ mod tests {
|
||||||
let config = YAMLConfig::parse_from_str(
|
let config = YAMLConfig::parse_from_str(
|
||||||
r#"
|
r#"
|
||||||
label: "test"
|
label: "test"
|
||||||
|
backend: clipboard
|
||||||
|
|
||||||
use_standard_includes: true
|
use_standard_includes: true
|
||||||
includes: ["test1"]
|
includes: ["test1"]
|
||||||
|
@ -123,6 +127,9 @@ mod tests {
|
||||||
parsed_config,
|
parsed_config,
|
||||||
ParsedConfig {
|
ParsedConfig {
|
||||||
label: Some("test".to_string()),
|
label: Some("test".to_string()),
|
||||||
|
|
||||||
|
backend: Some("clipboard".to_string()),
|
||||||
|
|
||||||
use_standard_includes: Some(true),
|
use_standard_includes: Some(true),
|
||||||
includes: Some(vec!["test1".to_string()]),
|
includes: Some(vec!["test1".to_string()]),
|
||||||
extra_includes: Some(vec!["test2".to_string()]),
|
extra_includes: Some(vec!["test2".to_string()]),
|
||||||
|
|
|
@ -17,9 +17,10 @@
|
||||||
* along with espanso. If not, see <https://www.gnu.org/licenses/>.
|
* 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 crate::merge;
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
|
use log::error;
|
||||||
use regex::Regex;
|
use regex::Regex;
|
||||||
use std::iter::FromIterator;
|
use std::iter::FromIterator;
|
||||||
use std::{collections::HashSet, path::Path};
|
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
|
// 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
|
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 {
|
impl ResolvedConfig {
|
||||||
|
@ -164,6 +177,7 @@ impl ResolvedConfig {
|
||||||
parent,
|
parent,
|
||||||
// Fields
|
// Fields
|
||||||
label,
|
label,
|
||||||
|
backend,
|
||||||
includes,
|
includes,
|
||||||
excludes,
|
excludes,
|
||||||
extra_includes,
|
extra_includes,
|
||||||
|
|
|
@ -145,6 +145,10 @@ mod tests {
|
||||||
fn is_match(&self, _: &crate::config::AppProperties) -> bool {
|
fn is_match(&self, _: &crate::config::AppProperties) -> bool {
|
||||||
self.is_match
|
self.is_match
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn backend(&self) -> crate::config::Backend {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|
|
@ -509,7 +509,7 @@ impl LegacyConfig {
|
||||||
|
|
||||||
fn triggers_for_match(m: &Value) -> Vec<String> {
|
fn triggers_for_match(m: &Value) -> Vec<String> {
|
||||||
if let Some(triggers) = m.get("triggers").and_then(|v| v.as_sequence()) {
|
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()) {
|
} else if let Some(trigger) = m.get("trigger").and_then(|v| v.as_str()) {
|
||||||
vec![trigger.to_string()]
|
vec![trigger.to_string()]
|
||||||
} else {
|
} else {
|
||||||
|
@ -517,6 +517,7 @@ fn triggers_for_match(m: &Value) -> Vec<String> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
fn replace_for_match(m: &Value) -> String {
|
fn replace_for_match(m: &Value) -> String {
|
||||||
m.get("replace").and_then(|v| v.as_str()).expect("match is missing replace field").to_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
|
// Error handling
|
||||||
#[derive(Debug, PartialEq)]
|
#[derive(Debug, PartialEq)]
|
||||||
|
#[allow(dead_code)]
|
||||||
pub enum ConfigLoadError {
|
pub enum ConfigLoadError {
|
||||||
FileNotFound,
|
FileNotFound,
|
||||||
UnableToReadFile,
|
UnableToReadFile,
|
||||||
|
|
|
@ -92,9 +92,10 @@ fn split_config(config: LegacyConfig) -> (LegacyInteropConfig, LegacyMatchGroup)
|
||||||
|
|
||||||
struct LegacyInteropConfig {
|
struct LegacyInteropConfig {
|
||||||
pub name: String,
|
pub name: String,
|
||||||
|
|
||||||
match_paths: Vec<String>,
|
match_paths: Vec<String>,
|
||||||
|
|
||||||
|
config: LegacyConfig,
|
||||||
|
|
||||||
filter_title: Option<Regex>,
|
filter_title: Option<Regex>,
|
||||||
filter_class: Option<Regex>,
|
filter_class: Option<Regex>,
|
||||||
filter_exec: Option<Regex>,
|
filter_exec: Option<Regex>,
|
||||||
|
@ -103,6 +104,7 @@ struct LegacyInteropConfig {
|
||||||
impl From<config::LegacyConfig> for LegacyInteropConfig {
|
impl From<config::LegacyConfig> for LegacyInteropConfig {
|
||||||
fn from(config: config::LegacyConfig) -> Self {
|
fn from(config: config::LegacyConfig) -> Self {
|
||||||
Self {
|
Self {
|
||||||
|
config: config.clone(),
|
||||||
name: config.name.clone(),
|
name: config.name.clone(),
|
||||||
match_paths: vec![config.name],
|
match_paths: vec![config.name],
|
||||||
filter_title: if !config.filter_title.is_empty() {
|
filter_title: if !config.filter_title.is_empty() {
|
||||||
|
@ -126,7 +128,15 @@ impl From<config::LegacyConfig> for LegacyInteropConfig {
|
||||||
|
|
||||||
impl Config for LegacyInteropConfig {
|
impl Config for LegacyInteropConfig {
|
||||||
fn label(&self) -> &str {
|
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] {
|
fn match_paths(&self) -> &[String] {
|
||||||
|
@ -237,7 +247,9 @@ mod tests {
|
||||||
#[test]
|
#[test]
|
||||||
fn load_legacy_works_correctly() {
|
fn load_legacy_works_correctly() {
|
||||||
use_test_directory(|base, user, packages| {
|
use_test_directory(|base, user, packages| {
|
||||||
std::fs::write(base.join("default.yml"), r#"
|
std::fs::write(
|
||||||
|
base.join("default.yml"),
|
||||||
|
r#"
|
||||||
backend: Clipboard
|
backend: Clipboard
|
||||||
|
|
||||||
global_vars:
|
global_vars:
|
||||||
|
@ -247,25 +259,35 @@ mod tests {
|
||||||
matches:
|
matches:
|
||||||
- trigger: "hello"
|
- trigger: "hello"
|
||||||
replace: "world"
|
replace: "world"
|
||||||
"#).unwrap();
|
"#,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
std::fs::write(user.join("specific.yml"), r#"
|
std::fs::write(
|
||||||
|
user.join("specific.yml"),
|
||||||
|
r#"
|
||||||
name: specific
|
name: specific
|
||||||
parent: default
|
parent: default
|
||||||
|
|
||||||
matches:
|
matches:
|
||||||
- trigger: "foo"
|
- trigger: "foo"
|
||||||
replace: "bar"
|
replace: "bar"
|
||||||
"#).unwrap();
|
"#,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
std::fs::write(user.join("separate.yml"), r#"
|
std::fs::write(
|
||||||
|
user.join("separate.yml"),
|
||||||
|
r#"
|
||||||
name: separate
|
name: separate
|
||||||
filter_title: "Google"
|
filter_title: "Google"
|
||||||
|
|
||||||
matches:
|
matches:
|
||||||
- trigger: "eren"
|
- trigger: "eren"
|
||||||
replace: "mikasa"
|
replace: "mikasa"
|
||||||
"#).unwrap();
|
"#,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
let (config_store, match_store) = load(base, packages).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!(default_fallback.match_paths().len(), 1);
|
||||||
|
|
||||||
assert_eq!(match_store.query(default_config.match_paths()).matches.len(), 2);
|
assert_eq!(
|
||||||
assert_eq!(match_store.query(default_config.match_paths()).global_vars.len(), 1);
|
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!(
|
||||||
assert_eq!(match_store.query(active_config.match_paths()).global_vars.len(), 1);
|
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!(
|
||||||
assert_eq!(match_store.query(default_fallback.match_paths()).global_vars.len(), 1);
|
match_store
|
||||||
|
.query(default_fallback.match_paths())
|
||||||
|
.matches
|
||||||
|
.len(),
|
||||||
|
2
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
match_store
|
||||||
|
.query(default_fallback.match_paths())
|
||||||
|
.global_vars
|
||||||
|
.len(),
|
||||||
|
1
|
||||||
|
);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn load_legacy_with_packages() {
|
fn load_legacy_with_packages() {
|
||||||
use_test_directory(|base, user, packages| {
|
use_test_directory(|base, _, packages| {
|
||||||
std::fs::write(base.join("default.yml"), r#"
|
std::fs::write(
|
||||||
|
base.join("default.yml"),
|
||||||
|
r#"
|
||||||
backend: Clipboard
|
backend: Clipboard
|
||||||
|
|
||||||
matches:
|
matches:
|
||||||
- trigger: "hello"
|
- trigger: "hello"
|
||||||
replace: "world"
|
replace: "world"
|
||||||
"#).unwrap();
|
"#,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
create_dir_all(packages.join("test-package")).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
|
name: test-package
|
||||||
parent: default
|
parent: default
|
||||||
|
|
||||||
matches:
|
matches:
|
||||||
- trigger: "foo"
|
- trigger: "foo"
|
||||||
replace: "bar"
|
replace: "bar"
|
||||||
"#).unwrap();
|
"#,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
let (config_store, match_store) = load(base, packages).unwrap();
|
let (config_store, match_store) = load(base, packages).unwrap();
|
||||||
|
|
||||||
let default_config = config_store.default();
|
let default_config = config_store.default();
|
||||||
assert_eq!(default_config.match_paths().len(), 1);
|
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