diff --git a/espanso-engine/src/event/external.rs b/espanso-engine/src/event/external.rs new file mode 100644 index 0000000..91ae9d1 --- /dev/null +++ b/espanso-engine/src/event/external.rs @@ -0,0 +1,26 @@ +/* + * 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 . + */ + +use std::collections::HashMap; + +#[derive(Debug, Clone, PartialEq)] +pub struct MatchExecRequestEvent { + pub trigger: Option, + pub args: HashMap, +} diff --git a/espanso-engine/src/event/mod.rs b/espanso-engine/src/event/mod.rs index 8769e0e..43397e7 100644 --- a/espanso-engine/src/event/mod.rs +++ b/espanso-engine/src/event/mod.rs @@ -18,6 +18,7 @@ */ pub mod effect; +pub mod external; pub mod input; pub mod internal; pub mod ui; @@ -60,6 +61,9 @@ pub enum EventType { TrayIconClicked, ContextMenuClicked(input::ContextMenuClickedEvent), + // External requests + MatchExecRequest(external::MatchExecRequestEvent), + // Internal MatchesDetected(internal::MatchesDetectedEvent), MatchSelected(internal::MatchSelectedEvent), diff --git a/espanso-engine/src/process/default.rs b/espanso-engine/src/process/default.rs index b0f85b8..0fc652f 100644 --- a/espanso-engine/src/process/default.rs +++ b/espanso-engine/src/process/default.rs @@ -33,16 +33,16 @@ use super::{ render::RenderMiddleware, }, DisableOptions, EnabledStatusProvider, MatchFilter, MatchInfoProvider, MatchProvider, - MatchSelector, Matcher, MatcherMiddlewareConfigProvider, Middleware, ModifierStateProvider, - Multiplexer, PathProvider, Processor, Renderer, UndoEnabledProvider, + MatchResolver, MatchSelector, Matcher, MatcherMiddlewareConfigProvider, Middleware, + ModifierStateProvider, Multiplexer, PathProvider, Processor, Renderer, UndoEnabledProvider, }; use crate::{ event::{Event, EventType}, process::middleware::{ context_menu::ContextMenuMiddleware, disable::DisableMiddleware, exit::ExitMiddleware, hotkey::HotKeyMiddleware, icon_status::IconStatusMiddleware, - image_resolve::ImageResolverMiddleware, search::SearchMiddleware, suppress::SuppressMiddleware, - undo::UndoMiddleware, + image_resolve::ImageResolverMiddleware, match_exec::MatchExecRequestMiddleware, + search::SearchMiddleware, suppress::SuppressMiddleware, undo::UndoMiddleware, }, }; use std::collections::VecDeque; @@ -70,6 +70,7 @@ impl<'a> DefaultProcessor<'a> { undo_enabled_provider: &'a dyn UndoEnabledProvider, enabled_status_provider: &'a dyn EnabledStatusProvider, modifier_state_provider: &'a dyn ModifierStateProvider, + match_resolver: &'a dyn MatchResolver, ) -> DefaultProcessor<'a> { Self { event_queue: VecDeque::new(), @@ -82,6 +83,7 @@ impl<'a> DefaultProcessor<'a> { matcher_options_provider, modifier_state_provider, )), + Box::new(MatchExecRequestMiddleware::new(match_resolver)), Box::new(SuppressMiddleware::new(enabled_status_provider)), Box::new(ContextMenuMiddleware::new()), Box::new(HotKeyMiddleware::new()), diff --git a/espanso-engine/src/process/middleware/match_exec.rs b/espanso-engine/src/process/middleware/match_exec.rs new file mode 100644 index 0000000..5b8a669 --- /dev/null +++ b/espanso-engine/src/process/middleware/match_exec.rs @@ -0,0 +1,80 @@ +/* + * 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 . + */ + +use log::warn; + +use super::super::Middleware; +use crate::event::{ + internal::{DetectedMatch, MatchesDetectedEvent}, + Event, EventType, +}; + +pub trait MatchResolver { + fn find_matches_from_trigger(&self, trigger: &str) -> Vec; +} + +pub struct MatchExecRequestMiddleware<'a> { + match_resolver: &'a dyn MatchResolver, +} + +impl<'a> MatchExecRequestMiddleware<'a> { + pub fn new(match_resolver: &'a dyn MatchResolver) -> Self { + Self { match_resolver } + } +} + +impl<'a> Middleware for MatchExecRequestMiddleware<'a> { + fn name(&self) -> &'static str { + "match_exec_request" + } + + fn next(&self, event: Event, _: &mut dyn FnMut(Event)) -> Event { + if let EventType::MatchExecRequest(m_event) = &event.etype { + let mut matches = if let Some(trigger) = &m_event.trigger { + self.match_resolver.find_matches_from_trigger(trigger) + } else { + Vec::new() + }; + + // Inject the request args into the detected matches + matches.iter_mut().for_each(|m| { + for (key, value) in &m_event.args { + m.args.insert(key.to_string(), value.to_string()); + } + }); + + if matches.is_empty() { + warn!("received match exec request, but no matches have been found for the given query."); + return Event::caused_by(event.source_id, EventType::NOOP); + } + + return Event::caused_by( + event.source_id, + EventType::MatchesDetected(MatchesDetectedEvent { + matches, + is_search: false, + }), + ); + } + + event + } +} + +// TODO: test diff --git a/espanso-engine/src/process/middleware/mod.rs b/espanso-engine/src/process/middleware/mod.rs index 9ba98b3..5c72d6e 100644 --- a/espanso-engine/src/process/middleware/mod.rs +++ b/espanso-engine/src/process/middleware/mod.rs @@ -29,6 +29,7 @@ pub mod hotkey; pub mod icon_status; pub mod image_resolve; pub mod markdown; +pub mod match_exec; pub mod match_select; pub mod matcher; pub mod multiplex; diff --git a/espanso-engine/src/process/mod.rs b/espanso-engine/src/process/mod.rs index 1e295f9..eb42768 100644 --- a/espanso-engine/src/process/mod.rs +++ b/espanso-engine/src/process/mod.rs @@ -37,6 +37,7 @@ pub use middleware::action::{EventSequenceProvider, MatchInfoProvider}; pub use middleware::delay_modifiers::ModifierStatusProvider; pub use middleware::disable::DisableOptions; pub use middleware::image_resolve::PathProvider; +pub use middleware::match_exec::MatchResolver; pub use middleware::match_select::{MatchFilter, MatchSelector}; pub use middleware::matcher::{ MatchResult, Matcher, MatcherEvent, MatcherMiddlewareConfigProvider, ModifierState, @@ -65,6 +66,7 @@ pub fn default<'a, MatcherState>( undo_enabled_provider: &'a dyn UndoEnabledProvider, enabled_status_provider: &'a dyn EnabledStatusProvider, modifier_state_provider: &'a dyn ModifierStateProvider, + match_resolver: &'a dyn MatchResolver, ) -> impl Processor + 'a { default::DefaultProcessor::new( matchers, @@ -82,5 +84,6 @@ pub fn default<'a, MatcherState>( undo_enabled_provider, enabled_status_provider, modifier_state_provider, + match_resolver, ) }