From 84b029854a15f82ab4b3a99f269ce8ae612289ac Mon Sep 17 00:00:00 2001 From: Federico Terzi Date: Sat, 9 Oct 2021 21:25:56 +0200 Subject: [PATCH 1/9] fix(migrate): update yaml-rust dependency to fix bad handling of multiline strings starting with a space. Fix #771 --- Cargo.lock | 8 ++++---- espanso-migrate/Cargo.toml | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 493e4f2..44058c5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -787,7 +787,7 @@ dependencies = [ "test-case", "thiserror", "walkdir", - "yaml-rust 0.4.5 (git+https://github.com/federico-terzi/yaml-rust)", + "yaml-rust 0.4.6", ] [[package]] @@ -2399,7 +2399,7 @@ dependencies = [ "dtoa", "linked-hash-map", "serde", - "yaml-rust 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", + "yaml-rust 0.4.5", ] [[package]] @@ -3312,8 +3312,8 @@ dependencies = [ [[package]] name = "yaml-rust" -version = "0.4.5" -source = "git+https://github.com/federico-terzi/yaml-rust#b1a195252fcdabf743f68d03f4d84d151a5a3f62" +version = "0.4.6" +source = "git+https://github.com/federico-terzi/yaml-rust#454221bebabc93307bbf7aa7f556407dd3027363" dependencies = [ "linked-hash-map", ] diff --git a/espanso-migrate/Cargo.toml b/espanso-migrate/Cargo.toml index 16aaab8..07d513c 100644 --- a/espanso-migrate/Cargo.toml +++ b/espanso-migrate/Cargo.toml @@ -13,7 +13,7 @@ regex = "1.4.3" lazy_static = "1.4.0" dunce = "1.0.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" tempdir = "0.3.7" fs_extra = "1.2.0" From 2d8e30525dd36f532bb6edebed053c0ddbb02192 Mon Sep 17 00:00:00 2001 From: Federico Terzi Date: Sun, 10 Oct 2021 11:21:38 +0200 Subject: [PATCH 2/9] chore(core): version bump --- Cargo.lock | 2 +- espanso/Cargo.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 44058c5..761f6f4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -572,7 +572,7 @@ dependencies = [ [[package]] name = "espanso" -version = "2.0.1" +version = "2.0.2-alpha" dependencies = [ "anyhow", "caps", diff --git a/espanso/Cargo.toml b/espanso/Cargo.toml index 0a5e80c..afd0778 100644 --- a/espanso/Cargo.toml +++ b/espanso/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "espanso" -version = "2.0.1" +version = "2.0.2-alpha" authors = ["Federico Terzi "] license = "GPL-3.0" description = "Cross-platform Text Expander written in Rust" From 2eabdf90bf7c90675a81b58bbc0f427e4a5a31c3 Mon Sep 17 00:00:00 2001 From: Federico Terzi Date: Sun, 10 Oct 2021 11:29:23 +0200 Subject: [PATCH 3/9] feat(core): port 'espanso status' subcommand. Fix #775 --- espanso/src/cli/service/mod.rs | 14 ++++++++++++++ espanso/src/main.rs | 14 ++++++++------ 2 files changed, 22 insertions(+), 6 deletions(-) diff --git a/espanso/src/cli/service/mod.rs b/espanso/src/cli/service/mod.rs index 0e710cb..c80e418 100644 --- a/espanso/src/cli/service/mod.rs +++ b/espanso/src/cli/service/mod.rs @@ -95,6 +95,8 @@ fn service_main(args: CliModuleArgs) -> i32 { return start_main(&paths, &paths_overrides, sub_args); } else if cli_args.subcommand_matches("stop").is_some() { 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") { stop_main(&paths); return start_main(&paths, &paths_overrides, sub_args); @@ -152,3 +154,15 @@ fn stop_main(paths: &Paths) -> i32 { 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 +} diff --git a/espanso/src/main.rs b/espanso/src/main.rs index 02b5671..d0897ed 100644 --- a/espanso/src/main.rs +++ b/espanso/src/main.rs @@ -85,6 +85,10 @@ lazy_static! { subcommand: "stop".to_owned(), forward_into: "service".to_owned(), }, + CliAlias { + subcommand: "status".to_owned(), + forward_into: "service".to_owned(), + }, CliAlias { subcommand: "install".to_owned(), forward_into: "package".to_owned(), @@ -171,6 +175,8 @@ fn main() { .about("Restart the espanso service") .name("restart"); 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") .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") // .about("Check if the espanso daemon is running or not.")) .subcommand( @@ -346,11 +346,13 @@ For example, specifying 'email' is equivalent to 'match/email.yml'."#)) .subcommand(start_subcommand.clone()) .subcommand(restart_subcommand.clone()) .subcommand(stop_subcommand.clone()) + .subcommand(status_subcommand.clone()) .about("Register and manage 'espanso' as a system service."), ) .subcommand(start_subcommand) .subcommand(restart_subcommand) .subcommand(stop_subcommand) + .subcommand(status_subcommand) // .subcommand(SubCommand::with_name("match") // .about("List and execute matches from the CLI") // .subcommand(SubCommand::with_name("list") From 7b7489a8d86a9449affdc6125ccd2d4c818fd3cb Mon Sep 17 00:00:00 2001 From: Federico Terzi Date: Sun, 10 Oct 2021 19:02:31 +0200 Subject: [PATCH 4/9] feat(core): add patch for Thunderbird. Fix #130 Fix #376 --- espanso/src/patch/mod.rs | 1 + espanso/src/patch/patches/linux/mod.rs | 1 + .../patch/patches/linux/thunderbird_x11.rs | 41 +++++++++++++++++++ 3 files changed, 43 insertions(+) create mode 100644 espanso/src/patch/patches/linux/thunderbird_x11.rs diff --git a/espanso/src/patch/mod.rs b/espanso/src/patch/mod.rs index 3582aae..e499181 100644 --- a/espanso/src/patch/mod.rs +++ b/espanso/src/patch/mod.rs @@ -50,6 +50,7 @@ fn get_builtin_patches() -> Vec { patches::linux::simple_terminal_2_x11::patch(), patches::linux::terminator_terminal_x11::patch(), patches::linux::termite_terminal_x11::patch(), + patches::linux::thunderbird_x11::patch(), patches::linux::tilix_terminal_x11::patch(), patches::linux::urxvt_terminal_x11::patch(), patches::linux::xterm_terminal_x11::patch(), diff --git a/espanso/src/patch/patches/linux/mod.rs b/espanso/src/patch/patches/linux/mod.rs index 6dd311b..d145f16 100644 --- a/espanso/src/patch/patches/linux/mod.rs +++ b/espanso/src/patch/patches/linux/mod.rs @@ -27,6 +27,7 @@ pub mod simple_terminal_2_x11; pub mod simple_terminal_x11; pub mod terminator_terminal_x11; pub mod termite_terminal_x11; +pub mod thunderbird_x11; pub mod tilix_terminal_x11; pub mod urxvt_terminal_x11; pub mod xterm_terminal_x11; diff --git a/espanso/src/patch/patches/linux/thunderbird_x11.rs b/espanso/src/patch/patches/linux/thunderbird_x11.rs new file mode 100644 index 0000000..df0df04 --- /dev/null +++ b/espanso/src/patch/patches/linux/thunderbird_x11.rs @@ -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 . + */ + +use std::sync::Arc; + +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())), + ..Default::default() + }, + )) + }, + } +} From d1ebcf62c8dddb31ade2a1e0510354680614b9eb Mon Sep 17 00:00:00 2001 From: Federico Terzi Date: Sun, 10 Oct 2021 19:27:44 +0200 Subject: [PATCH 5/9] fix(core): change Thunderbird parameters to account for edge cases described in #351 --- espanso/src/patch/patches/linux/thunderbird_x11.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/espanso/src/patch/patches/linux/thunderbird_x11.rs b/espanso/src/patch/patches/linux/thunderbird_x11.rs index df0df04..eeb366a 100644 --- a/espanso/src/patch/patches/linux/thunderbird_x11.rs +++ b/espanso/src/patch/patches/linux/thunderbird_x11.rs @@ -19,6 +19,8 @@ use std::sync::Arc; +use espanso_config::config::Backend; + use crate::patch::patches::{PatchedConfig, Patches}; use crate::patch::PatchDefinition; @@ -33,6 +35,9 @@ pub fn patch() -> PatchDefinition { 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() }, )) From 2c25d60e8756f56589135c7233ccffba146318e0 Mon Sep 17 00:00:00 2001 From: Federico Terzi Date: Sun, 10 Oct 2021 22:36:46 +0200 Subject: [PATCH 6/9] fix(core): fix config watcher debouncing mechanism. Fix #769 --- espanso/src/cli/daemon/watcher.rs | 59 +++++++++++++++++++++---------- 1 file changed, 41 insertions(+), 18 deletions(-) diff --git a/espanso/src/cli/daemon/watcher.rs b/espanso/src/cli/daemon/watcher.rs index 9bf817a..ce3f29c 100644 --- a/espanso/src/cli/daemon/watcher.rs +++ b/espanso/src/cli/daemon/watcher.rs @@ -17,36 +17,42 @@ * along with espanso. If not, see . */ -use std::{ - path::Path, - time::{Duration, Instant}, -}; +use std::{path::Path, time::Duration}; use notify::{DebouncedEvent, RecommendedWatcher, RecursiveMode, Watcher}; use anyhow::Result; -use crossbeam::channel::Sender; +use crossbeam::{channel::Sender, select}; 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<()> { let config_dir = config_dir.to_path_buf(); + let (debounce_tx, debounce_rx) = crossbeam::channel::unbounded(); + std::thread::Builder::new() .name("watcher".to_string()) .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(()) } -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 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"); watcher @@ -55,8 +61,6 @@ fn watcher_main(config_dir: &Path, watcher_notify: &Sender<()>) { info!("watching for changes in path: {:?}", config_dir); - let mut last_event_arrival = Instant::now(); - loop { let should_reload = match rx.recv() { 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 - && last_event_arrival.elapsed() > std::time::Duration::from_secs(WATCHER_DEBOUNCE_DURATION) - { - if let Err(error) = watcher_notify.send(()) { - error!("unable to send watcher file changed event: {}", error); + if should_reload { + if let Err(error) = debounce_tx.send(()) { + error!( + "unable to send watcher file changed event to debouncer: {}", + 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; + }, + } } } From ceade8d172bb7e827b69e21f2311a936e79a1f7b Mon Sep 17 00:00:00 2001 From: Federico Terzi Date: Mon, 11 Oct 2021 19:11:13 +0200 Subject: [PATCH 7/9] fix(core): prevent keyboard layout watcher from stopping when receiving invalid layout --- .../src/cli/daemon/keyboard_layout_watcher.rs | 34 ++++++++----------- 1 file changed, 14 insertions(+), 20 deletions(-) diff --git a/espanso/src/cli/daemon/keyboard_layout_watcher.rs b/espanso/src/cli/daemon/keyboard_layout_watcher.rs index 8f77892..f5bb034 100644 --- a/espanso/src/cli/daemon/keyboard_layout_watcher.rs +++ b/espanso/src/cli/daemon/keyboard_layout_watcher.rs @@ -19,7 +19,7 @@ use anyhow::Result; use crossbeam::channel::Sender; -use log::{debug, error}; +use log::{debug, error, warn}; const WATCHER_INTERVAL: u64 = 1000; @@ -39,34 +39,28 @@ pub fn initialize_and_spawn(watcher_notify: Sender<()>) -> Result<()> { } 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() { - error!("unable to start keyboard layout watcher, as espanso couldn't determine active layout."); - return; + warn!("keyboard layout watcher couldn't determine active layout.") } - let mut layout = layout.expect("missing active layout"); - loop { std::thread::sleep(std::time::Duration::from_millis(WATCHER_INTERVAL)); - if let Some(current_layout) = espanso_detect::get_active_layout() { - if current_layout != layout { - debug!( - "detected keyboard layout change: from {} to {}", - layout, current_layout - ); + let current_layout = espanso_detect::get_active_layout(); + if current_layout != layout { + debug!( + "detected keyboard layout change: from '{}' to '{}'", + layout.as_deref().unwrap_or_default(), + current_layout.as_deref().unwrap_or_default(), + ); - if let Err(error) = watcher_notify.send(()) { - error!("unable to send keyboard layout changed event: {}", error); - } - - layout = current_layout; + if let Err(error) = watcher_notify.send(()) { + error!("unable to send keyboard layout changed event: {}", error); } - } else { - error!("keyboard layout watcher couldn't determine active layout"); - break; + + layout = current_layout; } } } From c24acc6e46ed0badf743e97e67dd1c4b5f552cc6 Mon Sep 17 00:00:00 2001 From: Federico Terzi Date: Mon, 11 Oct 2021 19:17:58 +0200 Subject: [PATCH 8/9] fix(core): change worker exit code that was conflicting with Rust's panics. Fix #783 --- espanso/src/exit_code.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/espanso/src/exit_code.rs b/espanso/src/exit_code.rs index 81eda51..f99d1b0 100644 --- a/espanso/src/exit_code.rs +++ b/espanso/src/exit_code.rs @@ -21,8 +21,8 @@ pub const WORKER_SUCCESS: i32 = 0; pub const WORKER_ALREADY_RUNNING: i32 = 1; pub const WORKER_GENERAL_ERROR: i32 = 2; pub const WORKER_LEGACY_ALREADY_RUNNING: i32 = 3; -pub const WORKER_EXIT_ALL_PROCESSES: i32 = 101; -pub const WORKER_RESTART: i32 = 102; +pub const WORKER_EXIT_ALL_PROCESSES: i32 = 50; +pub const WORKER_RESTART: i32 = 51; pub const DAEMON_SUCCESS: i32 = 0; 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_CLEAN_FAILURE: i32 = 50; 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_FAILURE: i32 = 1; From ea698e13b36ee6f5b8622e5061fa971c0bb9dee8 Mon Sep 17 00:00:00 2001 From: Federico Terzi Date: Mon, 11 Oct 2021 19:23:03 +0200 Subject: [PATCH 9/9] feat(core): don't show AutoStart wizard page on Linux --- espanso/src/cli/launcher/mod.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/espanso/src/cli/launcher/mod.rs b/espanso/src/cli/launcher/mod.rs index 9be664a..aa77a19 100644 --- a/espanso/src/cli/launcher/mod.rs +++ b/espanso/src/cli/launcher/mod.rs @@ -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 auto_start_handler = Box::new(move |auto_start| { preferences_clone.set_has_selected_auto_start_option(true);