diff --git a/Cargo.lock b/Cargo.lock index 5dbbc8b..0758999 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -227,6 +227,7 @@ dependencies = [ "espanso-config", "espanso-detect", "espanso-inject", + "espanso-match", "espanso-ui", "maplit", "simplelog", @@ -295,6 +296,18 @@ dependencies = [ "thiserror", ] +[[package]] +name = "espanso-match" +version = "0.1.0" +dependencies = [ + "anyhow", + "lazy_static", + "log", + "regex", + "thiserror", + "unicase", +] + [[package]] name = "espanso-ui" version = "0.1.0" @@ -810,6 +823,15 @@ dependencies = [ "winapi", ] +[[package]] +name = "unicase" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50f37be617794602aabbeee0be4f259dc1778fabe05e2d67ee8f79326d5cb4f6" +dependencies = [ + "version_check", +] + [[package]] name = "unicode-segmentation" version = "1.7.1" @@ -828,6 +850,12 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564" +[[package]] +name = "version_check" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5a972e5669d67ba988ce3dc826706fb0a8b01471c088cb0b6110b805cc36aed" + [[package]] name = "wasi" version = "0.9.0+wasi-snapshot-preview1" diff --git a/Cargo.toml b/Cargo.toml index abb5918..54849d5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -7,4 +7,5 @@ members = [ "espanso-inject", "espanso-ipc", "espanso-config", + "espanso-match", ] \ No newline at end of file diff --git a/espanso-match/Cargo.toml b/espanso-match/Cargo.toml new file mode 100644 index 0000000..336eb24 --- /dev/null +++ b/espanso-match/Cargo.toml @@ -0,0 +1,13 @@ +[package] +name = "espanso-match" +version = "0.1.0" +authors = ["Federico Terzi "] +edition = "2018" + +[dependencies] +log = "0.4.14" +anyhow = "1.0.38" +thiserror = "1.0.23" +regex = "1.4.3" +lazy_static = "1.4.0" +unicase = "2.6.0" \ No newline at end of file diff --git a/espanso-match/src/event.rs b/espanso-match/src/event.rs new file mode 100644 index 0000000..9c457ae --- /dev/null +++ b/espanso-match/src/event.rs @@ -0,0 +1,84 @@ +/* + * 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 . + */ + +#[derive(Debug, PartialEq)] +pub enum Event { + Key { + key: Key, + char: Option + }, + VirtualSeparator, +} + +#[derive(Debug, PartialEq)] +pub enum Key { + // Modifiers + Alt, + CapsLock, + Control, + Meta, + NumLock, + Shift, + + // Whitespace + Enter, + Tab, + Space, + + // Navigation + ArrowDown, + ArrowLeft, + ArrowRight, + ArrowUp, + End, + Home, + PageDown, + PageUp, + + // UI + Escape, + + // Editing keys + Backspace, + + // Function keys + F1, + F2, + F3, + F4, + F5, + F6, + F7, + F8, + F9, + F10, + F11, + F12, + F13, + F14, + F15, + F16, + F17, + F18, + F19, + F20, + + // Others + Other, +} \ No newline at end of file diff --git a/espanso-match/src/lib.rs b/espanso-match/src/lib.rs new file mode 100644 index 0000000..dc9c1a2 --- /dev/null +++ b/espanso-match/src/lib.rs @@ -0,0 +1,31 @@ +/* + * 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 . + */ + +use std::any::Any; + +#[macro_use] +extern crate lazy_static; + +pub mod event; +pub mod rolling; + +pub trait Matcher { + // TODO: create suitable event type + fn process(&self, prev_state: Option<&dyn Any>, event: Option) -> (Box, Vec); +} \ No newline at end of file diff --git a/espanso-match/src/rolling/item.rs b/espanso-match/src/rolling/item.rs new file mode 100644 index 0000000..fce6f07 --- /dev/null +++ b/espanso-match/src/rolling/item.rs @@ -0,0 +1,28 @@ +use crate::event::Key; + +/* + * 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 . + */ + + +pub enum RollingItem { + WordSeparator, + Key(Key), + Char(String), + CharInsensitive(String), +} \ No newline at end of file diff --git a/espanso-match/src/rolling/matcher.rs b/espanso-match/src/rolling/matcher.rs new file mode 100644 index 0000000..3a22eee --- /dev/null +++ b/espanso-match/src/rolling/matcher.rs @@ -0,0 +1,110 @@ +/* + * 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 . + */ + +use unicase::UniCase; + +use crate::event::{Event, Key}; + +use super::tree::{MatcherTreeNode, MatcherTreeRef}; + +pub struct RollingMatcher { + char_word_separators: Vec, + key_word_separators: Vec, + + root: MatcherTreeNode, +} + +// impl Matcher for RollingMatcher { +// fn process( +// &self, +// prev_state: &dyn std::any::Any, +// event: Option, +// ) -> (Box, Vec) { +// todo!() +// } +// } + +impl RollingMatcher { + // TODO: to find the matches, we first call the `find_refs` to get the list of matching nodes + // then we scan them and if any of those references is of variant `Matches`, then we return those + // match ids, otherwise None + + // TODO: test + fn find_refs<'a>(&'a self, node: &'a MatcherTreeNode, event: &Event) -> Vec<&'a MatcherTreeRef> { + let mut refs = Vec::new(); + + if let Event::Key { key, char } = event { + // Key matching + if let Some((_, node_ref)) = node.keys.iter().find(|(_key, _)| _key == key) { + refs.push(node_ref); + } + + if let Some(char) = char { + // Char matching + if let Some((_, node_ref)) = node.chars.iter().find(|(_char, _)| _char == char) { + refs.push(node_ref); + } + + // Char case-insensitive + let insensitive_char = UniCase::new(char); + if let Some((_, node_ref)) = node + .chars_insensitive + .iter() + .find(|(_char, _)| *_char == insensitive_char) + { + refs.push(node_ref); + } + } + } + + if self.is_word_separator(event) { + if let Some(node_ref) = node.word_separators.as_ref() { + refs.push(node_ref) + } + } + + refs + } + + fn is_word_separator(&self, event: &Event) -> bool { + match event { + Event::Key { key, char } => { + if self.key_word_separators.contains(&key) { + true + } else if let Some(char) = char { + self.char_word_separators.contains(&char) + } else { + false + } + } + Event::VirtualSeparator => true, + _ => false, + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test() { + + } +} diff --git a/espanso-match/src/rolling/mod.rs b/espanso-match/src/rolling/mod.rs new file mode 100644 index 0000000..add1d83 --- /dev/null +++ b/espanso-match/src/rolling/mod.rs @@ -0,0 +1,35 @@ +/* + * 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 . + */ + +use self::item::RollingItem; + +mod item; +mod tree; +mod matcher; + +pub struct RollingMatch { + id: i32, + items: Vec, +} + +impl RollingMatch { + pub fn new(id: i32, items: Vec) -> Self { + Self { id, items } + } +} diff --git a/espanso-match/src/rolling/tree.rs b/espanso-match/src/rolling/tree.rs new file mode 100644 index 0000000..032135d --- /dev/null +++ b/espanso-match/src/rolling/tree.rs @@ -0,0 +1,46 @@ +/* + * 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 . + */ + +use unicase::UniCase; + +use crate::event::Key; + +use super::item::RollingItem; + +#[derive(Debug)] +pub(crate) enum MatcherTreeRef { + Matches(Vec), + Node(Box), +} + +#[derive(Debug)] +pub(crate) struct MatcherTreeNode { + pub word_separators: Option, + pub keys: Vec<(Key, MatcherTreeRef)>, + pub chars: Vec<(String, MatcherTreeRef)>, + pub chars_insensitive: Vec<(UniCase, MatcherTreeRef)>, +} + +impl MatcherTreeNode { + // TODO: test + pub fn from_items(items: &[RollingItem]) -> MatcherTreeNode { + todo!() + } +} + diff --git a/espanso/Cargo.toml b/espanso/Cargo.toml index d4ccd10..8e9445f 100644 --- a/espanso/Cargo.toml +++ b/espanso/Cargo.toml @@ -18,5 +18,6 @@ espanso-detect = { path = "../espanso-detect" } espanso-ui = { path = "../espanso-ui" } espanso-inject = { path = "../espanso-inject" } espanso-config = { path = "../espanso-config" } +espanso-match = { path = "../espanso-match" } maplit = "1.0.2" simplelog = "0.9.0" \ No newline at end of file