refactor(core): move engine into separate module

This commit is contained in:
Federico Terzi 2021-08-14 11:08:20 +02:00
parent 974e405b23
commit 1713b078be
71 changed files with 332 additions and 3374 deletions

20
Cargo.lock generated
View File

@ -522,6 +522,7 @@ dependencies = [
"espanso-clipboard",
"espanso-config",
"espanso-detect",
"espanso-engine",
"espanso-info",
"espanso-inject",
"espanso-ipc",
@ -535,13 +536,11 @@ dependencies = [
"espanso-ui",
"fs2",
"fs_extra",
"html2text",
"lazy_static",
"libc",
"log",
"log-panics",
"maplit",
"markdown",
"named_pipe",
"notify",
"opener",
@ -611,6 +610,19 @@ dependencies = [
"widestring",
]
[[package]]
name = "espanso-engine"
version = "0.1.0"
dependencies = [
"anyhow",
"crossbeam",
"html2text",
"log",
"markdown",
"tempdir",
"thiserror",
]
[[package]]
name = "espanso-info"
version = "0.1.0"
@ -1873,9 +1885,9 @@ dependencies = [
[[package]]
name = "siphasher"
version = "0.3.5"
version = "0.3.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cbce6d4507c7e4a3962091436e56e95290cb71fa302d0d270e32130b75fbff27"
checksum = "729a25c17d72b06c68cb47955d44fda88ad2d3e7d77e025663fdd69b93dd71a1"
[[package]]
name = "slab"

View File

@ -16,4 +16,5 @@ members = [
"espanso-migrate",
"espanso-mac-utils",
"espanso-kvs",
"espanso-engine",
]

View File

@ -33,6 +33,7 @@ espanso-ipc = { path = "../espanso-ipc" }
espanso-modulo = { path = "../espanso-modulo", optional = true }
espanso-migrate = { path = "../espanso-migrate" }
espanso-kvs = { path = "../espanso-kvs" }
espanso-engine = { path = "../espanso-engine" }
maplit = "1.0.2"
simplelog = "0.9.0"
log = "0.4.14"
@ -45,8 +46,6 @@ enum-as-inner = "0.3.3"
dirs = "3.0.1"
serde = { version = "1.0.123", features = ["derive"] }
serde_json = "1.0.62"
markdown = "0.3.0"
html2text = "0.2.1"
log-panics = "2.0.0"
fs2 = "0.4.3"
serde_yaml = "0.8.17"

View File

@ -17,10 +17,9 @@
* along with espanso. If not, see <https://www.gnu.org/licenses/>.
*/
use crate::{
cli::worker::builtin::generate_next_builtin_id,
engine::event::{effect::TextInjectRequest, EventType},
};
use espanso_engine::event::{effect::TextInjectRequest, EventType};
use crate::cli::worker::builtin::generate_next_builtin_id;
use super::BuiltInMatch;

View File

@ -21,7 +21,7 @@ use std::cell::Cell;
use espanso_config::config::Config;
use crate::engine::event::EventType;
use espanso_engine::event::EventType;
use super::context::Context;

View File

@ -17,19 +17,22 @@
* 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;
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 {
id: generate_next_builtin_id(),
label: "Open search bar",
triggers: trigger.map(|trigger| vec![trigger]).unwrap_or_default(),
hotkey,
action: |_| {
EventType::ShowSearchBar
},
action: |_| EventType::ShowSearchBar,
..Default::default()
}
}

View File

@ -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> {
let ids_set: HashSet<i32> = HashSet::from_iter(matches_ids.iter().copied());
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> {
fn active_mode(&self) -> crate::engine::dispatch::Mode {
impl<'a> espanso_engine::dispatch::ModeProvider for ConfigManager<'a> {
fn active_mode(&self) -> espanso_engine::dispatch::Mode {
let config = self.active();
match config.backend() {
espanso_config::config::Backend::Inject => crate::engine::dispatch::Mode::Event,
espanso_config::config::Backend::Clipboard => crate::engine::dispatch::Mode::Clipboard,
espanso_config::config::Backend::Auto => crate::engine::dispatch::Mode::Auto {
espanso_config::config::Backend::Inject => espanso_engine::dispatch::Mode::Event,
espanso_config::config::Backend::Clipboard => espanso_engine::dispatch::Mode::Clipboard,
espanso_config::config::Backend::Auto => espanso_engine::dispatch::Mode::Auto {
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 {
self.default().backspace_limit()
}

View File

@ -17,13 +17,14 @@
* along with espanso. If not, see <https://www.gnu.org/licenses/>.
*/
use std::{path::Path};
use std::path::Path;
use anyhow::Result;
use crossbeam::channel::Sender;
use espanso_engine::event::ExitMode;
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;
@ -40,7 +41,7 @@ pub fn initialize_and_spawn(runtime_dir: &Path, exit_notify: Sender<ExitMode>) -
fn daemon_monitor_main(runtime_dir: &Path, exit_notify: Sender<ExitMode>) {
info!("monitoring the status of the daemon process");
loop {
let is_daemon_lock_free = {
let lock = acquire_daemon_lock(runtime_dir);
@ -55,6 +56,8 @@ fn daemon_monitor_main(runtime_dir: &Path, exit_notify: Sender<ExitMode>) {
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,
));
}
}

View File

@ -23,7 +23,7 @@ use espanso_clipboard::Clipboard;
use espanso_inject::{keys::Key, InjectionOptions, Injector};
use log::error;
use crate::engine::{
use espanso_engine::{
dispatch::HtmlInjector,
dispatch::{ImageInjector, TextInjector},
};

View File

@ -19,7 +19,7 @@
use espanso_ui::UIRemote;
use crate::engine::dispatch::ContextMenuHandler;
use espanso_engine::dispatch::ContextMenuHandler;
pub struct ContextMenuHandlerAdapter<'a> {
remote: &'a dyn UIRemote,
@ -32,7 +32,7 @@ impl<'a> 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> =
items.iter().map(convert_to_ui_menu_item).collect();
let ui_menu = espanso_ui::menu::Menu {
@ -46,16 +46,16 @@ impl<'a> ContextMenuHandler for ContextMenuHandlerAdapter<'a> {
}
fn convert_to_ui_menu_item(
item: &crate::engine::event::ui::MenuItem,
item: &espanso_engine::event::ui::MenuItem,
) -> espanso_ui::menu::MenuItem {
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 {
id: simple.id,
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 {
label: sub.label.clone(),
items: sub
@ -65,6 +65,6 @@ fn convert_to_ui_menu_item(
.collect(),
})
}
crate::engine::event::ui::MenuItem::Separator => espanso_ui::menu::MenuItem::Separator,
espanso_engine::event::ui::MenuItem::Separator => espanso_ui::menu::MenuItem::Separator,
}
}

View File

@ -21,7 +21,7 @@ use std::convert::TryInto;
use espanso_inject::{InjectionOptions, Injector};
use crate::engine::dispatch::TextInjector;
use espanso_engine::dispatch::TextInjector;
use super::InjectParamsProvider;

View File

@ -19,7 +19,7 @@
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> {
remote: &'a dyn UIRemote,

View File

@ -20,7 +20,7 @@
use std::convert::TryInto;
use espanso_inject::{InjectionOptions, Injector};
use crate::engine::dispatch::KeyInjector;
use espanso_engine::dispatch::KeyInjector;
use super::InjectParamsProvider;
@ -36,7 +36,7 @@ impl<'a> 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 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 {
crate::engine::event::input::Key::Alt => espanso_inject::keys::Key::Alt,
crate::engine::event::input::Key::CapsLock => espanso_inject::keys::Key::CapsLock,
crate::engine::event::input::Key::Control => espanso_inject::keys::Key::Control,
crate::engine::event::input::Key::Meta => espanso_inject::keys::Key::Meta,
crate::engine::event::input::Key::NumLock => espanso_inject::keys::Key::NumLock,
crate::engine::event::input::Key::Shift => espanso_inject::keys::Key::Shift,
crate::engine::event::input::Key::Enter => espanso_inject::keys::Key::Enter,
crate::engine::event::input::Key::Tab => espanso_inject::keys::Key::Tab,
crate::engine::event::input::Key::Space => espanso_inject::keys::Key::Space,
crate::engine::event::input::Key::ArrowDown => espanso_inject::keys::Key::ArrowDown,
crate::engine::event::input::Key::ArrowLeft => espanso_inject::keys::Key::ArrowLeft,
crate::engine::event::input::Key::ArrowRight => espanso_inject::keys::Key::ArrowRight,
crate::engine::event::input::Key::ArrowUp => espanso_inject::keys::Key::ArrowUp,
crate::engine::event::input::Key::End => espanso_inject::keys::Key::End,
crate::engine::event::input::Key::Home => espanso_inject::keys::Key::Home,
crate::engine::event::input::Key::PageDown => espanso_inject::keys::Key::PageDown,
crate::engine::event::input::Key::PageUp => espanso_inject::keys::Key::PageUp,
crate::engine::event::input::Key::Escape => espanso_inject::keys::Key::Escape,
crate::engine::event::input::Key::Backspace => espanso_inject::keys::Key::Backspace,
crate::engine::event::input::Key::F1 => espanso_inject::keys::Key::F1,
crate::engine::event::input::Key::F2 => espanso_inject::keys::Key::F2,
crate::engine::event::input::Key::F3 => espanso_inject::keys::Key::F3,
crate::engine::event::input::Key::F4 => espanso_inject::keys::Key::F4,
crate::engine::event::input::Key::F5 => espanso_inject::keys::Key::F5,
crate::engine::event::input::Key::F6 => espanso_inject::keys::Key::F6,
crate::engine::event::input::Key::F7 => espanso_inject::keys::Key::F7,
crate::engine::event::input::Key::F8 => espanso_inject::keys::Key::F8,
crate::engine::event::input::Key::F9 => espanso_inject::keys::Key::F9,
crate::engine::event::input::Key::F10 => espanso_inject::keys::Key::F10,
crate::engine::event::input::Key::F11 => espanso_inject::keys::Key::F11,
crate::engine::event::input::Key::F12 => espanso_inject::keys::Key::F12,
crate::engine::event::input::Key::F13 => espanso_inject::keys::Key::F13,
crate::engine::event::input::Key::F14 => espanso_inject::keys::Key::F14,
crate::engine::event::input::Key::F15 => espanso_inject::keys::Key::F15,
crate::engine::event::input::Key::F16 => espanso_inject::keys::Key::F16,
crate::engine::event::input::Key::F17 => espanso_inject::keys::Key::F17,
crate::engine::event::input::Key::F18 => espanso_inject::keys::Key::F18,
crate::engine::event::input::Key::F19 => espanso_inject::keys::Key::F19,
crate::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::Alt => espanso_inject::keys::Key::Alt,
espanso_engine::event::input::Key::CapsLock => espanso_inject::keys::Key::CapsLock,
espanso_engine::event::input::Key::Control => espanso_inject::keys::Key::Control,
espanso_engine::event::input::Key::Meta => espanso_inject::keys::Key::Meta,
espanso_engine::event::input::Key::NumLock => espanso_inject::keys::Key::NumLock,
espanso_engine::event::input::Key::Shift => espanso_inject::keys::Key::Shift,
espanso_engine::event::input::Key::Enter => espanso_inject::keys::Key::Enter,
espanso_engine::event::input::Key::Tab => espanso_inject::keys::Key::Tab,
espanso_engine::event::input::Key::Space => espanso_inject::keys::Key::Space,
espanso_engine::event::input::Key::ArrowDown => espanso_inject::keys::Key::ArrowDown,
espanso_engine::event::input::Key::ArrowLeft => espanso_inject::keys::Key::ArrowLeft,
espanso_engine::event::input::Key::ArrowRight => espanso_inject::keys::Key::ArrowRight,
espanso_engine::event::input::Key::ArrowUp => espanso_inject::keys::Key::ArrowUp,
espanso_engine::event::input::Key::End => espanso_inject::keys::Key::End,
espanso_engine::event::input::Key::Home => espanso_inject::keys::Key::Home,
espanso_engine::event::input::Key::PageDown => espanso_inject::keys::Key::PageDown,
espanso_engine::event::input::Key::PageUp => espanso_inject::keys::Key::PageUp,
espanso_engine::event::input::Key::Escape => espanso_inject::keys::Key::Escape,
espanso_engine::event::input::Key::Backspace => espanso_inject::keys::Key::Backspace,
espanso_engine::event::input::Key::F1 => espanso_inject::keys::Key::F1,
espanso_engine::event::input::Key::F2 => espanso_inject::keys::Key::F2,
espanso_engine::event::input::Key::F3 => espanso_inject::keys::Key::F3,
espanso_engine::event::input::Key::F4 => espanso_inject::keys::Key::F4,
espanso_engine::event::input::Key::F5 => espanso_inject::keys::Key::F5,
espanso_engine::event::input::Key::F6 => espanso_inject::keys::Key::F6,
espanso_engine::event::input::Key::F7 => espanso_inject::keys::Key::F7,
espanso_engine::event::input::Key::F8 => espanso_inject::keys::Key::F8,
espanso_engine::event::input::Key::F9 => espanso_inject::keys::Key::F9,
espanso_engine::event::input::Key::F10 => espanso_inject::keys::Key::F10,
espanso_engine::event::input::Key::F11 => espanso_inject::keys::Key::F11,
espanso_engine::event::input::Key::F12 => espanso_inject::keys::Key::F12,
espanso_engine::event::input::Key::F13 => espanso_inject::keys::Key::F13,
espanso_engine::event::input::Key::F14 => espanso_inject::keys::Key::F14,
espanso_engine::event::input::Key::F15 => espanso_inject::keys::Key::F15,
espanso_engine::event::input::Key::F16 => espanso_inject::keys::Key::F16,
espanso_engine::event::input::Key::F17 => espanso_inject::keys::Key::F17,
espanso_engine::event::input::Key::F18 => espanso_inject::keys::Key::F18,
espanso_engine::event::input::Key::F19 => espanso_inject::keys::Key::F19,
espanso_engine::event::input::Key::F20 => espanso_inject::keys::Key::F20,
espanso_engine::event::input::Key::Other(raw) => espanso_inject::keys::Key::Raw(*raw),
}
}

View File

@ -21,7 +21,7 @@ use std::process::Stdio;
use anyhow::{bail, Context};
use log::{error, info};
use crate::engine::dispatch::SecureInputManager;
use espanso_engine::dispatch::SecureInputManager;
pub struct SecureInputManagerAdapter {}

View File

@ -18,9 +18,15 @@
*/
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 receiver: Receiver<(InputEvent, SourceId)>,
@ -39,105 +45,99 @@ impl<'a> funnel::Source<'a> for DetectSource {
InputEvent::Keyboard(keyboard_event) => Event {
source_id,
etype: EventType::Keyboard(KeyboardEvent {
key: keyboard_event.key.into(),
key: convert_to_engine_key(keyboard_event.key),
value: keyboard_event.value,
status: keyboard_event.status.into(),
variant: keyboard_event.variant.map(|variant| variant.into()),
status: convert_to_engine_status(keyboard_event.status),
variant: keyboard_event
.variant
.map(|variant| convert_to_engine_variant(variant)),
}),
},
InputEvent::Mouse(mouse_event) => Event {
source_id,
etype: EventType::Mouse(MouseEvent {
status: mouse_event.status.into(),
button: mouse_event.button.into(),
status: convert_to_engine_status(mouse_event.status),
button: convert_to_engine_mouse_button(mouse_event.button),
}),
},
InputEvent::HotKey(hotkey_event) => Event {
source_id,
etype: EventType::HotKey(HotKeyEvent {
hotkey_id: hotkey_event.hotkey_id,
})
}
}),
},
}
}
}
impl From<espanso_detect::event::Key> for Key {
fn from(key: espanso_detect::event::Key) -> Self {
match key {
espanso_detect::event::Key::Alt => Key::Alt,
espanso_detect::event::Key::CapsLock => Key::CapsLock,
espanso_detect::event::Key::Control => Key::Control,
espanso_detect::event::Key::Meta => Key::Meta,
espanso_detect::event::Key::NumLock => Key::NumLock,
espanso_detect::event::Key::Shift => Key::Shift,
espanso_detect::event::Key::Enter => Key::Enter,
espanso_detect::event::Key::Tab => Key::Tab,
espanso_detect::event::Key::Space => Key::Space,
espanso_detect::event::Key::ArrowDown => Key::ArrowDown,
espanso_detect::event::Key::ArrowLeft => Key::ArrowLeft,
espanso_detect::event::Key::ArrowRight => Key::ArrowRight,
espanso_detect::event::Key::ArrowUp => Key::ArrowUp,
espanso_detect::event::Key::End => Key::End,
espanso_detect::event::Key::Home => Key::Home,
espanso_detect::event::Key::PageDown => Key::PageDown,
espanso_detect::event::Key::PageUp => Key::PageUp,
espanso_detect::event::Key::Escape => Key::Escape,
espanso_detect::event::Key::Backspace => Key::Backspace,
espanso_detect::event::Key::F1 => Key::F1,
espanso_detect::event::Key::F2 => Key::F2,
espanso_detect::event::Key::F3 => Key::F3,
espanso_detect::event::Key::F4 => Key::F4,
espanso_detect::event::Key::F5 => Key::F5,
espanso_detect::event::Key::F6 => Key::F6,
espanso_detect::event::Key::F7 => Key::F7,
espanso_detect::event::Key::F8 => Key::F8,
espanso_detect::event::Key::F9 => Key::F9,
espanso_detect::event::Key::F10 => Key::F10,
espanso_detect::event::Key::F11 => Key::F11,
espanso_detect::event::Key::F12 => Key::F12,
espanso_detect::event::Key::F13 => Key::F13,
espanso_detect::event::Key::F14 => Key::F14,
espanso_detect::event::Key::F15 => Key::F15,
espanso_detect::event::Key::F16 => Key::F16,
espanso_detect::event::Key::F17 => Key::F17,
espanso_detect::event::Key::F18 => Key::F18,
espanso_detect::event::Key::F19 => Key::F19,
espanso_detect::event::Key::F20 => Key::F20,
espanso_detect::event::Key::Other(code) => Key::Other(code),
}
pub fn convert_to_engine_key(key: espanso_detect::event::Key) -> Key {
match key {
espanso_detect::event::Key::Alt => Key::Alt,
espanso_detect::event::Key::CapsLock => Key::CapsLock,
espanso_detect::event::Key::Control => Key::Control,
espanso_detect::event::Key::Meta => Key::Meta,
espanso_detect::event::Key::NumLock => Key::NumLock,
espanso_detect::event::Key::Shift => Key::Shift,
espanso_detect::event::Key::Enter => Key::Enter,
espanso_detect::event::Key::Tab => Key::Tab,
espanso_detect::event::Key::Space => Key::Space,
espanso_detect::event::Key::ArrowDown => Key::ArrowDown,
espanso_detect::event::Key::ArrowLeft => Key::ArrowLeft,
espanso_detect::event::Key::ArrowRight => Key::ArrowRight,
espanso_detect::event::Key::ArrowUp => Key::ArrowUp,
espanso_detect::event::Key::End => Key::End,
espanso_detect::event::Key::Home => Key::Home,
espanso_detect::event::Key::PageDown => Key::PageDown,
espanso_detect::event::Key::PageUp => Key::PageUp,
espanso_detect::event::Key::Escape => Key::Escape,
espanso_detect::event::Key::Backspace => Key::Backspace,
espanso_detect::event::Key::F1 => Key::F1,
espanso_detect::event::Key::F2 => Key::F2,
espanso_detect::event::Key::F3 => Key::F3,
espanso_detect::event::Key::F4 => Key::F4,
espanso_detect::event::Key::F5 => Key::F5,
espanso_detect::event::Key::F6 => Key::F6,
espanso_detect::event::Key::F7 => Key::F7,
espanso_detect::event::Key::F8 => Key::F8,
espanso_detect::event::Key::F9 => Key::F9,
espanso_detect::event::Key::F10 => Key::F10,
espanso_detect::event::Key::F11 => Key::F11,
espanso_detect::event::Key::F12 => Key::F12,
espanso_detect::event::Key::F13 => Key::F13,
espanso_detect::event::Key::F14 => Key::F14,
espanso_detect::event::Key::F15 => Key::F15,
espanso_detect::event::Key::F16 => Key::F16,
espanso_detect::event::Key::F17 => Key::F17,
espanso_detect::event::Key::F18 => Key::F18,
espanso_detect::event::Key::F19 => Key::F19,
espanso_detect::event::Key::F20 => Key::F20,
espanso_detect::event::Key::Other(code) => Key::Other(code),
}
}
impl From<espanso_detect::event::Variant> for Variant {
fn from(variant: espanso_detect::event::Variant) -> Self {
match variant {
espanso_detect::event::Variant::Left => Variant::Left,
espanso_detect::event::Variant::Right => Variant::Right,
}
pub fn convert_to_engine_variant(variant: espanso_detect::event::Variant) -> Variant {
match variant {
espanso_detect::event::Variant::Left => Variant::Left,
espanso_detect::event::Variant::Right => Variant::Right,
}
}
impl From<espanso_detect::event::Status> for Status {
fn from(status: espanso_detect::event::Status) -> Self {
match status {
espanso_detect::event::Status::Pressed => Status::Pressed,
espanso_detect::event::Status::Released => Status::Released,
}
pub fn convert_to_engine_status(status: espanso_detect::event::Status) -> Status {
match status {
espanso_detect::event::Status::Pressed => Status::Pressed,
espanso_detect::event::Status::Released => Status::Released,
}
}
impl From<espanso_detect::event::MouseButton> for MouseButton {
fn from(button: espanso_detect::event::MouseButton) -> Self {
match button {
espanso_detect::event::MouseButton::Left => MouseButton::Left,
espanso_detect::event::MouseButton::Right => MouseButton::Right,
espanso_detect::event::MouseButton::Middle => MouseButton::Middle,
espanso_detect::event::MouseButton::Button1 => MouseButton::Button1,
espanso_detect::event::MouseButton::Button2 => MouseButton::Button2,
espanso_detect::event::MouseButton::Button3 => MouseButton::Button3,
espanso_detect::event::MouseButton::Button4 => MouseButton::Button4,
espanso_detect::event::MouseButton::Button5 => MouseButton::Button5,
}
pub fn convert_to_engine_mouse_button(button: espanso_detect::event::MouseButton) -> MouseButton {
match button {
espanso_detect::event::MouseButton::Left => MouseButton::Left,
espanso_detect::event::MouseButton::Right => MouseButton::Right,
espanso_detect::event::MouseButton::Middle => MouseButton::Middle,
espanso_detect::event::MouseButton::Button1 => MouseButton::Button1,
espanso_detect::event::MouseButton::Button2 => MouseButton::Button2,
espanso_detect::event::MouseButton::Button3 => MouseButton::Button3,
espanso_detect::event::MouseButton::Button4 => MouseButton::Button4,
espanso_detect::event::MouseButton::Button5 => MouseButton::Button5,
}
}

View File

@ -19,7 +19,7 @@
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;

View File

@ -24,7 +24,7 @@ use std::{
use log::warn;
use crate::engine::process::ModifierStatusProvider;
use espanso_engine::process::ModifierStatusProvider;
/// This duration represents the maximum length for which a pressed modifier
/// event is considered valid. This is useful when the "release" event is

View File

@ -19,12 +19,10 @@
use crossbeam::channel::{Receiver, Select, SelectedOperation};
use crate::{
cli::worker::secure_input::SecureInputEvent,
engine::{
event::{internal::SecureInputEnabledEvent, Event, EventType},
funnel,
},
use crate::cli::worker::secure_input::SecureInputEvent;
use espanso_engine::{
event::{internal::SecureInputEnabledEvent, Event, EventType},
funnel,
};
use super::sequencer::Sequencer;

View File

@ -22,7 +22,7 @@ use std::sync::{
Arc,
};
use crate::engine::{event::SourceId, process::EventSequenceProvider};
use espanso_engine::{event::SourceId, process::EventSequenceProvider};
#[derive(Clone)]
pub struct Sequencer {

View File

@ -20,7 +20,7 @@
use crossbeam::channel::{Receiver, Select, SelectedOperation};
use espanso_ui::event::UIEvent;
use crate::engine::{
use espanso_engine::{
event::{input::ContextMenuClickedEvent, Event, EventType},
funnel,
};

View File

@ -23,6 +23,7 @@ use anyhow::Result;
use crossbeam::channel::Receiver;
use espanso_config::{config::ConfigStore, matches::store::MatchStore};
use espanso_detect::SourceCreationOptions;
use espanso_engine::event::ExitMode;
use espanso_inject::{InjectorCreationOptions, KeyboardStateProvider};
use espanso_path::Paths;
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},
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;
@ -100,13 +101,13 @@ pub fn initialize_and_spawn(
secure_input_receiver,
&sequencer,
);
let sources: Vec<&dyn crate::engine::funnel::Source> = vec![
let sources: Vec<&dyn espanso_engine::funnel::Source> = vec![
&detect_source,
&exit_source,
&ui_source,
&secure_input_source,
];
let funnel = crate::engine::funnel::default(&sources);
let funnel = espanso_engine::funnel::default(&sources);
let rolling_matcher = RollingMatcherAdapter::new(
&match_converter.get_rolling_matches(),
@ -121,7 +122,7 @@ pub fn initialize_and_spawn(
},
);
let matchers: Vec<
&dyn crate::engine::process::Matcher<
&dyn espanso_engine::process::Matcher<
super::engine::process::middleware::matcher::MatcherState,
>,
> = vec![&rolling_matcher, &regex_matcher];
@ -171,7 +172,7 @@ pub fn initialize_and_spawn(
let disable_options =
process::middleware::disable::extract_disable_options(&*config_manager.default());
let mut processor = crate::engine::process::default(
let mut processor = espanso_engine::process::default(
&matchers,
&config_manager,
&selector,
@ -193,7 +194,7 @@ pub fn initialize_and_spawn(
let context_menu_adapter = ContextMenuHandlerAdapter::new(&*ui_remote);
let icon_adapter = IconHandlerAdapter::new(&*ui_remote);
let secure_input_adapter = SecureInputManagerAdapter::new();
let dispatcher = crate::engine::dispatch::default(
let dispatcher = espanso_engine::dispatch::default(
&event_injector,
&clipboard_injector,
&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();
info!("engine eventloop has terminated, propagating exit event...");

View File

@ -19,8 +19,11 @@
use std::time::Duration;
use crate::engine::{event::input::{Key, Variant}, process::DisableOptions};
use espanso_config::config::Config;
use espanso_engine::{
event::input::{Key, Variant},
process::DisableOptions,
};
pub fn extract_disable_options(config: &dyn Config) -> DisableOptions {
let (toggle_key, variant) = match config.toggle_key() {
@ -29,7 +32,7 @@ pub fn extract_disable_options(config: &dyn Config) -> DisableOptions {
espanso_config::config::ToggleKey::Meta => (Some(Key::Meta), None),
espanso_config::config::ToggleKey::Alt => (Some(Key::Alt), None),
espanso_config::config::ToggleKey::Shift => (Some(Key::Shift), None),
espanso_config::config::ToggleKey::RightCtrl => (Some(Key::Control), Some(Variant::Right)),
espanso_config::config::ToggleKey::RightCtrl => (Some(Key::Control), Some(Variant::Right)),
espanso_config::config::ToggleKey::RightAlt => (Some(Key::Alt), Some(Variant::Right)),
espanso_config::config::ToggleKey::RightShift => (Some(Key::Shift), Some(Variant::Right)),
espanso_config::config::ToggleKey::RightMeta => (Some(Key::Meta), Some(Variant::Right)),

View File

@ -19,21 +19,19 @@
use espanso_path::Paths;
use crate::engine::process::PathProvider;
use espanso_engine::process::PathProvider;
pub struct PathProviderAdapter<'a> {
paths: &'a Paths,
}
impl <'a> PathProviderAdapter<'a> {
impl<'a> PathProviderAdapter<'a> {
pub fn new(paths: &'a Paths) -> Self {
Self {
paths,
}
Self { paths }
}
}
impl <'a> PathProvider for PathProviderAdapter<'a> {
impl<'a> PathProvider for PathProviderAdapter<'a> {
fn get_config_path(&self) -> &std::path::Path {
&self.paths.config
}

View File

@ -17,12 +17,10 @@
* along with espanso. If not, see <https://www.gnu.org/licenses/>.
*/
use espanso_engine::process::MatchSelector;
use log::error;
use crate::{
engine::process::MatchSelector,
gui::{SearchItem, SearchUI},
};
use crate::gui::{SearchItem, SearchUI};
const MAX_LABEL_LEN: usize = 100;

View File

@ -17,18 +17,18 @@
* along with espanso. If not, see <https://www.gnu.org/licenses/>.
*/
use espanso_match::rolling::matcher::RollingMatcherState;
use espanso_match::regex::RegexMatcherState;
use crate::engine::{
use espanso_engine::{
event::input::Key,
process::{MatchResult, MatcherEvent},
};
use espanso_match::regex::RegexMatcherState;
use espanso_match::rolling::matcher::RollingMatcherState;
use enum_as_inner::EnumAsInner;
pub mod rolling;
pub mod regex;
pub mod convert;
pub mod regex;
pub mod rolling;
#[derive(Clone, EnumAsInner)]
pub enum MatcherState<'a> {
@ -36,73 +36,67 @@ pub enum MatcherState<'a> {
Regex(RegexMatcherState),
}
impl From<&MatcherEvent> for espanso_match::event::Event {
fn from(event: &MatcherEvent) -> Self {
match event {
MatcherEvent::Key { key, chars } => espanso_match::event::Event::Key {
key: key.clone().into(),
chars: chars.to_owned(),
},
MatcherEvent::VirtualSeparator => espanso_match::event::Event::VirtualSeparator,
}
pub fn convert_to_match_event(event: &MatcherEvent) -> espanso_match::event::Event {
match event {
MatcherEvent::Key { key, chars } => espanso_match::event::Event::Key {
key: convert_to_match_key(key.clone()),
chars: chars.to_owned(),
},
MatcherEvent::VirtualSeparator => espanso_match::event::Event::VirtualSeparator,
}
}
impl From<espanso_match::MatchResult<i32>> for MatchResult {
fn from(result: espanso_match::MatchResult<i32>) -> Self {
Self {
id: result.id,
trigger: result.trigger,
left_separator: result.left_separator,
right_separator: result.right_separator,
args: result.vars,
}
pub fn convert_to_engine_result(result: espanso_match::MatchResult<i32>) -> MatchResult {
MatchResult {
id: result.id,
trigger: result.trigger,
left_separator: result.left_separator,
right_separator: result.right_separator,
args: result.vars,
}
}
impl From<Key> for espanso_match::event::Key {
fn from(key: Key) -> Self {
match key {
Key::Alt => espanso_match::event::Key::Alt,
Key::CapsLock => espanso_match::event::Key::CapsLock,
Key::Control => espanso_match::event::Key::Control,
Key::Meta => espanso_match::event::Key::Meta,
Key::NumLock => espanso_match::event::Key::NumLock,
Key::Shift => espanso_match::event::Key::Shift,
Key::Enter => espanso_match::event::Key::Enter,
Key::Tab => espanso_match::event::Key::Tab,
Key::Space => espanso_match::event::Key::Space,
Key::ArrowDown => espanso_match::event::Key::ArrowDown,
Key::ArrowLeft => espanso_match::event::Key::ArrowLeft,
Key::ArrowRight => espanso_match::event::Key::ArrowRight,
Key::ArrowUp => espanso_match::event::Key::ArrowUp,
Key::End => espanso_match::event::Key::End,
Key::Home => espanso_match::event::Key::Home,
Key::PageDown => espanso_match::event::Key::PageDown,
Key::PageUp => espanso_match::event::Key::PageUp,
Key::Escape => espanso_match::event::Key::Escape,
Key::Backspace => espanso_match::event::Key::Backspace,
Key::F1 => espanso_match::event::Key::F1,
Key::F2 => espanso_match::event::Key::F2,
Key::F3 => espanso_match::event::Key::F3,
Key::F4 => espanso_match::event::Key::F4,
Key::F5 => espanso_match::event::Key::F5,
Key::F6 => espanso_match::event::Key::F6,
Key::F7 => espanso_match::event::Key::F7,
Key::F8 => espanso_match::event::Key::F8,
Key::F9 => espanso_match::event::Key::F9,
Key::F10 => espanso_match::event::Key::F10,
Key::F11 => espanso_match::event::Key::F11,
Key::F12 => espanso_match::event::Key::F12,
Key::F13 => espanso_match::event::Key::F13,
Key::F14 => espanso_match::event::Key::F14,
Key::F15 => espanso_match::event::Key::F15,
Key::F16 => espanso_match::event::Key::F16,
Key::F17 => espanso_match::event::Key::F17,
Key::F18 => espanso_match::event::Key::F18,
Key::F19 => espanso_match::event::Key::F19,
Key::F20 => espanso_match::event::Key::F20,
Key::Other(_) => espanso_match::event::Key::Other,
}
pub fn convert_to_match_key(key: Key) -> espanso_match::event::Key {
match key {
Key::Alt => espanso_match::event::Key::Alt,
Key::CapsLock => espanso_match::event::Key::CapsLock,
Key::Control => espanso_match::event::Key::Control,
Key::Meta => espanso_match::event::Key::Meta,
Key::NumLock => espanso_match::event::Key::NumLock,
Key::Shift => espanso_match::event::Key::Shift,
Key::Enter => espanso_match::event::Key::Enter,
Key::Tab => espanso_match::event::Key::Tab,
Key::Space => espanso_match::event::Key::Space,
Key::ArrowDown => espanso_match::event::Key::ArrowDown,
Key::ArrowLeft => espanso_match::event::Key::ArrowLeft,
Key::ArrowRight => espanso_match::event::Key::ArrowRight,
Key::ArrowUp => espanso_match::event::Key::ArrowUp,
Key::End => espanso_match::event::Key::End,
Key::Home => espanso_match::event::Key::Home,
Key::PageDown => espanso_match::event::Key::PageDown,
Key::PageUp => espanso_match::event::Key::PageUp,
Key::Escape => espanso_match::event::Key::Escape,
Key::Backspace => espanso_match::event::Key::Backspace,
Key::F1 => espanso_match::event::Key::F1,
Key::F2 => espanso_match::event::Key::F2,
Key::F3 => espanso_match::event::Key::F3,
Key::F4 => espanso_match::event::Key::F4,
Key::F5 => espanso_match::event::Key::F5,
Key::F6 => espanso_match::event::Key::F6,
Key::F7 => espanso_match::event::Key::F7,
Key::F8 => espanso_match::event::Key::F8,
Key::F9 => espanso_match::event::Key::F9,
Key::F10 => espanso_match::event::Key::F10,
Key::F11 => espanso_match::event::Key::F11,
Key::F12 => espanso_match::event::Key::F12,
Key::F13 => espanso_match::event::Key::F13,
Key::F14 => espanso_match::event::Key::F14,
Key::F15 => espanso_match::event::Key::F15,
Key::F16 => espanso_match::event::Key::F16,
Key::F17 => espanso_match::event::Key::F17,
Key::F18 => espanso_match::event::Key::F18,
Key::F19 => espanso_match::event::Key::F19,
Key::F20 => espanso_match::event::Key::F20,
Key::Other(_) => espanso_match::event::Key::Other,
}
}

View File

@ -17,10 +17,10 @@
* 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 super::MatcherState;
use super::{convert_to_engine_result, convert_to_match_event, MatcherState};
pub struct RegexMatcherAdapterOptions {
pub max_buffer_size: usize,
@ -32,9 +32,12 @@ pub struct RegexMatcherAdapter {
impl RegexMatcherAdapter {
pub fn new(matches: &[RegexMatch<i32>], options: &RegexMatcherAdapterOptions) -> Self {
let matcher = RegexMatcher::new(matches, RegexMatcherOptions {
max_buffer_size: options.max_buffer_size,
});
let matcher = RegexMatcher::new(
matches,
RegexMatcherOptions {
max_buffer_size: options.max_buffer_size,
},
);
Self { matcher }
}
@ -55,12 +58,12 @@ impl<'a> Matcher<'a, MatcherState<'a>> for 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 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)
}

View File

@ -22,11 +22,9 @@ use espanso_match::rolling::{
RollingMatch,
};
use crate::engine::{
process::{MatchResult, Matcher, MatcherEvent},
};
use espanso_engine::process::{MatchResult, Matcher, MatcherEvent};
use super::MatcherState;
use super::{convert_to_engine_result, convert_to_match_event, MatcherState};
pub struct RollingMatcherAdapterOptions {
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")
}
});
let event = event.into();
let event = convert_to_match_event(event);
let (state, results) = self.matcher.process(prev_state, event);
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)
}

View File

@ -19,16 +19,14 @@
use espanso_config::matches::{Match, MatchEffect};
use crate::{
cli::worker::{builtin::BuiltInMatch, context::Context},
engine::{
event::{
internal::DetectedMatch,
internal::{ImageRequestedEvent, RenderingRequestedEvent, TextFormat},
EventType,
},
process::Multiplexer,
use crate::cli::worker::{builtin::BuiltInMatch, context::Context};
use espanso_engine::{
event::{
internal::DetectedMatch,
internal::{ImageRequestedEvent, RenderingRequestedEvent, TextFormat},
EventType,
},
process::Multiplexer,
};
pub trait MatchProvider<'a> {
@ -46,7 +44,7 @@ pub struct 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 }
}
}

View File

@ -27,9 +27,7 @@ use espanso_config::{
};
use espanso_render::{CasingStyle, Context, RenderOptions, Template, Value, Variable};
use crate::{
engine::process::{Renderer, RendererError},
};
use espanso_engine::process::{Renderer, RendererError};
pub trait MatchProvider<'a> {
fn matches(&self) -> Vec<&'a Match>;
@ -200,7 +198,7 @@ impl<'a> Renderer<'a> for RendererAdapter<'a> {
let context = context_cache
.entry(config.id())
.or_insert_with(|| generate_context(&match_set, &self.template_map, &self.global_vars_map));
let raw_match = self.match_provider.get(match_id);
let propagate_case = raw_match.map(is_propagate_case).unwrap_or(false);
let preferred_uppercasing_style = raw_match.and_then(extract_uppercasing_style);
@ -221,11 +219,14 @@ impl<'a> Renderer<'a> for RendererAdapter<'a> {
for (name, value) in trigger_vars {
let mut params = espanso_render::Params::new();
params.insert("echo".to_string(), Value::String(value));
augmented.vars.insert(0, Variable {
name,
var_type: "echo".to_string(),
params,
})
augmented.vars.insert(
0,
Variable {
name,
var_type: "echo".to_string(),
params,
},
)
}
Some(augmented)
} else {

View File

@ -21,10 +21,11 @@ use std::path::Path;
use anyhow::Result;
use crossbeam::channel::Sender;
use espanso_engine::event::ExitMode;
use espanso_ipc::{EventHandlerResponse, IPCServer};
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<()> {
let server = crate::ipc::create_worker_ipc_server(runtime_dir)?;
@ -32,38 +33,38 @@ pub fn initialize_and_spawn(runtime_dir: &Path, exit_notify: Sender<ExitMode>) -
std::thread::Builder::new()
.name("worker-ipc-handler".to_string())
.spawn(move || {
server.run(Box::new(move |event| {
match event {
IPCEvent::Exit => {
if let Err(err) = exit_notify.send(ExitMode::Exit) {
error!(
"experienced error while sending exit signal from worker ipc handler: {}",
err
);
}
EventHandlerResponse::NoResponse
}
IPCEvent::ExitAllProcesses => {
if let Err(err) = exit_notify.send(ExitMode::ExitAllProcesses) {
error!(
"experienced error while sending exit signal from worker ipc handler: {}",
err
);
}
EventHandlerResponse::NoResponse
}
unexpected_event => {
warn!(
"received unexpected event in worker ipc handler: {:?}",
unexpected_event
server
.run(Box::new(move |event| match event {
IPCEvent::Exit => {
if let Err(err) = exit_notify.send(ExitMode::Exit) {
error!(
"experienced error while sending exit signal from worker ipc handler: {}",
err
);
EventHandlerResponse::NoResponse
}
EventHandlerResponse::NoResponse
}
})).expect("unable to spawn IPC server");
IPCEvent::ExitAllProcesses => {
if let Err(err) = exit_notify.send(ExitMode::ExitAllProcesses) {
error!(
"experienced error while sending exit signal from worker ipc handler: {}",
err
);
}
EventHandlerResponse::NoResponse
}
unexpected_event => {
warn!(
"received unexpected event in worker ipc handler: {:?}",
unexpected_event
);
EventHandlerResponse::NoResponse
}
}))
.expect("unable to spawn IPC server");
})?;
Ok(())

View File

@ -59,17 +59,17 @@ impl<'a> super::engine::process::middleware::render::MatchProvider<'a> for Match
}
}
impl<'a> crate::engine::process::MatchInfoProvider for MatchCache<'a> {
fn get_force_mode(&self, match_id: i32) -> Option<crate::engine::event::effect::TextInjectMode> {
impl<'a> espanso_engine::process::MatchInfoProvider for MatchCache<'a> {
fn get_force_mode(&self, match_id: i32) -> Option<espanso_engine::event::effect::TextInjectMode> {
let m = self.cache.get(&match_id)?;
if let MatchEffect::Text(text_effect) = &m.effect {
if let Some(force_mode) = &text_effect.force_mode {
match force_mode {
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 => {
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> {
let mut ids: Vec<i32> = self.builtin_match_cache.keys().copied().collect();
ids.extend(self.user_match_cache.ids());

View File

@ -18,10 +18,10 @@
*/
use crossbeam::channel::unbounded;
use espanso_engine::event::ExitMode;
use log::{debug, error, info};
use crate::{
engine::event::ExitMode,
exit_code::{
WORKER_ALREADY_RUNNING, WORKER_EXIT_ALL_PROCESSES, WORKER_GENERAL_ERROR,
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");
// When restarted, the daemon passes the reason why the worker was restarted (config_change, etc)
let start_reason = cli_args
.value_of("start-reason")
.map(String::from);
let start_reason = cli_args.value_of("start-reason").map(String::from);
debug!("starting with start-reason = {:?}", start_reason);
// Avoid running multiple worker instances

View File

@ -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;
}
}
}
}

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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
}
}

View File

@ -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;

View File

@ -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
}
}

View File

@ -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

View File

@ -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,
)
}

View File

@ -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,
}

View File

@ -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,
}

View File

@ -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,
}

View File

@ -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,
}

View File

@ -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,
}

View File

@ -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)
}
}

View File

@ -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)
}

View File

@ -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;
}
}
}
}
}

View File

@ -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
}
}

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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;

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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,
)
}

View File

@ -42,7 +42,6 @@ mod capabilities;
mod cli;
mod common_flags;
mod config;
mod engine;
mod exit_code;
mod gui;
mod icon;