diff --git a/espanso/src/cli/worker/builtin/mod.rs b/espanso/src/cli/worker/builtin/mod.rs index 39a6794..d2f7bf9 100644 --- a/espanso/src/cli/worker/builtin/mod.rs +++ b/espanso/src/cli/worker/builtin/mod.rs @@ -19,11 +19,14 @@ use std::cell::Cell; +use espanso_config::config::Config; + use crate::engine::event::EventType; use super::context::Context; mod debug; +mod search; const MIN_BUILTIN_MATCH_ID: i32 = 1_000_000_000; @@ -34,11 +37,17 @@ pub struct BuiltInMatch { pub action: fn(context: &dyn Context) -> EventType, } -pub fn get_builtin_matches() -> Vec { - vec![ +pub fn get_builtin_matches(config: &dyn Config) -> Vec { + let mut matches = vec![ debug::create_match_paste_active_config_info(), debug::create_match_paste_active_app_info(), - ] + ]; + + if let Some(search_trigger) = config.search_trigger() { + matches.push(search::create_match_trigger_search_bar(&search_trigger)); + } + + matches } pub fn is_builtin_match(id: i32) -> bool { diff --git a/espanso/src/cli/worker/builtin/search.rs b/espanso/src/cli/worker/builtin/search.rs new file mode 100644 index 0000000..296540d --- /dev/null +++ b/espanso/src/cli/worker/builtin/search.rs @@ -0,0 +1,33 @@ +/* + * 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 crate::{cli::worker::builtin::generate_next_builtin_id, engine::event::{EventType}}; + +use super::BuiltInMatch; + +pub fn create_match_trigger_search_bar(shortcut: &str) -> BuiltInMatch { + BuiltInMatch { + id: generate_next_builtin_id(), + label: "Open search bar", + triggers: vec![shortcut.to_string()], + action: |_| { + EventType::ShowSearchBar + }, + } +} diff --git a/espanso/src/cli/worker/engine/mod.rs b/espanso/src/cli/worker/engine/mod.rs index 7bd3196..bdb6653 100644 --- a/espanso/src/cli/worker/engine/mod.rs +++ b/espanso/src/cli/worker/engine/mod.rs @@ -79,7 +79,7 @@ pub fn initialize_and_spawn( let modulo_search_ui = crate::gui::modulo::search::ModuloSearchUI::new(&modulo_manager); let context: Box = Box::new(super::context::DefaultContext::new(&config_manager, &*app_info_provider)); - let builtin_matches = super::builtin::get_builtin_matches(); + let builtin_matches = super::builtin::get_builtin_matches(&*config_manager.default()); let combined_match_cache = CombinedMatchCache::load(&match_cache, &builtin_matches); let match_converter = MatchConverter::new(&*config_store, &*match_store, &builtin_matches); @@ -183,6 +183,7 @@ pub fn initialize_and_spawn( &path_provider, disable_options, &config_manager, + &combined_match_cache, ); let event_injector = EventInjectorAdapter::new(&*injector, &config_manager); diff --git a/espanso/src/cli/worker/match_cache.rs b/espanso/src/cli/worker/match_cache.rs index 4ce7d85..987a615 100644 --- a/espanso/src/cli/worker/match_cache.rs +++ b/espanso/src/cli/worker/match_cache.rs @@ -43,6 +43,10 @@ impl<'a> MatchCache<'a> { Self { cache } } + + fn ids(&self) -> Vec { + self.cache.keys().copied().collect() + } } impl<'a> super::engine::process::middleware::render::MatchProvider<'a> for MatchCache<'a> { @@ -150,3 +154,11 @@ impl<'a> super::engine::process::middleware::multiplex::MatchProvider<'a> }) } } + +impl<'a> crate::engine::process::MatchProvider for CombinedMatchCache<'a> { + fn get_all_matches_ids(&self) -> Vec { + let mut ids: Vec = self.builtin_match_cache.keys().copied().collect(); + ids.extend(self.user_match_cache.ids()); + ids + } +} diff --git a/espanso/src/engine/event/mod.rs b/espanso/src/engine/event/mod.rs index 8b980a2..c0b1c9b 100644 --- a/espanso/src/engine/event/mod.rs +++ b/espanso/src/engine/event/mod.rs @@ -92,6 +92,7 @@ pub enum EventType { ShowContextMenu(ui::ShowContextMenuEvent), IconStatusChange(ui::IconStatusChangeEvent), DisplaySecureInputTroubleshoot, + ShowSearchBar, // Other LaunchSecureInputAutoFix, diff --git a/espanso/src/engine/process/default.rs b/espanso/src/engine/process/default.rs index 1be6f78..967ec6a 100644 --- a/espanso/src/engine/process/default.rs +++ b/espanso/src/engine/process/default.rs @@ -19,13 +19,13 @@ use log::trace; -use super::{DisableOptions, MatchFilter, MatchInfoProvider, MatchSelector, Matcher, MatcherMiddlewareConfigProvider, Middleware, Multiplexer, PathProvider, Processor, Renderer, middleware::{ +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, icon_status::IconStatusMiddleware, image_resolve::ImageResolverMiddleware}}; +use crate::engine::{event::{Event, EventType}, process::middleware::{context_menu::ContextMenuMiddleware, disable::DisableMiddleware, exit::ExitMiddleware, icon_status::IconStatusMiddleware, image_resolve::ImageResolverMiddleware, search::SearchMiddleware}}; use std::collections::VecDeque; pub struct DefaultProcessor<'a> { @@ -46,6 +46,7 @@ impl<'a> DefaultProcessor<'a> { 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(), @@ -63,6 +64,7 @@ impl<'a> DefaultProcessor<'a> { 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)), ], diff --git a/espanso/src/engine/process/middleware/mod.rs b/espanso/src/engine/process/middleware/mod.rs index 47fe060..1c7a9b4 100644 --- a/espanso/src/engine/process/middleware/mod.rs +++ b/espanso/src/engine/process/middleware/mod.rs @@ -32,3 +32,4 @@ pub mod markdown; pub mod multiplex; pub mod past_discard; pub mod render; +pub mod search; diff --git a/espanso/src/engine/process/middleware/search.rs b/espanso/src/engine/process/middleware/search.rs new file mode 100644 index 0000000..90becca --- /dev/null +++ b/espanso/src/engine/process/middleware/search.rs @@ -0,0 +1,75 @@ +/* + * 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; + +use super::super::Middleware; +use crate::engine::{event::{ + internal::{DetectedMatch, MatchesDetectedEvent}, + Event, EventType, + }}; + +pub trait MatchProvider { + fn get_all_matches_ids(&self) -> Vec; +} + +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 diff --git a/espanso/src/engine/process/mod.rs b/espanso/src/engine/process/mod.rs index 2724096..9c3f26a 100644 --- a/espanso/src/engine/process/mod.rs +++ b/espanso/src/engine/process/mod.rs @@ -97,6 +97,7 @@ 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>], @@ -110,6 +111,7 @@ pub fn default<'a, MatcherState>( 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, @@ -123,5 +125,6 @@ pub fn default<'a, MatcherState>( path_provider, disable_options, matcher_options_provider, + match_provider, ) } diff --git a/espanso/src/patch/patches/macros.rs b/espanso/src/patch/patches/macros.rs index a818057..5a41fd3 100644 --- a/espanso/src/patch/patches/macros.rs +++ b/espanso/src/patch/patches/macros.rs @@ -74,6 +74,10 @@ macro_rules! generate_patchable_config { fn is_match<'b>(&self, app: &AppProperties<'b>) -> bool { self.base.is_match(app) } + + fn search_trigger(&self) -> Option { + self.base.search_trigger() + } } }; } \ No newline at end of file