refactor(core): move engine into separate module
This commit is contained in:
parent
974e405b23
commit
1713b078be
20
Cargo.lock
generated
20
Cargo.lock
generated
|
@ -522,6 +522,7 @@ dependencies = [
|
||||||
"espanso-clipboard",
|
"espanso-clipboard",
|
||||||
"espanso-config",
|
"espanso-config",
|
||||||
"espanso-detect",
|
"espanso-detect",
|
||||||
|
"espanso-engine",
|
||||||
"espanso-info",
|
"espanso-info",
|
||||||
"espanso-inject",
|
"espanso-inject",
|
||||||
"espanso-ipc",
|
"espanso-ipc",
|
||||||
|
@ -535,13 +536,11 @@ dependencies = [
|
||||||
"espanso-ui",
|
"espanso-ui",
|
||||||
"fs2",
|
"fs2",
|
||||||
"fs_extra",
|
"fs_extra",
|
||||||
"html2text",
|
|
||||||
"lazy_static",
|
"lazy_static",
|
||||||
"libc",
|
"libc",
|
||||||
"log",
|
"log",
|
||||||
"log-panics",
|
"log-panics",
|
||||||
"maplit",
|
"maplit",
|
||||||
"markdown",
|
|
||||||
"named_pipe",
|
"named_pipe",
|
||||||
"notify",
|
"notify",
|
||||||
"opener",
|
"opener",
|
||||||
|
@ -611,6 +610,19 @@ dependencies = [
|
||||||
"widestring",
|
"widestring",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "espanso-engine"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"anyhow",
|
||||||
|
"crossbeam",
|
||||||
|
"html2text",
|
||||||
|
"log",
|
||||||
|
"markdown",
|
||||||
|
"tempdir",
|
||||||
|
"thiserror",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "espanso-info"
|
name = "espanso-info"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
|
@ -1873,9 +1885,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "siphasher"
|
name = "siphasher"
|
||||||
version = "0.3.5"
|
version = "0.3.6"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "cbce6d4507c7e4a3962091436e56e95290cb71fa302d0d270e32130b75fbff27"
|
checksum = "729a25c17d72b06c68cb47955d44fda88ad2d3e7d77e025663fdd69b93dd71a1"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "slab"
|
name = "slab"
|
||||||
|
|
|
@ -16,4 +16,5 @@ members = [
|
||||||
"espanso-migrate",
|
"espanso-migrate",
|
||||||
"espanso-mac-utils",
|
"espanso-mac-utils",
|
||||||
"espanso-kvs",
|
"espanso-kvs",
|
||||||
|
"espanso-engine",
|
||||||
]
|
]
|
|
@ -33,6 +33,7 @@ espanso-ipc = { path = "../espanso-ipc" }
|
||||||
espanso-modulo = { path = "../espanso-modulo", optional = true }
|
espanso-modulo = { path = "../espanso-modulo", optional = true }
|
||||||
espanso-migrate = { path = "../espanso-migrate" }
|
espanso-migrate = { path = "../espanso-migrate" }
|
||||||
espanso-kvs = { path = "../espanso-kvs" }
|
espanso-kvs = { path = "../espanso-kvs" }
|
||||||
|
espanso-engine = { path = "../espanso-engine" }
|
||||||
maplit = "1.0.2"
|
maplit = "1.0.2"
|
||||||
simplelog = "0.9.0"
|
simplelog = "0.9.0"
|
||||||
log = "0.4.14"
|
log = "0.4.14"
|
||||||
|
@ -45,8 +46,6 @@ enum-as-inner = "0.3.3"
|
||||||
dirs = "3.0.1"
|
dirs = "3.0.1"
|
||||||
serde = { version = "1.0.123", features = ["derive"] }
|
serde = { version = "1.0.123", features = ["derive"] }
|
||||||
serde_json = "1.0.62"
|
serde_json = "1.0.62"
|
||||||
markdown = "0.3.0"
|
|
||||||
html2text = "0.2.1"
|
|
||||||
log-panics = "2.0.0"
|
log-panics = "2.0.0"
|
||||||
fs2 = "0.4.3"
|
fs2 = "0.4.3"
|
||||||
serde_yaml = "0.8.17"
|
serde_yaml = "0.8.17"
|
||||||
|
|
|
@ -17,10 +17,9 @@
|
||||||
* along with espanso. If not, see <https://www.gnu.org/licenses/>.
|
* along with espanso. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
use crate::{
|
use espanso_engine::event::{effect::TextInjectRequest, EventType};
|
||||||
cli::worker::builtin::generate_next_builtin_id,
|
|
||||||
engine::event::{effect::TextInjectRequest, EventType},
|
use crate::cli::worker::builtin::generate_next_builtin_id;
|
||||||
};
|
|
||||||
|
|
||||||
use super::BuiltInMatch;
|
use super::BuiltInMatch;
|
||||||
|
|
||||||
|
|
|
@ -21,7 +21,7 @@ use std::cell::Cell;
|
||||||
|
|
||||||
use espanso_config::config::Config;
|
use espanso_config::config::Config;
|
||||||
|
|
||||||
use crate::engine::event::EventType;
|
use espanso_engine::event::EventType;
|
||||||
|
|
||||||
use super::context::Context;
|
use super::context::Context;
|
||||||
|
|
||||||
|
|
|
@ -17,19 +17,22 @@
|
||||||
* along with espanso. If not, see <https://www.gnu.org/licenses/>.
|
* along with espanso. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
use crate::{cli::worker::builtin::generate_next_builtin_id, engine::event::{EventType}};
|
use espanso_engine::event::EventType;
|
||||||
|
|
||||||
|
use crate::cli::worker::builtin::generate_next_builtin_id;
|
||||||
|
|
||||||
use super::BuiltInMatch;
|
use super::BuiltInMatch;
|
||||||
|
|
||||||
pub fn create_match_trigger_search_bar(trigger: Option<String>, hotkey: Option<String>) -> BuiltInMatch {
|
pub fn create_match_trigger_search_bar(
|
||||||
|
trigger: Option<String>,
|
||||||
|
hotkey: Option<String>,
|
||||||
|
) -> BuiltInMatch {
|
||||||
BuiltInMatch {
|
BuiltInMatch {
|
||||||
id: generate_next_builtin_id(),
|
id: generate_next_builtin_id(),
|
||||||
label: "Open search bar",
|
label: "Open search bar",
|
||||||
triggers: trigger.map(|trigger| vec![trigger]).unwrap_or_default(),
|
triggers: trigger.map(|trigger| vec![trigger]).unwrap_or_default(),
|
||||||
hotkey,
|
hotkey,
|
||||||
action: |_| {
|
action: |_| EventType::ShowSearchBar,
|
||||||
EventType::ShowSearchBar
|
|
||||||
},
|
|
||||||
..Default::default()
|
..Default::default()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -73,7 +73,7 @@ fn to_app_properties(info: &AppInfo) -> AppProperties {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> crate::engine::process::MatchFilter for ConfigManager<'a> {
|
impl<'a> espanso_engine::process::MatchFilter for ConfigManager<'a> {
|
||||||
fn filter_active(&self, matches_ids: &[i32]) -> Vec<i32> {
|
fn filter_active(&self, matches_ids: &[i32]) -> Vec<i32> {
|
||||||
let ids_set: HashSet<i32> = HashSet::from_iter(matches_ids.iter().copied());
|
let ids_set: HashSet<i32> = HashSet::from_iter(matches_ids.iter().copied());
|
||||||
let (_, match_set) = self.active_context();
|
let (_, match_set) = self.active_context();
|
||||||
|
@ -115,13 +115,13 @@ impl<'a> super::engine::process::middleware::render::ConfigProvider<'a> for Conf
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> crate::engine::dispatch::ModeProvider for ConfigManager<'a> {
|
impl<'a> espanso_engine::dispatch::ModeProvider for ConfigManager<'a> {
|
||||||
fn active_mode(&self) -> crate::engine::dispatch::Mode {
|
fn active_mode(&self) -> espanso_engine::dispatch::Mode {
|
||||||
let config = self.active();
|
let config = self.active();
|
||||||
match config.backend() {
|
match config.backend() {
|
||||||
espanso_config::config::Backend::Inject => crate::engine::dispatch::Mode::Event,
|
espanso_config::config::Backend::Inject => espanso_engine::dispatch::Mode::Event,
|
||||||
espanso_config::config::Backend::Clipboard => crate::engine::dispatch::Mode::Clipboard,
|
espanso_config::config::Backend::Clipboard => espanso_engine::dispatch::Mode::Clipboard,
|
||||||
espanso_config::config::Backend::Auto => crate::engine::dispatch::Mode::Auto {
|
espanso_config::config::Backend::Auto => espanso_engine::dispatch::Mode::Auto {
|
||||||
clipboard_threshold: config.clipboard_threshold(),
|
clipboard_threshold: config.clipboard_threshold(),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
@ -155,7 +155,7 @@ impl<'a> super::engine::dispatch::executor::InjectParamsProvider for ConfigManag
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> crate::engine::process::MatcherMiddlewareConfigProvider for ConfigManager<'a> {
|
impl<'a> espanso_engine::process::MatcherMiddlewareConfigProvider for ConfigManager<'a> {
|
||||||
fn max_history_size(&self) -> usize {
|
fn max_history_size(&self) -> usize {
|
||||||
self.default().backspace_limit()
|
self.default().backspace_limit()
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,13 +17,14 @@
|
||||||
* along with espanso. If not, see <https://www.gnu.org/licenses/>.
|
* along with espanso. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
use std::{path::Path};
|
use std::path::Path;
|
||||||
|
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use crossbeam::channel::Sender;
|
use crossbeam::channel::Sender;
|
||||||
|
use espanso_engine::event::ExitMode;
|
||||||
use log::{error, info, warn};
|
use log::{error, info, warn};
|
||||||
|
|
||||||
use crate::{engine::event::ExitMode, lock::acquire_daemon_lock};
|
use crate::lock::acquire_daemon_lock;
|
||||||
|
|
||||||
const DAEMON_STATUS_CHECK_INTERVAL: u64 = 1000;
|
const DAEMON_STATUS_CHECK_INTERVAL: u64 = 1000;
|
||||||
|
|
||||||
|
@ -55,6 +56,8 @@ fn daemon_monitor_main(runtime_dir: &Path, exit_notify: Sender<ExitMode>) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::thread::sleep(std::time::Duration::from_millis(DAEMON_STATUS_CHECK_INTERVAL));
|
std::thread::sleep(std::time::Duration::from_millis(
|
||||||
|
DAEMON_STATUS_CHECK_INTERVAL,
|
||||||
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,7 +23,7 @@ use espanso_clipboard::Clipboard;
|
||||||
use espanso_inject::{keys::Key, InjectionOptions, Injector};
|
use espanso_inject::{keys::Key, InjectionOptions, Injector};
|
||||||
use log::error;
|
use log::error;
|
||||||
|
|
||||||
use crate::engine::{
|
use espanso_engine::{
|
||||||
dispatch::HtmlInjector,
|
dispatch::HtmlInjector,
|
||||||
dispatch::{ImageInjector, TextInjector},
|
dispatch::{ImageInjector, TextInjector},
|
||||||
};
|
};
|
||||||
|
|
|
@ -19,7 +19,7 @@
|
||||||
|
|
||||||
use espanso_ui::UIRemote;
|
use espanso_ui::UIRemote;
|
||||||
|
|
||||||
use crate::engine::dispatch::ContextMenuHandler;
|
use espanso_engine::dispatch::ContextMenuHandler;
|
||||||
|
|
||||||
pub struct ContextMenuHandlerAdapter<'a> {
|
pub struct ContextMenuHandlerAdapter<'a> {
|
||||||
remote: &'a dyn UIRemote,
|
remote: &'a dyn UIRemote,
|
||||||
|
@ -32,7 +32,7 @@ impl<'a> ContextMenuHandlerAdapter<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> ContextMenuHandler for ContextMenuHandlerAdapter<'a> {
|
impl<'a> ContextMenuHandler for ContextMenuHandlerAdapter<'a> {
|
||||||
fn show_context_menu(&self, items: &[crate::engine::event::ui::MenuItem]) -> anyhow::Result<()> {
|
fn show_context_menu(&self, items: &[espanso_engine::event::ui::MenuItem]) -> anyhow::Result<()> {
|
||||||
let ui_menu_items: Vec<espanso_ui::menu::MenuItem> =
|
let ui_menu_items: Vec<espanso_ui::menu::MenuItem> =
|
||||||
items.iter().map(convert_to_ui_menu_item).collect();
|
items.iter().map(convert_to_ui_menu_item).collect();
|
||||||
let ui_menu = espanso_ui::menu::Menu {
|
let ui_menu = espanso_ui::menu::Menu {
|
||||||
|
@ -46,16 +46,16 @@ impl<'a> ContextMenuHandler for ContextMenuHandlerAdapter<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn convert_to_ui_menu_item(
|
fn convert_to_ui_menu_item(
|
||||||
item: &crate::engine::event::ui::MenuItem,
|
item: &espanso_engine::event::ui::MenuItem,
|
||||||
) -> espanso_ui::menu::MenuItem {
|
) -> espanso_ui::menu::MenuItem {
|
||||||
match item {
|
match item {
|
||||||
crate::engine::event::ui::MenuItem::Simple(simple) => {
|
espanso_engine::event::ui::MenuItem::Simple(simple) => {
|
||||||
espanso_ui::menu::MenuItem::Simple(espanso_ui::menu::SimpleMenuItem {
|
espanso_ui::menu::MenuItem::Simple(espanso_ui::menu::SimpleMenuItem {
|
||||||
id: simple.id,
|
id: simple.id,
|
||||||
label: simple.label.clone(),
|
label: simple.label.clone(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
crate::engine::event::ui::MenuItem::Sub(sub) => {
|
espanso_engine::event::ui::MenuItem::Sub(sub) => {
|
||||||
espanso_ui::menu::MenuItem::Sub(espanso_ui::menu::SubMenuItem {
|
espanso_ui::menu::MenuItem::Sub(espanso_ui::menu::SubMenuItem {
|
||||||
label: sub.label.clone(),
|
label: sub.label.clone(),
|
||||||
items: sub
|
items: sub
|
||||||
|
@ -65,6 +65,6 @@ fn convert_to_ui_menu_item(
|
||||||
.collect(),
|
.collect(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
crate::engine::event::ui::MenuItem::Separator => espanso_ui::menu::MenuItem::Separator,
|
espanso_engine::event::ui::MenuItem::Separator => espanso_ui::menu::MenuItem::Separator,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,7 +21,7 @@ use std::convert::TryInto;
|
||||||
|
|
||||||
use espanso_inject::{InjectionOptions, Injector};
|
use espanso_inject::{InjectionOptions, Injector};
|
||||||
|
|
||||||
use crate::engine::dispatch::TextInjector;
|
use espanso_engine::dispatch::TextInjector;
|
||||||
|
|
||||||
use super::InjectParamsProvider;
|
use super::InjectParamsProvider;
|
||||||
|
|
||||||
|
|
|
@ -19,7 +19,7 @@
|
||||||
|
|
||||||
use espanso_ui::{UIRemote, icons::TrayIcon};
|
use espanso_ui::{UIRemote, icons::TrayIcon};
|
||||||
|
|
||||||
use crate::engine::{dispatch::IconHandler, event::ui::IconStatus};
|
use espanso_engine::{dispatch::IconHandler, event::ui::IconStatus};
|
||||||
|
|
||||||
pub struct IconHandlerAdapter<'a> {
|
pub struct IconHandlerAdapter<'a> {
|
||||||
remote: &'a dyn UIRemote,
|
remote: &'a dyn UIRemote,
|
||||||
|
|
|
@ -20,7 +20,7 @@
|
||||||
use std::convert::TryInto;
|
use std::convert::TryInto;
|
||||||
use espanso_inject::{InjectionOptions, Injector};
|
use espanso_inject::{InjectionOptions, Injector};
|
||||||
|
|
||||||
use crate::engine::dispatch::KeyInjector;
|
use espanso_engine::dispatch::KeyInjector;
|
||||||
|
|
||||||
use super::InjectParamsProvider;
|
use super::InjectParamsProvider;
|
||||||
|
|
||||||
|
@ -36,7 +36,7 @@ impl<'a> KeyInjectorAdapter<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> KeyInjector for KeyInjectorAdapter<'a> {
|
impl<'a> KeyInjector for KeyInjectorAdapter<'a> {
|
||||||
fn inject_sequence(&self, keys: &[crate::engine::event::input::Key]) -> anyhow::Result<()> {
|
fn inject_sequence(&self, keys: &[espanso_engine::event::input::Key]) -> anyhow::Result<()> {
|
||||||
let params = self.params_provider.get();
|
let params = self.params_provider.get();
|
||||||
|
|
||||||
let injection_options = InjectionOptions {
|
let injection_options = InjectionOptions {
|
||||||
|
@ -53,47 +53,47 @@ impl<'a> KeyInjector for KeyInjectorAdapter<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn convert_to_inject_key(key: &crate::engine::event::input::Key) -> espanso_inject::keys::Key {
|
fn convert_to_inject_key(key: &espanso_engine::event::input::Key) -> espanso_inject::keys::Key {
|
||||||
match key {
|
match key {
|
||||||
crate::engine::event::input::Key::Alt => espanso_inject::keys::Key::Alt,
|
espanso_engine::event::input::Key::Alt => espanso_inject::keys::Key::Alt,
|
||||||
crate::engine::event::input::Key::CapsLock => espanso_inject::keys::Key::CapsLock,
|
espanso_engine::event::input::Key::CapsLock => espanso_inject::keys::Key::CapsLock,
|
||||||
crate::engine::event::input::Key::Control => espanso_inject::keys::Key::Control,
|
espanso_engine::event::input::Key::Control => espanso_inject::keys::Key::Control,
|
||||||
crate::engine::event::input::Key::Meta => espanso_inject::keys::Key::Meta,
|
espanso_engine::event::input::Key::Meta => espanso_inject::keys::Key::Meta,
|
||||||
crate::engine::event::input::Key::NumLock => espanso_inject::keys::Key::NumLock,
|
espanso_engine::event::input::Key::NumLock => espanso_inject::keys::Key::NumLock,
|
||||||
crate::engine::event::input::Key::Shift => espanso_inject::keys::Key::Shift,
|
espanso_engine::event::input::Key::Shift => espanso_inject::keys::Key::Shift,
|
||||||
crate::engine::event::input::Key::Enter => espanso_inject::keys::Key::Enter,
|
espanso_engine::event::input::Key::Enter => espanso_inject::keys::Key::Enter,
|
||||||
crate::engine::event::input::Key::Tab => espanso_inject::keys::Key::Tab,
|
espanso_engine::event::input::Key::Tab => espanso_inject::keys::Key::Tab,
|
||||||
crate::engine::event::input::Key::Space => espanso_inject::keys::Key::Space,
|
espanso_engine::event::input::Key::Space => espanso_inject::keys::Key::Space,
|
||||||
crate::engine::event::input::Key::ArrowDown => espanso_inject::keys::Key::ArrowDown,
|
espanso_engine::event::input::Key::ArrowDown => espanso_inject::keys::Key::ArrowDown,
|
||||||
crate::engine::event::input::Key::ArrowLeft => espanso_inject::keys::Key::ArrowLeft,
|
espanso_engine::event::input::Key::ArrowLeft => espanso_inject::keys::Key::ArrowLeft,
|
||||||
crate::engine::event::input::Key::ArrowRight => espanso_inject::keys::Key::ArrowRight,
|
espanso_engine::event::input::Key::ArrowRight => espanso_inject::keys::Key::ArrowRight,
|
||||||
crate::engine::event::input::Key::ArrowUp => espanso_inject::keys::Key::ArrowUp,
|
espanso_engine::event::input::Key::ArrowUp => espanso_inject::keys::Key::ArrowUp,
|
||||||
crate::engine::event::input::Key::End => espanso_inject::keys::Key::End,
|
espanso_engine::event::input::Key::End => espanso_inject::keys::Key::End,
|
||||||
crate::engine::event::input::Key::Home => espanso_inject::keys::Key::Home,
|
espanso_engine::event::input::Key::Home => espanso_inject::keys::Key::Home,
|
||||||
crate::engine::event::input::Key::PageDown => espanso_inject::keys::Key::PageDown,
|
espanso_engine::event::input::Key::PageDown => espanso_inject::keys::Key::PageDown,
|
||||||
crate::engine::event::input::Key::PageUp => espanso_inject::keys::Key::PageUp,
|
espanso_engine::event::input::Key::PageUp => espanso_inject::keys::Key::PageUp,
|
||||||
crate::engine::event::input::Key::Escape => espanso_inject::keys::Key::Escape,
|
espanso_engine::event::input::Key::Escape => espanso_inject::keys::Key::Escape,
|
||||||
crate::engine::event::input::Key::Backspace => espanso_inject::keys::Key::Backspace,
|
espanso_engine::event::input::Key::Backspace => espanso_inject::keys::Key::Backspace,
|
||||||
crate::engine::event::input::Key::F1 => espanso_inject::keys::Key::F1,
|
espanso_engine::event::input::Key::F1 => espanso_inject::keys::Key::F1,
|
||||||
crate::engine::event::input::Key::F2 => espanso_inject::keys::Key::F2,
|
espanso_engine::event::input::Key::F2 => espanso_inject::keys::Key::F2,
|
||||||
crate::engine::event::input::Key::F3 => espanso_inject::keys::Key::F3,
|
espanso_engine::event::input::Key::F3 => espanso_inject::keys::Key::F3,
|
||||||
crate::engine::event::input::Key::F4 => espanso_inject::keys::Key::F4,
|
espanso_engine::event::input::Key::F4 => espanso_inject::keys::Key::F4,
|
||||||
crate::engine::event::input::Key::F5 => espanso_inject::keys::Key::F5,
|
espanso_engine::event::input::Key::F5 => espanso_inject::keys::Key::F5,
|
||||||
crate::engine::event::input::Key::F6 => espanso_inject::keys::Key::F6,
|
espanso_engine::event::input::Key::F6 => espanso_inject::keys::Key::F6,
|
||||||
crate::engine::event::input::Key::F7 => espanso_inject::keys::Key::F7,
|
espanso_engine::event::input::Key::F7 => espanso_inject::keys::Key::F7,
|
||||||
crate::engine::event::input::Key::F8 => espanso_inject::keys::Key::F8,
|
espanso_engine::event::input::Key::F8 => espanso_inject::keys::Key::F8,
|
||||||
crate::engine::event::input::Key::F9 => espanso_inject::keys::Key::F9,
|
espanso_engine::event::input::Key::F9 => espanso_inject::keys::Key::F9,
|
||||||
crate::engine::event::input::Key::F10 => espanso_inject::keys::Key::F10,
|
espanso_engine::event::input::Key::F10 => espanso_inject::keys::Key::F10,
|
||||||
crate::engine::event::input::Key::F11 => espanso_inject::keys::Key::F11,
|
espanso_engine::event::input::Key::F11 => espanso_inject::keys::Key::F11,
|
||||||
crate::engine::event::input::Key::F12 => espanso_inject::keys::Key::F12,
|
espanso_engine::event::input::Key::F12 => espanso_inject::keys::Key::F12,
|
||||||
crate::engine::event::input::Key::F13 => espanso_inject::keys::Key::F13,
|
espanso_engine::event::input::Key::F13 => espanso_inject::keys::Key::F13,
|
||||||
crate::engine::event::input::Key::F14 => espanso_inject::keys::Key::F14,
|
espanso_engine::event::input::Key::F14 => espanso_inject::keys::Key::F14,
|
||||||
crate::engine::event::input::Key::F15 => espanso_inject::keys::Key::F15,
|
espanso_engine::event::input::Key::F15 => espanso_inject::keys::Key::F15,
|
||||||
crate::engine::event::input::Key::F16 => espanso_inject::keys::Key::F16,
|
espanso_engine::event::input::Key::F16 => espanso_inject::keys::Key::F16,
|
||||||
crate::engine::event::input::Key::F17 => espanso_inject::keys::Key::F17,
|
espanso_engine::event::input::Key::F17 => espanso_inject::keys::Key::F17,
|
||||||
crate::engine::event::input::Key::F18 => espanso_inject::keys::Key::F18,
|
espanso_engine::event::input::Key::F18 => espanso_inject::keys::Key::F18,
|
||||||
crate::engine::event::input::Key::F19 => espanso_inject::keys::Key::F19,
|
espanso_engine::event::input::Key::F19 => espanso_inject::keys::Key::F19,
|
||||||
crate::engine::event::input::Key::F20 => espanso_inject::keys::Key::F20,
|
espanso_engine::event::input::Key::F20 => espanso_inject::keys::Key::F20,
|
||||||
crate::engine::event::input::Key::Other(raw) => espanso_inject::keys::Key::Raw(*raw),
|
espanso_engine::event::input::Key::Other(raw) => espanso_inject::keys::Key::Raw(*raw),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,7 +21,7 @@ use std::process::Stdio;
|
||||||
use anyhow::{bail, Context};
|
use anyhow::{bail, Context};
|
||||||
use log::{error, info};
|
use log::{error, info};
|
||||||
|
|
||||||
use crate::engine::dispatch::SecureInputManager;
|
use espanso_engine::dispatch::SecureInputManager;
|
||||||
|
|
||||||
pub struct SecureInputManagerAdapter {}
|
pub struct SecureInputManagerAdapter {}
|
||||||
|
|
||||||
|
|
|
@ -18,9 +18,15 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
use crossbeam::channel::{Receiver, Select, SelectedOperation};
|
use crossbeam::channel::{Receiver, Select, SelectedOperation};
|
||||||
use espanso_detect::event::{InputEvent};
|
use espanso_detect::event::InputEvent;
|
||||||
|
|
||||||
use crate::engine::{event::{Event, EventType, SourceId, input::{HotKeyEvent, Key, KeyboardEvent, MouseButton, MouseEvent, Status, Variant}}, funnel};
|
use espanso_engine::{
|
||||||
|
event::{
|
||||||
|
input::{HotKeyEvent, Key, KeyboardEvent, MouseButton, MouseEvent, Status, Variant},
|
||||||
|
Event, EventType, SourceId,
|
||||||
|
},
|
||||||
|
funnel,
|
||||||
|
};
|
||||||
|
|
||||||
pub struct DetectSource {
|
pub struct DetectSource {
|
||||||
pub receiver: Receiver<(InputEvent, SourceId)>,
|
pub receiver: Receiver<(InputEvent, SourceId)>,
|
||||||
|
@ -39,31 +45,32 @@ impl<'a> funnel::Source<'a> for DetectSource {
|
||||||
InputEvent::Keyboard(keyboard_event) => Event {
|
InputEvent::Keyboard(keyboard_event) => Event {
|
||||||
source_id,
|
source_id,
|
||||||
etype: EventType::Keyboard(KeyboardEvent {
|
etype: EventType::Keyboard(KeyboardEvent {
|
||||||
key: keyboard_event.key.into(),
|
key: convert_to_engine_key(keyboard_event.key),
|
||||||
value: keyboard_event.value,
|
value: keyboard_event.value,
|
||||||
status: keyboard_event.status.into(),
|
status: convert_to_engine_status(keyboard_event.status),
|
||||||
variant: keyboard_event.variant.map(|variant| variant.into()),
|
variant: keyboard_event
|
||||||
|
.variant
|
||||||
|
.map(|variant| convert_to_engine_variant(variant)),
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
InputEvent::Mouse(mouse_event) => Event {
|
InputEvent::Mouse(mouse_event) => Event {
|
||||||
source_id,
|
source_id,
|
||||||
etype: EventType::Mouse(MouseEvent {
|
etype: EventType::Mouse(MouseEvent {
|
||||||
status: mouse_event.status.into(),
|
status: convert_to_engine_status(mouse_event.status),
|
||||||
button: mouse_event.button.into(),
|
button: convert_to_engine_mouse_button(mouse_event.button),
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
InputEvent::HotKey(hotkey_event) => Event {
|
InputEvent::HotKey(hotkey_event) => Event {
|
||||||
source_id,
|
source_id,
|
||||||
etype: EventType::HotKey(HotKeyEvent {
|
etype: EventType::HotKey(HotKeyEvent {
|
||||||
hotkey_id: hotkey_event.hotkey_id,
|
hotkey_id: hotkey_event.hotkey_id,
|
||||||
})
|
}),
|
||||||
}
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<espanso_detect::event::Key> for Key {
|
pub fn convert_to_engine_key(key: espanso_detect::event::Key) -> Key {
|
||||||
fn from(key: espanso_detect::event::Key) -> Self {
|
|
||||||
match key {
|
match key {
|
||||||
espanso_detect::event::Key::Alt => Key::Alt,
|
espanso_detect::event::Key::Alt => Key::Alt,
|
||||||
espanso_detect::event::Key::CapsLock => Key::CapsLock,
|
espanso_detect::event::Key::CapsLock => Key::CapsLock,
|
||||||
|
@ -107,28 +114,22 @@ impl From<espanso_detect::event::Key> for Key {
|
||||||
espanso_detect::event::Key::Other(code) => Key::Other(code),
|
espanso_detect::event::Key::Other(code) => Key::Other(code),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
impl From<espanso_detect::event::Variant> for Variant {
|
pub fn convert_to_engine_variant(variant: espanso_detect::event::Variant) -> Variant {
|
||||||
fn from(variant: espanso_detect::event::Variant) -> Self {
|
|
||||||
match variant {
|
match variant {
|
||||||
espanso_detect::event::Variant::Left => Variant::Left,
|
espanso_detect::event::Variant::Left => Variant::Left,
|
||||||
espanso_detect::event::Variant::Right => Variant::Right,
|
espanso_detect::event::Variant::Right => Variant::Right,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
impl From<espanso_detect::event::Status> for Status {
|
pub fn convert_to_engine_status(status: espanso_detect::event::Status) -> Status {
|
||||||
fn from(status: espanso_detect::event::Status) -> Self {
|
|
||||||
match status {
|
match status {
|
||||||
espanso_detect::event::Status::Pressed => Status::Pressed,
|
espanso_detect::event::Status::Pressed => Status::Pressed,
|
||||||
espanso_detect::event::Status::Released => Status::Released,
|
espanso_detect::event::Status::Released => Status::Released,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
impl From<espanso_detect::event::MouseButton> for MouseButton {
|
pub fn convert_to_engine_mouse_button(button: espanso_detect::event::MouseButton) -> MouseButton {
|
||||||
fn from(button: espanso_detect::event::MouseButton) -> Self {
|
|
||||||
match button {
|
match button {
|
||||||
espanso_detect::event::MouseButton::Left => MouseButton::Left,
|
espanso_detect::event::MouseButton::Left => MouseButton::Left,
|
||||||
espanso_detect::event::MouseButton::Right => MouseButton::Right,
|
espanso_detect::event::MouseButton::Right => MouseButton::Right,
|
||||||
|
@ -140,4 +141,3 @@ impl From<espanso_detect::event::MouseButton> for MouseButton {
|
||||||
espanso_detect::event::MouseButton::Button5 => MouseButton::Button5,
|
espanso_detect::event::MouseButton::Button5 => MouseButton::Button5,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
|
@ -19,7 +19,7 @@
|
||||||
|
|
||||||
use crossbeam::channel::{Receiver, Select, SelectedOperation};
|
use crossbeam::channel::{Receiver, Select, SelectedOperation};
|
||||||
|
|
||||||
use crate::engine::{event::{Event, EventType, ExitMode}, funnel};
|
use espanso_engine::{event::{Event, EventType, ExitMode}, funnel};
|
||||||
|
|
||||||
use super::sequencer::Sequencer;
|
use super::sequencer::Sequencer;
|
||||||
|
|
||||||
|
|
|
@ -24,7 +24,7 @@ use std::{
|
||||||
|
|
||||||
use log::warn;
|
use log::warn;
|
||||||
|
|
||||||
use crate::engine::process::ModifierStatusProvider;
|
use espanso_engine::process::ModifierStatusProvider;
|
||||||
|
|
||||||
/// This duration represents the maximum length for which a pressed modifier
|
/// This duration represents the maximum length for which a pressed modifier
|
||||||
/// event is considered valid. This is useful when the "release" event is
|
/// event is considered valid. This is useful when the "release" event is
|
||||||
|
|
|
@ -19,12 +19,10 @@
|
||||||
|
|
||||||
use crossbeam::channel::{Receiver, Select, SelectedOperation};
|
use crossbeam::channel::{Receiver, Select, SelectedOperation};
|
||||||
|
|
||||||
use crate::{
|
use crate::cli::worker::secure_input::SecureInputEvent;
|
||||||
cli::worker::secure_input::SecureInputEvent,
|
use espanso_engine::{
|
||||||
engine::{
|
|
||||||
event::{internal::SecureInputEnabledEvent, Event, EventType},
|
event::{internal::SecureInputEnabledEvent, Event, EventType},
|
||||||
funnel,
|
funnel,
|
||||||
},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::sequencer::Sequencer;
|
use super::sequencer::Sequencer;
|
||||||
|
|
|
@ -22,7 +22,7 @@ use std::sync::{
|
||||||
Arc,
|
Arc,
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::engine::{event::SourceId, process::EventSequenceProvider};
|
use espanso_engine::{event::SourceId, process::EventSequenceProvider};
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct Sequencer {
|
pub struct Sequencer {
|
||||||
|
|
|
@ -20,7 +20,7 @@
|
||||||
use crossbeam::channel::{Receiver, Select, SelectedOperation};
|
use crossbeam::channel::{Receiver, Select, SelectedOperation};
|
||||||
use espanso_ui::event::UIEvent;
|
use espanso_ui::event::UIEvent;
|
||||||
|
|
||||||
use crate::engine::{
|
use espanso_engine::{
|
||||||
event::{input::ContextMenuClickedEvent, Event, EventType},
|
event::{input::ContextMenuClickedEvent, Event, EventType},
|
||||||
funnel,
|
funnel,
|
||||||
};
|
};
|
||||||
|
|
|
@ -23,6 +23,7 @@ use anyhow::Result;
|
||||||
use crossbeam::channel::Receiver;
|
use crossbeam::channel::Receiver;
|
||||||
use espanso_config::{config::ConfigStore, matches::store::MatchStore};
|
use espanso_config::{config::ConfigStore, matches::store::MatchStore};
|
||||||
use espanso_detect::SourceCreationOptions;
|
use espanso_detect::SourceCreationOptions;
|
||||||
|
use espanso_engine::event::ExitMode;
|
||||||
use espanso_inject::{InjectorCreationOptions, KeyboardStateProvider};
|
use espanso_inject::{InjectorCreationOptions, KeyboardStateProvider};
|
||||||
use espanso_path::Paths;
|
use espanso_path::Paths;
|
||||||
use espanso_ui::{event::UIEvent, UIRemote};
|
use espanso_ui::{event::UIEvent, UIRemote};
|
||||||
|
@ -41,7 +42,7 @@ use crate::{cli::worker::{context::Context, engine::{dispatch::executor::{clipbo
|
||||||
extension::{clipboard::ClipboardAdapter, form::FormProviderAdapter},
|
extension::{clipboard::ClipboardAdapter, form::FormProviderAdapter},
|
||||||
RendererAdapter,
|
RendererAdapter,
|
||||||
},
|
},
|
||||||
}}, match_cache::{CombinedMatchCache, MatchCache}}, common_flags::{WORKER_START_REASON_CONFIG_CHANGED, WORKER_START_REASON_KEYBOARD_LAYOUT_CHANGED, WORKER_START_REASON_MANUAL}, engine::event::ExitMode, preferences::Preferences};
|
}}, match_cache::{CombinedMatchCache, MatchCache}}, common_flags::{WORKER_START_REASON_CONFIG_CHANGED, WORKER_START_REASON_KEYBOARD_LAYOUT_CHANGED, WORKER_START_REASON_MANUAL}, preferences::Preferences};
|
||||||
|
|
||||||
use super::secure_input::SecureInputEvent;
|
use super::secure_input::SecureInputEvent;
|
||||||
|
|
||||||
|
@ -100,13 +101,13 @@ pub fn initialize_and_spawn(
|
||||||
secure_input_receiver,
|
secure_input_receiver,
|
||||||
&sequencer,
|
&sequencer,
|
||||||
);
|
);
|
||||||
let sources: Vec<&dyn crate::engine::funnel::Source> = vec![
|
let sources: Vec<&dyn espanso_engine::funnel::Source> = vec![
|
||||||
&detect_source,
|
&detect_source,
|
||||||
&exit_source,
|
&exit_source,
|
||||||
&ui_source,
|
&ui_source,
|
||||||
&secure_input_source,
|
&secure_input_source,
|
||||||
];
|
];
|
||||||
let funnel = crate::engine::funnel::default(&sources);
|
let funnel = espanso_engine::funnel::default(&sources);
|
||||||
|
|
||||||
let rolling_matcher = RollingMatcherAdapter::new(
|
let rolling_matcher = RollingMatcherAdapter::new(
|
||||||
&match_converter.get_rolling_matches(),
|
&match_converter.get_rolling_matches(),
|
||||||
|
@ -121,7 +122,7 @@ pub fn initialize_and_spawn(
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
let matchers: Vec<
|
let matchers: Vec<
|
||||||
&dyn crate::engine::process::Matcher<
|
&dyn espanso_engine::process::Matcher<
|
||||||
super::engine::process::middleware::matcher::MatcherState,
|
super::engine::process::middleware::matcher::MatcherState,
|
||||||
>,
|
>,
|
||||||
> = vec![&rolling_matcher, ®ex_matcher];
|
> = vec![&rolling_matcher, ®ex_matcher];
|
||||||
|
@ -171,7 +172,7 @@ pub fn initialize_and_spawn(
|
||||||
let disable_options =
|
let disable_options =
|
||||||
process::middleware::disable::extract_disable_options(&*config_manager.default());
|
process::middleware::disable::extract_disable_options(&*config_manager.default());
|
||||||
|
|
||||||
let mut processor = crate::engine::process::default(
|
let mut processor = espanso_engine::process::default(
|
||||||
&matchers,
|
&matchers,
|
||||||
&config_manager,
|
&config_manager,
|
||||||
&selector,
|
&selector,
|
||||||
|
@ -193,7 +194,7 @@ pub fn initialize_and_spawn(
|
||||||
let context_menu_adapter = ContextMenuHandlerAdapter::new(&*ui_remote);
|
let context_menu_adapter = ContextMenuHandlerAdapter::new(&*ui_remote);
|
||||||
let icon_adapter = IconHandlerAdapter::new(&*ui_remote);
|
let icon_adapter = IconHandlerAdapter::new(&*ui_remote);
|
||||||
let secure_input_adapter = SecureInputManagerAdapter::new();
|
let secure_input_adapter = SecureInputManagerAdapter::new();
|
||||||
let dispatcher = crate::engine::dispatch::default(
|
let dispatcher = espanso_engine::dispatch::default(
|
||||||
&event_injector,
|
&event_injector,
|
||||||
&clipboard_injector,
|
&clipboard_injector,
|
||||||
&config_manager,
|
&config_manager,
|
||||||
|
@ -233,7 +234,7 @@ pub fn initialize_and_spawn(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut engine = crate::engine::Engine::new(&funnel, &mut processor, &dispatcher);
|
let mut engine = espanso_engine::Engine::new(&funnel, &mut processor, &dispatcher);
|
||||||
let exit_mode = engine.run();
|
let exit_mode = engine.run();
|
||||||
|
|
||||||
info!("engine eventloop has terminated, propagating exit event...");
|
info!("engine eventloop has terminated, propagating exit event...");
|
||||||
|
|
|
@ -19,8 +19,11 @@
|
||||||
|
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
|
||||||
use crate::engine::{event::input::{Key, Variant}, process::DisableOptions};
|
|
||||||
use espanso_config::config::Config;
|
use espanso_config::config::Config;
|
||||||
|
use espanso_engine::{
|
||||||
|
event::input::{Key, Variant},
|
||||||
|
process::DisableOptions,
|
||||||
|
};
|
||||||
|
|
||||||
pub fn extract_disable_options(config: &dyn Config) -> DisableOptions {
|
pub fn extract_disable_options(config: &dyn Config) -> DisableOptions {
|
||||||
let (toggle_key, variant) = match config.toggle_key() {
|
let (toggle_key, variant) = match config.toggle_key() {
|
||||||
|
|
|
@ -19,7 +19,7 @@
|
||||||
|
|
||||||
use espanso_path::Paths;
|
use espanso_path::Paths;
|
||||||
|
|
||||||
use crate::engine::process::PathProvider;
|
use espanso_engine::process::PathProvider;
|
||||||
|
|
||||||
pub struct PathProviderAdapter<'a> {
|
pub struct PathProviderAdapter<'a> {
|
||||||
paths: &'a Paths,
|
paths: &'a Paths,
|
||||||
|
@ -27,9 +27,7 @@ pub struct PathProviderAdapter<'a> {
|
||||||
|
|
||||||
impl<'a> PathProviderAdapter<'a> {
|
impl<'a> PathProviderAdapter<'a> {
|
||||||
pub fn new(paths: &'a Paths) -> Self {
|
pub fn new(paths: &'a Paths) -> Self {
|
||||||
Self {
|
Self { paths }
|
||||||
paths,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -17,12 +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 espanso_engine::process::MatchSelector;
|
||||||
use log::error;
|
use log::error;
|
||||||
|
|
||||||
use crate::{
|
use crate::gui::{SearchItem, SearchUI};
|
||||||
engine::process::MatchSelector,
|
|
||||||
gui::{SearchItem, SearchUI},
|
|
||||||
};
|
|
||||||
|
|
||||||
const MAX_LABEL_LEN: usize = 100;
|
const MAX_LABEL_LEN: usize = 100;
|
||||||
|
|
||||||
|
|
|
@ -17,18 +17,18 @@
|
||||||
* along with espanso. If not, see <https://www.gnu.org/licenses/>.
|
* along with espanso. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
use espanso_match::rolling::matcher::RollingMatcherState;
|
use espanso_engine::{
|
||||||
use espanso_match::regex::RegexMatcherState;
|
|
||||||
use crate::engine::{
|
|
||||||
event::input::Key,
|
event::input::Key,
|
||||||
process::{MatchResult, MatcherEvent},
|
process::{MatchResult, MatcherEvent},
|
||||||
};
|
};
|
||||||
|
use espanso_match::regex::RegexMatcherState;
|
||||||
|
use espanso_match::rolling::matcher::RollingMatcherState;
|
||||||
|
|
||||||
use enum_as_inner::EnumAsInner;
|
use enum_as_inner::EnumAsInner;
|
||||||
|
|
||||||
pub mod rolling;
|
|
||||||
pub mod regex;
|
|
||||||
pub mod convert;
|
pub mod convert;
|
||||||
|
pub mod regex;
|
||||||
|
pub mod rolling;
|
||||||
|
|
||||||
#[derive(Clone, EnumAsInner)]
|
#[derive(Clone, EnumAsInner)]
|
||||||
pub enum MatcherState<'a> {
|
pub enum MatcherState<'a> {
|
||||||
|
@ -36,21 +36,18 @@ pub enum MatcherState<'a> {
|
||||||
Regex(RegexMatcherState),
|
Regex(RegexMatcherState),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<&MatcherEvent> for espanso_match::event::Event {
|
pub fn convert_to_match_event(event: &MatcherEvent) -> espanso_match::event::Event {
|
||||||
fn from(event: &MatcherEvent) -> Self {
|
|
||||||
match event {
|
match event {
|
||||||
MatcherEvent::Key { key, chars } => espanso_match::event::Event::Key {
|
MatcherEvent::Key { key, chars } => espanso_match::event::Event::Key {
|
||||||
key: key.clone().into(),
|
key: convert_to_match_key(key.clone()),
|
||||||
chars: chars.to_owned(),
|
chars: chars.to_owned(),
|
||||||
},
|
},
|
||||||
MatcherEvent::VirtualSeparator => espanso_match::event::Event::VirtualSeparator,
|
MatcherEvent::VirtualSeparator => espanso_match::event::Event::VirtualSeparator,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
impl From<espanso_match::MatchResult<i32>> for MatchResult {
|
pub fn convert_to_engine_result(result: espanso_match::MatchResult<i32>) -> MatchResult {
|
||||||
fn from(result: espanso_match::MatchResult<i32>) -> Self {
|
MatchResult {
|
||||||
Self {
|
|
||||||
id: result.id,
|
id: result.id,
|
||||||
trigger: result.trigger,
|
trigger: result.trigger,
|
||||||
left_separator: result.left_separator,
|
left_separator: result.left_separator,
|
||||||
|
@ -58,10 +55,8 @@ impl From<espanso_match::MatchResult<i32>> for MatchResult {
|
||||||
args: result.vars,
|
args: result.vars,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
impl From<Key> for espanso_match::event::Key {
|
pub fn convert_to_match_key(key: Key) -> espanso_match::event::Key {
|
||||||
fn from(key: Key) -> Self {
|
|
||||||
match key {
|
match key {
|
||||||
Key::Alt => espanso_match::event::Key::Alt,
|
Key::Alt => espanso_match::event::Key::Alt,
|
||||||
Key::CapsLock => espanso_match::event::Key::CapsLock,
|
Key::CapsLock => espanso_match::event::Key::CapsLock,
|
||||||
|
@ -105,4 +100,3 @@ impl From<Key> for espanso_match::event::Key {
|
||||||
Key::Other(_) => espanso_match::event::Key::Other,
|
Key::Other(_) => espanso_match::event::Key::Other,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
|
@ -17,10 +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 crate::engine::process::{MatchResult, Matcher, MatcherEvent};
|
use espanso_engine::process::{MatchResult, Matcher, MatcherEvent};
|
||||||
use espanso_match::regex::{RegexMatch, RegexMatcher, RegexMatcherOptions};
|
use espanso_match::regex::{RegexMatch, RegexMatcher, RegexMatcherOptions};
|
||||||
|
|
||||||
use super::MatcherState;
|
use super::{convert_to_engine_result, convert_to_match_event, MatcherState};
|
||||||
|
|
||||||
pub struct RegexMatcherAdapterOptions {
|
pub struct RegexMatcherAdapterOptions {
|
||||||
pub max_buffer_size: usize,
|
pub max_buffer_size: usize,
|
||||||
|
@ -32,9 +32,12 @@ pub struct RegexMatcherAdapter {
|
||||||
|
|
||||||
impl RegexMatcherAdapter {
|
impl RegexMatcherAdapter {
|
||||||
pub fn new(matches: &[RegexMatch<i32>], options: &RegexMatcherAdapterOptions) -> Self {
|
pub fn new(matches: &[RegexMatch<i32>], options: &RegexMatcherAdapterOptions) -> Self {
|
||||||
let matcher = RegexMatcher::new(matches, RegexMatcherOptions {
|
let matcher = RegexMatcher::new(
|
||||||
|
matches,
|
||||||
|
RegexMatcherOptions {
|
||||||
max_buffer_size: options.max_buffer_size,
|
max_buffer_size: options.max_buffer_size,
|
||||||
});
|
},
|
||||||
|
);
|
||||||
|
|
||||||
Self { matcher }
|
Self { matcher }
|
||||||
}
|
}
|
||||||
|
@ -55,12 +58,12 @@ impl<'a> Matcher<'a, MatcherState<'a>> for RegexMatcherAdapter {
|
||||||
panic!("invalid state type received in RegexMatcherAdapter")
|
panic!("invalid state type received in RegexMatcherAdapter")
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
let event = event.into();
|
let event = convert_to_match_event(event);
|
||||||
|
|
||||||
let (state, results) = self.matcher.process(prev_state, event);
|
let (state, results) = self.matcher.process(prev_state, event);
|
||||||
|
|
||||||
let enum_state = MatcherState::Regex(state);
|
let enum_state = MatcherState::Regex(state);
|
||||||
let results: Vec<MatchResult> = results.into_iter().map(|result| result.into()).collect();
|
let results: Vec<MatchResult> = results.into_iter().map(convert_to_engine_result).collect();
|
||||||
|
|
||||||
(enum_state, results)
|
(enum_state, results)
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,11 +22,9 @@ use espanso_match::rolling::{
|
||||||
RollingMatch,
|
RollingMatch,
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::engine::{
|
use espanso_engine::process::{MatchResult, Matcher, MatcherEvent};
|
||||||
process::{MatchResult, Matcher, MatcherEvent},
|
|
||||||
};
|
|
||||||
|
|
||||||
use super::MatcherState;
|
use super::{convert_to_engine_result, convert_to_match_event, MatcherState};
|
||||||
|
|
||||||
pub struct RollingMatcherAdapterOptions {
|
pub struct RollingMatcherAdapterOptions {
|
||||||
pub char_word_separators: Vec<String>,
|
pub char_word_separators: Vec<String>,
|
||||||
|
@ -65,12 +63,12 @@ impl<'a> Matcher<'a, MatcherState<'a>> for RollingMatcherAdapter {
|
||||||
panic!("invalid state type received in RollingMatcherAdapter")
|
panic!("invalid state type received in RollingMatcherAdapter")
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
let event = event.into();
|
let event = convert_to_match_event(event);
|
||||||
|
|
||||||
let (state, results) = self.matcher.process(prev_state, event);
|
let (state, results) = self.matcher.process(prev_state, event);
|
||||||
|
|
||||||
let enum_state = MatcherState::Rolling(state);
|
let enum_state = MatcherState::Rolling(state);
|
||||||
let results: Vec<MatchResult> = results.into_iter().map(|result| result.into()).collect();
|
let results: Vec<MatchResult> = results.into_iter().map(convert_to_engine_result).collect();
|
||||||
|
|
||||||
(enum_state, results)
|
(enum_state, results)
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,16 +19,14 @@
|
||||||
|
|
||||||
use espanso_config::matches::{Match, MatchEffect};
|
use espanso_config::matches::{Match, MatchEffect};
|
||||||
|
|
||||||
use crate::{
|
use crate::cli::worker::{builtin::BuiltInMatch, context::Context};
|
||||||
cli::worker::{builtin::BuiltInMatch, context::Context},
|
use espanso_engine::{
|
||||||
engine::{
|
|
||||||
event::{
|
event::{
|
||||||
internal::DetectedMatch,
|
internal::DetectedMatch,
|
||||||
internal::{ImageRequestedEvent, RenderingRequestedEvent, TextFormat},
|
internal::{ImageRequestedEvent, RenderingRequestedEvent, TextFormat},
|
||||||
EventType,
|
EventType,
|
||||||
},
|
},
|
||||||
process::Multiplexer,
|
process::Multiplexer,
|
||||||
},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
pub trait MatchProvider<'a> {
|
pub trait MatchProvider<'a> {
|
||||||
|
@ -46,7 +44,7 @@ pub struct MultiplexAdapter<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> MultiplexAdapter<'a> {
|
impl<'a> MultiplexAdapter<'a> {
|
||||||
pub fn new(provider: &'a dyn MatchProvider<'a>, context: &'a Context) -> Self {
|
pub fn new(provider: &'a dyn MatchProvider<'a>, context: &'a dyn Context) -> Self {
|
||||||
Self { provider, context }
|
Self { provider, context }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,9 +27,7 @@ use espanso_config::{
|
||||||
};
|
};
|
||||||
use espanso_render::{CasingStyle, Context, RenderOptions, Template, Value, Variable};
|
use espanso_render::{CasingStyle, Context, RenderOptions, Template, Value, Variable};
|
||||||
|
|
||||||
use crate::{
|
use espanso_engine::process::{Renderer, RendererError};
|
||||||
engine::process::{Renderer, RendererError},
|
|
||||||
};
|
|
||||||
|
|
||||||
pub trait MatchProvider<'a> {
|
pub trait MatchProvider<'a> {
|
||||||
fn matches(&self) -> Vec<&'a Match>;
|
fn matches(&self) -> Vec<&'a Match>;
|
||||||
|
@ -221,11 +219,14 @@ impl<'a> Renderer<'a> for RendererAdapter<'a> {
|
||||||
for (name, value) in trigger_vars {
|
for (name, value) in trigger_vars {
|
||||||
let mut params = espanso_render::Params::new();
|
let mut params = espanso_render::Params::new();
|
||||||
params.insert("echo".to_string(), Value::String(value));
|
params.insert("echo".to_string(), Value::String(value));
|
||||||
augmented.vars.insert(0, Variable {
|
augmented.vars.insert(
|
||||||
|
0,
|
||||||
|
Variable {
|
||||||
name,
|
name,
|
||||||
var_type: "echo".to_string(),
|
var_type: "echo".to_string(),
|
||||||
params,
|
params,
|
||||||
})
|
},
|
||||||
|
)
|
||||||
}
|
}
|
||||||
Some(augmented)
|
Some(augmented)
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -21,10 +21,11 @@ use std::path::Path;
|
||||||
|
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use crossbeam::channel::Sender;
|
use crossbeam::channel::Sender;
|
||||||
|
use espanso_engine::event::ExitMode;
|
||||||
use espanso_ipc::{EventHandlerResponse, IPCServer};
|
use espanso_ipc::{EventHandlerResponse, IPCServer};
|
||||||
use log::{error, warn};
|
use log::{error, warn};
|
||||||
|
|
||||||
use crate::{engine::event::ExitMode, ipc::IPCEvent};
|
use crate::ipc::IPCEvent;
|
||||||
|
|
||||||
pub fn initialize_and_spawn(runtime_dir: &Path, exit_notify: Sender<ExitMode>) -> Result<()> {
|
pub fn initialize_and_spawn(runtime_dir: &Path, exit_notify: Sender<ExitMode>) -> Result<()> {
|
||||||
let server = crate::ipc::create_worker_ipc_server(runtime_dir)?;
|
let server = crate::ipc::create_worker_ipc_server(runtime_dir)?;
|
||||||
|
@ -32,8 +33,8 @@ pub fn initialize_and_spawn(runtime_dir: &Path, exit_notify: Sender<ExitMode>) -
|
||||||
std::thread::Builder::new()
|
std::thread::Builder::new()
|
||||||
.name("worker-ipc-handler".to_string())
|
.name("worker-ipc-handler".to_string())
|
||||||
.spawn(move || {
|
.spawn(move || {
|
||||||
server.run(Box::new(move |event| {
|
server
|
||||||
match event {
|
.run(Box::new(move |event| match event {
|
||||||
IPCEvent::Exit => {
|
IPCEvent::Exit => {
|
||||||
if let Err(err) = exit_notify.send(ExitMode::Exit) {
|
if let Err(err) = exit_notify.send(ExitMode::Exit) {
|
||||||
error!(
|
error!(
|
||||||
|
@ -62,8 +63,8 @@ pub fn initialize_and_spawn(runtime_dir: &Path, exit_notify: Sender<ExitMode>) -
|
||||||
|
|
||||||
EventHandlerResponse::NoResponse
|
EventHandlerResponse::NoResponse
|
||||||
}
|
}
|
||||||
}
|
}))
|
||||||
})).expect("unable to spawn IPC server");
|
.expect("unable to spawn IPC server");
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|
|
@ -59,17 +59,17 @@ impl<'a> super::engine::process::middleware::render::MatchProvider<'a> for Match
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> crate::engine::process::MatchInfoProvider for MatchCache<'a> {
|
impl<'a> espanso_engine::process::MatchInfoProvider for MatchCache<'a> {
|
||||||
fn get_force_mode(&self, match_id: i32) -> Option<crate::engine::event::effect::TextInjectMode> {
|
fn get_force_mode(&self, match_id: i32) -> Option<espanso_engine::event::effect::TextInjectMode> {
|
||||||
let m = self.cache.get(&match_id)?;
|
let m = self.cache.get(&match_id)?;
|
||||||
if let MatchEffect::Text(text_effect) = &m.effect {
|
if let MatchEffect::Text(text_effect) = &m.effect {
|
||||||
if let Some(force_mode) = &text_effect.force_mode {
|
if let Some(force_mode) = &text_effect.force_mode {
|
||||||
match force_mode {
|
match force_mode {
|
||||||
espanso_config::matches::TextInjectMode::Keys => {
|
espanso_config::matches::TextInjectMode::Keys => {
|
||||||
return Some(crate::engine::event::effect::TextInjectMode::Keys)
|
return Some(espanso_engine::event::effect::TextInjectMode::Keys)
|
||||||
}
|
}
|
||||||
espanso_config::matches::TextInjectMode::Clipboard => {
|
espanso_config::matches::TextInjectMode::Clipboard => {
|
||||||
return Some(crate::engine::event::effect::TextInjectMode::Clipboard)
|
return Some(espanso_engine::event::effect::TextInjectMode::Clipboard)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -155,7 +155,7 @@ impl<'a> super::engine::process::middleware::multiplex::MatchProvider<'a>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> crate::engine::process::MatchProvider for CombinedMatchCache<'a> {
|
impl<'a> espanso_engine::process::MatchProvider for CombinedMatchCache<'a> {
|
||||||
fn get_all_matches_ids(&self) -> Vec<i32> {
|
fn get_all_matches_ids(&self) -> Vec<i32> {
|
||||||
let mut ids: Vec<i32> = self.builtin_match_cache.keys().copied().collect();
|
let mut ids: Vec<i32> = self.builtin_match_cache.keys().copied().collect();
|
||||||
ids.extend(self.user_match_cache.ids());
|
ids.extend(self.user_match_cache.ids());
|
||||||
|
|
|
@ -18,10 +18,10 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
use crossbeam::channel::unbounded;
|
use crossbeam::channel::unbounded;
|
||||||
|
use espanso_engine::event::ExitMode;
|
||||||
use log::{debug, error, info};
|
use log::{debug, error, info};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
engine::event::ExitMode,
|
|
||||||
exit_code::{
|
exit_code::{
|
||||||
WORKER_ALREADY_RUNNING, WORKER_EXIT_ALL_PROCESSES, WORKER_GENERAL_ERROR,
|
WORKER_ALREADY_RUNNING, WORKER_EXIT_ALL_PROCESSES, WORKER_GENERAL_ERROR,
|
||||||
WORKER_LEGACY_ALREADY_RUNNING, WORKER_RESTART, WORKER_SUCCESS,
|
WORKER_LEGACY_ALREADY_RUNNING, WORKER_RESTART, WORKER_SUCCESS,
|
||||||
|
@ -62,9 +62,7 @@ fn worker_main(args: CliModuleArgs) -> i32 {
|
||||||
let cli_args = args.cli_args.expect("missing cli_args in worker main");
|
let cli_args = args.cli_args.expect("missing cli_args in worker main");
|
||||||
|
|
||||||
// When restarted, the daemon passes the reason why the worker was restarted (config_change, etc)
|
// When restarted, the daemon passes the reason why the worker was restarted (config_change, etc)
|
||||||
let start_reason = cli_args
|
let start_reason = cli_args.value_of("start-reason").map(String::from);
|
||||||
.value_of("start-reason")
|
|
||||||
.map(String::from);
|
|
||||||
debug!("starting with start-reason = {:?}", start_reason);
|
debug!("starting with start-reason = {:?}", start_reason);
|
||||||
|
|
||||||
// Avoid running multiple worker instances
|
// Avoid running multiple worker instances
|
||||||
|
|
|
@ -1,77 +0,0 @@
|
||||||
/*
|
|
||||||
* 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 <https://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
use super::{ContextMenuHandler, Event, IconHandler, ImageInjector, SecureInputManager};
|
|
||||||
use super::{ModeProvider, Dispatcher, Executor, KeyInjector, TextInjector, HtmlInjector};
|
|
||||||
|
|
||||||
pub struct DefaultDispatcher<'a> {
|
|
||||||
executors: Vec<Box<dyn Executor + 'a>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> DefaultDispatcher<'a> {
|
|
||||||
pub fn new(
|
|
||||||
event_injector: &'a dyn TextInjector,
|
|
||||||
clipboard_injector: &'a dyn TextInjector,
|
|
||||||
mode_provider: &'a dyn ModeProvider,
|
|
||||||
key_injector: &'a dyn KeyInjector,
|
|
||||||
html_injector: &'a dyn HtmlInjector,
|
|
||||||
image_injector: &'a dyn ImageInjector,
|
|
||||||
context_menu_handler: &'a dyn ContextMenuHandler,
|
|
||||||
icon_handler: &'a dyn IconHandler,
|
|
||||||
secure_input_manager: &'a dyn SecureInputManager,
|
|
||||||
) -> Self {
|
|
||||||
Self {
|
|
||||||
executors: vec![
|
|
||||||
Box::new(super::executor::text_inject::TextInjectExecutor::new(
|
|
||||||
event_injector,
|
|
||||||
clipboard_injector,
|
|
||||||
mode_provider,
|
|
||||||
)),
|
|
||||||
Box::new(super::executor::key_inject::KeyInjectExecutor::new(
|
|
||||||
key_injector,
|
|
||||||
)),
|
|
||||||
Box::new(super::executor::html_inject::HtmlInjectExecutor::new(
|
|
||||||
html_injector,
|
|
||||||
)),
|
|
||||||
Box::new(super::executor::image_inject::ImageInjectExecutor::new(
|
|
||||||
image_injector,
|
|
||||||
)),
|
|
||||||
Box::new(super::executor::context_menu::ContextMenuExecutor::new(
|
|
||||||
context_menu_handler,
|
|
||||||
)),
|
|
||||||
Box::new(super::executor::icon_update::IconUpdateExecutor::new(
|
|
||||||
icon_handler,
|
|
||||||
)),
|
|
||||||
Box::new(super::executor::secure_input::SecureInputExecutor::new(
|
|
||||||
secure_input_manager,
|
|
||||||
)),
|
|
||||||
],
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> Dispatcher for DefaultDispatcher<'a> {
|
|
||||||
fn dispatch(&self, event: Event) {
|
|
||||||
for executor in self.executors.iter() {
|
|
||||||
if executor.execute(&event) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,53 +0,0 @@
|
||||||
/*
|
|
||||||
* 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 <https://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
use super::super::{Event, Executor};
|
|
||||||
use crate::engine::event::{ui::MenuItem, EventType};
|
|
||||||
use anyhow::Result;
|
|
||||||
use log::error;
|
|
||||||
|
|
||||||
pub trait ContextMenuHandler {
|
|
||||||
fn show_context_menu(&self, items: &[MenuItem]) -> Result<()>;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct ContextMenuExecutor<'a> {
|
|
||||||
handler: &'a dyn ContextMenuHandler,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> ContextMenuExecutor<'a> {
|
|
||||||
pub fn new(handler: &'a dyn ContextMenuHandler) -> Self {
|
|
||||||
Self { handler }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> Executor for ContextMenuExecutor<'a> {
|
|
||||||
fn execute(&self, event: &Event) -> bool {
|
|
||||||
if let EventType::ShowContextMenu(context_menu_event) = &event.etype {
|
|
||||||
if let Err(error) = self.handler.show_context_menu(&context_menu_event.items) {
|
|
||||||
error!("context menu handler reported an error: {:?}", error);
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: test
|
|
|
@ -1,61 +0,0 @@
|
||||||
/*
|
|
||||||
* 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 <https://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
use super::super::{Event, Executor};
|
|
||||||
use crate::engine::event::EventType;
|
|
||||||
use anyhow::Result;
|
|
||||||
use log::error;
|
|
||||||
|
|
||||||
pub trait HtmlInjector {
|
|
||||||
fn inject_html(&self, html: &str, fallback: &str) -> Result<()>;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct HtmlInjectExecutor<'a> {
|
|
||||||
injector: &'a dyn HtmlInjector,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> HtmlInjectExecutor<'a> {
|
|
||||||
pub fn new(injector: &'a dyn HtmlInjector) -> Self {
|
|
||||||
Self { injector }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> Executor for HtmlInjectExecutor<'a> {
|
|
||||||
fn execute(&self, event: &Event) -> bool {
|
|
||||||
if let EventType::HtmlInject(inject_event) = &event.etype {
|
|
||||||
// Render the text fallback for those applications that don't support HTML clipboard
|
|
||||||
let decorator = html2text::render::text_renderer::TrivialDecorator::new();
|
|
||||||
let fallback_text =
|
|
||||||
html2text::from_read_with_decorator(inject_event.html.as_bytes(), 1000000, decorator);
|
|
||||||
|
|
||||||
if let Err(error) = self
|
|
||||||
.injector
|
|
||||||
.inject_html(&inject_event.html, &fallback_text)
|
|
||||||
{
|
|
||||||
error!("html injector reported an error: {:?}", error);
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: test
|
|
|
@ -1,53 +0,0 @@
|
||||||
/*
|
|
||||||
* 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 <https://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
use super::super::{Event, Executor};
|
|
||||||
use crate::engine::event::{EventType, ui::{IconStatus}};
|
|
||||||
use anyhow::Result;
|
|
||||||
use log::error;
|
|
||||||
|
|
||||||
pub trait IconHandler {
|
|
||||||
fn update_icon(&self, status: &IconStatus) -> Result<()>;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct IconUpdateExecutor<'a> {
|
|
||||||
handler: &'a dyn IconHandler,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> IconUpdateExecutor<'a> {
|
|
||||||
pub fn new(handler: &'a dyn IconHandler) -> Self {
|
|
||||||
Self { handler }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> Executor for IconUpdateExecutor<'a> {
|
|
||||||
fn execute(&self, event: &Event) -> bool {
|
|
||||||
if let EventType::IconStatusChange(m_event) = &event.etype {
|
|
||||||
if let Err(error) = self.handler.update_icon(&m_event.status) {
|
|
||||||
error!("icon handler reported an error: {:?}", error);
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: test
|
|
|
@ -1,56 +0,0 @@
|
||||||
/*
|
|
||||||
* 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 <https://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
use super::super::{Event, Executor};
|
|
||||||
use crate::engine::event::EventType;
|
|
||||||
use anyhow::Result;
|
|
||||||
use log::error;
|
|
||||||
|
|
||||||
pub trait ImageInjector {
|
|
||||||
fn inject_image(&self, path: &str) -> Result<()>;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct ImageInjectExecutor<'a> {
|
|
||||||
injector: &'a dyn ImageInjector,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> ImageInjectExecutor<'a> {
|
|
||||||
pub fn new(injector: &'a dyn ImageInjector) -> Self {
|
|
||||||
Self { injector }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> Executor for ImageInjectExecutor<'a> {
|
|
||||||
fn execute(&self, event: &Event) -> bool {
|
|
||||||
if let EventType::ImageInject(inject_event) = &event.etype {
|
|
||||||
if let Err(error) = self
|
|
||||||
.injector
|
|
||||||
.inject_image(&inject_event.image_path)
|
|
||||||
{
|
|
||||||
error!("image injector reported an error: {:?}", error);
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: test
|
|
|
@ -1,46 +0,0 @@
|
||||||
/*
|
|
||||||
* 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 <https://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
use crate::engine::event::EventType;
|
|
||||||
|
|
||||||
use super::super::{Event, Executor, KeyInjector};
|
|
||||||
use log::error;
|
|
||||||
|
|
||||||
pub struct KeyInjectExecutor<'a> {
|
|
||||||
injector: &'a dyn KeyInjector,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> KeyInjectExecutor<'a> {
|
|
||||||
pub fn new(injector: &'a dyn KeyInjector) -> Self {
|
|
||||||
Self { injector }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> Executor for KeyInjectExecutor<'a> {
|
|
||||||
fn execute(&self, event: &Event) -> bool {
|
|
||||||
if let EventType::KeySequenceInject(inject_event) = &event.etype {
|
|
||||||
if let Err(error) = self.injector.inject_sequence(&inject_event.keys) {
|
|
||||||
error!("key injector reported an error: {}", error);
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
false
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,26 +0,0 @@
|
||||||
/*
|
|
||||||
* 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 <https://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
pub mod context_menu;
|
|
||||||
pub mod icon_update;
|
|
||||||
pub mod image_inject;
|
|
||||||
pub mod html_inject;
|
|
||||||
pub mod key_inject;
|
|
||||||
pub mod secure_input;
|
|
||||||
pub mod text_inject;
|
|
|
@ -1,58 +0,0 @@
|
||||||
/*
|
|
||||||
* 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 <https://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
use crate::engine::event::EventType;
|
|
||||||
|
|
||||||
use super::super::{Event, Executor};
|
|
||||||
use anyhow::Result;
|
|
||||||
use log::error;
|
|
||||||
|
|
||||||
pub trait SecureInputManager {
|
|
||||||
fn display_secure_input_troubleshoot(&self) -> Result<()>;
|
|
||||||
fn launch_secure_input_autofix(&self) -> Result<()>;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct SecureInputExecutor<'a> {
|
|
||||||
manager: &'a dyn SecureInputManager,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> SecureInputExecutor<'a> {
|
|
||||||
pub fn new(manager: &'a dyn SecureInputManager) -> Self {
|
|
||||||
Self { manager }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> Executor for SecureInputExecutor<'a> {
|
|
||||||
fn execute(&self, event: &Event) -> bool {
|
|
||||||
if let EventType::DisplaySecureInputTroubleshoot = &event.etype {
|
|
||||||
if let Err(error) = self.manager.display_secure_input_troubleshoot() {
|
|
||||||
error!("unable to display secure input troubleshoot: {}", error);
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
} else if let EventType::LaunchSecureInputAutoFix = &event.etype {
|
|
||||||
if let Err(error) = self.manager.launch_secure_input_autofix() {
|
|
||||||
error!("unable to launch secure input autofix: {}", error);
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
false
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,108 +0,0 @@
|
||||||
/*
|
|
||||||
* 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 <https://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
use anyhow::Result;
|
|
||||||
use super::super::{Event, Executor};
|
|
||||||
use crate::engine::event::{EventType, effect::TextInjectMode};
|
|
||||||
use log::{error, trace};
|
|
||||||
|
|
||||||
pub trait TextInjector {
|
|
||||||
fn name(&self) -> &'static str;
|
|
||||||
fn inject_text(&self, text: &str) -> Result<()>;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub trait ModeProvider {
|
|
||||||
fn active_mode(&self) -> Mode;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub enum Mode {
|
|
||||||
Event,
|
|
||||||
Clipboard,
|
|
||||||
Auto {
|
|
||||||
// Maximum size after which the clipboard backend
|
|
||||||
// is used over the event one to speed up the injection.
|
|
||||||
clipboard_threshold: usize,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct TextInjectExecutor<'a> {
|
|
||||||
event_injector: &'a dyn TextInjector,
|
|
||||||
clipboard_injector: &'a dyn TextInjector,
|
|
||||||
mode_provider: &'a dyn ModeProvider,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> TextInjectExecutor<'a> {
|
|
||||||
pub fn new(
|
|
||||||
event_injector: &'a dyn TextInjector,
|
|
||||||
clipboard_injector: &'a dyn TextInjector,
|
|
||||||
mode_provider: &'a dyn ModeProvider,
|
|
||||||
) -> Self {
|
|
||||||
Self {
|
|
||||||
event_injector,
|
|
||||||
clipboard_injector,
|
|
||||||
mode_provider,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> Executor for TextInjectExecutor<'a> {
|
|
||||||
fn execute(&self, event: &Event) -> bool {
|
|
||||||
if let EventType::TextInject(inject_event) = &event.etype {
|
|
||||||
let active_mode = self.mode_provider.active_mode();
|
|
||||||
|
|
||||||
let injector = if let Some(force_mode) = &inject_event.force_mode {
|
|
||||||
if let TextInjectMode::Keys = force_mode {
|
|
||||||
self.event_injector
|
|
||||||
} else {
|
|
||||||
self.clipboard_injector
|
|
||||||
}
|
|
||||||
} else if let Mode::Clipboard = active_mode {
|
|
||||||
self.clipboard_injector
|
|
||||||
} else if let Mode::Event = active_mode {
|
|
||||||
self.event_injector
|
|
||||||
} else if let Mode::Auto { clipboard_threshold } = active_mode {
|
|
||||||
if inject_event.text.chars().count() > clipboard_threshold {
|
|
||||||
self.clipboard_injector
|
|
||||||
} else if cfg!(target_os = "linux") {
|
|
||||||
if inject_event.text.chars().all(|c| c.is_ascii()) {
|
|
||||||
self.event_injector
|
|
||||||
} else {
|
|
||||||
self.clipboard_injector
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
self.event_injector
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
self.event_injector
|
|
||||||
};
|
|
||||||
|
|
||||||
trace!("using injector: {}", injector.name());
|
|
||||||
|
|
||||||
if let Err(error) = injector.inject_text(&inject_event.text) {
|
|
||||||
error!("text injector ({}) reported an error: {:?}", injector.name(), error);
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: test
|
|
|
@ -1,70 +0,0 @@
|
||||||
/*
|
|
||||||
* 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 <https://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
use anyhow::Result;
|
|
||||||
|
|
||||||
use super::{event::input::Key, Event};
|
|
||||||
|
|
||||||
mod default;
|
|
||||||
mod executor;
|
|
||||||
|
|
||||||
pub trait Executor {
|
|
||||||
fn execute(&self, event: &Event) -> bool;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub trait Dispatcher {
|
|
||||||
fn dispatch(&self, event: Event);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Re-export dependency injection entities
|
|
||||||
pub use executor::html_inject::HtmlInjector;
|
|
||||||
pub use executor::text_inject::{Mode, ModeProvider, TextInjector};
|
|
||||||
pub use executor::image_inject::{ImageInjector};
|
|
||||||
pub use executor::context_menu::{ContextMenuHandler};
|
|
||||||
pub use executor::icon_update::IconHandler;
|
|
||||||
pub use executor::secure_input::SecureInputManager;
|
|
||||||
|
|
||||||
// TODO: move into module
|
|
||||||
pub trait KeyInjector {
|
|
||||||
fn inject_sequence(&self, keys: &[Key]) -> Result<()>;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn default<'a>(
|
|
||||||
event_injector: &'a dyn TextInjector,
|
|
||||||
clipboard_injector: &'a dyn TextInjector,
|
|
||||||
mode_provider: &'a dyn ModeProvider,
|
|
||||||
key_injector: &'a dyn KeyInjector,
|
|
||||||
html_injector: &'a dyn HtmlInjector,
|
|
||||||
image_injector: &'a dyn ImageInjector,
|
|
||||||
context_menu_handler: &'a dyn ContextMenuHandler,
|
|
||||||
icon_handler: &'a dyn IconHandler,
|
|
||||||
secure_input_manager: &'a dyn SecureInputManager,
|
|
||||||
) -> impl Dispatcher + 'a {
|
|
||||||
default::DefaultDispatcher::new(
|
|
||||||
event_injector,
|
|
||||||
clipboard_injector,
|
|
||||||
mode_provider,
|
|
||||||
key_injector,
|
|
||||||
html_injector,
|
|
||||||
image_injector,
|
|
||||||
context_menu_handler,
|
|
||||||
icon_handler,
|
|
||||||
secure_input_manager,
|
|
||||||
)
|
|
||||||
}
|
|
|
@ -1,63 +0,0 @@
|
||||||
/*
|
|
||||||
* 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 <https://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
use super::input::Key;
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
|
||||||
pub struct TriggerCompensationEvent {
|
|
||||||
pub trigger: String,
|
|
||||||
pub left_separator: Option<String>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
|
||||||
pub struct CursorHintCompensationEvent {
|
|
||||||
pub cursor_hint_back_count: usize,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
|
||||||
pub struct TextInjectRequest {
|
|
||||||
pub text: String,
|
|
||||||
pub force_mode: Option<TextInjectMode>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
|
||||||
pub struct MarkdownInjectRequest {
|
|
||||||
pub markdown: String,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
|
||||||
pub struct HtmlInjectRequest {
|
|
||||||
pub html: String,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Clone)]
|
|
||||||
pub enum TextInjectMode {
|
|
||||||
Keys,
|
|
||||||
Clipboard,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
|
||||||
pub struct KeySequenceInjectRequest {
|
|
||||||
pub keys: Vec<Key>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
|
||||||
pub struct ImageInjectRequest {
|
|
||||||
pub image_path: String,
|
|
||||||
}
|
|
|
@ -1,123 +0,0 @@
|
||||||
/*
|
|
||||||
* 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 <https://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Clone)]
|
|
||||||
pub enum Status {
|
|
||||||
Pressed,
|
|
||||||
Released,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Clone)]
|
|
||||||
pub enum Variant {
|
|
||||||
Left,
|
|
||||||
Right,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Clone)]
|
|
||||||
pub struct KeyboardEvent {
|
|
||||||
pub key: Key,
|
|
||||||
pub value: Option<String>,
|
|
||||||
pub status: Status,
|
|
||||||
pub variant: Option<Variant>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
|
||||||
pub enum MouseButton {
|
|
||||||
Left,
|
|
||||||
Right,
|
|
||||||
Middle,
|
|
||||||
Button1,
|
|
||||||
Button2,
|
|
||||||
Button3,
|
|
||||||
Button4,
|
|
||||||
Button5,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
|
||||||
pub struct MouseEvent {
|
|
||||||
pub button: MouseButton,
|
|
||||||
pub status: Status,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
|
||||||
pub enum Key {
|
|
||||||
// Modifiers
|
|
||||||
Alt,
|
|
||||||
CapsLock,
|
|
||||||
Control,
|
|
||||||
Meta,
|
|
||||||
NumLock,
|
|
||||||
Shift,
|
|
||||||
|
|
||||||
// Whitespace
|
|
||||||
Enter,
|
|
||||||
Tab,
|
|
||||||
Space,
|
|
||||||
|
|
||||||
// Navigation
|
|
||||||
ArrowDown,
|
|
||||||
ArrowLeft,
|
|
||||||
ArrowRight,
|
|
||||||
ArrowUp,
|
|
||||||
End,
|
|
||||||
Home,
|
|
||||||
PageDown,
|
|
||||||
PageUp,
|
|
||||||
|
|
||||||
// UI
|
|
||||||
Escape,
|
|
||||||
|
|
||||||
// Editing keys
|
|
||||||
Backspace,
|
|
||||||
|
|
||||||
// Function keys
|
|
||||||
F1,
|
|
||||||
F2,
|
|
||||||
F3,
|
|
||||||
F4,
|
|
||||||
F5,
|
|
||||||
F6,
|
|
||||||
F7,
|
|
||||||
F8,
|
|
||||||
F9,
|
|
||||||
F10,
|
|
||||||
F11,
|
|
||||||
F12,
|
|
||||||
F13,
|
|
||||||
F14,
|
|
||||||
F15,
|
|
||||||
F16,
|
|
||||||
F17,
|
|
||||||
F18,
|
|
||||||
F19,
|
|
||||||
F20,
|
|
||||||
|
|
||||||
// Other keys, includes the raw code provided by the operating system
|
|
||||||
Other(i32),
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
|
||||||
pub struct ContextMenuClickedEvent {
|
|
||||||
pub context_item_id: u32,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
|
||||||
pub struct HotKeyEvent {
|
|
||||||
pub hotkey_id: i32,
|
|
||||||
}
|
|
|
@ -1,91 +0,0 @@
|
||||||
/*
|
|
||||||
* 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 <https://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
use std::collections::HashMap;
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
|
||||||
pub struct MatchesDetectedEvent {
|
|
||||||
pub matches: Vec<DetectedMatch>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Default)]
|
|
||||||
pub struct DetectedMatch {
|
|
||||||
pub id: i32,
|
|
||||||
pub trigger: Option<String>,
|
|
||||||
pub left_separator: Option<String>,
|
|
||||||
pub right_separator: Option<String>,
|
|
||||||
pub args: HashMap<String, String>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
|
||||||
pub struct MatchSelectedEvent {
|
|
||||||
pub chosen: DetectedMatch,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
|
||||||
pub struct CauseCompensatedMatchEvent {
|
|
||||||
pub m: DetectedMatch,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
|
||||||
pub struct RenderingRequestedEvent {
|
|
||||||
pub match_id: i32,
|
|
||||||
pub trigger: Option<String>,
|
|
||||||
pub left_separator: Option<String>,
|
|
||||||
pub right_separator: Option<String>,
|
|
||||||
pub trigger_args: HashMap<String, String>,
|
|
||||||
pub format: TextFormat,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
|
||||||
pub enum TextFormat {
|
|
||||||
Plain,
|
|
||||||
Markdown,
|
|
||||||
Html,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
|
||||||
pub struct ImageRequestedEvent {
|
|
||||||
pub match_id: i32,
|
|
||||||
pub image_path: String,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
|
||||||
pub struct ImageResolvedEvent {
|
|
||||||
pub image_path: String,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
|
||||||
pub struct RenderedEvent {
|
|
||||||
pub match_id: i32,
|
|
||||||
pub body: String,
|
|
||||||
pub format: TextFormat,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
|
||||||
pub struct DiscardPreviousEvent {
|
|
||||||
// All Events with a source_id smaller than this one will be discarded
|
|
||||||
pub minimum_source_id: u32,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
|
||||||
pub struct SecureInputEnabledEvent {
|
|
||||||
pub app_name: String,
|
|
||||||
pub app_path: String,
|
|
||||||
}
|
|
|
@ -1,106 +0,0 @@
|
||||||
/*
|
|
||||||
* 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 <https://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
pub mod input;
|
|
||||||
pub mod effect;
|
|
||||||
pub mod internal;
|
|
||||||
pub mod ui;
|
|
||||||
|
|
||||||
pub type SourceId = u32;
|
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
|
||||||
pub struct Event {
|
|
||||||
// The source id is a unique, monothonically increasing number
|
|
||||||
// that is given to each event by the source and is propagated
|
|
||||||
// to all consequential events.
|
|
||||||
// For example, if a keyboard event with source_id = 5 generates
|
|
||||||
// a detected match event, this event will have source_id = 5
|
|
||||||
pub source_id: SourceId,
|
|
||||||
pub etype: EventType,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Event {
|
|
||||||
pub fn caused_by(cause_id: SourceId, event_type: EventType) -> Event {
|
|
||||||
Event {
|
|
||||||
source_id: cause_id,
|
|
||||||
etype: event_type,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
|
||||||
pub enum EventType {
|
|
||||||
NOOP,
|
|
||||||
ProcessingError(String),
|
|
||||||
ExitRequested(ExitMode),
|
|
||||||
Exit(ExitMode),
|
|
||||||
Heartbeat,
|
|
||||||
|
|
||||||
// Inputs
|
|
||||||
Keyboard(input::KeyboardEvent),
|
|
||||||
Mouse(input::MouseEvent),
|
|
||||||
HotKey(input::HotKeyEvent),
|
|
||||||
TrayIconClicked,
|
|
||||||
ContextMenuClicked(input::ContextMenuClickedEvent),
|
|
||||||
|
|
||||||
// Internal
|
|
||||||
MatchesDetected(internal::MatchesDetectedEvent),
|
|
||||||
MatchSelected(internal::MatchSelectedEvent),
|
|
||||||
CauseCompensatedMatch(internal::CauseCompensatedMatchEvent),
|
|
||||||
|
|
||||||
RenderingRequested(internal::RenderingRequestedEvent),
|
|
||||||
ImageRequested(internal::ImageRequestedEvent),
|
|
||||||
Rendered(internal::RenderedEvent),
|
|
||||||
ImageResolved(internal::ImageResolvedEvent),
|
|
||||||
MatchInjected,
|
|
||||||
DiscardPrevious(internal::DiscardPreviousEvent),
|
|
||||||
|
|
||||||
Disabled,
|
|
||||||
Enabled,
|
|
||||||
DisableRequest,
|
|
||||||
EnableRequest,
|
|
||||||
SecureInputEnabled(internal::SecureInputEnabledEvent),
|
|
||||||
SecureInputDisabled,
|
|
||||||
|
|
||||||
// Effects
|
|
||||||
TriggerCompensation(effect::TriggerCompensationEvent),
|
|
||||||
CursorHintCompensation(effect::CursorHintCompensationEvent),
|
|
||||||
|
|
||||||
KeySequenceInject(effect::KeySequenceInjectRequest),
|
|
||||||
TextInject(effect::TextInjectRequest),
|
|
||||||
MarkdownInject(effect::MarkdownInjectRequest),
|
|
||||||
HtmlInject(effect::HtmlInjectRequest),
|
|
||||||
ImageInject(effect::ImageInjectRequest),
|
|
||||||
|
|
||||||
// UI
|
|
||||||
ShowContextMenu(ui::ShowContextMenuEvent),
|
|
||||||
IconStatusChange(ui::IconStatusChangeEvent),
|
|
||||||
DisplaySecureInputTroubleshoot,
|
|
||||||
ShowSearchBar,
|
|
||||||
|
|
||||||
// Other
|
|
||||||
LaunchSecureInputAutoFix,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
|
||||||
pub enum ExitMode {
|
|
||||||
Exit,
|
|
||||||
ExitAllProcesses,
|
|
||||||
RestartWorker,
|
|
||||||
}
|
|
|
@ -1,54 +0,0 @@
|
||||||
/*
|
|
||||||
* 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 <https://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
|
||||||
pub struct ShowContextMenuEvent {
|
|
||||||
pub items: Vec<MenuItem>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
|
||||||
pub enum MenuItem {
|
|
||||||
Simple(SimpleMenuItem),
|
|
||||||
Sub(SubMenuItem),
|
|
||||||
Separator,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
|
||||||
pub struct SimpleMenuItem {
|
|
||||||
pub id: u32,
|
|
||||||
pub label: String,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
|
||||||
pub struct SubMenuItem {
|
|
||||||
pub label: String,
|
|
||||||
pub items: Vec<MenuItem>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
|
||||||
pub struct IconStatusChangeEvent {
|
|
||||||
pub status: IconStatus
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
|
||||||
pub enum IconStatus {
|
|
||||||
Enabled,
|
|
||||||
Disabled,
|
|
||||||
SecureInputDisabled,
|
|
||||||
}
|
|
|
@ -1,56 +0,0 @@
|
||||||
/*
|
|
||||||
* 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 <https://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
use crossbeam::channel::Select;
|
|
||||||
|
|
||||||
use super::{Funnel, FunnelResult, Source};
|
|
||||||
|
|
||||||
pub struct DefaultFunnel<'a> {
|
|
||||||
sources: &'a [&'a dyn Source<'a>],
|
|
||||||
}
|
|
||||||
|
|
||||||
impl <'a> DefaultFunnel<'a> {
|
|
||||||
pub fn new(sources: &'a [&'a dyn Source<'a>]) -> Self {
|
|
||||||
Self {
|
|
||||||
sources
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl <'a> Funnel for DefaultFunnel<'a> {
|
|
||||||
fn receive(&self) -> FunnelResult {
|
|
||||||
let mut select = Select::new();
|
|
||||||
|
|
||||||
// First register all the sources to the select operation
|
|
||||||
for source in self.sources.iter() {
|
|
||||||
source.register(&mut select);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Wait for the first source (blocking operation)
|
|
||||||
let op = select.select();
|
|
||||||
let source = self
|
|
||||||
.sources
|
|
||||||
.get(op.index())
|
|
||||||
.expect("invalid source index returned by select operation");
|
|
||||||
|
|
||||||
// Receive (and convert) the event
|
|
||||||
let event = source.receive(op);
|
|
||||||
FunnelResult::Event(event)
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,44 +0,0 @@
|
||||||
/*
|
|
||||||
* 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 <https://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
use crossbeam::{channel::Select, channel::SelectedOperation};
|
|
||||||
|
|
||||||
use self::default::DefaultFunnel;
|
|
||||||
|
|
||||||
use super::Event;
|
|
||||||
|
|
||||||
mod default;
|
|
||||||
|
|
||||||
pub trait Source<'a> {
|
|
||||||
fn register<'b>(&'a self, select: &mut Select<'a>) -> usize;
|
|
||||||
fn receive<'b>(&'a self, op: SelectedOperation) -> Event;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub trait Funnel {
|
|
||||||
fn receive(&self) -> FunnelResult;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub enum FunnelResult {
|
|
||||||
Event(Event),
|
|
||||||
EndOfStream,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn default<'a>(sources: &'a [&'a dyn Source<'a>]) -> impl Funnel + 'a {
|
|
||||||
DefaultFunnel::new(sources)
|
|
||||||
}
|
|
|
@ -1,65 +0,0 @@
|
||||||
/*
|
|
||||||
* 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 <https://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
use log::{debug};
|
|
||||||
|
|
||||||
use self::{dispatch::Dispatcher, event::{Event, EventType, ExitMode}, funnel::{Funnel, FunnelResult}, process::Processor};
|
|
||||||
|
|
||||||
pub mod dispatch;
|
|
||||||
pub mod event;
|
|
||||||
pub mod process;
|
|
||||||
pub mod funnel;
|
|
||||||
|
|
||||||
pub struct Engine<'a> {
|
|
||||||
funnel: &'a dyn Funnel,
|
|
||||||
processor: &'a mut dyn Processor,
|
|
||||||
dispatcher: &'a dyn Dispatcher,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl <'a> Engine<'a> {
|
|
||||||
pub fn new(funnel: &'a dyn Funnel, processor: &'a mut dyn Processor, dispatcher: &'a dyn Dispatcher) -> Self {
|
|
||||||
Self {
|
|
||||||
funnel,
|
|
||||||
processor,
|
|
||||||
dispatcher,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn run(&mut self) -> ExitMode {
|
|
||||||
loop {
|
|
||||||
match self.funnel.receive() {
|
|
||||||
FunnelResult::Event(event) => {
|
|
||||||
let processed_events = self.processor.process(event);
|
|
||||||
for event in processed_events {
|
|
||||||
if let EventType::Exit(mode) = &event.etype {
|
|
||||||
debug!("exit event received with mode {:?}, exiting engine", mode);
|
|
||||||
return mode.clone();
|
|
||||||
}
|
|
||||||
|
|
||||||
self.dispatcher.dispatch(event);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
FunnelResult::EndOfStream => {
|
|
||||||
debug!("end of stream received");
|
|
||||||
return ExitMode::Exit;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,124 +0,0 @@
|
||||||
/*
|
|
||||||
* 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 <https://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
use log::trace;
|
|
||||||
|
|
||||||
use super::{DisableOptions, MatchFilter, MatchInfoProvider, MatchProvider, MatchSelector, Matcher, MatcherMiddlewareConfigProvider, Middleware, Multiplexer, PathProvider, Processor, Renderer, middleware::{
|
|
||||||
match_select::MatchSelectMiddleware, matcher::MatcherMiddleware, multiplex::MultiplexMiddleware,
|
|
||||||
render::RenderMiddleware, action::{ActionMiddleware, EventSequenceProvider}, cursor_hint::CursorHintMiddleware, cause::CauseCompensateMiddleware,
|
|
||||||
delay_modifiers::{DelayForModifierReleaseMiddleware, ModifierStatusProvider}, markdown::MarkdownMiddleware,
|
|
||||||
past_discard::PastEventsDiscardMiddleware,
|
|
||||||
}};
|
|
||||||
use crate::engine::{event::{Event, EventType}, process::middleware::{context_menu::ContextMenuMiddleware, disable::DisableMiddleware, exit::ExitMiddleware, hotkey::HotKeyMiddleware, icon_status::IconStatusMiddleware, image_resolve::ImageResolverMiddleware, search::SearchMiddleware}};
|
|
||||||
use std::collections::VecDeque;
|
|
||||||
|
|
||||||
pub struct DefaultProcessor<'a> {
|
|
||||||
event_queue: VecDeque<Event>,
|
|
||||||
middleware: Vec<Box<dyn Middleware + 'a>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> DefaultProcessor<'a> {
|
|
||||||
pub fn new<MatcherState>(
|
|
||||||
matchers: &'a [&'a dyn Matcher<'a, MatcherState>],
|
|
||||||
match_filter: &'a dyn MatchFilter,
|
|
||||||
match_selector: &'a dyn MatchSelector,
|
|
||||||
multiplexer: &'a dyn Multiplexer,
|
|
||||||
renderer: &'a dyn Renderer<'a>,
|
|
||||||
match_info_provider: &'a dyn MatchInfoProvider,
|
|
||||||
modifier_status_provider: &'a dyn ModifierStatusProvider,
|
|
||||||
event_sequence_provider: &'a dyn EventSequenceProvider,
|
|
||||||
path_provider: &'a dyn PathProvider,
|
|
||||||
disable_options: DisableOptions,
|
|
||||||
matcher_options_provider: &'a dyn MatcherMiddlewareConfigProvider,
|
|
||||||
match_provider: &'a dyn MatchProvider,
|
|
||||||
) -> DefaultProcessor<'a> {
|
|
||||||
Self {
|
|
||||||
event_queue: VecDeque::new(),
|
|
||||||
middleware: vec![
|
|
||||||
Box::new(PastEventsDiscardMiddleware::new()),
|
|
||||||
Box::new(DisableMiddleware::new(disable_options)),
|
|
||||||
Box::new(IconStatusMiddleware::new()),
|
|
||||||
Box::new(MatcherMiddleware::new(matchers, matcher_options_provider)),
|
|
||||||
Box::new(ContextMenuMiddleware::new()),
|
|
||||||
Box::new(HotKeyMiddleware::new()),
|
|
||||||
Box::new(MatchSelectMiddleware::new(match_filter, match_selector)),
|
|
||||||
Box::new(CauseCompensateMiddleware::new()),
|
|
||||||
Box::new(MultiplexMiddleware::new(multiplexer)),
|
|
||||||
Box::new(RenderMiddleware::new(renderer)),
|
|
||||||
Box::new(ImageResolverMiddleware::new(path_provider)),
|
|
||||||
Box::new(CursorHintMiddleware::new()),
|
|
||||||
Box::new(ExitMiddleware::new()),
|
|
||||||
Box::new(ActionMiddleware::new(match_info_provider, event_sequence_provider)),
|
|
||||||
Box::new(SearchMiddleware::new(match_provider)),
|
|
||||||
Box::new(MarkdownMiddleware::new()),
|
|
||||||
Box::new(DelayForModifierReleaseMiddleware::new(modifier_status_provider)),
|
|
||||||
],
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn process_one(&mut self) -> Option<Event> {
|
|
||||||
if let Some(event) = self.event_queue.pop_back() {
|
|
||||||
let mut current_event = event;
|
|
||||||
|
|
||||||
let mut current_queue = VecDeque::new();
|
|
||||||
let mut dispatch = |event: Event| {
|
|
||||||
trace!("dispatched event: {:?}", event);
|
|
||||||
current_queue.push_front(event);
|
|
||||||
};
|
|
||||||
|
|
||||||
trace!("--------------- new event -----------------");
|
|
||||||
for middleware in self.middleware.iter() {
|
|
||||||
trace!("middleware '{}' received event: {:?}", middleware.name(), current_event);
|
|
||||||
|
|
||||||
current_event = middleware.next(current_event, &mut dispatch);
|
|
||||||
|
|
||||||
trace!("middleware '{}' produced event: {:?}", middleware.name(), current_event);
|
|
||||||
|
|
||||||
if let EventType::NOOP = current_event.etype {
|
|
||||||
trace!("interrupting chain as the event is NOOP");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
while let Some(event) = current_queue.pop_back() {
|
|
||||||
self.event_queue.push_front(event);
|
|
||||||
}
|
|
||||||
|
|
||||||
Some(current_event)
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> Processor for DefaultProcessor<'a> {
|
|
||||||
fn process(&mut self, event: Event) -> Vec<Event> {
|
|
||||||
self.event_queue.push_front(event);
|
|
||||||
|
|
||||||
let mut processed_events = Vec::new();
|
|
||||||
|
|
||||||
while !self.event_queue.is_empty() {
|
|
||||||
if let Some(event) = self.process_one() {
|
|
||||||
processed_events.push(event);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
processed_events
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,136 +0,0 @@
|
||||||
/*
|
|
||||||
* 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 <https://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
use super::super::Middleware;
|
|
||||||
use crate::engine::event::{
|
|
||||||
effect::{
|
|
||||||
HtmlInjectRequest, ImageInjectRequest, KeySequenceInjectRequest, MarkdownInjectRequest,
|
|
||||||
TextInjectMode, TextInjectRequest,
|
|
||||||
},
|
|
||||||
input::Key,
|
|
||||||
internal::{DiscardPreviousEvent, TextFormat},
|
|
||||||
Event, EventType,
|
|
||||||
};
|
|
||||||
|
|
||||||
pub trait MatchInfoProvider {
|
|
||||||
fn get_force_mode(&self, match_id: i32) -> Option<TextInjectMode>;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub trait EventSequenceProvider {
|
|
||||||
fn get_next_id(&self) -> u32;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct ActionMiddleware<'a> {
|
|
||||||
match_info_provider: &'a dyn MatchInfoProvider,
|
|
||||||
event_sequence_provider: &'a dyn EventSequenceProvider,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> ActionMiddleware<'a> {
|
|
||||||
pub fn new(
|
|
||||||
match_info_provider: &'a dyn MatchInfoProvider,
|
|
||||||
event_sequence_provider: &'a dyn EventSequenceProvider,
|
|
||||||
) -> Self {
|
|
||||||
Self {
|
|
||||||
match_info_provider,
|
|
||||||
event_sequence_provider,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> Middleware for ActionMiddleware<'a> {
|
|
||||||
fn name(&self) -> &'static str {
|
|
||||||
"action"
|
|
||||||
}
|
|
||||||
|
|
||||||
fn next(&self, event: Event, dispatch: &mut dyn FnMut(Event)) -> Event {
|
|
||||||
match &event.etype {
|
|
||||||
EventType::Rendered(_) | EventType::ImageResolved(_) => {
|
|
||||||
dispatch(Event::caused_by(event.source_id, EventType::MatchInjected));
|
|
||||||
dispatch(Event::caused_by(
|
|
||||||
event.source_id,
|
|
||||||
EventType::DiscardPrevious(DiscardPreviousEvent {
|
|
||||||
minimum_source_id: self.event_sequence_provider.get_next_id(),
|
|
||||||
}),
|
|
||||||
));
|
|
||||||
|
|
||||||
match &event.etype {
|
|
||||||
EventType::Rendered(m_event) => Event::caused_by(
|
|
||||||
event.source_id,
|
|
||||||
match m_event.format {
|
|
||||||
TextFormat::Plain => EventType::TextInject(TextInjectRequest {
|
|
||||||
text: m_event.body.clone(),
|
|
||||||
force_mode: self.match_info_provider.get_force_mode(m_event.match_id),
|
|
||||||
}),
|
|
||||||
TextFormat::Html => EventType::HtmlInject(HtmlInjectRequest {
|
|
||||||
html: m_event.body.clone(),
|
|
||||||
}),
|
|
||||||
TextFormat::Markdown => EventType::MarkdownInject(MarkdownInjectRequest {
|
|
||||||
markdown: m_event.body.clone(),
|
|
||||||
}),
|
|
||||||
},
|
|
||||||
),
|
|
||||||
EventType::ImageResolved(m_event) => Event::caused_by(
|
|
||||||
event.source_id,
|
|
||||||
EventType::ImageInject(ImageInjectRequest {
|
|
||||||
image_path: m_event.image_path.clone(),
|
|
||||||
}),
|
|
||||||
),
|
|
||||||
_ => unreachable!()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
EventType::CursorHintCompensation(m_event) => {
|
|
||||||
dispatch(Event::caused_by(
|
|
||||||
event.source_id,
|
|
||||||
EventType::DiscardPrevious(DiscardPreviousEvent {
|
|
||||||
minimum_source_id: self.event_sequence_provider.get_next_id(),
|
|
||||||
}),
|
|
||||||
));
|
|
||||||
|
|
||||||
Event::caused_by(
|
|
||||||
event.source_id,
|
|
||||||
EventType::KeySequenceInject(KeySequenceInjectRequest {
|
|
||||||
keys: (0..m_event.cursor_hint_back_count)
|
|
||||||
.map(|_| Key::ArrowLeft)
|
|
||||||
.collect(),
|
|
||||||
}),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
EventType::TriggerCompensation(m_event) => {
|
|
||||||
let mut backspace_count = m_event.trigger.chars().count();
|
|
||||||
|
|
||||||
// We want to preserve the left separator if present
|
|
||||||
if let Some(left_separator) = &m_event.left_separator {
|
|
||||||
backspace_count -= left_separator.chars().count();
|
|
||||||
}
|
|
||||||
|
|
||||||
Event::caused_by(
|
|
||||||
event.source_id,
|
|
||||||
EventType::KeySequenceInject(KeySequenceInjectRequest {
|
|
||||||
keys: (0..backspace_count).map(|_| Key::Backspace).collect(),
|
|
||||||
}),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
_ => event,
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: handle images
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: test
|
|
|
@ -1,58 +0,0 @@
|
||||||
/*
|
|
||||||
* 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 <https://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
use super::super::Middleware;
|
|
||||||
use crate::engine::{event::{Event, EventType, effect::TriggerCompensationEvent, internal::CauseCompensatedMatchEvent}};
|
|
||||||
|
|
||||||
pub struct CauseCompensateMiddleware {}
|
|
||||||
|
|
||||||
impl CauseCompensateMiddleware {
|
|
||||||
pub fn new() -> Self {
|
|
||||||
Self {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Middleware for CauseCompensateMiddleware {
|
|
||||||
fn name(&self) -> &'static str {
|
|
||||||
"cause_compensate"
|
|
||||||
}
|
|
||||||
|
|
||||||
fn next(&self, event: Event, dispatch: &mut dyn FnMut(Event)) -> Event {
|
|
||||||
if let EventType::MatchSelected(m_event) = &event.etype {
|
|
||||||
let compensated_event =
|
|
||||||
Event::caused_by(event.source_id, EventType::CauseCompensatedMatch(CauseCompensatedMatchEvent { m: m_event.chosen.clone() }));
|
|
||||||
|
|
||||||
if let Some(trigger) = &m_event.chosen.trigger {
|
|
||||||
dispatch(compensated_event);
|
|
||||||
|
|
||||||
// Before the event, place a trigger compensation
|
|
||||||
return Event::caused_by(event.source_id, EventType::TriggerCompensation(TriggerCompensationEvent {
|
|
||||||
trigger: trigger.clone(),
|
|
||||||
left_separator: m_event.chosen.left_separator.clone(),
|
|
||||||
}));
|
|
||||||
} else {
|
|
||||||
return compensated_event;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
event
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: test
|
|
|
@ -1,172 +0,0 @@
|
||||||
/*
|
|
||||||
* This file is part of espanso.
|
|
||||||
*
|
|
||||||
* Copyright id: (), label: () id: (), label: () id: (), label: ()(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 <https://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
use std::cell::RefCell;
|
|
||||||
|
|
||||||
use super::super::Middleware;
|
|
||||||
use crate::engine::event::{
|
|
||||||
ui::{MenuItem, ShowContextMenuEvent, SimpleMenuItem},
|
|
||||||
Event, EventType, ExitMode,
|
|
||||||
};
|
|
||||||
|
|
||||||
const CONTEXT_ITEM_EXIT: u32 = 0;
|
|
||||||
const CONTEXT_ITEM_RELOAD: u32 = 1;
|
|
||||||
const CONTEXT_ITEM_ENABLE: u32 = 2;
|
|
||||||
const CONTEXT_ITEM_DISABLE: u32 = 3;
|
|
||||||
const CONTEXT_ITEM_SECURE_INPUT_EXPLAIN: u32 = 4;
|
|
||||||
const CONTEXT_ITEM_SECURE_INPUT_TRIGGER_WORKAROUND: u32 = 5;
|
|
||||||
const CONTEXT_ITEM_OPEN_SEARCH: u32 = 6;
|
|
||||||
|
|
||||||
pub struct ContextMenuMiddleware {
|
|
||||||
is_enabled: RefCell<bool>,
|
|
||||||
is_secure_input_enabled: RefCell<bool>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ContextMenuMiddleware {
|
|
||||||
pub fn new() -> Self {
|
|
||||||
Self {
|
|
||||||
is_enabled: RefCell::new(true),
|
|
||||||
is_secure_input_enabled: RefCell::new(false),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Middleware for ContextMenuMiddleware {
|
|
||||||
fn name(&self) -> &'static str {
|
|
||||||
"context_menu"
|
|
||||||
}
|
|
||||||
|
|
||||||
fn next(&self, event: Event, dispatch: &mut dyn FnMut(Event)) -> Event {
|
|
||||||
let mut is_enabled = self.is_enabled.borrow_mut();
|
|
||||||
let mut is_secure_input_enabled = self.is_secure_input_enabled.borrow_mut();
|
|
||||||
|
|
||||||
match &event.etype {
|
|
||||||
EventType::TrayIconClicked => {
|
|
||||||
// TODO: fetch top matches for the active config to be added
|
|
||||||
|
|
||||||
let mut items = vec![
|
|
||||||
MenuItem::Simple(if *is_enabled {
|
|
||||||
SimpleMenuItem {
|
|
||||||
id: CONTEXT_ITEM_DISABLE,
|
|
||||||
label: "Disable".to_string(),
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
SimpleMenuItem {
|
|
||||||
id: CONTEXT_ITEM_ENABLE,
|
|
||||||
label: "Enable".to_string(),
|
|
||||||
}
|
|
||||||
}),
|
|
||||||
MenuItem::Simple(SimpleMenuItem {
|
|
||||||
id: CONTEXT_ITEM_OPEN_SEARCH,
|
|
||||||
label: "Open search bar".to_string(),
|
|
||||||
}),
|
|
||||||
MenuItem::Separator,
|
|
||||||
MenuItem::Simple(SimpleMenuItem {
|
|
||||||
id: CONTEXT_ITEM_RELOAD,
|
|
||||||
label: "Reload config".to_string(),
|
|
||||||
}),
|
|
||||||
MenuItem::Separator,
|
|
||||||
MenuItem::Simple(SimpleMenuItem {
|
|
||||||
id: CONTEXT_ITEM_EXIT,
|
|
||||||
label: "Exit espanso".to_string(),
|
|
||||||
}),
|
|
||||||
];
|
|
||||||
|
|
||||||
if *is_secure_input_enabled {
|
|
||||||
items.insert(0, MenuItem::Simple(SimpleMenuItem {
|
|
||||||
id: CONTEXT_ITEM_SECURE_INPUT_EXPLAIN,
|
|
||||||
label: "Why is espanso not working?".to_string(),
|
|
||||||
}));
|
|
||||||
items.insert(1, MenuItem::Simple(SimpleMenuItem {
|
|
||||||
id: CONTEXT_ITEM_SECURE_INPUT_TRIGGER_WORKAROUND,
|
|
||||||
label: "Launch SecureInput auto-fix".to_string(),
|
|
||||||
}));
|
|
||||||
items.insert(2, MenuItem::Separator);
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: my idea is to use a set of reserved u32 ids for built-in
|
|
||||||
// actions such as Exit, Open Editor etc
|
|
||||||
// then we need some u32 for the matches, so we need to create
|
|
||||||
// a mapping structure match_id <-> context-menu-id
|
|
||||||
return Event::caused_by(
|
|
||||||
event.source_id,
|
|
||||||
EventType::ShowContextMenu(ShowContextMenuEvent {
|
|
||||||
// TODO: add actual entries
|
|
||||||
items,
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
EventType::ContextMenuClicked(context_click_event) => {
|
|
||||||
match context_click_event.context_item_id {
|
|
||||||
CONTEXT_ITEM_EXIT => Event::caused_by(
|
|
||||||
event.source_id,
|
|
||||||
EventType::ExitRequested(ExitMode::ExitAllProcesses),
|
|
||||||
),
|
|
||||||
CONTEXT_ITEM_RELOAD => Event::caused_by(
|
|
||||||
event.source_id,
|
|
||||||
EventType::ExitRequested(ExitMode::RestartWorker),
|
|
||||||
),
|
|
||||||
CONTEXT_ITEM_ENABLE => {
|
|
||||||
dispatch(Event::caused_by(event.source_id, EventType::EnableRequest));
|
|
||||||
Event::caused_by(event.source_id, EventType::NOOP)
|
|
||||||
}
|
|
||||||
CONTEXT_ITEM_DISABLE => {
|
|
||||||
dispatch(Event::caused_by(event.source_id, EventType::DisableRequest));
|
|
||||||
Event::caused_by(event.source_id, EventType::NOOP)
|
|
||||||
}
|
|
||||||
CONTEXT_ITEM_SECURE_INPUT_EXPLAIN => {
|
|
||||||
dispatch(Event::caused_by(event.source_id, EventType::DisplaySecureInputTroubleshoot));
|
|
||||||
Event::caused_by(event.source_id, EventType::NOOP)
|
|
||||||
}
|
|
||||||
CONTEXT_ITEM_SECURE_INPUT_TRIGGER_WORKAROUND => {
|
|
||||||
dispatch(Event::caused_by(event.source_id, EventType::LaunchSecureInputAutoFix));
|
|
||||||
Event::caused_by(event.source_id, EventType::NOOP)
|
|
||||||
}
|
|
||||||
CONTEXT_ITEM_OPEN_SEARCH => {
|
|
||||||
dispatch(Event::caused_by(event.source_id, EventType::ShowSearchBar));
|
|
||||||
Event::caused_by(event.source_id, EventType::NOOP)
|
|
||||||
}
|
|
||||||
custom => {
|
|
||||||
// TODO: handle dynamic items
|
|
||||||
todo!()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
EventType::Disabled => {
|
|
||||||
*is_enabled = false;
|
|
||||||
event
|
|
||||||
}
|
|
||||||
EventType::Enabled => {
|
|
||||||
*is_enabled = true;
|
|
||||||
event
|
|
||||||
}
|
|
||||||
EventType::SecureInputEnabled(_) => {
|
|
||||||
*is_secure_input_enabled = true;
|
|
||||||
event
|
|
||||||
}
|
|
||||||
EventType::SecureInputDisabled => {
|
|
||||||
*is_secure_input_enabled = false;
|
|
||||||
event
|
|
||||||
}
|
|
||||||
_ => event,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: test
|
|
|
@ -1,77 +0,0 @@
|
||||||
/*
|
|
||||||
* 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 <https://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
use super::super::Middleware;
|
|
||||||
use crate::engine::{event::{Event, EventType, effect::CursorHintCompensationEvent, internal::RenderedEvent}};
|
|
||||||
|
|
||||||
pub struct CursorHintMiddleware {}
|
|
||||||
|
|
||||||
impl CursorHintMiddleware {
|
|
||||||
pub fn new() -> Self {
|
|
||||||
Self {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Middleware for CursorHintMiddleware {
|
|
||||||
fn name(&self) -> &'static str {
|
|
||||||
"cursor_hint"
|
|
||||||
}
|
|
||||||
|
|
||||||
fn next(&self, event: Event, dispatch: &mut dyn FnMut(Event)) -> Event {
|
|
||||||
if let EventType::Rendered(m_event) = event.etype {
|
|
||||||
let (body, cursor_hint_back_count) = process_cursor_hint(m_event.body);
|
|
||||||
|
|
||||||
if let Some(cursor_hint_back_count) = cursor_hint_back_count {
|
|
||||||
dispatch(Event::caused_by(event.source_id, EventType::CursorHintCompensation(CursorHintCompensationEvent {
|
|
||||||
cursor_hint_back_count,
|
|
||||||
})));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Alter the rendered event to remove the cursor hint from the body
|
|
||||||
return Event::caused_by(event.source_id, EventType::Rendered(RenderedEvent {
|
|
||||||
body,
|
|
||||||
..m_event
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
|
|
||||||
event
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: test
|
|
||||||
fn process_cursor_hint(body: String) -> (String, Option<usize>) {
|
|
||||||
if let Some(index) = body.find("$|$") {
|
|
||||||
// Convert the byte index to a char index
|
|
||||||
let char_str = &body[0..index];
|
|
||||||
let char_index = char_str.chars().count();
|
|
||||||
let total_size = body.chars().count();
|
|
||||||
|
|
||||||
// Remove the $|$ placeholder
|
|
||||||
let body = body.replace("$|$", "");
|
|
||||||
|
|
||||||
// Calculate the amount of rewind moves needed (LEFT ARROW).
|
|
||||||
// Subtract also 3, equal to the number of chars of the placeholder "$|$"
|
|
||||||
let moves = total_size - char_index - 3;
|
|
||||||
(body, Some(moves))
|
|
||||||
} else {
|
|
||||||
(body, None)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: test
|
|
|
@ -1,88 +0,0 @@
|
||||||
/*
|
|
||||||
* 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 <https://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
use std::{
|
|
||||||
time::{Duration, Instant},
|
|
||||||
};
|
|
||||||
|
|
||||||
use log::{trace, warn};
|
|
||||||
|
|
||||||
use super::super::Middleware;
|
|
||||||
use crate::engine::event::{Event, EventType};
|
|
||||||
|
|
||||||
/// Maximum time to wait for modifiers being released before
|
|
||||||
/// giving up.
|
|
||||||
const MODIFIER_DELAY_TIMEOUT: Duration = Duration::from_secs(3);
|
|
||||||
|
|
||||||
pub trait ModifierStatusProvider {
|
|
||||||
fn is_any_conflicting_modifier_pressed(&self) -> bool;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// This middleware is used to delay the injection of text until
|
|
||||||
/// all modifiers have been released. This is needed as otherwise,
|
|
||||||
/// injections might misbehave as pressed modifiers might alter
|
|
||||||
/// the keys being injected.
|
|
||||||
pub struct DelayForModifierReleaseMiddleware<'a> {
|
|
||||||
provider: &'a dyn ModifierStatusProvider,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl <'a> DelayForModifierReleaseMiddleware<'a> {
|
|
||||||
pub fn new(provider: &'a dyn ModifierStatusProvider) -> Self {
|
|
||||||
Self {
|
|
||||||
provider
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl <'a> Middleware for DelayForModifierReleaseMiddleware<'a> {
|
|
||||||
fn name(&self) -> &'static str {
|
|
||||||
"delay_modifiers"
|
|
||||||
}
|
|
||||||
|
|
||||||
fn next(&self, event: Event, _: &mut dyn FnMut(Event)) -> Event {
|
|
||||||
if is_injection_event(&event.etype) {
|
|
||||||
let start = Instant::now();
|
|
||||||
while self.provider.is_any_conflicting_modifier_pressed() {
|
|
||||||
if Instant::now().duration_since(start) > MODIFIER_DELAY_TIMEOUT {
|
|
||||||
warn!("injection delay has timed out, please release the modifier keys (SHIFT, CTRL, ALT, CMD) to trigger an expansion");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: here we might show a popup window to tell the users to release those keys
|
|
||||||
|
|
||||||
trace!("delaying injection event as some modifiers are pressed");
|
|
||||||
std::thread::sleep(Duration::from_millis(100));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
event
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn is_injection_event(event_type: &EventType) -> bool {
|
|
||||||
match event_type {
|
|
||||||
EventType::TriggerCompensation(_) => true,
|
|
||||||
EventType::CursorHintCompensation(_) => true,
|
|
||||||
EventType::KeySequenceInject(_) => true,
|
|
||||||
EventType::TextInject(_) => true,
|
|
||||||
_ => false,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: test
|
|
|
@ -1,138 +0,0 @@
|
||||||
/*
|
|
||||||
* 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 <https://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
use std::{
|
|
||||||
cell::RefCell,
|
|
||||||
time::{Duration, Instant},
|
|
||||||
};
|
|
||||||
|
|
||||||
use log::info;
|
|
||||||
|
|
||||||
use super::super::Middleware;
|
|
||||||
use crate::engine::event::{
|
|
||||||
input::{Key, KeyboardEvent, Status, Variant},
|
|
||||||
Event, EventType,
|
|
||||||
};
|
|
||||||
|
|
||||||
pub struct DisableOptions {
|
|
||||||
pub toggle_key: Option<Key>,
|
|
||||||
pub toggle_key_variant: Option<Variant>,
|
|
||||||
pub toggle_key_maximum_window: Duration,
|
|
||||||
// TODO: toggle shortcut?
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct DisableMiddleware {
|
|
||||||
enabled: RefCell<bool>,
|
|
||||||
last_toggle_press: RefCell<Option<Instant>>,
|
|
||||||
options: DisableOptions,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl DisableMiddleware {
|
|
||||||
pub fn new(options: DisableOptions) -> Self {
|
|
||||||
Self {
|
|
||||||
enabled: RefCell::new(true),
|
|
||||||
last_toggle_press: RefCell::new(None),
|
|
||||||
options,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Middleware for DisableMiddleware {
|
|
||||||
fn name(&self) -> &'static str {
|
|
||||||
"disable"
|
|
||||||
}
|
|
||||||
|
|
||||||
fn next(&self, event: Event, dispatch: &mut dyn FnMut(Event)) -> Event {
|
|
||||||
let mut has_status_changed = false;
|
|
||||||
let mut enabled = self.enabled.borrow_mut();
|
|
||||||
|
|
||||||
match &event.etype {
|
|
||||||
EventType::Keyboard(m_event) => {
|
|
||||||
if is_toggle_key(m_event, &self.options) {
|
|
||||||
let mut last_toggle_press = self.last_toggle_press.borrow_mut();
|
|
||||||
if let Some(previous_press) = *last_toggle_press {
|
|
||||||
if previous_press.elapsed() < self.options.toggle_key_maximum_window {
|
|
||||||
*enabled = !*enabled;
|
|
||||||
*last_toggle_press = None;
|
|
||||||
has_status_changed = true;
|
|
||||||
} else {
|
|
||||||
*last_toggle_press = Some(Instant::now());
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
*last_toggle_press = Some(Instant::now());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
EventType::EnableRequest => {
|
|
||||||
*enabled = true;
|
|
||||||
has_status_changed = true;
|
|
||||||
},
|
|
||||||
EventType::DisableRequest => {
|
|
||||||
*enabled = false;
|
|
||||||
has_status_changed = true;
|
|
||||||
}
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
|
|
||||||
if has_status_changed {
|
|
||||||
info!("toggled enabled state, is_enabled = {}", *enabled);
|
|
||||||
dispatch(Event::caused_by(
|
|
||||||
event.source_id,
|
|
||||||
if *enabled {
|
|
||||||
EventType::Enabled
|
|
||||||
} else {
|
|
||||||
EventType::Disabled
|
|
||||||
},
|
|
||||||
))
|
|
||||||
}
|
|
||||||
|
|
||||||
// Block keyboard events when disabled
|
|
||||||
if let EventType::Keyboard(_) = &event.etype {
|
|
||||||
if !*enabled {
|
|
||||||
return Event::caused_by(event.source_id, EventType::NOOP);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// TODO: also ignore hotkey and mouse events
|
|
||||||
|
|
||||||
event
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn is_toggle_key(event: &KeyboardEvent, options: &DisableOptions) -> bool {
|
|
||||||
if event.status != Status::Released {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if options
|
|
||||||
.toggle_key
|
|
||||||
.as_ref()
|
|
||||||
.map(|key| key == &event.key)
|
|
||||||
.unwrap_or(false)
|
|
||||||
{
|
|
||||||
if let (Some(variant), Some(e_variant)) = (&options.toggle_key_variant, &event.variant) {
|
|
||||||
variant == e_variant
|
|
||||||
} else {
|
|
||||||
true
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: test
|
|
|
@ -1,48 +0,0 @@
|
||||||
/*
|
|
||||||
* 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 <https://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
use log::debug;
|
|
||||||
|
|
||||||
use super::super::Middleware;
|
|
||||||
use crate::engine::{event::{Event, EventType}};
|
|
||||||
|
|
||||||
pub struct ExitMiddleware {}
|
|
||||||
|
|
||||||
impl ExitMiddleware {
|
|
||||||
pub fn new() -> Self {
|
|
||||||
Self {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Middleware for ExitMiddleware {
|
|
||||||
fn name(&self) -> &'static str {
|
|
||||||
"exit"
|
|
||||||
}
|
|
||||||
|
|
||||||
fn next(&self, event: Event, _: &mut dyn FnMut(Event)) -> Event {
|
|
||||||
if let EventType::ExitRequested(mode) = &event.etype {
|
|
||||||
debug!("received ExitRequested event with mode: {:?}, dispatching exit", mode);
|
|
||||||
return Event::caused_by(event.source_id, EventType::Exit(mode.clone()));
|
|
||||||
}
|
|
||||||
|
|
||||||
event
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: test
|
|
|
@ -1,52 +0,0 @@
|
||||||
/*
|
|
||||||
* This file is part of espanso id: (), trigger: (), trigger: (), left_separator: (), right_separator: (), args: () left_separator: (), right_separator: (), args: () id: (), trigger: (), left_separator: (), right_separator: (), args: ().
|
|
||||||
*
|
|
||||||
* 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 <https://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
use super::super::Middleware;
|
|
||||||
use crate::engine::{event::{Event, EventType, internal::{DetectedMatch, MatchesDetectedEvent}}};
|
|
||||||
|
|
||||||
pub struct HotKeyMiddleware {}
|
|
||||||
|
|
||||||
impl HotKeyMiddleware {
|
|
||||||
pub fn new() -> Self {
|
|
||||||
Self {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Middleware for HotKeyMiddleware {
|
|
||||||
fn name(&self) -> &'static str {
|
|
||||||
"hotkey"
|
|
||||||
}
|
|
||||||
|
|
||||||
fn next(&self, event: Event, _: &mut dyn FnMut(Event)) -> Event {
|
|
||||||
if let EventType::HotKey(m_event) = &event.etype {
|
|
||||||
return Event::caused_by(event.source_id, EventType::MatchesDetected(MatchesDetectedEvent {
|
|
||||||
matches: vec![
|
|
||||||
DetectedMatch {
|
|
||||||
id: m_event.hotkey_id,
|
|
||||||
..Default::default()
|
|
||||||
}
|
|
||||||
],
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
|
|
||||||
event
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: test
|
|
|
@ -1,79 +0,0 @@
|
||||||
/*
|
|
||||||
* 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 <https://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
use std::{
|
|
||||||
cell::RefCell,
|
|
||||||
};
|
|
||||||
|
|
||||||
use super::super::Middleware;
|
|
||||||
use crate::engine::event::{Event, EventType, ui::{IconStatus, IconStatusChangeEvent}};
|
|
||||||
|
|
||||||
pub struct IconStatusMiddleware {
|
|
||||||
enabled: RefCell<bool>,
|
|
||||||
secure_input_enabled: RefCell<bool>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl IconStatusMiddleware {
|
|
||||||
pub fn new() -> Self {
|
|
||||||
Self {
|
|
||||||
enabled: RefCell::new(true),
|
|
||||||
secure_input_enabled: RefCell::new(false),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Middleware for IconStatusMiddleware {
|
|
||||||
fn name(&self) -> &'static str {
|
|
||||||
"icon_status"
|
|
||||||
}
|
|
||||||
|
|
||||||
fn next(&self, event: Event, dispatch: &mut dyn FnMut(Event)) -> Event {
|
|
||||||
let mut enabled = self.enabled.borrow_mut();
|
|
||||||
let mut secure_input_enabled = self.secure_input_enabled.borrow_mut();
|
|
||||||
|
|
||||||
let mut did_update = true;
|
|
||||||
match &event.etype {
|
|
||||||
EventType::Enabled => *enabled = true,
|
|
||||||
EventType::Disabled => *enabled = false,
|
|
||||||
EventType::SecureInputEnabled(_) => *secure_input_enabled = true,
|
|
||||||
EventType::SecureInputDisabled => *secure_input_enabled = false,
|
|
||||||
_ => did_update = false,
|
|
||||||
}
|
|
||||||
|
|
||||||
if did_update {
|
|
||||||
let status = if *enabled {
|
|
||||||
if *secure_input_enabled {
|
|
||||||
IconStatus::SecureInputDisabled
|
|
||||||
} else {
|
|
||||||
IconStatus::Enabled
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
IconStatus::Disabled
|
|
||||||
};
|
|
||||||
|
|
||||||
dispatch(Event::caused_by(event.source_id, EventType::IconStatusChange(IconStatusChangeEvent {
|
|
||||||
status,
|
|
||||||
})));
|
|
||||||
}
|
|
||||||
|
|
||||||
event
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: test
|
|
|
@ -1,81 +0,0 @@
|
||||||
/*
|
|
||||||
* 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 <https://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
use std::{
|
|
||||||
path::Path,
|
|
||||||
};
|
|
||||||
|
|
||||||
use log::{error};
|
|
||||||
|
|
||||||
use super::super::Middleware;
|
|
||||||
use crate::engine::event::{Event, EventType, internal::ImageResolvedEvent};
|
|
||||||
|
|
||||||
pub trait PathProvider {
|
|
||||||
fn get_config_path(&self) -> &Path;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct ImageResolverMiddleware<'a> {
|
|
||||||
provider: &'a dyn PathProvider,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> ImageResolverMiddleware<'a> {
|
|
||||||
pub fn new(provider: &'a dyn PathProvider) -> Self {
|
|
||||||
Self { provider }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> Middleware for ImageResolverMiddleware<'a> {
|
|
||||||
fn name(&self) -> &'static str {
|
|
||||||
"image_resolve"
|
|
||||||
}
|
|
||||||
|
|
||||||
fn next(&self, event: Event, _: &mut dyn FnMut(Event)) -> Event {
|
|
||||||
if let EventType::ImageRequested(m_event) = &event.etype {
|
|
||||||
// On Windows, we have to replace the forward / with the backslash \ in the path
|
|
||||||
let path = if cfg!(target_os = "windows") {
|
|
||||||
m_event.image_path.replace("/", "\\")
|
|
||||||
} else {
|
|
||||||
m_event.image_path.to_owned()
|
|
||||||
};
|
|
||||||
|
|
||||||
let path = if path.contains("$CONFIG") {
|
|
||||||
let config_path = match self.provider.get_config_path().canonicalize() {
|
|
||||||
Ok(path) => path,
|
|
||||||
Err(err) => {
|
|
||||||
error!("unable to canonicalize the config path into the image resolver: {}", err);
|
|
||||||
self.provider.get_config_path().to_owned()
|
|
||||||
},
|
|
||||||
};
|
|
||||||
path.replace("$CONFIG", &config_path.to_string_lossy())
|
|
||||||
} else {
|
|
||||||
path
|
|
||||||
};
|
|
||||||
|
|
||||||
return Event::caused_by(event.source_id, EventType::ImageResolved(ImageResolvedEvent {
|
|
||||||
image_path: path,
|
|
||||||
}))
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
event
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: test
|
|
|
@ -1,60 +0,0 @@
|
||||||
/*
|
|
||||||
* 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 <https://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
use super::super::Middleware;
|
|
||||||
use crate::engine::event::{Event, EventType, effect::{HtmlInjectRequest}};
|
|
||||||
|
|
||||||
// Convert markdown injection requests to HTML on the fly
|
|
||||||
pub struct MarkdownMiddleware {}
|
|
||||||
|
|
||||||
impl MarkdownMiddleware {
|
|
||||||
pub fn new() -> Self {
|
|
||||||
Self {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Middleware for MarkdownMiddleware {
|
|
||||||
fn name(&self) -> &'static str {
|
|
||||||
"markdown"
|
|
||||||
}
|
|
||||||
|
|
||||||
fn next(&self, event: Event, _: &mut dyn FnMut(Event)) -> Event {
|
|
||||||
if let EventType::MarkdownInject(m_event) = &event.etype {
|
|
||||||
// Render the markdown into HTML
|
|
||||||
let html = markdown::to_html(&m_event.markdown);
|
|
||||||
let mut html = html.trim();
|
|
||||||
|
|
||||||
// Remove the surrounding paragraph
|
|
||||||
if html.starts_with("<p>") {
|
|
||||||
html = html.trim_start_matches("<p>");
|
|
||||||
}
|
|
||||||
if html.ends_with("</p>") {
|
|
||||||
html = html.trim_end_matches("</p>");
|
|
||||||
}
|
|
||||||
|
|
||||||
return Event::caused_by(event.source_id, EventType::HtmlInject(HtmlInjectRequest {
|
|
||||||
html: html.to_owned(),
|
|
||||||
}))
|
|
||||||
}
|
|
||||||
|
|
||||||
event
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: test
|
|
|
@ -1,91 +0,0 @@
|
||||||
/*
|
|
||||||
* 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 <https://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
use log::{debug, error};
|
|
||||||
|
|
||||||
use super::super::Middleware;
|
|
||||||
use crate::engine::{event::{Event, EventType, internal::{MatchSelectedEvent}}, process::{MatchFilter, MatchSelector}};
|
|
||||||
|
|
||||||
pub struct MatchSelectMiddleware<'a> {
|
|
||||||
match_filter: &'a dyn MatchFilter,
|
|
||||||
match_selector: &'a dyn MatchSelector,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> MatchSelectMiddleware<'a> {
|
|
||||||
pub fn new(match_filter: &'a dyn MatchFilter, match_selector: &'a dyn MatchSelector) -> Self {
|
|
||||||
Self {
|
|
||||||
match_filter,
|
|
||||||
match_selector,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> Middleware for MatchSelectMiddleware<'a> {
|
|
||||||
fn name(&self) -> &'static str {
|
|
||||||
"match_select"
|
|
||||||
}
|
|
||||||
|
|
||||||
fn next(&self, event: Event, _: &mut dyn FnMut(Event)) -> Event {
|
|
||||||
if let EventType::MatchesDetected(m_event) = event.etype {
|
|
||||||
let matches_ids: Vec<i32> = m_event.matches.iter().map(|m| m.id).collect();
|
|
||||||
|
|
||||||
// Find the matches that are actually valid in the current context
|
|
||||||
let valid_ids = self.match_filter.filter_active(&matches_ids);
|
|
||||||
|
|
||||||
return match valid_ids.len() {
|
|
||||||
0 => Event::caused_by(event.source_id, EventType::NOOP), // No valid matches, consume the event
|
|
||||||
1 => {
|
|
||||||
// Only one match, no need to show a selection dialog
|
|
||||||
let m = m_event
|
|
||||||
.matches
|
|
||||||
.into_iter()
|
|
||||||
.find(|m| m.id == *valid_ids.first().unwrap());
|
|
||||||
if let Some(m) = m {
|
|
||||||
Event::caused_by(event.source_id, EventType::MatchSelected(MatchSelectedEvent { chosen: m }))
|
|
||||||
} else {
|
|
||||||
error!("MatchSelectMiddleware could not find the correspondent match");
|
|
||||||
Event::caused_by(event.source_id, EventType::NOOP)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => {
|
|
||||||
// Multiple matches, we need to ask the user which one to use
|
|
||||||
if let Some(selected_id) = self.match_selector.select(&valid_ids) {
|
|
||||||
let m = m_event
|
|
||||||
.matches
|
|
||||||
.into_iter()
|
|
||||||
.find(|m| m.id == selected_id);
|
|
||||||
if let Some(m) = m {
|
|
||||||
Event::caused_by(event.source_id, EventType::MatchSelected(MatchSelectedEvent { chosen: m }))
|
|
||||||
} else {
|
|
||||||
error!("MatchSelectMiddleware could not find the correspondent match");
|
|
||||||
Event::caused_by(event.source_id, EventType::NOOP)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
debug!("MatchSelectMiddleware did not receive any match selection");
|
|
||||||
Event::caused_by(event.source_id, EventType::NOOP)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
event
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: test
|
|
|
@ -1,187 +0,0 @@
|
||||||
/*
|
|
||||||
* 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 <https://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
use log::trace;
|
|
||||||
use std::{cell::RefCell, collections::VecDeque};
|
|
||||||
|
|
||||||
use super::super::Middleware;
|
|
||||||
use crate::engine::{
|
|
||||||
event::{
|
|
||||||
input::{Key, Status},
|
|
||||||
internal::{DetectedMatch, MatchesDetectedEvent},
|
|
||||||
Event, EventType,
|
|
||||||
},
|
|
||||||
process::{Matcher, MatcherEvent},
|
|
||||||
};
|
|
||||||
|
|
||||||
pub trait MatcherMiddlewareConfigProvider {
|
|
||||||
fn max_history_size(&self) -> usize;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct MatcherMiddleware<'a, State> {
|
|
||||||
matchers: &'a [&'a dyn Matcher<'a, State>],
|
|
||||||
|
|
||||||
matcher_states: RefCell<VecDeque<Vec<State>>>,
|
|
||||||
|
|
||||||
max_history_size: usize,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a, State> MatcherMiddleware<'a, State> {
|
|
||||||
pub fn new(matchers: &'a [&'a dyn Matcher<'a, State>], options_provider: &'a dyn MatcherMiddlewareConfigProvider) -> Self {
|
|
||||||
let max_history_size = options_provider.max_history_size();
|
|
||||||
|
|
||||||
Self {
|
|
||||||
matchers,
|
|
||||||
matcher_states: RefCell::new(VecDeque::new()),
|
|
||||||
max_history_size,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a, State> Middleware for MatcherMiddleware<'a, State> {
|
|
||||||
fn name(&self) -> &'static str {
|
|
||||||
"matcher"
|
|
||||||
}
|
|
||||||
|
|
||||||
fn next(&self, event: Event, _: &mut dyn FnMut(Event)) -> Event {
|
|
||||||
if is_event_of_interest(&event.etype) {
|
|
||||||
let mut matcher_states = self.matcher_states.borrow_mut();
|
|
||||||
let prev_states = if !matcher_states.is_empty() {
|
|
||||||
matcher_states.get(matcher_states.len() - 1)
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
};
|
|
||||||
|
|
||||||
if let EventType::Keyboard(keyboard_event) = &event.etype {
|
|
||||||
// Backspace handling
|
|
||||||
if keyboard_event.key == Key::Backspace {
|
|
||||||
trace!("popping the last matcher state");
|
|
||||||
matcher_states.pop_back();
|
|
||||||
return event;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Some keys (such as the arrow keys) and mouse clicks prevent espanso from building
|
|
||||||
// an accurate key buffer, so we need to invalidate it.
|
|
||||||
if is_invalidating_event(&event.etype) {
|
|
||||||
trace!("invalidating event detected, clearing matching state");
|
|
||||||
matcher_states.clear();
|
|
||||||
return event;
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut all_results = Vec::new();
|
|
||||||
|
|
||||||
if let Some(matcher_event) = convert_to_matcher_event(&event.etype) {
|
|
||||||
let mut new_states = Vec::new();
|
|
||||||
for (i, matcher) in self.matchers.iter().enumerate() {
|
|
||||||
let prev_state = prev_states.and_then(|states| states.get(i));
|
|
||||||
|
|
||||||
let (state, results) = matcher.process(prev_state, &matcher_event);
|
|
||||||
all_results.extend(results);
|
|
||||||
|
|
||||||
new_states.push(state);
|
|
||||||
}
|
|
||||||
|
|
||||||
matcher_states.push_back(new_states);
|
|
||||||
if matcher_states.len() > self.max_history_size {
|
|
||||||
matcher_states.pop_front();
|
|
||||||
}
|
|
||||||
|
|
||||||
if !all_results.is_empty() {
|
|
||||||
return Event::caused_by(
|
|
||||||
event.source_id,
|
|
||||||
EventType::MatchesDetected(MatchesDetectedEvent {
|
|
||||||
matches: all_results
|
|
||||||
.into_iter()
|
|
||||||
.map(|result| DetectedMatch {
|
|
||||||
id: result.id,
|
|
||||||
trigger: Some(result.trigger),
|
|
||||||
right_separator: result.right_separator,
|
|
||||||
left_separator: result.left_separator,
|
|
||||||
args: result.args,
|
|
||||||
})
|
|
||||||
.collect(),
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
event
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn is_event_of_interest(event_type: &EventType) -> bool {
|
|
||||||
match event_type {
|
|
||||||
EventType::Keyboard(keyboard_event) => {
|
|
||||||
if keyboard_event.status != Status::Pressed {
|
|
||||||
// Skip non-press events
|
|
||||||
false
|
|
||||||
} else {
|
|
||||||
match keyboard_event.key {
|
|
||||||
// Skip modifier keys
|
|
||||||
Key::Alt => false,
|
|
||||||
Key::Shift => false,
|
|
||||||
Key::CapsLock => false,
|
|
||||||
Key::Meta => false,
|
|
||||||
Key::NumLock => false,
|
|
||||||
Key::Control => false,
|
|
||||||
|
|
||||||
_ => true,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
EventType::Mouse(mouse_event) => mouse_event.status == Status::Pressed,
|
|
||||||
EventType::MatchInjected => true,
|
|
||||||
_ => false,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn convert_to_matcher_event(event_type: &EventType) -> Option<MatcherEvent> {
|
|
||||||
match event_type {
|
|
||||||
EventType::Keyboard(keyboard_event) => Some(MatcherEvent::Key {
|
|
||||||
key: keyboard_event.key.clone(),
|
|
||||||
chars: keyboard_event.value.clone(),
|
|
||||||
}),
|
|
||||||
EventType::Mouse(_) => Some(MatcherEvent::VirtualSeparator),
|
|
||||||
EventType::MatchInjected => Some(MatcherEvent::VirtualSeparator),
|
|
||||||
_ => None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn is_invalidating_event(event_type: &EventType) -> bool {
|
|
||||||
match event_type {
|
|
||||||
EventType::Keyboard(keyboard_event) => match keyboard_event.key {
|
|
||||||
Key::ArrowDown => true,
|
|
||||||
Key::ArrowLeft => true,
|
|
||||||
Key::ArrowRight => true,
|
|
||||||
Key::ArrowUp => true,
|
|
||||||
Key::End => true,
|
|
||||||
Key::Home => true,
|
|
||||||
Key::PageDown => true,
|
|
||||||
Key::PageUp => true,
|
|
||||||
Key::Escape => true,
|
|
||||||
_ => false,
|
|
||||||
},
|
|
||||||
EventType::Mouse(_) => true,
|
|
||||||
_ => false,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: test
|
|
|
@ -1,36 +0,0 @@
|
||||||
/*
|
|
||||||
* 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 <https://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
pub mod action;
|
|
||||||
pub mod cause;
|
|
||||||
pub mod context_menu;
|
|
||||||
pub mod cursor_hint;
|
|
||||||
pub mod delay_modifiers;
|
|
||||||
pub mod disable;
|
|
||||||
pub mod exit;
|
|
||||||
pub mod hotkey;
|
|
||||||
pub mod icon_status;
|
|
||||||
pub mod image_resolve;
|
|
||||||
pub mod match_select;
|
|
||||||
pub mod matcher;
|
|
||||||
pub mod markdown;
|
|
||||||
pub mod multiplex;
|
|
||||||
pub mod past_discard;
|
|
||||||
pub mod render;
|
|
||||||
pub mod search;
|
|
|
@ -1,58 +0,0 @@
|
||||||
/*
|
|
||||||
* 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 <https://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
use log::error;
|
|
||||||
|
|
||||||
use super::super::Middleware;
|
|
||||||
use crate::engine::{
|
|
||||||
event::{Event, EventType},
|
|
||||||
process::Multiplexer,
|
|
||||||
};
|
|
||||||
|
|
||||||
pub struct MultiplexMiddleware<'a> {
|
|
||||||
multiplexer: &'a dyn Multiplexer,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> MultiplexMiddleware<'a> {
|
|
||||||
pub fn new(multiplexer: &'a dyn Multiplexer) -> Self {
|
|
||||||
Self { multiplexer }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> Middleware for MultiplexMiddleware<'a> {
|
|
||||||
fn name(&self) -> &'static str {
|
|
||||||
"multiplex"
|
|
||||||
}
|
|
||||||
|
|
||||||
fn next(&self, event: Event, _: &mut dyn FnMut(Event)) -> Event {
|
|
||||||
if let EventType::CauseCompensatedMatch(m_event) = event.etype {
|
|
||||||
return match self.multiplexer.convert(m_event.m) {
|
|
||||||
Some(new_event) => Event::caused_by(event.source_id, new_event),
|
|
||||||
None => {
|
|
||||||
error!("match multiplexing failed");
|
|
||||||
Event::caused_by(event.source_id, EventType::NOOP)
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
event
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: test
|
|
|
@ -1,66 +0,0 @@
|
||||||
/*
|
|
||||||
* 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 <https://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
use std::cell::RefCell;
|
|
||||||
|
|
||||||
use log::trace;
|
|
||||||
|
|
||||||
use super::super::Middleware;
|
|
||||||
use crate::engine::{event::{Event, EventType, SourceId}};
|
|
||||||
|
|
||||||
/// This middleware discards all events that have a source_id smaller than its
|
|
||||||
/// configured threshold. This useful to discard past events that might have
|
|
||||||
/// been stuck in the event queue for too long.
|
|
||||||
pub struct PastEventsDiscardMiddleware {
|
|
||||||
source_id_threshold: RefCell<SourceId>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl PastEventsDiscardMiddleware {
|
|
||||||
pub fn new() -> Self {
|
|
||||||
Self {
|
|
||||||
source_id_threshold: RefCell::new(0),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Middleware for PastEventsDiscardMiddleware {
|
|
||||||
fn name(&self) -> &'static str {
|
|
||||||
"past_discard"
|
|
||||||
}
|
|
||||||
|
|
||||||
fn next(&self, event: Event, _: &mut dyn FnMut(Event)) -> Event {
|
|
||||||
let mut source_id_threshold = self.source_id_threshold.borrow_mut();
|
|
||||||
|
|
||||||
// Filter out previous events
|
|
||||||
if event.source_id < *source_id_threshold {
|
|
||||||
trace!("discarding previous event: {:?}", event);
|
|
||||||
return Event::caused_by(event.source_id, EventType::NOOP);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update the minimum threshold
|
|
||||||
if let EventType::DiscardPrevious(m_event) = &event.etype {
|
|
||||||
trace!("updating minimum source id threshold for events to: {}", m_event.minimum_source_id);
|
|
||||||
*source_id_threshold = m_event.minimum_source_id;
|
|
||||||
}
|
|
||||||
|
|
||||||
event
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: test
|
|
|
@ -1,83 +0,0 @@
|
||||||
/*
|
|
||||||
* 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 <https://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
use log::error;
|
|
||||||
|
|
||||||
use super::super::Middleware;
|
|
||||||
use crate::engine::{
|
|
||||||
event::{
|
|
||||||
internal::RenderedEvent,
|
|
||||||
Event, EventType,
|
|
||||||
},
|
|
||||||
process::{Renderer, RendererError},
|
|
||||||
};
|
|
||||||
|
|
||||||
pub struct RenderMiddleware<'a> {
|
|
||||||
renderer: &'a dyn Renderer<'a>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> RenderMiddleware<'a> {
|
|
||||||
pub fn new(renderer: &'a dyn Renderer<'a>) -> Self {
|
|
||||||
Self { renderer }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> Middleware for RenderMiddleware<'a> {
|
|
||||||
fn name(&self) -> &'static str {
|
|
||||||
"render"
|
|
||||||
}
|
|
||||||
|
|
||||||
fn next(&self, event: Event, _: &mut dyn FnMut(Event)) -> Event {
|
|
||||||
if let EventType::RenderingRequested(m_event) = event.etype {
|
|
||||||
match self.renderer.render(
|
|
||||||
m_event.match_id,
|
|
||||||
m_event.trigger.as_deref(),
|
|
||||||
m_event.trigger_args,
|
|
||||||
) {
|
|
||||||
Ok(body) => {
|
|
||||||
let body = if let Some(right_separator) = m_event.right_separator {
|
|
||||||
format!("{}{}", body, right_separator)
|
|
||||||
} else {
|
|
||||||
body
|
|
||||||
};
|
|
||||||
|
|
||||||
return Event::caused_by(
|
|
||||||
event.source_id,
|
|
||||||
EventType::Rendered(RenderedEvent {
|
|
||||||
match_id: m_event.match_id,
|
|
||||||
body,
|
|
||||||
format: m_event.format,
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
Err(err) => match err.downcast_ref::<RendererError>() {
|
|
||||||
Some(RendererError::Aborted) => return Event::caused_by(event.source_id, EventType::NOOP),
|
|
||||||
_ => {
|
|
||||||
error!("error during rendering: {}", err);
|
|
||||||
return Event::caused_by(event.source_id, EventType::ProcessingError("An error has occurred during rendering, please examine the logs or contact support.".to_string()));
|
|
||||||
}
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
event
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: test
|
|
|
@ -1,75 +0,0 @@
|
||||||
/*
|
|
||||||
* 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 <https://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
use std::collections::HashMap;
|
|
||||||
|
|
||||||
use super::super::Middleware;
|
|
||||||
use crate::engine::{event::{
|
|
||||||
internal::{DetectedMatch, MatchesDetectedEvent},
|
|
||||||
Event, EventType,
|
|
||||||
}};
|
|
||||||
|
|
||||||
pub trait MatchProvider {
|
|
||||||
fn get_all_matches_ids(&self) -> Vec<i32>;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct SearchMiddleware<'a> {
|
|
||||||
match_provider: &'a dyn MatchProvider,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> SearchMiddleware<'a> {
|
|
||||||
pub fn new(match_provider: &'a dyn MatchProvider) -> Self {
|
|
||||||
Self { match_provider }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> Middleware for SearchMiddleware<'a> {
|
|
||||||
fn name(&self) -> &'static str {
|
|
||||||
"search"
|
|
||||||
}
|
|
||||||
|
|
||||||
fn next(&self, event: Event, dispatch: &mut dyn FnMut(Event)) -> Event {
|
|
||||||
if let EventType::ShowSearchBar = event.etype {
|
|
||||||
let detected_matches = Event::caused_by(
|
|
||||||
event.source_id,
|
|
||||||
EventType::MatchesDetected(MatchesDetectedEvent {
|
|
||||||
matches: self
|
|
||||||
.match_provider
|
|
||||||
.get_all_matches_ids()
|
|
||||||
.into_iter()
|
|
||||||
.map(|id| DetectedMatch {
|
|
||||||
id,
|
|
||||||
trigger: None,
|
|
||||||
left_separator: None,
|
|
||||||
right_separator: None,
|
|
||||||
args: HashMap::new(),
|
|
||||||
})
|
|
||||||
.collect(),
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
dispatch(detected_matches);
|
|
||||||
|
|
||||||
return Event::caused_by(event.source_id, EventType::NOOP);
|
|
||||||
}
|
|
||||||
|
|
||||||
event
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: test
|
|
|
@ -1,130 +0,0 @@
|
||||||
/*
|
|
||||||
* 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 <https://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
use super::{Event, event::{EventType, input::Key, internal::DetectedMatch}};
|
|
||||||
use anyhow::Result;
|
|
||||||
use std::collections::HashMap;
|
|
||||||
use thiserror::Error;
|
|
||||||
|
|
||||||
mod default;
|
|
||||||
mod middleware;
|
|
||||||
|
|
||||||
pub trait Middleware {
|
|
||||||
fn name(&self) -> &'static str;
|
|
||||||
fn next(&self, event: Event, dispatch: &mut dyn FnMut(Event)) -> Event;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub trait Processor {
|
|
||||||
fn process(&mut self, event: Event) -> Vec<Event>;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Dependency inversion entities
|
|
||||||
|
|
||||||
// TODO: move these traits inside the various modules and then re-export it
|
|
||||||
|
|
||||||
pub trait Matcher<'a, State> {
|
|
||||||
fn process(
|
|
||||||
&'a self,
|
|
||||||
prev_state: Option<&State>,
|
|
||||||
event: &MatcherEvent,
|
|
||||||
) -> (State, Vec<MatchResult>);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub enum MatcherEvent {
|
|
||||||
Key { key: Key, chars: Option<String> },
|
|
||||||
VirtualSeparator,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
|
||||||
pub struct MatchResult {
|
|
||||||
pub id: i32,
|
|
||||||
pub trigger: String,
|
|
||||||
pub left_separator: Option<String>,
|
|
||||||
pub right_separator: Option<String>,
|
|
||||||
pub args: HashMap<String, String>,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub trait MatchFilter {
|
|
||||||
fn filter_active(&self, matches_ids: &[i32]) -> Vec<i32>;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub trait MatchSelector {
|
|
||||||
fn select(&self, matches_ids: &[i32]) -> Option<i32>;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub trait Multiplexer {
|
|
||||||
fn convert(
|
|
||||||
&self,
|
|
||||||
m: DetectedMatch,
|
|
||||||
) -> Option<EventType>;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub trait Renderer<'a> {
|
|
||||||
fn render(&'a self, match_id: i32, trigger: Option<&str>, trigger_args: HashMap<String, String>) -> Result<String>;
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Error, Debug)]
|
|
||||||
pub enum RendererError {
|
|
||||||
#[error("rendering error")]
|
|
||||||
RenderingError(#[from] anyhow::Error),
|
|
||||||
|
|
||||||
#[error("match not found")]
|
|
||||||
NotFound,
|
|
||||||
|
|
||||||
#[error("aborted")]
|
|
||||||
Aborted,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub use middleware::action::{MatchInfoProvider, EventSequenceProvider};
|
|
||||||
pub use middleware::delay_modifiers::ModifierStatusProvider;
|
|
||||||
pub use middleware::image_resolve::PathProvider;
|
|
||||||
pub use middleware::disable::DisableOptions;
|
|
||||||
pub use middleware::matcher::MatcherMiddlewareConfigProvider;
|
|
||||||
pub use middleware::search::MatchProvider;
|
|
||||||
|
|
||||||
pub fn default<'a, MatcherState>(
|
|
||||||
matchers: &'a [&'a dyn Matcher<'a, MatcherState>],
|
|
||||||
match_filter: &'a dyn MatchFilter,
|
|
||||||
match_selector: &'a dyn MatchSelector,
|
|
||||||
multiplexer: &'a dyn Multiplexer,
|
|
||||||
renderer: &'a dyn Renderer<'a>,
|
|
||||||
match_info_provider: &'a dyn MatchInfoProvider,
|
|
||||||
modifier_status_provider: &'a dyn ModifierStatusProvider,
|
|
||||||
event_sequence_provider: &'a dyn EventSequenceProvider,
|
|
||||||
path_provider: &'a dyn PathProvider,
|
|
||||||
disable_options: DisableOptions,
|
|
||||||
matcher_options_provider: &'a dyn MatcherMiddlewareConfigProvider,
|
|
||||||
match_provider: &'a dyn MatchProvider,
|
|
||||||
) -> impl Processor + 'a {
|
|
||||||
default::DefaultProcessor::new(
|
|
||||||
matchers,
|
|
||||||
match_filter,
|
|
||||||
match_selector,
|
|
||||||
multiplexer,
|
|
||||||
renderer,
|
|
||||||
match_info_provider,
|
|
||||||
modifier_status_provider,
|
|
||||||
event_sequence_provider,
|
|
||||||
path_provider,
|
|
||||||
disable_options,
|
|
||||||
matcher_options_provider,
|
|
||||||
match_provider,
|
|
||||||
)
|
|
||||||
}
|
|
|
@ -42,7 +42,6 @@ mod capabilities;
|
||||||
mod cli;
|
mod cli;
|
||||||
mod common_flags;
|
mod common_flags;
|
||||||
mod config;
|
mod config;
|
||||||
mod engine;
|
|
||||||
mod exit_code;
|
mod exit_code;
|
||||||
mod gui;
|
mod gui;
|
||||||
mod icon;
|
mod icon;
|
||||||
|
|
Loading…
Reference in New Issue
Block a user