feat(core): early structure of the engine
This commit is contained in:
parent
5c912777c7
commit
a4958ff352
1
Cargo.lock
generated
1
Cargo.lock
generated
|
@ -287,6 +287,7 @@ version = "1.0.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"clap",
|
"clap",
|
||||||
|
"crossbeam",
|
||||||
"espanso-clipboard",
|
"espanso-clipboard",
|
||||||
"espanso-config",
|
"espanso-config",
|
||||||
"espanso-detect",
|
"espanso-detect",
|
||||||
|
|
|
@ -29,3 +29,4 @@ anyhow = "1.0.38"
|
||||||
thiserror = "1.0.23"
|
thiserror = "1.0.23"
|
||||||
clap = "2.33.3"
|
clap = "2.33.3"
|
||||||
lazy_static = "1.4.0"
|
lazy_static = "1.4.0"
|
||||||
|
crossbeam = "0.8.0"
|
|
@ -23,6 +23,7 @@ use espanso_path::Paths;
|
||||||
|
|
||||||
pub mod log;
|
pub mod log;
|
||||||
pub mod path;
|
pub mod path;
|
||||||
|
pub mod worker;
|
||||||
|
|
||||||
pub struct CliModule {
|
pub struct CliModule {
|
||||||
pub enable_logs: bool,
|
pub enable_logs: bool,
|
||||||
|
|
44
espanso/src/cli/worker/mod.rs
Normal file
44
espanso/src/cli/worker/mod.rs
Normal file
|
@ -0,0 +1,44 @@
|
||||||
|
/*
|
||||||
|
* 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 <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
use crate::engine::{Engine, funnel};
|
||||||
|
use super::{CliModule, CliModuleArgs};
|
||||||
|
|
||||||
|
mod source;
|
||||||
|
|
||||||
|
pub fn new() -> CliModule {
|
||||||
|
#[allow(clippy::needless_update)]
|
||||||
|
CliModule {
|
||||||
|
requires_paths: true,
|
||||||
|
requires_config: true,
|
||||||
|
enable_logs: true,
|
||||||
|
subcommand: "worker".to_string(),
|
||||||
|
entry: worker_main,
|
||||||
|
..Default::default()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn worker_main(args: CliModuleArgs) {
|
||||||
|
let funnel = funnel::default(vec![
|
||||||
|
Box::new(),
|
||||||
|
]);
|
||||||
|
|
||||||
|
let engine = Engine::new(funnel);
|
||||||
|
}
|
||||||
|
|
41
espanso/src/cli/worker/source/detect.rs
Normal file
41
espanso/src/cli/worker/source/detect.rs
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
/*
|
||||||
|
* 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 <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
use crossbeam::channel::{Receiver, Select, SelectedOperation};
|
||||||
|
use espanso_detect::event::InputEvent;
|
||||||
|
|
||||||
|
use crate::engine::{event::Event, funnel::Source};
|
||||||
|
|
||||||
|
pub struct DetectorSource {
|
||||||
|
receiver: Receiver<InputEvent>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Source for DetectorSource {
|
||||||
|
fn register(&self, select: &Select) -> i32 {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn receive(&self, select: &SelectedOperation) -> Event {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn new() {
|
||||||
|
todo!()
|
||||||
|
}
|
20
espanso/src/cli/worker/source/mod.rs
Normal file
20
espanso/src/cli/worker/source/mod.rs
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
/*
|
||||||
|
* 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 <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
pub mod detect;
|
45
espanso/src/engine/dispatch/default.rs
Normal file
45
espanso/src/engine/dispatch/default.rs
Normal file
|
@ -0,0 +1,45 @@
|
||||||
|
/*
|
||||||
|
* 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 <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
use super::{Dispatcher, Executor, TextInjector};
|
||||||
|
use super::Event;
|
||||||
|
|
||||||
|
pub struct DefaultDispatcher {
|
||||||
|
executors: Vec<Box<dyn Executor>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DefaultDispatcher {
|
||||||
|
pub fn new(text_injector: impl TextInjector + 'static) -> Self {
|
||||||
|
Self {
|
||||||
|
executors: vec![
|
||||||
|
Box::new(super::executor::text_inject::TextInjectExecutor::new(text_injector)),
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Dispatcher for DefaultDispatcher {
|
||||||
|
fn dispatch(&self, event: Event) {
|
||||||
|
for executor in self.executors.iter() {
|
||||||
|
if executor.execute(&event) {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
20
espanso/src/engine/dispatch/executor/mod.rs
Normal file
20
espanso/src/engine/dispatch/executor/mod.rs
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
/*
|
||||||
|
* 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 <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
pub mod text_inject;
|
47
espanso/src/engine/dispatch/executor/text_inject.rs
Normal file
47
espanso/src/engine/dispatch/executor/text_inject.rs
Normal file
|
@ -0,0 +1,47 @@
|
||||||
|
/*
|
||||||
|
* 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 <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
use super::super::{Event, Executor, TextInjector};
|
||||||
|
use crate::engine::event::inject::TextInjectMode;
|
||||||
|
use log::error;
|
||||||
|
|
||||||
|
pub struct TextInjectExecutor<T: TextInjector> {
|
||||||
|
injector: T,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: TextInjector> TextInjectExecutor<T> {
|
||||||
|
pub fn new(injector: T) -> Self {
|
||||||
|
Self { injector }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: TextInjector> Executor for TextInjectExecutor<T> {
|
||||||
|
fn execute(&self, event: &Event) -> bool {
|
||||||
|
if let Event::TextInject(inject_event) = event {
|
||||||
|
if inject_event.mode == TextInjectMode::Keys {
|
||||||
|
if let Err(error) = self.injector.inject(&inject_event.text) {
|
||||||
|
error!("text injector reported an error: {:?}", error);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
42
espanso/src/engine/dispatch/mod.rs
Normal file
42
espanso/src/engine/dispatch/mod.rs
Normal file
|
@ -0,0 +1,42 @@
|
||||||
|
/*
|
||||||
|
* 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 <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
use anyhow::Result;
|
||||||
|
use super::Event;
|
||||||
|
|
||||||
|
mod executor;
|
||||||
|
mod default;
|
||||||
|
|
||||||
|
pub trait Executor {
|
||||||
|
fn execute(&self, event: &Event) -> bool;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait Dispatcher {
|
||||||
|
fn dispatch(&self, event: Event);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait TextInjector {
|
||||||
|
fn inject(&self, text: &str) -> Result<()>;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn default(text_injector: impl TextInjector + 'static) -> impl Dispatcher {
|
||||||
|
default::DefaultDispatcher::new(
|
||||||
|
text_injector,
|
||||||
|
)
|
||||||
|
}
|
30
espanso/src/engine/event/inject.rs
Normal file
30
espanso/src/engine/event/inject.rs
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
/*
|
||||||
|
* 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 <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct TextInjectEvent {
|
||||||
|
pub text: String,
|
||||||
|
pub mode: TextInjectMode,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq)]
|
||||||
|
pub enum TextInjectMode {
|
||||||
|
Keys,
|
||||||
|
Clipboard,
|
||||||
|
}
|
95
espanso/src/engine/event/keyboard.rs
Normal file
95
espanso/src/engine/event/keyboard.rs
Normal file
|
@ -0,0 +1,95 @@
|
||||||
|
/*
|
||||||
|
* 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 <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq)]
|
||||||
|
pub enum Status {
|
||||||
|
Pressed,
|
||||||
|
Released,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq)]
|
||||||
|
pub enum Variant {
|
||||||
|
Left,
|
||||||
|
Right,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq)]
|
||||||
|
pub struct KeyboardEvent {
|
||||||
|
pub key: Key,
|
||||||
|
pub value: Option<String>,
|
||||||
|
pub status: Status,
|
||||||
|
pub variant: Option<Variant>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, 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,
|
||||||
|
|
||||||
|
// Other keys, includes the raw code provided by the operating system
|
||||||
|
Other(i32),
|
||||||
|
}
|
32
espanso/src/engine/event/matches_detected.rs
Normal file
32
espanso/src/engine/event/matches_detected.rs
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
/*
|
||||||
|
* 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 <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
use std::collections::HashMap;
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
|
pub struct MatchesDetectedEvent {
|
||||||
|
pub results: Vec<MatchResult>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
|
pub struct MatchResult {
|
||||||
|
pub id: i32,
|
||||||
|
pub trigger: String,
|
||||||
|
pub vars: HashMap<String, String>,
|
||||||
|
}
|
36
espanso/src/engine/event/mod.rs
Normal file
36
espanso/src/engine/event/mod.rs
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
/*
|
||||||
|
* 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 <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
pub mod keyboard;
|
||||||
|
pub mod inject;
|
||||||
|
pub mod matches_detected;
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum Event {
|
||||||
|
NOOP,
|
||||||
|
|
||||||
|
// Inputs
|
||||||
|
Keyboard(keyboard::KeyboardEvent),
|
||||||
|
|
||||||
|
// Internal
|
||||||
|
MatchesDetected(matches_detected::MatchesDetectedEvent),
|
||||||
|
|
||||||
|
// Effects
|
||||||
|
TextInject(inject::TextInjectEvent),
|
||||||
|
}
|
56
espanso/src/engine/funnel/default.rs
Normal file
56
espanso/src/engine/funnel/default.rs
Normal file
|
@ -0,0 +1,56 @@
|
||||||
|
/*
|
||||||
|
* 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 <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
use crossbeam::channel::Select;
|
||||||
|
|
||||||
|
use super::{Funnel, FunnelResult, Source};
|
||||||
|
|
||||||
|
pub struct DefaultFunnel {
|
||||||
|
sources: Vec<Box<dyn Source>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DefaultFunnel {
|
||||||
|
pub fn new(sources: Vec<Box<dyn Source>>) -> Self {
|
||||||
|
Self {
|
||||||
|
sources
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Funnel for DefaultFunnel {
|
||||||
|
fn receive(&self) -> FunnelResult {
|
||||||
|
let mut select = Select::new();
|
||||||
|
|
||||||
|
// First register all the sources to the select operation
|
||||||
|
for source in self.sources.iter() {
|
||||||
|
source.register(&select);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wait for the first source (blocking operation)
|
||||||
|
let op = select.select();
|
||||||
|
let source = self
|
||||||
|
.sources
|
||||||
|
.get(op.index())
|
||||||
|
.expect("invalid source index returned by select operation");
|
||||||
|
|
||||||
|
// Receive (and convert) the event
|
||||||
|
let event = source.receive(&op);
|
||||||
|
FunnelResult::Event(event)
|
||||||
|
}
|
||||||
|
}
|
44
espanso/src/engine/funnel/mod.rs
Normal file
44
espanso/src/engine/funnel/mod.rs
Normal file
|
@ -0,0 +1,44 @@
|
||||||
|
/*
|
||||||
|
* 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 <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
use crossbeam::{channel::Select, channel::SelectedOperation};
|
||||||
|
|
||||||
|
use self::default::DefaultFunnel;
|
||||||
|
|
||||||
|
use super::Event;
|
||||||
|
|
||||||
|
mod default;
|
||||||
|
|
||||||
|
pub trait Source {
|
||||||
|
fn register(&self, select: &Select) -> i32;
|
||||||
|
fn receive(&self, select: &SelectedOperation) -> Event;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait Funnel {
|
||||||
|
fn receive(&self) -> FunnelResult;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub enum FunnelResult {
|
||||||
|
Event(Event),
|
||||||
|
EndOfStream,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn default(sources: Vec<Box<dyn Source>>) -> impl Funnel {
|
||||||
|
DefaultFunnel::new(sources)
|
||||||
|
}
|
68
espanso/src/engine/mod.rs
Normal file
68
espanso/src/engine/mod.rs
Normal file
|
@ -0,0 +1,68 @@
|
||||||
|
/*
|
||||||
|
* 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 <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
use log::{debug, trace};
|
||||||
|
use std::collections::VecDeque;
|
||||||
|
|
||||||
|
use self::{
|
||||||
|
dispatch::Dispatcher,
|
||||||
|
event::Event,
|
||||||
|
process::Processor,
|
||||||
|
funnel::{Funnel, FunnelResult},
|
||||||
|
};
|
||||||
|
|
||||||
|
pub mod dispatch;
|
||||||
|
pub mod event;
|
||||||
|
pub mod process;
|
||||||
|
pub mod funnel;
|
||||||
|
|
||||||
|
pub struct Engine<TFunnel: Funnel, TProcessor: Processor, TDispatcher: Dispatcher> {
|
||||||
|
funnel: TFunnel,
|
||||||
|
processor: TProcessor,
|
||||||
|
dispatcher: TDispatcher,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl <TFunnel: Funnel, TProcessor: Processor, TDispatcher: Dispatcher> Engine<TFunnel, TProcessor, TDispatcher> {
|
||||||
|
pub fn new(funnel: TFunnel, processor: TProcessor, dispatcher: TDispatcher) -> Self {
|
||||||
|
Self {
|
||||||
|
funnel,
|
||||||
|
processor,
|
||||||
|
dispatcher,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn run(&mut self) {
|
||||||
|
loop {
|
||||||
|
match self.funnel.receive() {
|
||||||
|
FunnelResult::Event(event) => {
|
||||||
|
trace!("received event from stream: {:?}", event);
|
||||||
|
|
||||||
|
let processed_events = self.processor.process(event);
|
||||||
|
for event in processed_events {
|
||||||
|
self.dispatcher.dispatch(event);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
FunnelResult::EndOfStream => {
|
||||||
|
debug!("end of stream received");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
78
espanso/src/engine/process/default.rs
Normal file
78
espanso/src/engine/process/default.rs
Normal file
|
@ -0,0 +1,78 @@
|
||||||
|
/*
|
||||||
|
* 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 <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
use super::{Event, Matcher, Middleware, Processor, middleware::matcher::MatchMiddleware};
|
||||||
|
use std::collections::VecDeque;
|
||||||
|
|
||||||
|
pub struct DefaultProcessor {
|
||||||
|
event_queue: VecDeque<Event>,
|
||||||
|
middleware: Vec<Box<dyn Middleware>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DefaultProcessor {
|
||||||
|
pub fn new<MatcherState: 'static>(matchers: Vec<Box<dyn Matcher<MatcherState>>>) -> Self {
|
||||||
|
Self {
|
||||||
|
event_queue: VecDeque::new(),
|
||||||
|
middleware: vec![
|
||||||
|
Box::new(MatchMiddleware::new(matchers)),
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn process_one(&mut self) -> Option<Event> {
|
||||||
|
if let Some(event) = self.event_queue.pop_back() {
|
||||||
|
let mut current_event = event;
|
||||||
|
|
||||||
|
let mut current_queue = VecDeque::new();
|
||||||
|
let dispatch = |event: Event| {
|
||||||
|
// TODO: add tracing information
|
||||||
|
current_queue.push_front(event);
|
||||||
|
};
|
||||||
|
|
||||||
|
for middleware in self.middleware.iter() {
|
||||||
|
// TODO: add tracing information
|
||||||
|
current_event = middleware.next(current_event, &dispatch);
|
||||||
|
}
|
||||||
|
|
||||||
|
while let Some(event) = current_queue.pop_back() {
|
||||||
|
self.event_queue.push_front(event);
|
||||||
|
}
|
||||||
|
|
||||||
|
Some(current_event)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Processor for DefaultProcessor {
|
||||||
|
fn process(&mut self, event: Event) -> Vec<Event> {
|
||||||
|
self.event_queue.push_front(event);
|
||||||
|
|
||||||
|
let mut processed_events = Vec::new();
|
||||||
|
|
||||||
|
while !self.event_queue.is_empty() {
|
||||||
|
if let Some(event) = self.process_one() {
|
||||||
|
processed_events.push(event);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
processed_events
|
||||||
|
}
|
||||||
|
}
|
133
espanso/src/engine/process/middleware/matcher.rs
Normal file
133
espanso/src/engine/process/middleware/matcher.rs
Normal file
|
@ -0,0 +1,133 @@
|
||||||
|
/*
|
||||||
|
* 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 <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
use log::trace;
|
||||||
|
use std::{cell::RefCell, collections::VecDeque};
|
||||||
|
|
||||||
|
use super::super::Middleware;
|
||||||
|
use crate::engine::{event::{Event, keyboard::{Key, Status}, matches_detected::{MatchResult, MatchesDetectedEvent}}, process::{Matcher, MatcherEvent}};
|
||||||
|
|
||||||
|
const MAX_HISTORY: usize = 3; // TODO: get as parameter
|
||||||
|
|
||||||
|
pub struct MatchMiddleware<State> {
|
||||||
|
matchers: Vec<Box<dyn Matcher<State>>>,
|
||||||
|
|
||||||
|
matcher_states: RefCell<VecDeque<Vec<State>>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<State> MatchMiddleware<State> {
|
||||||
|
pub fn new(matchers: Vec<Box<dyn Matcher<State>>>) -> Self {
|
||||||
|
Self {
|
||||||
|
matchers,
|
||||||
|
matcher_states: RefCell::new(VecDeque::new()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<State> Middleware for MatchMiddleware<State> {
|
||||||
|
fn next(&self, event: Event, _: &dyn FnMut(Event)) -> Event {
|
||||||
|
let mut matcher_states = self.matcher_states.borrow_mut();
|
||||||
|
let prev_states = if !matcher_states.is_empty() {
|
||||||
|
matcher_states.get(matcher_states.len() - 1)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
|
||||||
|
if let Event::Keyboard(keyboard_event) = &event {
|
||||||
|
// Backspace handling
|
||||||
|
if keyboard_event.key == Key::Backspace {
|
||||||
|
trace!("popping the last matcher state");
|
||||||
|
matcher_states.pop_back();
|
||||||
|
return event;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Some keys (such as the arrow keys) prevent espanso from building
|
||||||
|
// an accurate key buffer, so we need to invalidate it.
|
||||||
|
if is_invalidating_key(&keyboard_event.key) {
|
||||||
|
matcher_states.clear();
|
||||||
|
return event;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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) {
|
||||||
|
let mut new_states = Vec::new();
|
||||||
|
for (i, matcher) in self.matchers.iter().enumerate() {
|
||||||
|
let prev_state = prev_states.and_then(|states| states.get(i));
|
||||||
|
|
||||||
|
let (state, results) = matcher.process(prev_state, &matcher_event);
|
||||||
|
all_results.extend(results);
|
||||||
|
|
||||||
|
new_states.push(state);
|
||||||
|
}
|
||||||
|
|
||||||
|
matcher_states.push_back(new_states);
|
||||||
|
if matcher_states.len() > MAX_HISTORY {
|
||||||
|
matcher_states.pop_front();
|
||||||
|
}
|
||||||
|
|
||||||
|
if !all_results.is_empty() {
|
||||||
|
return Event::MatchesDetected(MatchesDetectedEvent {
|
||||||
|
results: all_results.into_iter().map(|result | {
|
||||||
|
MatchResult {
|
||||||
|
id: result.id,
|
||||||
|
trigger: result.trigger,
|
||||||
|
vars: result.vars,
|
||||||
|
}
|
||||||
|
}).collect()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
event
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn convert_to_matcher_event(event: &Event) -> Option<MatcherEvent> {
|
||||||
|
if let Event::Keyboard(keyboard_event) = event {
|
||||||
|
if keyboard_event.status == Status::Pressed {
|
||||||
|
return Some(MatcherEvent::Key {
|
||||||
|
key: keyboard_event.key.clone(),
|
||||||
|
chars: keyboard_event.value.clone(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: mouse event should act as separator
|
||||||
|
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_invalidating_key(key: &Key) -> bool {
|
||||||
|
match key {
|
||||||
|
Key::ArrowDown => true,
|
||||||
|
Key::ArrowLeft => true,
|
||||||
|
Key::ArrowRight => true,
|
||||||
|
Key::ArrowUp => true,
|
||||||
|
Key::End => true,
|
||||||
|
Key::Home => true,
|
||||||
|
Key::PageDown => true,
|
||||||
|
Key::PageUp => true,
|
||||||
|
Key::Escape => true,
|
||||||
|
_ => false,
|
||||||
|
}
|
||||||
|
}
|
20
espanso/src/engine/process/middleware/mod.rs
Normal file
20
espanso/src/engine/process/middleware/mod.rs
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
/*
|
||||||
|
* 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 <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
pub mod matcher;
|
56
espanso/src/engine/process/mod.rs
Normal file
56
espanso/src/engine/process/mod.rs
Normal file
|
@ -0,0 +1,56 @@
|
||||||
|
/*
|
||||||
|
* 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 <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
use std::collections::HashMap;
|
||||||
|
|
||||||
|
use super::{Event, event::keyboard::Key};
|
||||||
|
|
||||||
|
mod middleware;
|
||||||
|
mod default;
|
||||||
|
|
||||||
|
pub trait Middleware {
|
||||||
|
fn next(&self, event: Event, dispatch: &dyn FnMut(Event)) -> Event;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait Processor {
|
||||||
|
fn process(&mut self, event: Event) -> Vec<Event>;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Dependency inversion entities
|
||||||
|
|
||||||
|
pub trait Matcher<State> {
|
||||||
|
fn process(&self, prev_state: Option<&State>, event: &MatcherEvent) -> (State, Vec<MatchResult>);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub enum MatcherEvent {
|
||||||
|
Key { key: Key, chars: Option<String> },
|
||||||
|
VirtualSeparator,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
|
pub struct MatchResult {
|
||||||
|
id: i32,
|
||||||
|
trigger: String,
|
||||||
|
vars: HashMap<String, String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn default<MatcherState: 'static>(matchers: Vec<Box<dyn Matcher<MatcherState>>>) -> impl Processor {
|
||||||
|
default::DefaultProcessor::new(matchers)
|
||||||
|
}
|
|
@ -28,7 +28,6 @@ use simplelog::{CombinedLogger, ConfigBuilder, LevelFilter, TermLogger, Terminal
|
||||||
mod cli;
|
mod cli;
|
||||||
mod engine;
|
mod engine;
|
||||||
mod logging;
|
mod logging;
|
||||||
mod util;
|
|
||||||
|
|
||||||
const VERSION: &str = env!("CARGO_PKG_VERSION");
|
const VERSION: &str = env!("CARGO_PKG_VERSION");
|
||||||
const LOG_FILE_NAME: &str = "espanso.log";
|
const LOG_FILE_NAME: &str = "espanso.log";
|
||||||
|
@ -37,6 +36,7 @@ lazy_static! {
|
||||||
static ref CLI_HANDLERS: Vec<CliModule> = vec![
|
static ref CLI_HANDLERS: Vec<CliModule> = vec![
|
||||||
cli::path::new(),
|
cli::path::new(),
|
||||||
cli::log::new(),
|
cli::log::new(),
|
||||||
|
cli::worker::new(),
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -170,19 +170,19 @@ fn main() {
|
||||||
// )
|
// )
|
||||||
// )
|
// )
|
||||||
// Package manager
|
// Package manager
|
||||||
.subcommand(SubCommand::with_name("package")
|
// .subcommand(SubCommand::with_name("package")
|
||||||
.about("Espanso package manager commands")
|
// .about("Espanso package manager commands")
|
||||||
.subcommand(install_subcommand.clone())
|
// .subcommand(install_subcommand.clone())
|
||||||
.subcommand(uninstall_subcommand.clone())
|
// .subcommand(uninstall_subcommand.clone())
|
||||||
.subcommand(SubCommand::with_name("list")
|
// .subcommand(SubCommand::with_name("list")
|
||||||
.about("List all installed packages")
|
// .about("List all installed packages")
|
||||||
.arg(Arg::with_name("full")
|
// .arg(Arg::with_name("full")
|
||||||
.help("Print all package info")
|
// .help("Print all package info")
|
||||||
.long("full")))
|
// .long("full")))
|
||||||
|
|
||||||
.subcommand(SubCommand::with_name("refresh")
|
// .subcommand(SubCommand::with_name("refresh")
|
||||||
.about("Update espanso package index"))
|
// .about("Update espanso package index"))
|
||||||
)
|
// )
|
||||||
.subcommand(SubCommand::with_name("worker")
|
.subcommand(SubCommand::with_name("worker")
|
||||||
.setting(AppSettings::Hidden)
|
.setting(AppSettings::Hidden)
|
||||||
.arg(Arg::with_name("reload")
|
.arg(Arg::with_name("reload")
|
||||||
|
@ -190,9 +190,9 @@ fn main() {
|
||||||
.long("reload")
|
.long("reload")
|
||||||
.required(false)
|
.required(false)
|
||||||
.takes_value(false))
|
.takes_value(false))
|
||||||
)
|
);
|
||||||
.subcommand(install_subcommand)
|
// .subcommand(install_subcommand)
|
||||||
.subcommand(uninstall_subcommand);
|
// .subcommand(uninstall_subcommand);
|
||||||
|
|
||||||
// TODO: explain that the start and restart commands are only meaningful
|
// TODO: explain that the start and restart commands are only meaningful
|
||||||
// when using the system daemon manager on macOS and Linux
|
// when using the system daemon manager on macOS and Linux
|
||||||
|
|
Loading…
Reference in New Issue
Block a user