feat(core): implement propagate_case option
This commit is contained in:
parent
5a729f5810
commit
cedb073f06
|
@ -19,11 +19,14 @@
|
|||
|
||||
use std::{collections::HashMap, iter::FromIterator};
|
||||
|
||||
use espanso_config::{config::ConfigStore, matches::{Match, MatchEffect, store::MatchStore}};
|
||||
use espanso_config::{
|
||||
config::ConfigStore,
|
||||
matches::{store::MatchStore, Match, MatchEffect},
|
||||
};
|
||||
|
||||
use crate::engine::process::MatchInfoProvider;
|
||||
|
||||
use super::{multiplex::MatchProvider, render::MatchIterator};
|
||||
use super::multiplex::MatchProvider;
|
||||
|
||||
pub struct MatchCache<'a> {
|
||||
cache: HashMap<i32, &'a Match>,
|
||||
|
@ -50,10 +53,14 @@ impl<'a> MatchProvider<'a> for MatchCache<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'a> MatchIterator<'a> for MatchCache<'a> {
|
||||
impl<'a> super::render::MatchProvider<'a> for MatchCache<'a> {
|
||||
fn matches(&self) -> Vec<&'a Match> {
|
||||
self.cache.iter().map(|(_, m)| *m).collect()
|
||||
}
|
||||
|
||||
fn get(&self, id: i32) -> Option<&'a Match> {
|
||||
self.cache.get(&id).map(|m| *m)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> MatchInfoProvider for MatchCache<'a> {
|
||||
|
|
|
@ -53,7 +53,6 @@ impl<'a> MatchConverter<'a> {
|
|||
&trigger,
|
||||
&StringMatchOptions {
|
||||
case_insensitive: cause.propagate_case,
|
||||
preserve_case_markers: cause.propagate_case,
|
||||
left_word: cause.left_word,
|
||||
right_word: cause.right_word,
|
||||
},
|
||||
|
|
|
@ -21,14 +21,17 @@ use std::{cell::RefCell, collections::HashMap, convert::TryInto};
|
|||
|
||||
use espanso_config::{
|
||||
config::Config,
|
||||
matches::{store::MatchSet, Match, MatchCause, MatchEffect},
|
||||
matches::{store::MatchSet, Match, MatchCause, MatchEffect, UpperCasingStyle},
|
||||
};
|
||||
use espanso_render::{CasingStyle, Context, RenderOptions, Template, Value, Variable};
|
||||
|
||||
use crate::{cli::worker::config::ConfigManager, engine::process::{Renderer, RendererError}};
|
||||
use crate::{
|
||||
engine::process::{Renderer, RendererError},
|
||||
};
|
||||
|
||||
pub trait MatchIterator<'a> {
|
||||
pub trait MatchProvider<'a> {
|
||||
fn matches(&self) -> Vec<&'a Match>;
|
||||
fn get(&self, id: i32) -> Option<&'a Match>;
|
||||
}
|
||||
|
||||
pub trait ConfigProvider<'a> {
|
||||
|
@ -38,6 +41,7 @@ pub trait ConfigProvider<'a> {
|
|||
|
||||
pub struct RendererAdapter<'a> {
|
||||
renderer: &'a dyn espanso_render::Renderer,
|
||||
match_provider: &'a dyn MatchProvider<'a>,
|
||||
config_provider: &'a dyn ConfigProvider<'a>,
|
||||
|
||||
template_map: HashMap<i32, Option<Template>>,
|
||||
|
@ -48,16 +52,17 @@ pub struct RendererAdapter<'a> {
|
|||
|
||||
impl<'a> RendererAdapter<'a> {
|
||||
pub fn new(
|
||||
match_iterator: &'a dyn MatchIterator,
|
||||
match_provider: &'a dyn MatchProvider<'a>,
|
||||
config_provider: &'a dyn ConfigProvider<'a>,
|
||||
renderer: &'a dyn espanso_render::Renderer,
|
||||
) -> Self {
|
||||
let template_map = generate_template_map(match_iterator);
|
||||
let template_map = generate_template_map(match_provider);
|
||||
let global_vars_map = generate_global_vars_map(config_provider);
|
||||
|
||||
Self {
|
||||
renderer,
|
||||
config_provider,
|
||||
match_provider,
|
||||
template_map,
|
||||
global_vars_map,
|
||||
context_cache: RefCell::new(HashMap::new()),
|
||||
|
@ -66,9 +71,9 @@ impl<'a> RendererAdapter<'a> {
|
|||
}
|
||||
|
||||
// TODO: test
|
||||
fn generate_template_map(match_iterator: &dyn MatchIterator) -> HashMap<i32, Option<Template>> {
|
||||
fn generate_template_map(match_provider: &dyn MatchProvider) -> HashMap<i32, Option<Template>> {
|
||||
let mut template_map = HashMap::new();
|
||||
for m in match_iterator.matches() {
|
||||
for m in match_provider.matches() {
|
||||
let entry = convert_to_template(m);
|
||||
template_map.insert(m.id, entry);
|
||||
}
|
||||
|
@ -113,7 +118,7 @@ fn generate_context<'a>(
|
|||
|
||||
Context {
|
||||
templates,
|
||||
global_vars
|
||||
global_vars,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -180,16 +185,29 @@ fn convert_value(value: espanso_config::matches::Value) -> espanso_render::Value
|
|||
}
|
||||
|
||||
impl<'a> Renderer<'a> for RendererAdapter<'a> {
|
||||
fn render(&'a self, match_id: i32, trigger_vars: HashMap<String, String>) -> anyhow::Result<String> {
|
||||
fn render(
|
||||
&'a self,
|
||||
match_id: i32,
|
||||
trigger: Option<&str>,
|
||||
trigger_vars: HashMap<String, String>,
|
||||
) -> anyhow::Result<String> {
|
||||
if let Some(Some(template)) = self.template_map.get(&match_id) {
|
||||
let (config, match_set) = self.config_provider.active();
|
||||
|
||||
let mut context_cache = self.context_cache.borrow_mut();
|
||||
let context = context_cache.entry(config.id()).or_insert(generate_context(&match_set, &self.template_map, &self.global_vars_map));
|
||||
let context = context_cache
|
||||
.entry(config.id())
|
||||
.or_insert_with(|| generate_context(&match_set, &self.template_map, &self.global_vars_map));
|
||||
|
||||
let raw_match = self.match_provider.get(match_id);
|
||||
let preferred_uppercasing_style = raw_match.and_then(extract_uppercasing_style);
|
||||
|
||||
// TODO: calculate the casing style instead of hardcoding it
|
||||
let options = RenderOptions {
|
||||
casing_style: CasingStyle::None,
|
||||
casing_style: if let Some(trigger) = trigger {
|
||||
calculate_casing_style(trigger, preferred_uppercasing_style)
|
||||
} else {
|
||||
CasingStyle::None
|
||||
},
|
||||
};
|
||||
|
||||
// If some trigger vars are specified, augment the template with them
|
||||
|
@ -199,9 +217,9 @@ impl<'a> Renderer<'a> for RendererAdapter<'a> {
|
|||
let mut params = espanso_render::Params::new();
|
||||
params.insert("echo".to_string(), Value::String(value));
|
||||
augmented.vars.push(Variable {
|
||||
name,
|
||||
var_type: "echo".to_string(),
|
||||
params,
|
||||
name,
|
||||
var_type: "echo".to_string(),
|
||||
params,
|
||||
})
|
||||
}
|
||||
Some(augmented)
|
||||
|
@ -218,7 +236,7 @@ impl<'a> Renderer<'a> for RendererAdapter<'a> {
|
|||
match self.renderer.render(template, context, &options) {
|
||||
espanso_render::RenderResult::Success(body) => Ok(body),
|
||||
espanso_render::RenderResult::Aborted => Err(RendererError::Aborted.into()),
|
||||
espanso_render::RenderResult::Error(err) => Err(RendererError::RenderingError(err).into()),
|
||||
espanso_render::RenderResult::Error(err) => Err(RendererError::RenderingError(err).into()),
|
||||
}
|
||||
} else {
|
||||
Err(RendererError::NotFound.into())
|
||||
|
@ -226,3 +244,58 @@ impl<'a> Renderer<'a> for RendererAdapter<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
fn extract_uppercasing_style(m: &Match) -> Option<UpperCasingStyle> {
|
||||
if let MatchCause::Trigger(cause) = &m.cause {
|
||||
Some(cause.uppercase_style.clone())
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: test
|
||||
fn calculate_casing_style(
|
||||
trigger: &str,
|
||||
uppercasing_style: Option<UpperCasingStyle>,
|
||||
) -> CasingStyle {
|
||||
let mut first_alphabetic = None;
|
||||
let mut second_alphabetic = None;
|
||||
|
||||
for c in trigger.chars() {
|
||||
if c.is_alphabetic() {
|
||||
if first_alphabetic.is_none() {
|
||||
first_alphabetic = Some(c);
|
||||
} else if second_alphabetic.is_none() {
|
||||
second_alphabetic = Some(c);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(first) = first_alphabetic {
|
||||
if let Some(second) = second_alphabetic {
|
||||
if first.is_uppercase() {
|
||||
if second.is_uppercase() {
|
||||
CasingStyle::Uppercase
|
||||
} else {
|
||||
match uppercasing_style {
|
||||
Some(UpperCasingStyle::CapitalizeWords) => CasingStyle::CapitalizeWords,
|
||||
_ => CasingStyle::Capitalize,
|
||||
}
|
||||
}
|
||||
} else {
|
||||
CasingStyle::None
|
||||
}
|
||||
} else if first.is_uppercase() {
|
||||
match uppercasing_style {
|
||||
Some(UpperCasingStyle::Capitalize) => CasingStyle::Capitalize,
|
||||
Some(UpperCasingStyle::CapitalizeWords) => CasingStyle::CapitalizeWords,
|
||||
_ => CasingStyle::Uppercase,
|
||||
}
|
||||
} else {
|
||||
CasingStyle::None
|
||||
}
|
||||
} else {
|
||||
CasingStyle::None
|
||||
}
|
||||
}
|
||||
|
|
|
@ -78,8 +78,6 @@ impl<'a, State> Middleware for MatcherMiddleware<'a, State> {
|
|||
}
|
||||
}
|
||||
|
||||
// TODO: test if the matcher detects a word match when the states are cleared (probably not :( )
|
||||
|
||||
let mut all_results = Vec::new();
|
||||
|
||||
if let Some(matcher_event) = convert_to_matcher_event(&event) {
|
||||
|
@ -121,7 +119,24 @@ impl<'a, State> Middleware for MatcherMiddleware<'a, State> {
|
|||
|
||||
fn is_event_of_interest(event: &Event) -> bool {
|
||||
match event {
|
||||
Event::Keyboard(keyboard_event) if keyboard_event.status == Status::Pressed => true,
|
||||
Event::Keyboard(keyboard_event) => {
|
||||
if keyboard_event.status != Status::Pressed {
|
||||
// Skip non-press events
|
||||
false
|
||||
} else {
|
||||
match keyboard_event.key {
|
||||
// Skip modifier keys
|
||||
Key::Alt => false,
|
||||
Key::Shift => false,
|
||||
Key::CapsLock => false,
|
||||
Key::Meta => false,
|
||||
Key::NumLock => false,
|
||||
Key::Control => false,
|
||||
|
||||
_ => true
|
||||
}
|
||||
}
|
||||
},
|
||||
// TODO: handle mouse
|
||||
Event::MatchInjected => true,
|
||||
_ => false,
|
||||
|
|
|
@ -46,7 +46,7 @@ impl<'a> Middleware for RenderMiddleware<'a> {
|
|||
|
||||
fn next(&self, event: Event, _: &mut dyn FnMut(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.as_deref(), m_event.trigger_args) {
|
||||
Ok(body) => {
|
||||
let body = if let Some(right_separator) = m_event.right_separator {
|
||||
format!("{}{}", body, right_separator)
|
||||
|
|
|
@ -77,7 +77,7 @@ pub trait Multiplexer {
|
|||
}
|
||||
|
||||
pub trait Renderer<'a> {
|
||||
fn render(&'a self, match_id: i32, trigger_args: HashMap<String, String>) -> Result<String>;
|
||||
fn render(&'a self, match_id: i32, trigger: Option<&str>, trigger_args: HashMap<String, String>) -> Result<String>;
|
||||
}
|
||||
|
||||
#[derive(Error, Debug)]
|
||||
|
|
Loading…
Reference in New Issue
Block a user