diff --git a/src/config.rs b/src/config.rs index a7c3095..d0f6344 100644 --- a/src/config.rs +++ b/src/config.rs @@ -7,7 +7,6 @@ use std::fs::File; use std::io::Read; use serde::{Serialize, Deserialize}; use crate::keyboard::KeyModifier; -use crate::keyboard::KeyModifier::*; // TODO: add documentation link const DEFAULT_CONFIG_FILE_CONTENT : &str = include_str!("res/config.yaml"); @@ -18,6 +17,10 @@ fn default_toggle_interval() -> u32 { 230 } +fn default_backspace_limit() -> i32 { + 3 +} + #[derive(Clone, Debug, Serialize, Deserialize)] pub struct Configs { #[serde(default)] @@ -26,6 +29,9 @@ pub struct Configs { #[serde(default = "default_toggle_interval")] pub toggle_interval: u32, + #[serde(default = "default_backspace_limit")] + pub backspace_limit: i32, + pub matches: Vec } diff --git a/src/keyboard/windows.rs b/src/keyboard/windows.rs index c3af680..3fb9825 100644 --- a/src/keyboard/windows.rs +++ b/src/keyboard/windows.rs @@ -1,4 +1,3 @@ -use std::thread; use std::sync::mpsc; use widestring::{U16CString}; use crate::keyboard::{KeyEvent, KeyModifier}; diff --git a/src/matcher/scrolling.rs b/src/matcher/scrolling.rs index c190cb0..3f1a1f1 100644 --- a/src/matcher/scrolling.rs +++ b/src/matcher/scrolling.rs @@ -4,11 +4,12 @@ use crate::keyboard::KeyModifier; use crate::config::Configs; use crate::keyboard::KeyModifier::BACKSPACE; use std::time::SystemTime; +use std::collections::VecDeque; pub struct ScrollingMatcher<'a, R> where R: MatchReceiver{ configs: Configs, receiver: R, - current_set: RefCell>>, + current_set_queue: RefCell>>>, toggle_press_time: RefCell, is_enabled: RefCell, } @@ -25,7 +26,7 @@ impl <'a, R> super::Matcher<'a> for ScrollingMatcher<'a, R> where R: MatchReceiv return; } - let mut current_set = self.current_set.borrow_mut(); + let mut current_set_queue = self.current_set_queue.borrow_mut(); let new_matches: Vec = self.configs.matches.iter() .filter(|&x| x.trigger.chars().nth(0).unwrap() == c) @@ -33,27 +34,40 @@ impl <'a, R> super::Matcher<'a> for ScrollingMatcher<'a, R> where R: MatchReceiv .collect(); // TODO: use an associative structure to improve the efficiency of this first "new_matches" lookup. - let old_matches: Vec = (*current_set).iter() - .filter(|&x| { - x._match.trigger[x.start..].chars().nth(0).unwrap() == c - }) - .map(|x | MatchEntry{start: x.start+1, _match: &x._match}) - .collect(); + let combined_matches: Vec = match current_set_queue.back() { + Some(last_matches) => { + let mut updated: Vec = last_matches.iter() + .filter(|&x| { + x._match.trigger[x.start..].chars().nth(0).unwrap() == c + }) + .map(|x | MatchEntry{start: x.start+1, _match: &x._match}) + .collect(); - (*current_set) = old_matches; - (*current_set).extend(new_matches); + updated.extend(new_matches); + updated + }, + None => {new_matches}, + }; let mut found_match = None; - for entry in (*current_set).iter() { + for entry in combined_matches.iter() { if entry.start == entry._match.trigger.len() { found_match = Some(entry._match); break; } } + current_set_queue.push_back(combined_matches); + + if current_set_queue.len() as i32 > (self.configs.backspace_limit + 1) { + current_set_queue.pop_front(); + } + if let Some(_match) = found_match { - (*current_set).clear(); + if let Some(last) = current_set_queue.back_mut() { + last.clear(); + } self.receiver.on_match(_match); } } @@ -67,7 +81,7 @@ impl <'a, R> super::Matcher<'a> for ScrollingMatcher<'a, R> where R: MatchReceiv *is_enabled = !(*is_enabled); if !*is_enabled { - self.current_set.borrow_mut().clear(); + self.current_set_queue.borrow_mut().clear(); } println!("Enabled {}", *is_enabled); @@ -76,18 +90,23 @@ impl <'a, R> super::Matcher<'a> for ScrollingMatcher<'a, R> where R: MatchReceiv (*toggle_press_time) = SystemTime::now(); } + + // Backspace handling, basically "rewinding history" + if m == BACKSPACE { + let mut current_set_queue = self.current_set_queue.borrow_mut(); + current_set_queue.pop_back(); + } } } - impl <'a, R> ScrollingMatcher<'a, R> where R: MatchReceiver { pub fn new(configs: Configs, receiver: R) -> ScrollingMatcher<'a, R> { - let current_set = RefCell::new(Vec::new()); + let current_set_queue = RefCell::new(VecDeque::new()); let toggle_press_time = RefCell::new(SystemTime::now()); ScrollingMatcher{ configs, receiver, - current_set, + current_set_queue, toggle_press_time, is_enabled: RefCell::new(true) }