diff --git a/Cargo.lock b/Cargo.lock
index b609af8..4b711da 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -220,6 +220,12 @@ dependencies = [
"libdbus-sys",
]
+[[package]]
+name = "difference"
+version = "2.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "524cbf6897b527295dff137cec09ecf3a05f4fddffd7dfcd1585403449e74198"
+
[[package]]
name = "dirs"
version = "1.0.5"
@@ -251,6 +257,12 @@ dependencies = [
"winapi",
]
+[[package]]
+name = "downcast"
+version = "0.10.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4bb454f0228b18c7f4c3b0ebbee346ed9c52e7443b0999cd543ff3571205701d"
+
[[package]]
name = "dtoa"
version = "0.4.7"
@@ -334,6 +346,7 @@ dependencies = [
"glob",
"lazy_static",
"log",
+ "mockall",
"ordered-float",
"regex",
"serde",
@@ -455,6 +468,21 @@ dependencies = [
"widestring",
]
+[[package]]
+name = "float-cmp"
+version = "0.8.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e1267f4ac4f343772758f7b1bdcbe767c218bbab93bb432acbf5162bbf85a6c4"
+dependencies = [
+ "num-traits",
+]
+
+[[package]]
+name = "fragile"
+version = "1.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "69a039c3498dc930fe810151a34ba0c1c70b02b8625035592e74432f678591f2"
+
[[package]]
name = "fuchsia-cprng"
version = "0.1.1"
@@ -684,6 +712,33 @@ dependencies = [
"autocfg",
]
+[[package]]
+name = "mockall"
+version = "0.9.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "18d614ad23f9bb59119b8b5670a85c7ba92c5e9adf4385c81ea00c51c8be33d5"
+dependencies = [
+ "cfg-if",
+ "downcast",
+ "fragile",
+ "lazy_static",
+ "mockall_derive",
+ "predicates",
+ "predicates-tree",
+]
+
+[[package]]
+name = "mockall_derive"
+version = "0.9.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5dd4234635bca06fc96c7368d038061e0aae1b00a764dc817e900dc974e3deea"
+dependencies = [
+ "cfg-if",
+ "proc-macro2",
+ "quote 1.0.9",
+ "syn 1.0.60",
+]
+
[[package]]
name = "named_pipe"
version = "0.4.1"
@@ -699,6 +754,12 @@ version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e4a24736216ec316047a1fc4252e27dabb04218aa4a3f37c6e7ddbf1f9782b54"
+[[package]]
+name = "normalize-line-endings"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "61807f77802ff30975e01f4f071c8ba10c022052f98b3294119f3e615d13e5be"
+
[[package]]
name = "notify-rust"
version = "4.2.2"
@@ -829,6 +890,35 @@ version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c"
+[[package]]
+name = "predicates"
+version = "1.0.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f49cfaf7fdaa3bfacc6fa3e7054e65148878354a5cfddcf661df4c851f8021df"
+dependencies = [
+ "difference",
+ "float-cmp",
+ "normalize-line-endings",
+ "predicates-core",
+ "regex",
+]
+
+[[package]]
+name = "predicates-core"
+version = "1.0.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "57e35a3326b75e49aa85f5dc6ec15b41108cf5aee58eabb1f274dd18b73c2451"
+
+[[package]]
+name = "predicates-tree"
+version = "1.0.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "15f553275e5721409451eb85e15fd9a860a6e5ab4496eb215987502b5f5391f2"
+dependencies = [
+ "predicates-core",
+ "treeline",
+]
+
[[package]]
name = "proc-macro2"
version = "1.0.24"
@@ -1288,6 +1378,12 @@ dependencies = [
"winapi",
]
+[[package]]
+name = "treeline"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a7f741b240f1a48843f9b8e0444fb55fb2a4ff67293b50a9179dfd5ea67f8d41"
+
[[package]]
name = "unicase"
version = "2.6.0"
diff --git a/espanso-config/Cargo.toml b/espanso-config/Cargo.toml
index 2e230f8..a4e8dbd 100644
--- a/espanso-config/Cargo.toml
+++ b/espanso-config/Cargo.toml
@@ -20,4 +20,5 @@ ordered-float = "2.0"
[dev-dependencies]
tempdir = "0.3.7"
-tempfile = "3.2.0"
\ No newline at end of file
+tempfile = "3.2.0"
+mockall = "0.9.1"
\ No newline at end of file
diff --git a/espanso-config/src/config/default.rs b/espanso-config/src/config/default.rs
new file mode 100644
index 0000000..a023f5d
--- /dev/null
+++ b/espanso-config/src/config/default.rs
@@ -0,0 +1,22 @@
+/*
+ * This file is part of espanso.
+ *
+ * Copyright (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
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * espanso is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with espanso. If not, see .
+ */
+
+pub(crate) const DEFAULT_CLIPBOARD_THRESHOLD: usize = 100;
+
+pub(crate) const DEFAULT_PRE_PASTE_DELAY: usize = 100;
\ No newline at end of file
diff --git a/espanso-config/src/config/mod.rs b/espanso-config/src/config/mod.rs
index 4968f48..d68d9c8 100644
--- a/espanso-config/src/config/mod.rs
+++ b/espanso-config/src/config/mod.rs
@@ -25,16 +25,33 @@ mod parse;
mod path;
mod resolve;
mod util;
+pub(crate) mod default;
pub(crate) mod store;
+#[cfg(test)]
+use mockall::{automock, predicate::*};
+#[cfg_attr(test, automock)]
pub trait Config: Send {
fn id(&self) -> i32;
fn label(&self) -> &str;
fn match_paths(&self) -> &[String];
fn backend(&self) -> Backend;
- fn clipboard_threshold(&self) -> usize;
- fn is_match(&self, app: &AppProperties) -> bool;
+ // Number of chars after which a match is injected with the clipboard
+ // backend instead of the default one. This is done for efficiency
+ // reasons, as injecting a long match through separate events becomes
+ // slow for long strings.
+ fn clipboard_threshold(&self) -> usize;
+
+ // Delay (in ms) that espanso should wait to trigger the paste shortcut
+ // after copying the content in the clipboard. This is needed because
+ // if we trigger a "paste" shortcut before the content is actually
+ // copied in the clipboard, the operation will fail.
+ fn pre_paste_delay(&self) -> usize;
+
+ // TODO: add other delay options (start by the ones needed in clipboard injector)
+
+ fn is_match<'a>(&self, app: &AppProperties<'a>) -> bool;
}
pub trait ConfigStore: Send {
diff --git a/espanso-config/src/config/parse/mod.rs b/espanso-config/src/config/parse/mod.rs
index 38bd6f9..f3fae0d 100644
--- a/espanso-config/src/config/parse/mod.rs
+++ b/espanso-config/src/config/parse/mod.rs
@@ -30,6 +30,8 @@ pub(crate) struct ParsedConfig {
pub backend: Option,
pub clipboard_threshold: Option,
+ pub pre_paste_delay: Option,
+
// Includes
pub includes: Option>,
pub excludes: Option>,
diff --git a/espanso-config/src/config/parse/yaml.rs b/espanso-config/src/config/parse/yaml.rs
index 6021b9a..a229ba7 100644
--- a/espanso-config/src/config/parse/yaml.rs
+++ b/espanso-config/src/config/parse/yaml.rs
@@ -36,6 +36,9 @@ pub(crate) struct YAMLConfig {
#[serde(default)]
pub clipboard_threshold: Option,
+ #[serde(default)]
+ pub pre_paste_delay: Option,
+
#[serde(default)]
pub includes: Option>,
@@ -86,6 +89,9 @@ impl TryFrom for ParsedConfig {
label: yaml_config.label,
backend: yaml_config.backend,
clipboard_threshold: yaml_config.clipboard_threshold,
+
+ pre_paste_delay: yaml_config.pre_paste_delay,
+
use_standard_includes: yaml_config.use_standard_includes,
includes: yaml_config.includes,
extra_includes: yaml_config.extra_includes,
@@ -112,6 +118,7 @@ mod tests {
label: "test"
backend: clipboard
clipboard_threshold: 200
+ pre_paste_delay: 300
use_standard_includes: true
includes: ["test1"]
@@ -136,6 +143,8 @@ mod tests {
backend: Some("clipboard".to_string()),
clipboard_threshold: Some(200),
+ pre_paste_delay: Some(300),
+
use_standard_includes: Some(true),
includes: Some(vec!["test1".to_string()]),
extra_includes: Some(vec!["test2".to_string()]),
diff --git a/espanso-config/src/config/resolve.rs b/espanso-config/src/config/resolve.rs
index e4df76b..72abb92 100644
--- a/espanso-config/src/config/resolve.rs
+++ b/espanso-config/src/config/resolve.rs
@@ -17,7 +17,13 @@
* along with espanso. If not, see .
*/
-use super::{AppProperties, Backend, Config, parse::ParsedConfig, path::calculate_paths, util::os_matches};
+use super::{
+ default::{DEFAULT_CLIPBOARD_THRESHOLD, DEFAULT_PRE_PASTE_DELAY},
+ parse::ParsedConfig,
+ path::calculate_paths,
+ util::os_matches,
+ AppProperties, Backend, Config,
+};
use crate::{counter::next_id, merge};
use anyhow::Result;
use log::error;
@@ -118,7 +124,13 @@ impl Config for ResolvedConfig {
}
fn backend(&self) -> Backend {
- match self.parsed.backend.as_deref().map(|b| b.to_lowercase()).as_deref() {
+ 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,
@@ -130,7 +142,17 @@ impl Config for ResolvedConfig {
}
fn clipboard_threshold(&self) -> usize {
- self.parsed.clipboard_threshold.unwrap_or(100)
+ self
+ .parsed
+ .clipboard_threshold
+ .unwrap_or(DEFAULT_CLIPBOARD_THRESHOLD)
+ }
+
+ fn pre_paste_delay(&self) -> usize {
+ self
+ .parsed
+ .pre_paste_delay
+ .unwrap_or(DEFAULT_PRE_PASTE_DELAY)
}
}
@@ -190,6 +212,7 @@ impl ResolvedConfig {
label,
backend,
clipboard_threshold,
+ pre_paste_delay,
includes,
excludes,
extra_includes,
diff --git a/espanso-config/src/config/store.rs b/espanso-config/src/config/store.rs
index 57b9885..e48222c 100644
--- a/espanso-config/src/config/store.rs
+++ b/espanso-config/src/config/store.rs
@@ -126,52 +126,22 @@ impl DefaultConfigStore {
#[cfg(test)]
mod tests {
use super::*;
+ use crate::config::MockConfig;
- struct MockConfig {
- label: String,
- is_match: bool,
- }
-
- impl MockConfig {
- pub fn new(label: &str, is_match: bool) -> Self {
- Self {
- label: label.to_string(),
- is_match,
- }
- }
- }
-
- impl Config for MockConfig {
- fn id(&self) -> i32 {
- 0
- }
-
- fn label(&self) -> &str {
- &self.label
- }
-
- fn match_paths(&self) -> &[String] {
- unimplemented!()
- }
-
- fn is_match(&self, _: &crate::config::AppProperties) -> bool {
- self.is_match
- }
-
- fn backend(&self) -> crate::config::Backend {
- unimplemented!()
- }
-
- fn clipboard_threshold(&self) -> usize {
- unimplemented!()
- }
+ pub fn new_mock(label: &'static str, is_match: bool) -> MockConfig {
+ let label = label.to_owned();
+ let mut mock = MockConfig::new();
+ mock.expect_id().return_const(0);
+ mock.expect_label().return_const(label);
+ mock.expect_is_match().return_const(is_match);
+ mock
}
#[test]
fn config_store_selects_correctly() {
- let default = MockConfig::new("default", false);
- let custom1 = MockConfig::new("custom1", false);
- let custom2 = MockConfig::new("custom2", true);
+ let default = new_mock("default", false);
+ let custom1 = new_mock("custom1", false);
+ let custom2 = new_mock("custom2", true);
let store = DefaultConfigStore {
default: Box::new(default),
@@ -193,9 +163,9 @@ mod tests {
#[test]
fn config_store_active_fallback_to_default_if_no_match() {
- let default = MockConfig::new("default", false);
- let custom1 = MockConfig::new("custom1", false);
- let custom2 = MockConfig::new("custom2", false);
+ let default = new_mock("default", false);
+ let custom1 = new_mock("custom1", false);
+ let custom2 = new_mock("custom2", false);
let store = DefaultConfigStore {
default: Box::new(default),
diff --git a/espanso-config/src/legacy/mod.rs b/espanso-config/src/legacy/mod.rs
index bea0251..d050bbc 100644
--- a/espanso-config/src/legacy/mod.rs
+++ b/espanso-config/src/legacy/mod.rs
@@ -22,7 +22,10 @@ use regex::Regex;
use std::{collections::HashMap, path::Path};
use self::config::LegacyConfig;
-use crate::matches::{MatchEffect, group::loader::yaml::parse::{YAMLMatch, YAMLVariable}};
+use crate::matches::{
+ group::loader::yaml::parse::{YAMLMatch, YAMLVariable},
+ MatchEffect,
+};
use crate::{config::store::DefaultConfigStore, counter::StructId};
use crate::{
config::Config,
@@ -139,10 +142,7 @@ fn deduplicate_matches(
}
// TODO: test case of matches with inner variables
-fn deduplicate_vars(
- vars: &mut [Variable],
- var_map: &mut HashMap,
-) {
+fn deduplicate_vars(vars: &mut [Variable], var_map: &mut HashMap) {
for v in vars.iter_mut() {
let mut v_without_id = v.clone();
v_without_id.id = 0;
@@ -254,7 +254,11 @@ impl Config for LegacyInteropConfig {
}
fn clipboard_threshold(&self) -> usize {
- 100
+ crate::config::default::DEFAULT_CLIPBOARD_THRESHOLD
+ }
+
+ fn pre_paste_delay(&self) -> usize {
+ crate::config::default::DEFAULT_PRE_PASTE_DELAY
}
}
@@ -472,8 +476,21 @@ mod tests {
exec: None,
});
- for (i, m) in match_store.query(default_config.match_paths()).matches.into_iter().enumerate() {
- assert_eq!(m.id, match_store.query(active_config.match_paths()).matches.get(i).unwrap().id);
+ for (i, m) in match_store
+ .query(default_config.match_paths())
+ .matches
+ .into_iter()
+ .enumerate()
+ {
+ assert_eq!(
+ m.id,
+ match_store
+ .query(active_config.match_paths())
+ .matches
+ .get(i)
+ .unwrap()
+ .id
+ );
}
assert_eq!(