feat(core): progress in the core implementation
This commit is contained in:
parent
459e414a09
commit
e643609d57
82
espanso/src/cli/worker/config.rs
Normal file
82
espanso/src/cli/worker/config.rs
Normal file
|
@ -0,0 +1,82 @@
|
||||||
|
/*
|
||||||
|
* 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::HashSet;
|
||||||
|
|
||||||
|
use crate::engine::process::MatchFilter;
|
||||||
|
use espanso_config::{
|
||||||
|
config::{AppProperties, Config, ConfigStore},
|
||||||
|
matches::store::{MatchSet, MatchStore},
|
||||||
|
};
|
||||||
|
use espanso_info::{AppInfo, AppInfoProvider};
|
||||||
|
use std::iter::FromIterator;
|
||||||
|
|
||||||
|
pub struct ConfigManager<'a> {
|
||||||
|
config_store: &'a dyn ConfigStore,
|
||||||
|
match_store: &'a dyn MatchStore,
|
||||||
|
app_info_provider: &'a dyn AppInfoProvider,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> ConfigManager<'a> {
|
||||||
|
pub fn new(
|
||||||
|
config_store: &'a dyn ConfigStore,
|
||||||
|
match_store: &'a dyn MatchStore,
|
||||||
|
app_info_provider: &'a dyn AppInfoProvider,
|
||||||
|
) -> Self {
|
||||||
|
Self {
|
||||||
|
config_store,
|
||||||
|
match_store,
|
||||||
|
app_info_provider,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn active(&self) -> &'a dyn Config {
|
||||||
|
let current_app = self.app_info_provider.get_info();
|
||||||
|
let info = to_app_properties(¤t_app);
|
||||||
|
self.config_store.active(&info)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn active_match_set(&self) -> MatchSet {
|
||||||
|
let match_paths = self.active().match_paths();
|
||||||
|
self.match_store.query(&match_paths)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> 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_match_set();
|
||||||
|
|
||||||
|
match_set
|
||||||
|
.matches
|
||||||
|
.iter()
|
||||||
|
.filter(|m| ids_set.contains(&m.id))
|
||||||
|
.map(|m| m.id)
|
||||||
|
.collect()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: test
|
||||||
|
fn to_app_properties(info: &AppInfo) -> AppProperties {
|
||||||
|
AppProperties {
|
||||||
|
title: info.title.as_deref(),
|
||||||
|
class: info.class.as_deref(),
|
||||||
|
exec: info.exec.as_deref(),
|
||||||
|
}
|
||||||
|
}
|
72
espanso/src/cli/worker/matcher/convert.rs
Normal file
72
espanso/src/cli/worker/matcher/convert.rs
Normal file
|
@ -0,0 +1,72 @@
|
||||||
|
/*
|
||||||
|
* 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 espanso_config::{
|
||||||
|
config::ConfigStore,
|
||||||
|
matches::{
|
||||||
|
store::{MatchSet, MatchStore},
|
||||||
|
MatchCause,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
use espanso_match::rolling::{RollingMatch, StringMatchOptions};
|
||||||
|
use std::iter::FromIterator;
|
||||||
|
|
||||||
|
pub struct MatchConverter<'a> {
|
||||||
|
config_store: &'a dyn ConfigStore,
|
||||||
|
match_store: &'a dyn MatchStore,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> MatchConverter<'a> {
|
||||||
|
pub fn new(config_store: &'a dyn ConfigStore, match_store: &'a dyn MatchStore) -> Self {
|
||||||
|
Self {
|
||||||
|
config_store,
|
||||||
|
match_store,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: test (might need to move the conversion logic into a separate function)
|
||||||
|
pub fn get_rolling_matches(&self) -> Vec<RollingMatch<i32>> {
|
||||||
|
let match_set = self.global_match_set();
|
||||||
|
let mut matches = Vec::new();
|
||||||
|
|
||||||
|
for m in match_set.matches {
|
||||||
|
if let MatchCause::Trigger(cause) = &m.cause {
|
||||||
|
for trigger in cause.triggers.iter() {
|
||||||
|
matches.push(RollingMatch::from_string(
|
||||||
|
m.id,
|
||||||
|
&trigger,
|
||||||
|
&StringMatchOptions {
|
||||||
|
case_insensitive: cause.propagate_case,
|
||||||
|
preserve_case_markers: cause.propagate_case,
|
||||||
|
left_word: cause.left_word,
|
||||||
|
right_word: cause.right_word,
|
||||||
|
},
|
||||||
|
))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
matches
|
||||||
|
}
|
||||||
|
|
||||||
|
fn global_match_set(&self) -> MatchSet {
|
||||||
|
let paths = self.config_store.get_all_match_paths();
|
||||||
|
self.match_store.query(&Vec::from_iter(paths.into_iter()))
|
||||||
|
}
|
||||||
|
}
|
|
@ -22,6 +22,7 @@ use espanso_match::rolling::matcher::RollingMatcherState;
|
||||||
use enum_as_inner::EnumAsInner;
|
use enum_as_inner::EnumAsInner;
|
||||||
|
|
||||||
pub mod rolling;
|
pub mod rolling;
|
||||||
|
pub mod convert;
|
||||||
|
|
||||||
#[derive(Clone, EnumAsInner)]
|
#[derive(Clone, EnumAsInner)]
|
||||||
pub enum MatcherState<'a> {
|
pub enum MatcherState<'a> {
|
||||||
|
|
|
@ -31,14 +31,8 @@ pub struct RollingMatcherAdapter {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl RollingMatcherAdapter {
|
impl RollingMatcherAdapter {
|
||||||
pub fn new() -> Self {
|
pub fn new(matches: &[RollingMatch<i32>]) -> Self {
|
||||||
// TODO: pass actual matches
|
let matcher = RollingMatcher::new(matches, Default::default());
|
||||||
let matches = vec![
|
|
||||||
RollingMatch::from_string(1, "esp", &Default::default()),
|
|
||||||
RollingMatch::from_string(2, "test", &Default::default()),
|
|
||||||
];
|
|
||||||
|
|
||||||
let matcher = RollingMatcher::new(&matches, Default::default());
|
|
||||||
|
|
||||||
Self { matcher }
|
Self { matcher }
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,10 +19,13 @@
|
||||||
|
|
||||||
use funnel::Source;
|
use funnel::Source;
|
||||||
use process::Matcher;
|
use process::Matcher;
|
||||||
|
use ui::selector::MatchSelectorAdapter;
|
||||||
|
|
||||||
use crate::engine::{Engine, funnel, process, dispatch};
|
use crate::engine::{Engine, funnel, process, dispatch};
|
||||||
use super::{CliModule, CliModuleArgs};
|
use super::{CliModule, CliModuleArgs};
|
||||||
|
|
||||||
|
mod ui;
|
||||||
|
mod config;
|
||||||
mod source;
|
mod source;
|
||||||
mod matcher;
|
mod matcher;
|
||||||
mod executor;
|
mod executor;
|
||||||
|
@ -40,13 +43,21 @@ pub fn new() -> CliModule {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn worker_main(args: CliModuleArgs) {
|
fn worker_main(args: CliModuleArgs) {
|
||||||
let detect_source = source::detect::init_and_spawn().unwrap(); // TODO: handle error
|
let config_store = args.config_store.expect("missing config store in worker main");
|
||||||
|
let match_store = args.match_store.expect("missing match store in worker main");
|
||||||
|
|
||||||
|
let app_info_provider = espanso_info::get_provider().expect("unable to initialize app info provider");
|
||||||
|
let config_manager = config::ConfigManager::new(&*config_store, &*match_store, &*app_info_provider);
|
||||||
|
let match_converter = matcher::convert::MatchConverter::new(&*config_store, &*match_store);
|
||||||
|
|
||||||
|
let detect_source = source::detect::init_and_spawn().expect("failed to initialize detector module");
|
||||||
let sources: Vec<&dyn Source> = vec![&detect_source];
|
let sources: Vec<&dyn Source> = vec![&detect_source];
|
||||||
let funnel = funnel::default(&sources);
|
let funnel = funnel::default(&sources);
|
||||||
|
|
||||||
let matcher = matcher::rolling::RollingMatcherAdapter::new();
|
let matcher = matcher::rolling::RollingMatcherAdapter::new(&match_converter.get_rolling_matches());
|
||||||
let matchers: Vec<&dyn Matcher<matcher::MatcherState>> = vec![&matcher];
|
let matchers: Vec<&dyn Matcher<matcher::MatcherState>> = vec![&matcher];
|
||||||
let mut processor = process::default(&matchers);
|
let selector = MatchSelectorAdapter::new();
|
||||||
|
let mut processor = process::default(&matchers, &config_manager, &selector);
|
||||||
|
|
||||||
let text_injector = executor::text_injector::TextInjectorAdapter::new();
|
let text_injector = executor::text_injector::TextInjectorAdapter::new();
|
||||||
let dispatcher = dispatch::default(&text_injector);
|
let dispatcher = dispatch::default(&text_injector);
|
||||||
|
|
20
espanso/src/cli/worker/ui/mod.rs
Normal file
20
espanso/src/cli/worker/ui/mod.rs
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
/*
|
||||||
|
* 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 selector;
|
37
espanso/src/cli/worker/ui/selector.rs
Normal file
37
espanso/src/cli/worker/ui/selector.rs
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
/*
|
||||||
|
* 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::process::MatchSelector;
|
||||||
|
|
||||||
|
pub struct MatchSelectorAdapter {
|
||||||
|
// TODO: pass Modulo search UI manager
|
||||||
|
}
|
||||||
|
|
||||||
|
impl MatchSelectorAdapter {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Self {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl MatchSelector for MatchSelectorAdapter {
|
||||||
|
fn select(&self, matches_ids: &[i32]) -> Option<i32> {
|
||||||
|
// TODO: replace with actual selection
|
||||||
|
Some(*matches_ids.first().unwrap())
|
||||||
|
}
|
||||||
|
}
|
|
@ -19,6 +19,7 @@
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct TextInjectEvent {
|
pub struct TextInjectEvent {
|
||||||
|
pub delete_count: i32,
|
||||||
pub text: String,
|
pub text: String,
|
||||||
pub mode: TextInjectMode,
|
pub mode: TextInjectMode,
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,12 +21,17 @@ use std::collections::HashMap;
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
pub struct MatchesDetectedEvent {
|
pub struct MatchesDetectedEvent {
|
||||||
pub results: Vec<MatchResult>,
|
pub matches: Vec<DetectedMatch>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
pub struct MatchResult {
|
pub struct DetectedMatch {
|
||||||
pub id: i32,
|
pub id: i32,
|
||||||
pub trigger: String,
|
pub trigger: String,
|
||||||
pub vars: HashMap<String, String>,
|
pub vars: HashMap<String, String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
|
pub struct MatchSelectedEvent {
|
||||||
|
pub chosen: DetectedMatch,
|
||||||
|
}
|
|
@ -19,7 +19,7 @@
|
||||||
|
|
||||||
pub mod keyboard;
|
pub mod keyboard;
|
||||||
pub mod inject;
|
pub mod inject;
|
||||||
pub mod matches_detected;
|
pub mod matches;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum Event {
|
pub enum Event {
|
||||||
|
@ -29,7 +29,8 @@ pub enum Event {
|
||||||
Keyboard(keyboard::KeyboardEvent),
|
Keyboard(keyboard::KeyboardEvent),
|
||||||
|
|
||||||
// Internal
|
// Internal
|
||||||
MatchesDetected(matches_detected::MatchesDetectedEvent),
|
MatchesDetected(matches::MatchesDetectedEvent),
|
||||||
|
MatchSelected(matches::MatchSelectedEvent),
|
||||||
|
|
||||||
// Effects
|
// Effects
|
||||||
TextInject(inject::TextInjectEvent),
|
TextInject(inject::TextInjectEvent),
|
||||||
|
|
|
@ -19,7 +19,7 @@
|
||||||
|
|
||||||
use log::trace;
|
use log::trace;
|
||||||
|
|
||||||
use super::{Event, Matcher, Middleware, Processor, middleware::matcher::MatchMiddleware};
|
use super::{Event, MatchFilter, MatchSelector, Matcher, Middleware, Processor, middleware::match_select::MatchSelectMiddleware, middleware::matcher::MatchMiddleware};
|
||||||
use std::collections::VecDeque;
|
use std::collections::VecDeque;
|
||||||
|
|
||||||
pub struct DefaultProcessor<'a> {
|
pub struct DefaultProcessor<'a> {
|
||||||
|
@ -27,13 +27,18 @@ pub struct DefaultProcessor<'a> {
|
||||||
middleware: Vec<Box<dyn Middleware + 'a>>,
|
middleware: Vec<Box<dyn Middleware + 'a>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl <'a> DefaultProcessor<'a> {
|
impl<'a> DefaultProcessor<'a> {
|
||||||
pub fn new<MatcherState>(matchers: &'a [&'a dyn Matcher<'a, MatcherState>]) -> DefaultProcessor<'a> {
|
pub fn new<MatcherState>(
|
||||||
|
matchers: &'a [&'a dyn Matcher<'a, MatcherState>],
|
||||||
|
match_filter: &'a dyn MatchFilter,
|
||||||
|
match_selector: &'a dyn MatchSelector,
|
||||||
|
) -> DefaultProcessor<'a> {
|
||||||
Self {
|
Self {
|
||||||
event_queue: VecDeque::new(),
|
event_queue: VecDeque::new(),
|
||||||
middleware: vec![
|
middleware: vec![
|
||||||
Box::new(MatchMiddleware::new(matchers)),
|
Box::new(MatchMiddleware::new(matchers)),
|
||||||
]
|
Box::new(MatchSelectMiddleware::new(match_filter, match_selector)),
|
||||||
|
],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -66,7 +71,7 @@ impl <'a> DefaultProcessor<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl <'a> Processor for DefaultProcessor<'a> {
|
impl<'a> Processor for DefaultProcessor<'a> {
|
||||||
fn process(&mut self, event: Event) -> Vec<Event> {
|
fn process(&mut self, event: Event) -> Vec<Event> {
|
||||||
self.event_queue.push_front(event);
|
self.event_queue.push_front(event);
|
||||||
|
|
||||||
|
|
93
espanso/src/engine/process/middleware/match_select.rs
Normal file
93
espanso/src/engine/process/middleware/match_select.rs
Normal file
|
@ -0,0 +1,93 @@
|
||||||
|
/*
|
||||||
|
* 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::{
|
||||||
|
matches::{MatchSelectedEvent},
|
||||||
|
Event,
|
||||||
|
},
|
||||||
|
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 next(&self, event: Event, _: &dyn FnMut(Event)) -> Event {
|
||||||
|
if let Event::MatchesDetected(m_event) = event {
|
||||||
|
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::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::MatchSelected(MatchSelectedEvent { chosen: m })
|
||||||
|
} else {
|
||||||
|
error!("MatchSelectMiddleware could not find the correspondent match");
|
||||||
|
Event::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::MatchSelected(MatchSelectedEvent { chosen: m })
|
||||||
|
} else {
|
||||||
|
error!("MatchSelectMiddleware could not find the correspondent match");
|
||||||
|
Event::NOOP
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
debug!("MatchSelectMiddleware did not receive any match selection");
|
||||||
|
Event::NOOP
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
event
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: test
|
|
@ -21,7 +21,7 @@ use log::trace;
|
||||||
use std::{cell::RefCell, collections::VecDeque};
|
use std::{cell::RefCell, collections::VecDeque};
|
||||||
|
|
||||||
use super::super::Middleware;
|
use super::super::Middleware;
|
||||||
use crate::engine::{event::{Event, keyboard::{Key, Status}, matches_detected::{MatchResult, MatchesDetectedEvent}}, process::{Matcher, MatcherEvent}};
|
use crate::engine::{event::{Event, keyboard::{Key, Status}, matches::{DetectedMatch, MatchesDetectedEvent}}, process::{Matcher, MatcherEvent}};
|
||||||
|
|
||||||
const MAX_HISTORY: usize = 3; // TODO: get as parameter
|
const MAX_HISTORY: usize = 3; // TODO: get as parameter
|
||||||
|
|
||||||
|
@ -85,12 +85,10 @@ impl<'a, State> Middleware for MatchMiddleware<'a, State> {
|
||||||
matcher_states.pop_front();
|
matcher_states.pop_front();
|
||||||
}
|
}
|
||||||
|
|
||||||
println!("results: {:?}", all_results);
|
|
||||||
|
|
||||||
if !all_results.is_empty() {
|
if !all_results.is_empty() {
|
||||||
return Event::MatchesDetected(MatchesDetectedEvent {
|
return Event::MatchesDetected(MatchesDetectedEvent {
|
||||||
results: all_results.into_iter().map(|result | {
|
matches: all_results.into_iter().map(|result | {
|
||||||
MatchResult {
|
DetectedMatch {
|
||||||
id: result.id,
|
id: result.id,
|
||||||
trigger: result.trigger,
|
trigger: result.trigger,
|
||||||
vars: result.vars,
|
vars: result.vars,
|
||||||
|
@ -133,3 +131,5 @@ fn is_invalidating_key(key: &Key) -> bool {
|
||||||
_ => false,
|
_ => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: test
|
|
@ -18,3 +18,4 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
pub mod matcher;
|
pub mod matcher;
|
||||||
|
pub mod match_select;
|
|
@ -17,13 +17,12 @@
|
||||||
* along with espanso. If not, see <https://www.gnu.org/licenses/>.
|
* along with espanso. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
use super::{Event, event::keyboard::Key};
|
use super::{event::keyboard::Key, Event};
|
||||||
|
|
||||||
mod middleware;
|
|
||||||
mod default;
|
mod default;
|
||||||
|
mod middleware;
|
||||||
|
|
||||||
pub trait Middleware {
|
pub trait Middleware {
|
||||||
fn next(&self, event: Event, dispatch: &dyn FnMut(Event)) -> Event;
|
fn next(&self, event: Event, dispatch: &dyn FnMut(Event)) -> Event;
|
||||||
|
@ -36,7 +35,11 @@ pub trait Processor {
|
||||||
// Dependency inversion entities
|
// Dependency inversion entities
|
||||||
|
|
||||||
pub trait Matcher<'a, State> {
|
pub trait Matcher<'a, State> {
|
||||||
fn process(&'a self, prev_state: Option<&State>, event: &MatcherEvent) -> (State, Vec<MatchResult>);
|
fn process(
|
||||||
|
&'a self,
|
||||||
|
prev_state: Option<&State>,
|
||||||
|
event: &MatcherEvent,
|
||||||
|
) -> (State, Vec<MatchResult>);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
@ -52,6 +55,18 @@ pub struct MatchResult {
|
||||||
pub vars: HashMap<String, String>,
|
pub vars: HashMap<String, String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn default<'a, MatcherState>(matchers: &'a [&'a dyn Matcher<'a, MatcherState>]) -> impl Processor + 'a {
|
pub trait MatchFilter {
|
||||||
default::DefaultProcessor::new(matchers)
|
fn filter_active(&self, matches_ids: &[i32]) -> Vec<i32>;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait MatchSelector {
|
||||||
|
fn select(&self, matches_ids: &[i32]) -> Option<i32>;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn default<'a, MatcherState>(
|
||||||
|
matchers: &'a [&'a dyn Matcher<'a, MatcherState>],
|
||||||
|
match_filter: &'a dyn MatchFilter,
|
||||||
|
match_selector: &'a dyn MatchSelector,
|
||||||
|
) -> impl Processor + 'a {
|
||||||
|
default::DefaultProcessor::new(matchers, match_filter, match_selector)
|
||||||
}
|
}
|
|
@ -201,8 +201,12 @@ fn main() {
|
||||||
let log_level = match matches.occurrences_of("v") {
|
let log_level = match matches.occurrences_of("v") {
|
||||||
0 => LevelFilter::Warn,
|
0 => LevelFilter::Warn,
|
||||||
1 => LevelFilter::Info,
|
1 => LevelFilter::Info,
|
||||||
2 => LevelFilter::Debug,
|
|
||||||
_ => LevelFilter::Trace,
|
// Trace mode is only available in debug mode for security reasons
|
||||||
|
#[cfg(debug_assertions)]
|
||||||
|
3 => LevelFilter::Trace,
|
||||||
|
|
||||||
|
_ => LevelFilter::Debug,
|
||||||
};
|
};
|
||||||
|
|
||||||
let handler = CLI_HANDLERS
|
let handler = CLI_HANDLERS
|
||||||
|
|
Loading…
Reference in New Issue
Block a user