Initial implementation of #239 on Windows

This commit is contained in:
Federico Terzi 2020-05-08 19:04:50 +02:00
parent 53e72bb8a3
commit da3e65c0a0
8 changed files with 265 additions and 1 deletions

88
Cargo.lock generated
View File

@ -379,6 +379,7 @@ dependencies = [
"libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
"log-panics 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
"notify 4.0.15 (registry+https://github.com/rust-lang/crates.io-index)",
"rand 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)",
"regex 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
"reqwest 0.9.20 (registry+https://github.com/rust-lang/crates.io-index)",
@ -412,6 +413,17 @@ dependencies = [
"synstructure 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "filetime"
version = "0.2.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)",
"redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "flate2"
version = "1.0.11"
@ -449,6 +461,23 @@ dependencies = [
"winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "fsevent"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"fsevent-sys 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "fsevent-sys"
version = "2.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "fuchsia-cprng"
version = "0.1.1"
@ -601,6 +630,24 @@ name = "indexmap"
version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "inotify"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"inotify-sys 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "inotify-sys"
version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "iovec"
version = "0.1.2"
@ -629,6 +676,11 @@ name = "lazy_static"
version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "lazycell"
version = "1.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "libc"
version = "0.2.62"
@ -722,6 +774,17 @@ dependencies = [
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "mio-extras"
version = "2.0.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"lazycell 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
"mio 0.6.19 (registry+https://github.com/rust-lang/crates.io-index)",
"slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "miow"
version = "0.2.1"
@ -765,6 +828,23 @@ name = "nodrop"
version = "0.1.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "notify"
version = "4.0.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"filetime 0.2.9 (registry+https://github.com/rust-lang/crates.io-index)",
"fsevent 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"fsevent-sys 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
"inotify 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)",
"mio 0.6.19 (registry+https://github.com/rust-lang/crates.io-index)",
"mio-extras 2.0.6 (registry+https://github.com/rust-lang/crates.io-index)",
"walkdir 2.2.9 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "num-integer"
version = "0.1.41"
@ -1762,11 +1842,14 @@ dependencies = [
"checksum error-chain 0.12.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3ab49e9dcb602294bc42f9a7dfc9bc6e936fca4418ea300dbfb84fe16de0b7d9"
"checksum failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "795bd83d3abeb9220f257e597aa0080a508b27533824adf336529648f6abf7e2"
"checksum failure_derive 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "ea1063915fd7ef4309e222a5a07cf9c319fb9c7836b1f89b85458672dbb127e1"
"checksum filetime 0.2.9 (registry+https://github.com/rust-lang/crates.io-index)" = "f59efc38004c988e4201d11d263b8171f49a2e7ec0bdbb71773433f271504a5e"
"checksum flate2 1.0.11 (registry+https://github.com/rust-lang/crates.io-index)" = "2adaffba6388640136149e18ed080b77a78611c1e1d6de75aedcdf78df5d4682"
"checksum fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "2fad85553e09a6f881f739c29f0b00b0f01357c743266d478b68951ce23285f3"
"checksum foreign-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1"
"checksum foreign-types-shared 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b"
"checksum fs2 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "9564fc758e15025b46aa6643b1b77d047d1a56a1aea6e01002ac0c7026876213"
"checksum fsevent 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5ab7d1bd1bd33cc98b0889831b72da23c0aa4df9cec7e0702f46ecea04b35db6"
"checksum fsevent-sys 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f41b048a94555da0f42f1d632e2e19510084fb8e303b0daa2816e733fb3644a0"
"checksum fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba"
"checksum fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82"
"checksum fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7"
@ -1782,10 +1865,13 @@ dependencies = [
"checksum idna 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "38f09e0f0b1fb55fdee1f17470ad800da77af5186a1a76c026b679358b7e844e"
"checksum idna 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "02e2673c30ee86b5b96a9cb52ad15718aa1f966f5ab9ad54a8b95d5ca33120a9"
"checksum indexmap 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a61202fbe46c4a951e9404a720a0180bcf3212c750d735cb5c4ba4dc551299f3"
"checksum inotify 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "24e40d6fd5d64e2082e0c796495c8ef5ad667a96d03e5aaa0becfd9d47bcbfb8"
"checksum inotify-sys 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "e74a1aa87c59aeff6ef2cc2fa62d41bc43f54952f55652656b18a02fd5e356c0"
"checksum iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "dbe6e417e7d0975db6512b90796e8ce223145ac4e33c377e4a42882a0e88bb08"
"checksum itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "501266b7edd0174f8530248f87f99c88fbe60ca4ef3dd486835b8d8d53136f7f"
"checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d"
"checksum lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
"checksum lazycell 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b294d6fa9ee409a054354afc4352b0b9ef7ca222c69b8812cbea9e7d2bf3783f"
"checksum libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)" = "34fcd2c08d2f832f376f4173a231990fa5aef4e99fb569867318a227ef4c06ba"
"checksum linked-hash-map 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "ae91b68aebc4ddb91978b11a1b02ddd8602a05ec19002801c5666000e05e0f83"
"checksum lock_api 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "62ebf1391f6acad60e5c8b43706dde4582df75c06698ab44511d15016bc2442c"
@ -1798,10 +1884,12 @@ dependencies = [
"checksum mime_guess 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "1a0ed03949aef72dbdf3116a383d7b38b4768e6f960528cd6a6044aa9ed68599"
"checksum miniz_oxide 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7108aff85b876d06f22503dcce091e29f76733b2bfdd91eebce81f5e68203a10"
"checksum mio 0.6.19 (registry+https://github.com/rust-lang/crates.io-index)" = "83f51996a3ed004ef184e16818edc51fadffe8e7ca68be67f9dee67d84d0ff23"
"checksum mio-extras 2.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "52403fe290012ce777c4626790c8951324a2b9e3316b3143779c72b029742f19"
"checksum miow 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8c1f2f3b1cf331de6896aabf6e9d55dca90356cc9960cca7eaaf408a355ae919"
"checksum native-tls 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "4b2df1a4c22fd44a62147fd8f13dd0f95c9d8ca7b2610299b2a2f9cf8964274e"
"checksum net2 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)" = "42550d9fb7b6684a6d404d9fa7250c2eb2646df731d1c06afc06dcee9e1bcf88"
"checksum nodrop 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "2f9667ddcc6cc8a43afc9b7917599d7216aa09c463919ea32c59ed6cac8bc945"
"checksum notify 4.0.15 (registry+https://github.com/rust-lang/crates.io-index)" = "80ae4a7688d1fab81c5bf19c64fc8db920be8d519ce6336ed4e7efe024724dbd"
"checksum num-integer 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)" = "b85e541ef8255f6cf42bbfe4ef361305c6c135d10919ecc26126c4e5ae94bc09"
"checksum num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "6ba9a427cfca2be13aa6f6403b0b7e7368fe982bfa16fccc450ce74c46cd9b32"
"checksum num_cpus 1.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "bcef43580c035376c0705c42792c294b66974abbfd2789b511784023f71f3273"

View File

@ -30,6 +30,7 @@ tempfile = "3.1.0"
dialoguer = "0.4.0"
rand = "0.7.2"
zip = "0.5.3"
notify = "4.0.13"
[target.'cfg(unix)'.dependencies]
libc = "0.2.62"

View File

@ -710,6 +710,35 @@ int32_t start_daemon_process() {
return 1;
}
int32_t start_process(wchar_t * _cmd) {
wchar_t cmd[MAX_PATH];
swprintf(cmd, MAX_PATH, _cmd);
STARTUPINFO si = { sizeof(si) };
PROCESS_INFORMATION pi;
// Documentation: https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-createprocessw
BOOL res = CreateProcess(
NULL,
cmd,
NULL,
NULL,
FALSE,
DETACHED_PROCESS,
NULL,
NULL,
&si,
&pi
);
if (!res) {
return -1;
}
return 1;
}
// CLIPBOARD
int32_t set_clipboard(wchar_t *text) {

View File

@ -164,4 +164,8 @@ extern "C" int32_t set_clipboard(wchar_t * text);
*/
extern "C" int32_t set_clipboard_image(wchar_t * path);
// PROCESSES
extern "C" int32_t start_process(wchar_t * cmd);
#endif //ESPANSO_BRIDGE_H

View File

@ -60,4 +60,8 @@ extern {
pub fn delete_string(count: i32, delay: i32);
pub fn trigger_paste();
pub fn trigger_copy();
// PROCESSES
pub fn start_process(cmd: *const u16) -> i32;
}

View File

@ -69,6 +69,7 @@ fn default_exclude_default_entries() -> bool {false}
fn default_secure_input_watcher_enabled() -> bool {true}
fn default_secure_input_notification() -> bool {true}
fn default_show_notifications() -> bool {true}
fn default_auto_restart() -> bool {false}
fn default_show_icon() -> bool {true}
fn default_fast_inject() -> bool {true}
fn default_secure_input_watcher_interval() -> i32 {5000}
@ -176,6 +177,9 @@ pub struct Configs {
#[serde(default = "default_inject_delay")]
pub inject_delay: i32,
#[serde(default = "default_auto_restart")]
pub auto_restart: bool,
#[serde(default = "default_matches")]
pub matches: Vec<Match>,

View File

@ -28,6 +28,7 @@ use std::sync::atomic::AtomicBool;
use std::sync::mpsc::Receiver;
use std::thread;
use std::time::Duration;
use std::process::{Command, Stdio};
use clap::{App, Arg, ArgMatches, SubCommand};
use fs2::FileExt;
@ -59,6 +60,7 @@ mod render;
mod system;
mod context;
mod matcher;
mod process;
mod package;
mod keyboard;
mod protocol;
@ -161,6 +163,8 @@ fn main() {
.subcommand(SubCommand::with_name("refresh")
.about("Update espanso package index"))
)
.subcommand(SubCommand::with_name("watch")
.about("Wait until one of the config files is changed, then restart espanso."))
.subcommand(install_subcommand)
.subcommand(uninstall_subcommand);
@ -275,6 +279,11 @@ fn main() {
}
}
if matches.subcommand_matches("watch").is_some() {
watch_main(config_set);
return;
}
// Defaults help print
clap_instance.print_long_help().expect("Unable to print help");
println!();
@ -345,6 +354,12 @@ fn daemon_main(config_set: ConfigSet) {
daemon_background(receive_channel, config_set_copy, is_injecting);
}).expect("Unable to spawn daemon background thread");
if config_set.default.auto_restart {
info!("starting auto-restart daemon...");
let espanso_path = std::env::current_exe().expect("unable to obtain espanso path location");
crate::process::spawn_process(&espanso_path.to_string_lossy().to_string(), &vec!("watch".to_owned()));
}
let ipc_server = protocol::get_ipc_server(config_set, send_channel.clone());
ipc_server.start();
@ -1019,9 +1034,80 @@ fn edit_main(matches: &ArgMatches) {
}
}
fn watch_main(_: ConfigSet) {
// Make sure only one watch is running
let lock_file = acquire_custom_lock("watcher.lock");
if lock_file.is_none() {
eprintln!("Another watcher is already running, terminating...");
std::process::exit(2);
}
use notify::{RecommendedWatcher, Watcher, RecursiveMode, DebouncedEvent};
use std::sync::mpsc::channel;
use std::time::Duration;
// Create a channel to receive the events.
let (tx, rx) = channel();
let mut watcher: RecommendedWatcher = Watcher::new(tx, Duration::from_secs(1)).expect("unable to create file watcher");
let config_path = crate::context::get_config_dir();
watcher.watch(&config_path, RecursiveMode::Recursive).expect("unable to start watcher");
println!("Watching for changes in path: {:?}", config_path);
loop {
let should_reload = match rx.recv() {
Ok(event) => {
let path = match event {
DebouncedEvent::Create(path) => Some(path),
DebouncedEvent::Write(path) => Some(path),
DebouncedEvent::Remove(path) => Some(path),
DebouncedEvent::Rename(_, path) => Some(path),
_ => None,
};
if let Some(path) = path {
if path.extension().unwrap_or_default() == "yml" { // Only load yml files
true
}else{
false
}
}else{
false
}
},
Err(e) => {
eprintln!("error while watching files: {:?}", e);
false
}
};
if should_reload {
println!("change detected, restarting espanso");
let mut config_set = ConfigSet::load_default();
match config_set {
Ok(config_set) => {
restart_main(config_set);
std::process::exit(0);
},
Err(error) => {
// TODO: send notification to user
}
}
}
}
}
fn acquire_lock() -> Option<File> {
acquire_custom_lock("espanso.lock")
}
fn acquire_custom_lock(name: &str) -> Option<File> {
let espanso_dir = context::get_data_dir();
let lock_file_path = espanso_dir.join("espanso.lock");
let lock_file_path = espanso_dir.join(name);
let file = OpenOptions::new()
.read(true)
.write(true)

48
src/process.rs Normal file
View File

@ -0,0 +1,48 @@
/*
* This file is part of espanso.
*
* Copyright (C) 2020 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::warn;
use widestring::WideCString;
#[cfg(target_os = "windows")]
pub fn spawn_process(cmd: &str, args: &Vec<String>) {
let quoted_args: Vec<String> = args.iter().map(|arg| {
format!("\"{}\"", arg)
}).collect();
let quoted_args = quoted_args.join(" ");
let final_cmd = format!("\"{}\" {}", cmd, quoted_args);
unsafe {
let cmd_wstr = WideCString::from_str(&final_cmd);
if let Ok(string) = cmd_wstr {
let res = crate::bridge::windows::start_process(string.as_ptr());
if res < 0 {
warn!("unable to start process: {}", final_cmd);
}
}else{
warn!("unable to convert process string into wide format")
}
}
}
#[cfg(not(target_os = "windows"))]
pub fn spawn_process(cmd: &str, args: &Vec<String>) {
use std::process::{Command, Stdio};
Command::new(cmd).args(args).stdout(Stdio::null()).spawn();
}