feat(core): improve support for word matches

This commit is contained in:
Federico Terzi 2021-04-18 12:22:08 +02:00
parent 97b789e946
commit 04f1449046
11 changed files with 66 additions and 24 deletions

View File

@ -17,7 +17,10 @@
* along with espanso. If not, see <https://www.gnu.org/licenses/>. * along with espanso. If not, see <https://www.gnu.org/licenses/>.
*/ */
use espanso_match::rolling::{matcher::RollingMatcher, RollingMatch}; use espanso_match::rolling::{
matcher::{RollingMatcher, RollingMatcherOptions},
RollingMatch,
};
use crate::engine::{ use crate::engine::{
event::keyboard::Key, event::keyboard::Key,
@ -32,7 +35,24 @@ pub struct RollingMatcherAdapter {
impl RollingMatcherAdapter { impl RollingMatcherAdapter {
pub fn new(matches: &[RollingMatch<i32>]) -> Self { pub fn new(matches: &[RollingMatch<i32>]) -> 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 } Self { matcher }
} }
@ -81,6 +101,8 @@ impl From<espanso_match::MatchResult<i32>> for MatchResult {
Self { Self {
id: result.id, id: result.id,
trigger: result.trigger, trigger: result.trigger,
left_separator: result.left_separator,
right_separator: result.right_separator,
args: result.vars, args: result.vars,
} }
} }

View File

@ -21,10 +21,7 @@ use std::collections::HashMap;
use espanso_config::matches::{Match, MatchEffect}; use espanso_config::matches::{Match, MatchEffect};
use crate::engine::{ use crate::engine::{event::{Event, matches::DetectedMatch, render::RenderingRequestedEvent}, process::Multiplexer};
event::{render::RenderingRequestedEvent, Event},
process::Multiplexer,
};
pub trait MatchProvider<'a> { pub trait MatchProvider<'a> {
fn get(&self, match_id: i32) -> Option<&'a Match>; fn get(&self, match_id: i32) -> Option<&'a Match>;
@ -41,14 +38,16 @@ impl<'a> MultiplexAdapter<'a> {
} }
impl<'a> Multiplexer for MultiplexAdapter<'a> { impl<'a> Multiplexer for MultiplexAdapter<'a> {
fn convert(&self, match_id: i32, trigger: Option<String>, trigger_args: HashMap<String, String>) -> Option<Event> { fn convert(&self, detected_match: DetectedMatch) -> Option<Event> {
let m = self.provider.get(match_id)?; let m = self.provider.get(detected_match.id)?;
match &m.effect { match &m.effect {
MatchEffect::Text(_) => Some(Event::RenderingRequested(RenderingRequestedEvent { MatchEffect::Text(_) => Some(Event::RenderingRequested(RenderingRequestedEvent {
match_id, match_id: detected_match.id,
trigger, trigger: detected_match.trigger,
trigger_args, left_separator: detected_match.left_separator,
right_separator: detected_match.right_separator,
trigger_args: detected_match.args,
})), })),
// TODO: think about rich text and image // TODO: think about rich text and image
MatchEffect::None => None, MatchEffect::None => None,

View File

@ -20,6 +20,7 @@
#[derive(Debug, Clone, PartialEq)] #[derive(Debug, Clone, PartialEq)]
pub struct TriggerCompensationEvent { pub struct TriggerCompensationEvent {
pub trigger: String, pub trigger: String,
pub left_separator: Option<String>,
} }
#[derive(Debug, Clone, PartialEq)] #[derive(Debug, Clone, PartialEq)]

View File

@ -28,6 +28,8 @@ pub struct MatchesDetectedEvent {
pub struct DetectedMatch { pub struct DetectedMatch {
pub id: i32, pub id: i32,
pub trigger: Option<String>, pub trigger: Option<String>,
pub left_separator: Option<String>,
pub right_separator: Option<String>,
pub args: HashMap<String, String>, pub args: HashMap<String, String>,
} }

View File

@ -23,6 +23,8 @@ use std::collections::HashMap;
pub struct RenderingRequestedEvent { pub struct RenderingRequestedEvent {
pub match_id: i32, pub match_id: i32,
pub trigger: Option<String>, pub trigger: Option<String>,
pub left_separator: Option<String>,
pub right_separator: Option<String>,
pub trigger_args: HashMap<String, String>, pub trigger_args: HashMap<String, String>,
} }

View File

@ -61,11 +61,18 @@ impl<'a> Middleware for ActionMiddleware<'a> {
.collect(), .collect(),
}) })
} }
Event::TriggerCompensation(m_event) => Event::KeySequenceInject(KeySequenceInjectRequest { Event::TriggerCompensation(m_event) => {
keys: (0..m_event.trigger.chars().count()) let mut backspace_count = m_event.trigger.chars().count();
.map(|_| Key::Backspace)
.collect(), // 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, _ => event,
} }

View File

@ -53,6 +53,7 @@ impl Middleware for CauseCompensateMiddleware {
// Before the event, place a trigger compensation // Before the event, place a trigger compensation
return Event::TriggerCompensation(TriggerCompensationEvent { return Event::TriggerCompensation(TriggerCompensationEvent {
trigger: trigger.clone(), trigger: trigger.clone(),
left_separator: m_event.chosen.left_separator.clone(),
}); });
} else { } else {
return compensated_event; return compensated_event;

View File

@ -105,6 +105,8 @@ impl<'a, State> Middleware for MatcherMiddleware<'a, State> {
.map(|result| DetectedMatch { .map(|result| DetectedMatch {
id: result.id, id: result.id,
trigger: Some(result.trigger), trigger: Some(result.trigger),
right_separator: result.right_separator,
left_separator: result.left_separator,
args: result.args, args: result.args,
}) })
.collect(), .collect(),

View File

@ -39,7 +39,7 @@ impl<'a> Middleware for MultiplexMiddleware<'a> {
fn next(&self, event: Event, _: &mut dyn FnMut(Event)) -> Event { fn next(&self, event: Event, _: &mut dyn FnMut(Event)) -> Event {
if let Event::CauseCompensatedMatch(m_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, Some(event) => event,
None => { None => {
error!("match multiplexing failed"); error!("match multiplexing failed");

View File

@ -48,6 +48,12 @@ impl<'a> Middleware for RenderMiddleware<'a> {
if let Event::RenderingRequested(m_event) = event { if let Event::RenderingRequested(m_event) = event {
match self.renderer.render(m_event.match_id, m_event.trigger_args) { match self.renderer.render(m_event.match_id, m_event.trigger_args) {
Ok(body) => { Ok(body) => {
let body = if let Some(right_separator) = m_event.right_separator {
format!("{}{}", body, right_separator)
} else {
body
};
return Event::Rendered(RenderedEvent { return Event::Rendered(RenderedEvent {
match_id: m_event.match_id, match_id: m_event.match_id,
body, body,

View File

@ -17,7 +17,7 @@
* along with espanso. If not, see <https://www.gnu.org/licenses/>. * along with espanso. If not, see <https://www.gnu.org/licenses/>.
*/ */
use super::{event::keyboard::Key, Event}; use super::{Event, event::{keyboard::Key, matches::DetectedMatch}};
use anyhow::Result; use anyhow::Result;
use std::collections::HashMap; use std::collections::HashMap;
use thiserror::Error; use thiserror::Error;
@ -56,6 +56,8 @@ pub enum MatcherEvent {
pub struct MatchResult { pub struct MatchResult {
pub id: i32, pub id: i32,
pub trigger: String, pub trigger: String,
pub left_separator: Option<String>,
pub right_separator: Option<String>,
pub args: HashMap<String, String>, pub args: HashMap<String, String>,
} }
@ -70,9 +72,7 @@ pub trait MatchSelector {
pub trait Multiplexer { pub trait Multiplexer {
fn convert( fn convert(
&self, &self,
match_id: i32, m: DetectedMatch,
trigger: Option<String>,
trigger_args: HashMap<String, String>,
) -> Option<Event>; ) -> Option<Event>;
} }