diff --git a/espanso/src/cli/worker/engine/matcher/rolling.rs b/espanso/src/cli/worker/engine/matcher/rolling.rs index dfe1fc9..b0e6b90 100644 --- a/espanso/src/cli/worker/engine/matcher/rolling.rs +++ b/espanso/src/cli/worker/engine/matcher/rolling.rs @@ -17,7 +17,10 @@ * along with espanso. If not, see . */ -use espanso_match::rolling::{matcher::RollingMatcher, RollingMatch}; +use espanso_match::rolling::{ + matcher::{RollingMatcher, RollingMatcherOptions}, + RollingMatch, +}; use crate::engine::{ event::keyboard::Key, @@ -32,13 +35,30 @@ pub struct RollingMatcherAdapter { impl RollingMatcherAdapter { pub fn new(matches: &[RollingMatch]) -> Self { - let matcher = RollingMatcher::new(matches, Default::default()); + // TODO: load them from config + + let matcher = RollingMatcher::new( + matches, + RollingMatcherOptions { + char_word_separators: vec![ + " ".to_string(), + ",".to_string(), + ".".to_string(), + "?".to_string(), + "!".to_string(), + "\r".to_string(), + "\n".to_string(), + (22u8 as char).to_string(), + ], + key_word_separators: vec![], + }, + ); Self { matcher } } } -impl <'a> Matcher<'a, MatcherState<'a>> for RollingMatcherAdapter { +impl<'a> Matcher<'a, MatcherState<'a>> for RollingMatcherAdapter { fn process( &'a self, prev_state: Option<&MatcherState<'a>>, @@ -80,8 +100,10 @@ impl From> for MatchResult { fn from(result: espanso_match::MatchResult) -> Self { Self { id: result.id, - trigger: result.trigger, - args: result.vars, + trigger: result.trigger, + left_separator: result.left_separator, + right_separator: result.right_separator, + args: result.vars, } } } diff --git a/espanso/src/cli/worker/engine/multiplex.rs b/espanso/src/cli/worker/engine/multiplex.rs index 6961d72..41a4d8d 100644 --- a/espanso/src/cli/worker/engine/multiplex.rs +++ b/espanso/src/cli/worker/engine/multiplex.rs @@ -21,10 +21,7 @@ use std::collections::HashMap; use espanso_config::matches::{Match, MatchEffect}; -use crate::engine::{ - event::{render::RenderingRequestedEvent, Event}, - process::Multiplexer, -}; +use crate::engine::{event::{Event, matches::DetectedMatch, render::RenderingRequestedEvent}, process::Multiplexer}; pub trait MatchProvider<'a> { fn get(&self, match_id: i32) -> Option<&'a Match>; @@ -41,14 +38,16 @@ impl<'a> MultiplexAdapter<'a> { } impl<'a> Multiplexer for MultiplexAdapter<'a> { - fn convert(&self, match_id: i32, trigger: Option, trigger_args: HashMap) -> Option { - let m = self.provider.get(match_id)?; + fn convert(&self, detected_match: DetectedMatch) -> Option { + let m = self.provider.get(detected_match.id)?; match &m.effect { MatchEffect::Text(_) => Some(Event::RenderingRequested(RenderingRequestedEvent { - match_id, - trigger, - trigger_args, + match_id: detected_match.id, + trigger: detected_match.trigger, + left_separator: detected_match.left_separator, + right_separator: detected_match.right_separator, + trigger_args: detected_match.args, })), // TODO: think about rich text and image MatchEffect::None => None, diff --git a/espanso/src/engine/event/effect.rs b/espanso/src/engine/event/effect.rs index 8c8c7a6..501ebc8 100644 --- a/espanso/src/engine/event/effect.rs +++ b/espanso/src/engine/event/effect.rs @@ -20,6 +20,7 @@ #[derive(Debug, Clone, PartialEq)] pub struct TriggerCompensationEvent { pub trigger: String, + pub left_separator: Option, } #[derive(Debug, Clone, PartialEq)] diff --git a/espanso/src/engine/event/matches.rs b/espanso/src/engine/event/matches.rs index 6c68fd8..af1976c 100644 --- a/espanso/src/engine/event/matches.rs +++ b/espanso/src/engine/event/matches.rs @@ -28,6 +28,8 @@ pub struct MatchesDetectedEvent { pub struct DetectedMatch { pub id: i32, pub trigger: Option, + pub left_separator: Option, + pub right_separator: Option, pub args: HashMap, } diff --git a/espanso/src/engine/event/render.rs b/espanso/src/engine/event/render.rs index 23e2573..09a6a22 100644 --- a/espanso/src/engine/event/render.rs +++ b/espanso/src/engine/event/render.rs @@ -23,6 +23,8 @@ use std::collections::HashMap; pub struct RenderingRequestedEvent { pub match_id: i32, pub trigger: Option, + pub left_separator: Option, + pub right_separator: Option, pub trigger_args: HashMap, } diff --git a/espanso/src/engine/process/middleware/action.rs b/espanso/src/engine/process/middleware/action.rs index e6ef859..4c99871 100644 --- a/espanso/src/engine/process/middleware/action.rs +++ b/espanso/src/engine/process/middleware/action.rs @@ -61,11 +61,18 @@ impl<'a> Middleware for ActionMiddleware<'a> { .collect(), }) } - Event::TriggerCompensation(m_event) => Event::KeySequenceInject(KeySequenceInjectRequest { - keys: (0..m_event.trigger.chars().count()) - .map(|_| Key::Backspace) - .collect(), - }), + Event::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::KeySequenceInject(KeySequenceInjectRequest { + keys: (0..backspace_count).map(|_| Key::Backspace).collect(), + }) + } _ => event, } diff --git a/espanso/src/engine/process/middleware/cause.rs b/espanso/src/engine/process/middleware/cause.rs index cf65731..f4ff571 100644 --- a/espanso/src/engine/process/middleware/cause.rs +++ b/espanso/src/engine/process/middleware/cause.rs @@ -53,6 +53,7 @@ impl Middleware for CauseCompensateMiddleware { // Before the event, place a trigger compensation return Event::TriggerCompensation(TriggerCompensationEvent { trigger: trigger.clone(), + left_separator: m_event.chosen.left_separator.clone(), }); } else { return compensated_event; diff --git a/espanso/src/engine/process/middleware/matcher.rs b/espanso/src/engine/process/middleware/matcher.rs index 0923754..827c6e7 100644 --- a/espanso/src/engine/process/middleware/matcher.rs +++ b/espanso/src/engine/process/middleware/matcher.rs @@ -105,6 +105,8 @@ impl<'a, State> Middleware for MatcherMiddleware<'a, State> { .map(|result| DetectedMatch { id: result.id, trigger: Some(result.trigger), + right_separator: result.right_separator, + left_separator: result.left_separator, args: result.args, }) .collect(), diff --git a/espanso/src/engine/process/middleware/multiplex.rs b/espanso/src/engine/process/middleware/multiplex.rs index ff9d9cc..49391a4 100644 --- a/espanso/src/engine/process/middleware/multiplex.rs +++ b/espanso/src/engine/process/middleware/multiplex.rs @@ -39,7 +39,7 @@ impl<'a> Middleware for MultiplexMiddleware<'a> { fn next(&self, event: Event, _: &mut dyn FnMut(Event)) -> Event { if let Event::CauseCompensatedMatch(m_event) = event { - return match self.multiplexer.convert(m_event.m.id, m_event.m.trigger, m_event.m.args) { + return match self.multiplexer.convert(m_event.m) { Some(event) => event, None => { error!("match multiplexing failed"); diff --git a/espanso/src/engine/process/middleware/render.rs b/espanso/src/engine/process/middleware/render.rs index ccbb889..1040ea4 100644 --- a/espanso/src/engine/process/middleware/render.rs +++ b/espanso/src/engine/process/middleware/render.rs @@ -48,6 +48,12 @@ impl<'a> Middleware for RenderMiddleware<'a> { if let Event::RenderingRequested(m_event) = event { match self.renderer.render(m_event.match_id, 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::Rendered(RenderedEvent { match_id: m_event.match_id, body, diff --git a/espanso/src/engine/process/mod.rs b/espanso/src/engine/process/mod.rs index e4937d3..0b91b2a 100644 --- a/espanso/src/engine/process/mod.rs +++ b/espanso/src/engine/process/mod.rs @@ -17,7 +17,7 @@ * along with espanso. If not, see . */ -use super::{event::keyboard::Key, Event}; +use super::{Event, event::{keyboard::Key, matches::DetectedMatch}}; use anyhow::Result; use std::collections::HashMap; use thiserror::Error; @@ -56,6 +56,8 @@ pub enum MatcherEvent { pub struct MatchResult { pub id: i32, pub trigger: String, + pub left_separator: Option, + pub right_separator: Option, pub args: HashMap, } @@ -70,9 +72,7 @@ pub trait MatchSelector { pub trait Multiplexer { fn convert( &self, - match_id: i32, - trigger: Option, - trigger_args: HashMap, + m: DetectedMatch, ) -> Option; }