Merge pull request #784 from federico-terzi/dev

v2.0.2-alpha release
This commit is contained in:
Federico Terzi 2021-10-11 21:01:40 +02:00 committed by GitHub
commit f436a9757d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 137 additions and 55 deletions

10
Cargo.lock generated
View File

@ -572,7 +572,7 @@ dependencies = [
[[package]] [[package]]
name = "espanso" name = "espanso"
version = "2.0.1" version = "2.0.2-alpha"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"caps", "caps",
@ -787,7 +787,7 @@ dependencies = [
"test-case", "test-case",
"thiserror", "thiserror",
"walkdir", "walkdir",
"yaml-rust 0.4.5 (git+https://github.com/federico-terzi/yaml-rust)", "yaml-rust 0.4.6",
] ]
[[package]] [[package]]
@ -2399,7 +2399,7 @@ dependencies = [
"dtoa", "dtoa",
"linked-hash-map", "linked-hash-map",
"serde", "serde",
"yaml-rust 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", "yaml-rust 0.4.5",
] ]
[[package]] [[package]]
@ -3312,8 +3312,8 @@ dependencies = [
[[package]] [[package]]
name = "yaml-rust" name = "yaml-rust"
version = "0.4.5" version = "0.4.6"
source = "git+https://github.com/federico-terzi/yaml-rust#b1a195252fcdabf743f68d03f4d84d151a5a3f62" source = "git+https://github.com/federico-terzi/yaml-rust#454221bebabc93307bbf7aa7f556407dd3027363"
dependencies = [ dependencies = [
"linked-hash-map", "linked-hash-map",
] ]

View File

@ -13,7 +13,7 @@ regex = "1.4.3"
lazy_static = "1.4.0" lazy_static = "1.4.0"
dunce = "1.0.1" dunce = "1.0.1"
walkdir = "2.3.1" walkdir = "2.3.1"
yaml-rust = { git = "https://github.com/federico-terzi/yaml-rust" } yaml-rust = { version = "0.4.6", git = "https://github.com/federico-terzi/yaml-rust" }
path-slash = "0.1.4" path-slash = "0.1.4"
tempdir = "0.3.7" tempdir = "0.3.7"
fs_extra = "1.2.0" fs_extra = "1.2.0"

View File

@ -1,6 +1,6 @@
[package] [package]
name = "espanso" name = "espanso"
version = "2.0.1" version = "2.0.2-alpha"
authors = ["Federico Terzi <federicoterzi96@gmail.com>"] authors = ["Federico Terzi <federicoterzi96@gmail.com>"]
license = "GPL-3.0" license = "GPL-3.0"
description = "Cross-platform Text Expander written in Rust" description = "Cross-platform Text Expander written in Rust"

View File

@ -19,7 +19,7 @@
use anyhow::Result; use anyhow::Result;
use crossbeam::channel::Sender; use crossbeam::channel::Sender;
use log::{debug, error}; use log::{debug, error, warn};
const WATCHER_INTERVAL: u64 = 1000; const WATCHER_INTERVAL: u64 = 1000;
@ -39,34 +39,28 @@ pub fn initialize_and_spawn(watcher_notify: Sender<()>) -> Result<()> {
} }
fn watcher_main(watcher_notify: &Sender<()>) { fn watcher_main(watcher_notify: &Sender<()>) {
let layout = espanso_detect::get_active_layout(); let mut layout = espanso_detect::get_active_layout();
if layout.is_none() { if layout.is_none() {
error!("unable to start keyboard layout watcher, as espanso couldn't determine active layout."); warn!("keyboard layout watcher couldn't determine active layout.")
return;
} }
let mut layout = layout.expect("missing active layout");
loop { loop {
std::thread::sleep(std::time::Duration::from_millis(WATCHER_INTERVAL)); std::thread::sleep(std::time::Duration::from_millis(WATCHER_INTERVAL));
if let Some(current_layout) = espanso_detect::get_active_layout() { let current_layout = espanso_detect::get_active_layout();
if current_layout != layout { if current_layout != layout {
debug!( debug!(
"detected keyboard layout change: from {} to {}", "detected keyboard layout change: from '{}' to '{}'",
layout, current_layout layout.as_deref().unwrap_or_default(),
); current_layout.as_deref().unwrap_or_default(),
);
if let Err(error) = watcher_notify.send(()) { if let Err(error) = watcher_notify.send(()) {
error!("unable to send keyboard layout changed event: {}", error); error!("unable to send keyboard layout changed event: {}", error);
}
layout = current_layout;
} }
} else {
error!("keyboard layout watcher couldn't determine active layout"); layout = current_layout;
break;
} }
} }
} }

View File

@ -17,36 +17,42 @@
* along with espanso. If not, see <https://www.gnu.org/licenses/>. * along with espanso. If not, see <https://www.gnu.org/licenses/>.
*/ */
use std::{ use std::{path::Path, time::Duration};
path::Path,
time::{Duration, Instant},
};
use notify::{DebouncedEvent, RecommendedWatcher, RecursiveMode, Watcher}; use notify::{DebouncedEvent, RecommendedWatcher, RecursiveMode, Watcher};
use anyhow::Result; use anyhow::Result;
use crossbeam::channel::Sender; use crossbeam::{channel::Sender, select};
use log::{error, info, warn}; use log::{error, info, warn};
const WATCHER_DEBOUNCE_DURATION: u64 = 1; const WATCHER_NOTIFY_DELAY_MS: u64 = 500;
const WATCHER_DEBOUNCE_DURATION_MS: u64 = 1000;
pub fn initialize_and_spawn(config_dir: &Path, watcher_notify: Sender<()>) -> Result<()> { pub fn initialize_and_spawn(config_dir: &Path, watcher_notify: Sender<()>) -> Result<()> {
let config_dir = config_dir.to_path_buf(); let config_dir = config_dir.to_path_buf();
let (debounce_tx, debounce_rx) = crossbeam::channel::unbounded();
std::thread::Builder::new() std::thread::Builder::new()
.name("watcher".to_string()) .name("watcher".to_string())
.spawn(move || { .spawn(move || {
watcher_main(&config_dir, &watcher_notify); watcher_main(&config_dir, debounce_tx);
})?;
std::thread::Builder::new()
.name("watcher-debouncer".to_string())
.spawn(move || {
debouncer_main(debounce_rx, &watcher_notify);
})?; })?;
Ok(()) Ok(())
} }
fn watcher_main(config_dir: &Path, watcher_notify: &Sender<()>) { fn watcher_main(config_dir: &Path, debounce_tx: crossbeam::channel::Sender<()>) {
let (tx, rx) = std::sync::mpsc::channel(); let (tx, rx) = std::sync::mpsc::channel();
let mut watcher: RecommendedWatcher = let mut watcher: RecommendedWatcher =
Watcher::new(tx, Duration::from_secs(WATCHER_DEBOUNCE_DURATION)) Watcher::new(tx, Duration::from_millis(WATCHER_NOTIFY_DELAY_MS))
.expect("unable to create file watcher"); .expect("unable to create file watcher");
watcher watcher
@ -55,8 +61,6 @@ fn watcher_main(config_dir: &Path, watcher_notify: &Sender<()>) {
info!("watching for changes in path: {:?}", config_dir); info!("watching for changes in path: {:?}", config_dir);
let mut last_event_arrival = Instant::now();
loop { loop {
let should_reload = match rx.recv() { let should_reload = match rx.recv() {
Ok(event) => { Ok(event) => {
@ -92,16 +96,35 @@ fn watcher_main(config_dir: &Path, watcher_notify: &Sender<()>) {
} }
}; };
// Send only one event, otherwise we could run the risk of useless reloads or even race conditions. if should_reload {
if should_reload if let Err(error) = debounce_tx.send(()) {
&& last_event_arrival.elapsed() > std::time::Duration::from_secs(WATCHER_DEBOUNCE_DURATION) error!(
{ "unable to send watcher file changed event to debouncer: {}",
if let Err(error) = watcher_notify.send(()) { error
error!("unable to send watcher file changed event: {}", error); );
} }
} }
}
}
last_event_arrival = Instant::now(); fn debouncer_main(debounce_rx: crossbeam::channel::Receiver<()>, watcher_notify: &Sender<()>) {
let mut has_received_event = false;
loop {
select! {
recv(debounce_rx) -> _ => {
has_received_event = true;
},
default(Duration::from_millis(WATCHER_DEBOUNCE_DURATION_MS)) => {
if has_received_event {
if let Err(error) = watcher_notify.send(()) {
error!("unable to send watcher file changed event: {}", error);
}
}
has_received_event = false;
},
}
} }
} }

View File

@ -94,7 +94,8 @@ fn launcher_main(args: CliModuleArgs) -> i32 {
}, },
}); });
let is_auto_start_page_enabled = !preferences.has_selected_auto_start_option(); let is_auto_start_page_enabled =
!preferences.has_selected_auto_start_option() && !cfg!(target_os = "linux");
let preferences_clone = preferences.clone(); let preferences_clone = preferences.clone();
let auto_start_handler = Box::new(move |auto_start| { let auto_start_handler = Box::new(move |auto_start| {
preferences_clone.set_has_selected_auto_start_option(true); preferences_clone.set_has_selected_auto_start_option(true);

View File

@ -95,6 +95,8 @@ fn service_main(args: CliModuleArgs) -> i32 {
return start_main(&paths, &paths_overrides, sub_args); return start_main(&paths, &paths_overrides, sub_args);
} else if cli_args.subcommand_matches("stop").is_some() { } else if cli_args.subcommand_matches("stop").is_some() {
return stop_main(&paths); return stop_main(&paths);
} else if cli_args.subcommand_matches("status").is_some() {
return status_main(&paths);
} else if let Some(sub_args) = cli_args.subcommand_matches("restart") { } else if let Some(sub_args) = cli_args.subcommand_matches("restart") {
stop_main(&paths); stop_main(&paths);
return start_main(&paths, &paths_overrides, sub_args); return start_main(&paths, &paths_overrides, sub_args);
@ -152,3 +154,15 @@ fn stop_main(paths: &Paths) -> i32 {
SERVICE_SUCCESS SERVICE_SUCCESS
} }
fn status_main(paths: &Paths) -> i32 {
let lock_file = acquire_worker_lock(&paths.runtime);
if lock_file.is_some() {
error_eprintln!("espanso is not running");
return SERVICE_NOT_RUNNING;
}
drop(lock_file);
info_println!("espanso is running");
SERVICE_SUCCESS
}

View File

@ -21,8 +21,8 @@ pub const WORKER_SUCCESS: i32 = 0;
pub const WORKER_ALREADY_RUNNING: i32 = 1; pub const WORKER_ALREADY_RUNNING: i32 = 1;
pub const WORKER_GENERAL_ERROR: i32 = 2; pub const WORKER_GENERAL_ERROR: i32 = 2;
pub const WORKER_LEGACY_ALREADY_RUNNING: i32 = 3; pub const WORKER_LEGACY_ALREADY_RUNNING: i32 = 3;
pub const WORKER_EXIT_ALL_PROCESSES: i32 = 101; pub const WORKER_EXIT_ALL_PROCESSES: i32 = 50;
pub const WORKER_RESTART: i32 = 102; pub const WORKER_RESTART: i32 = 51;
pub const DAEMON_SUCCESS: i32 = 0; pub const DAEMON_SUCCESS: i32 = 0;
pub const DAEMON_ALREADY_RUNNING: i32 = 1; pub const DAEMON_ALREADY_RUNNING: i32 = 1;
@ -36,7 +36,7 @@ pub const MIGRATE_LEGACY_INSTANCE_RUNNING: i32 = 2;
pub const MIGRATE_USER_ABORTED: i32 = 3; pub const MIGRATE_USER_ABORTED: i32 = 3;
pub const MIGRATE_CLEAN_FAILURE: i32 = 50; pub const MIGRATE_CLEAN_FAILURE: i32 = 50;
pub const MIGRATE_DIRTY_FAILURE: i32 = 51; pub const MIGRATE_DIRTY_FAILURE: i32 = 51;
pub const MIGRATE_UNEXPECTED_FAILURE: i32 = 101; pub const MIGRATE_UNEXPECTED_FAILURE: i32 = 52;
pub const ADD_TO_PATH_SUCCESS: i32 = 0; pub const ADD_TO_PATH_SUCCESS: i32 = 0;
pub const ADD_TO_PATH_FAILURE: i32 = 1; pub const ADD_TO_PATH_FAILURE: i32 = 1;

View File

@ -85,6 +85,10 @@ lazy_static! {
subcommand: "stop".to_owned(), subcommand: "stop".to_owned(),
forward_into: "service".to_owned(), forward_into: "service".to_owned(),
}, },
CliAlias {
subcommand: "status".to_owned(),
forward_into: "service".to_owned(),
},
CliAlias { CliAlias {
subcommand: "install".to_owned(), subcommand: "install".to_owned(),
forward_into: "package".to_owned(), forward_into: "package".to_owned(),
@ -171,6 +175,8 @@ fn main() {
.about("Restart the espanso service") .about("Restart the espanso service")
.name("restart"); .name("restart");
let stop_subcommand = SubCommand::with_name("stop").about("Stop espanso service"); let stop_subcommand = SubCommand::with_name("stop").about("Stop espanso service");
let status_subcommand =
SubCommand::with_name("status").about("Check if the espanso daemon is running or not.");
let mut clap_instance = App::new("espanso") let mut clap_instance = App::new("espanso")
.version(VERSION) .version(VERSION)
@ -299,12 +305,6 @@ For example, specifying 'email' is equivalent to 'match/email.yml'."#))
), ),
), ),
) )
// .subcommand(SubCommand::with_name("start")
// .about("Start the daemon spawning a new process in the background."))
// .subcommand(SubCommand::with_name("stop")
// .about("Stop the espanso daemon."))
// .subcommand(SubCommand::with_name("restart")
// .about("Restart the espanso daemon."))
// .subcommand(SubCommand::with_name("status") // .subcommand(SubCommand::with_name("status")
// .about("Check if the espanso daemon is running or not.")) // .about("Check if the espanso daemon is running or not."))
.subcommand( .subcommand(
@ -346,11 +346,13 @@ For example, specifying 'email' is equivalent to 'match/email.yml'."#))
.subcommand(start_subcommand.clone()) .subcommand(start_subcommand.clone())
.subcommand(restart_subcommand.clone()) .subcommand(restart_subcommand.clone())
.subcommand(stop_subcommand.clone()) .subcommand(stop_subcommand.clone())
.subcommand(status_subcommand.clone())
.about("Register and manage 'espanso' as a system service."), .about("Register and manage 'espanso' as a system service."),
) )
.subcommand(start_subcommand) .subcommand(start_subcommand)
.subcommand(restart_subcommand) .subcommand(restart_subcommand)
.subcommand(stop_subcommand) .subcommand(stop_subcommand)
.subcommand(status_subcommand)
// .subcommand(SubCommand::with_name("match") // .subcommand(SubCommand::with_name("match")
// .about("List and execute matches from the CLI") // .about("List and execute matches from the CLI")
// .subcommand(SubCommand::with_name("list") // .subcommand(SubCommand::with_name("list")

View File

@ -50,6 +50,7 @@ fn get_builtin_patches() -> Vec<PatchDefinition> {
patches::linux::simple_terminal_2_x11::patch(), patches::linux::simple_terminal_2_x11::patch(),
patches::linux::terminator_terminal_x11::patch(), patches::linux::terminator_terminal_x11::patch(),
patches::linux::termite_terminal_x11::patch(), patches::linux::termite_terminal_x11::patch(),
patches::linux::thunderbird_x11::patch(),
patches::linux::tilix_terminal_x11::patch(), patches::linux::tilix_terminal_x11::patch(),
patches::linux::urxvt_terminal_x11::patch(), patches::linux::urxvt_terminal_x11::patch(),
patches::linux::xterm_terminal_x11::patch(), patches::linux::xterm_terminal_x11::patch(),

View File

@ -27,6 +27,7 @@ pub mod simple_terminal_2_x11;
pub mod simple_terminal_x11; pub mod simple_terminal_x11;
pub mod terminator_terminal_x11; pub mod terminator_terminal_x11;
pub mod termite_terminal_x11; pub mod termite_terminal_x11;
pub mod thunderbird_x11;
pub mod tilix_terminal_x11; pub mod tilix_terminal_x11;
pub mod urxvt_terminal_x11; pub mod urxvt_terminal_x11;
pub mod xterm_terminal_x11; pub mod xterm_terminal_x11;

View File

@ -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 <https://www.gnu.org/licenses/>.
*/
use std::sync::Arc;
use espanso_config::config::Backend;
use crate::patch::patches::{PatchedConfig, Patches};
use crate::patch::PatchDefinition;
pub fn patch() -> PatchDefinition {
PatchDefinition {
name: module_path!().split(':').last().unwrap_or("unknown"),
is_enabled: || cfg!(target_os = "linux") && !super::util::is_wayland(),
should_patch: |app| app.class.unwrap_or_default().contains("Thunderbird"),
apply: |base, name| {
Arc::new(PatchedConfig::patch(
base,
name,
Patches {
paste_shortcut: Some(Some("CTRL+SHIFT+V".to_string())),
backend: Some(Backend::Clipboard),
key_delay: Some(Some(15)),
inject_delay: Some(Some(15)),
..Default::default()
},
))
},
}
}