feat(core): add support for modulo in espanso core

This commit is contained in:
Federico Terzi 2021-05-21 22:03:54 +02:00
parent 23895841e3
commit 074eae309c
8 changed files with 342 additions and 5 deletions

114
Cargo.lock generated
View File

@ -1,5 +1,11 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
[[package]]
name = "adler"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
[[package]]
name = "aho-corasick"
version = "0.7.15"
@ -88,6 +94,33 @@ version = "0.1.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0d8c1fef690941d3e7788d328517591fecc684c084084702d6ff1641e993699a"
[[package]]
name = "byteorder"
version = "1.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610"
[[package]]
name = "bzip2"
version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "42b7c3cbf0fa9c1b82308d57191728ca0256cb821220f4e2fd410a72ade26e3b"
dependencies = [
"bzip2-sys",
"libc",
]
[[package]]
name = "bzip2-sys"
version = "0.1.10+1.0.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "17fa3d1ac1ca21c5c4e36a97f3c3eb25084576f6fc47bf0139c1123434216c6c"
dependencies = [
"cc",
"libc",
"pkg-config",
]
[[package]]
name = "cc"
version = "1.0.66"
@ -140,6 +173,15 @@ version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc"
[[package]]
name = "crc32fast"
version = "1.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "81156fece84ab6a9f2afdb109ce3ae577e42b1228441eded99bd77f627953b1a"
dependencies = [
"cfg-if",
]
[[package]]
name = "crossbeam"
version = "0.8.0"
@ -309,6 +351,7 @@ dependencies = [
"espanso-inject",
"espanso-ipc",
"espanso-match",
"espanso-modulo",
"espanso-path",
"espanso-render",
"espanso-ui",
@ -322,6 +365,7 @@ dependencies = [
"named_pipe",
"serde",
"serde_json",
"serde_yaml",
"simplelog",
"thiserror",
"winapi",
@ -434,6 +478,22 @@ dependencies = [
"unicase",
]
[[package]]
name = "espanso-modulo"
version = "0.1.0"
dependencies = [
"anyhow",
"cc",
"lazy_static",
"log",
"regex",
"serde",
"serde_json",
"thiserror",
"winres",
"zip",
]
[[package]]
name = "espanso-path"
version = "0.1.0"
@ -473,6 +533,18 @@ dependencies = [
"widestring",
]
[[package]]
name = "flate2"
version = "1.0.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cd3aec53de10fe96d7d8c565eb17f2c687bb5518a2ec453b5b1252964526abe0"
dependencies = [
"cfg-if",
"crc32fast",
"libc",
"miniz_oxide",
]
[[package]]
name = "float-cmp"
version = "0.8.0"
@ -736,6 +808,16 @@ dependencies = [
"autocfg",
]
[[package]]
name = "miniz_oxide"
version = "0.4.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a92518e98c078586bc6c934028adcca4c92a53d6a958196de835170a01d84e4b"
dependencies = [
"adler",
"autocfg",
]
[[package]]
name = "mockall"
version = "0.9.1"
@ -1402,6 +1484,15 @@ dependencies = [
"winapi",
]
[[package]]
name = "toml"
version = "0.5.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a31142970826733df8241ef35dc040ef98c679ab14d7c3e54d827099b3acecaa"
dependencies = [
"serde",
]
[[package]]
name = "treeline"
version = "0.1.0"
@ -1528,6 +1619,15 @@ version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
[[package]]
name = "winres"
version = "0.1.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ff4fb510bbfe5b8992ff15f77a2e6fe6cf062878f0eda00c0f44963a807ca5dc"
dependencies = [
"toml",
]
[[package]]
name = "winrt"
version = "0.4.0"
@ -1579,3 +1679,17 @@ checksum = "56c1936c4cc7a1c9ab21a1ebb602eb942ba868cbd44a99cb7cdc5892335e1c85"
dependencies = [
"linked-hash-map",
]
[[package]]
name = "zip"
version = "0.5.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c83dc9b784d252127720168abd71ea82bf8c3d96b17dc565b5e2a02854f2b27"
dependencies = [
"byteorder",
"bzip2",
"crc32fast",
"flate2",
"thiserror",
"time",
]

View File

@ -12,4 +12,5 @@ members = [
"espanso-render",
"espanso-info",
"espanso-path",
"espanso-modulo",
]

View File

@ -9,10 +9,16 @@ homepage = "https://github.com/federico-terzi/espanso"
edition = "2018"
[features]
default = ["modulo"] # TODO: we might want to avoid specifying a default and instead rely on cargo make
# If the wayland feature is enabled, all X11 dependencies will be dropped
# and only methods suitable for Wayland will be used
wayland = ["espanso-detect/wayland", "espanso-inject/wayland", "espanso-clipboard/wayland", "espanso-info/wayland"]
# Compile modulo and all its dependencies (including wxWidgets). If you don't
# enable it, features like Forms and Search might not be available.
modulo = ["espanso-modulo", "espanso-clipboard/avoid-gdi", "espanso-ui/avoid-gdi"]
[dependencies]
espanso-detect = { path = "../espanso-detect" }
espanso-ui = { path = "../espanso-ui" }
@ -24,6 +30,7 @@ espanso-info = { path = "../espanso-info" }
espanso-render = { path = "../espanso-render" }
espanso-path = { path = "../espanso-path" }
espanso-ipc = { path = "../espanso-ipc" }
espanso-modulo = { path = "../espanso-modulo", optional = true }
maplit = "1.0.2"
simplelog = "0.9.0"
log = "0.4.14"
@ -40,6 +47,7 @@ markdown = "0.3.0"
html2text = "0.2.1"
log-panics = "2.0.0"
fs2 = "0.4.3"
serde_yaml = "0.8.17"
[target.'cfg(windows)'.dependencies]
named_pipe = "0.4.1"

View File

@ -23,6 +23,7 @@ use espanso_path::Paths;
pub mod daemon;
pub mod log;
pub mod modulo;
pub mod path;
pub mod worker;

View File

@ -0,0 +1,53 @@
/*
* 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 clap::{ArgMatches};
use espanso_modulo::form::*;
pub fn form_main(matches: &ArgMatches) -> i32 {
let as_json: bool = matches.is_present("json");
let input_file = matches
.value_of("input_file")
.expect("missing input, please specify the -i option");
let data = if input_file == "-" {
use std::io::Read;
let mut buffer = String::new();
std::io::stdin()
.read_to_string(&mut buffer)
.expect("unable to obtain input from stdin");
buffer
} else {
std::fs::read_to_string(input_file).expect("unable to read input file")
};
let config: config::FormConfig = if !as_json {
serde_yaml::from_str(&data).expect("unable to parse form configuration")
} else {
serde_json::from_str(&data).expect("unable to parse form configuration")
};
let form = generator::generate(config);
let values = show(form);
let output = serde_json::to_string(&values).expect("unable to encode values as JSON");
println!("{}", output);
0
}

View File

@ -0,0 +1,57 @@
/*
* 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::{CliModule, CliModuleArgs};
#[cfg(feature = "modulo")]
mod form;
#[cfg(feature = "modulo")]
mod search;
pub fn new() -> CliModule {
#[allow(clippy::needless_update)]
CliModule {
requires_paths: true,
enable_logs: false,
subcommand: "modulo".to_string(),
entry: modulo_main,
..Default::default()
}
}
#[cfg(feature = "modulo")]
fn modulo_main(args: CliModuleArgs) -> i32 {
let paths = args.paths.expect("missing paths in modulo main");
let cli_args = args.cli_args.expect("missing cli_args in modulo main");
if let Some(matches) = cli_args.subcommand_matches("form") {
return form::form_main(matches);
}
if let Some(matches) = cli_args.subcommand_matches("search") {
return search::search_main(matches);
}
0
}
#[cfg(not(feature = "modulo"))]
fn modulo_main(_: CliModuleArgs) -> i32 {
panic!("this version of espanso was not compiled with 'modulo' support, please obtain a version that does or recompile it with the 'modulo' feature flag");
}

View File

@ -0,0 +1,58 @@
/*
* 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 clap::{ArgMatches};
use espanso_modulo::search::*;
pub fn search_main(matches: &ArgMatches) -> i32 {
let as_json: bool = matches.is_present("json");
let input_file = matches
.value_of("input_file")
.expect("missing input, please specify the -i option");
let data = if input_file == "-" {
use std::io::Read;
let mut buffer = String::new();
std::io::stdin()
.read_to_string(&mut buffer)
.expect("unable to obtain input from stdin");
buffer
} else {
std::fs::read_to_string(input_file).expect("unable to read input file")
};
let config: config::SearchConfig = if !as_json {
serde_yaml::from_str(&data).expect("unable to parse search configuration")
} else {
serde_json::from_str(&data).expect("unable to parse search configuration")
};
let algorithm = algorithm::get_algorithm(&config.algorithm);
let search = generator::generate(config);
let result = show(search, algorithm);
let mut result_map = HashMap::new();
result_map.insert("selected", result);
let output = serde_json::to_string(&result_map).expect("unable to encode values as JSON");
println!("{}", output);
0
}

View File

@ -52,7 +52,8 @@ lazy_static! {
cli::path::new(),
cli::log::new(),
cli::worker::new(),
cli::daemon::new()
cli::daemon::new(),
cli::modulo::new(),
];
}
@ -140,14 +141,54 @@ fn main() {
// )
// .subcommand(SubCommand::with_name("detect")
// .about("Tool to detect current window properties, to simplify filters creation."))
.subcommand(SubCommand::with_name("daemon")
.subcommand(
SubCommand::with_name("daemon")
.setting(AppSettings::Hidden)
.about("Start the daemon without spawning a new process."))
.about("Start the daemon without spawning a new process."),
)
// .subcommand(SubCommand::with_name("register")
// .about("MacOS and Linux only. Register espanso in the system daemon manager."))
// .subcommand(SubCommand::with_name("unregister")
// .about("MacOS and Linux only. Unregister espanso from the system daemon manager."))
.subcommand(SubCommand::with_name("log").about("Print the daemon logs."))
.subcommand(
SubCommand::with_name("modulo")
.setting(AppSettings::Hidden)
.subcommand(
SubCommand::with_name("form")
.about("Display a customizable form")
.arg(
Arg::with_name("input_file")
.short("i")
.takes_value(true)
.help("Input file or - for stdin"),
)
.arg(
Arg::with_name("json")
.short("j")
.required(false)
.takes_value(false)
.help("Interpret the input data as JSON"),
),
)
.subcommand(
SubCommand::with_name("search")
.about("Display a search box")
.arg(
Arg::with_name("input_file")
.short("i")
.takes_value(true)
.help("Input file or - for stdin"),
)
.arg(
Arg::with_name("json")
.short("j")
.required(false)
.takes_value(false)
.help("Interpret the input data as JSON"),
),
),
)
// .subcommand(SubCommand::with_name("start")
// .about("Start the daemon spawning a new process in the background."))
// .subcommand(SubCommand::with_name("stop")
@ -259,7 +300,11 @@ fn main() {
if handler.enable_logs {
let config = ConfigBuilder::new()
.set_time_to_local(true)
.set_time_format(format!("%H:%M:%S [{}({})]", handler.subcommand, std::process::id()))
.set_time_format(format!(
"%H:%M:%S [{}({})]",
handler.subcommand,
std::process::id()
))
.set_location_level(LevelFilter::Off)
.add_filter_ignore_str("html5ever")
.build();