Merge pull request #142 from federico-terzi/dev

Version 0.4.1
This commit is contained in:
Federico Terzi 2019-12-16 18:33:16 +01:00 committed by GitHub
commit f28874f9b1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 284 additions and 15 deletions

9
Cargo.lock generated
View File

@ -370,7 +370,7 @@ dependencies = [
[[package]] [[package]]
name = "espanso" name = "espanso"
version = "0.4.0" version = "0.4.1"
dependencies = [ dependencies = [
"backtrace 0.3.37 (registry+https://github.com/rust-lang/crates.io-index)", "backtrace 0.3.37 (registry+https://github.com/rust-lang/crates.io-index)",
"chrono 0.4.9 (registry+https://github.com/rust-lang/crates.io-index)", "chrono 0.4.9 (registry+https://github.com/rust-lang/crates.io-index)",
@ -384,6 +384,7 @@ dependencies = [
"libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", "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 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)", "log-panics 2.0.0 (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)", "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)", "reqwest 0.9.20 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.99 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.99 (registry+https://github.com/rust-lang/crates.io-index)",
@ -1003,7 +1004,7 @@ dependencies = [
[[package]] [[package]]
name = "rand" name = "rand"
version = "0.7.0" version = "0.7.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [ dependencies = [
"getrandom 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", "getrandom 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)",
@ -1410,7 +1411,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [ dependencies = [
"cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", "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)", "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)",
"rand 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)",
"redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)", "redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)",
"remove_dir_all 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", "remove_dir_all 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
@ -1892,7 +1893,7 @@ dependencies = [
"checksum quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)" = "6ce23b6b870e8f94f81fb0a363d65d86675884b34a09043c81e5562f11c1f8e1" "checksum quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)" = "6ce23b6b870e8f94f81fb0a363d65d86675884b34a09043c81e5562f11c1f8e1"
"checksum quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "053a8c8bcc71fcce321828dc897a98ab9760bef03a4fc36693c231e5b3216cfe" "checksum quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "053a8c8bcc71fcce321828dc897a98ab9760bef03a4fc36693c231e5b3216cfe"
"checksum rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)" = "6d71dacdc3c88c1fde3885a3be3fbab9f35724e6ce99467f7d9c5026132184ca" "checksum rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)" = "6d71dacdc3c88c1fde3885a3be3fbab9f35724e6ce99467f7d9c5026132184ca"
"checksum rand 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d47eab0e83d9693d40f825f86948aa16eff6750ead4bdffc4ab95b8b3a7f052c" "checksum rand 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "3ae1b169243eaf61759b8475a998f0a385e42042370f3a7dbaf35246eacc8412"
"checksum rand_chacha 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "556d3a1ca6600bfcbab7c7c91ccb085ac7fbbcd70e008a98742e7847f4f7bcef" "checksum rand_chacha 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "556d3a1ca6600bfcbab7c7c91ccb085ac7fbbcd70e008a98742e7847f4f7bcef"
"checksum rand_chacha 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "03a2a90da8c7523f554344f921aa97283eadf6ac484a6d2a7d0212fa7f8d6853" "checksum rand_chacha 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "03a2a90da8c7523f554344f921aa97283eadf6ac484a6d2a7d0212fa7f8d6853"
"checksum rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b" "checksum rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b"

View File

@ -1,6 +1,6 @@
[package] [package]
name = "espanso" name = "espanso"
version = "0.4.0" version = "0.4.1"
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"
@ -29,6 +29,7 @@ reqwest = "0.9.20"
git2 = {version = "0.10.1", features = ["https"]} git2 = {version = "0.10.1", features = ["https"]}
tempfile = "3.1.0" tempfile = "3.1.0"
dialoguer = "0.4.0" dialoguer = "0.4.0"
rand = "0.7.2"
[target.'cfg(unix)'.dependencies] [target.'cfg(unix)'.dependencies]
libc = "0.2.62" libc = "0.2.62"

View File

@ -29,6 +29,7 @@ ___
* Works on **Windows**, **macOS** and **Linux** * Works on **Windows**, **macOS** and **Linux**
* Works with almost **any program** * Works with almost **any program**
* Works with **Emojis** 😄 * Works with **Emojis** 😄
* Works with **Images**
* **Date** expansion support * **Date** expansion support
* **Custom scripts** support * **Custom scripts** support
* **Shell commands** support * **Shell commands** support
@ -54,7 +55,8 @@ espanso is a free, open source software developed in my (little) spare time.
If you liked the project and would like to support further development, If you liked the project and would like to support further development,
please consider making a small donation, it really helps :) please consider making a small donation, it really helps :)
[![Donate with PayPal](images/donate.gif)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=FHNLR5DRS267E&source=url) [![Donate with PayPal](images/githubsponsor.png)](https://github.com/sponsors/federico-terzi)
[![Donate with PayPal](images/paypal.png)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=FHNLR5DRS267E&source=url)
## Contributors ## Contributors
@ -65,6 +67,7 @@ Many people helped the project along the way, thanks to all of you. In particula
* [Matteo Pellegrino](https://www.matteopellegrino.me/) - MacOS Tester * [Matteo Pellegrino](https://www.matteopellegrino.me/) - MacOS Tester
* [Timo Runge](http://timorunge.com/) - MacOS contributor * [Timo Runge](http://timorunge.com/) - MacOS contributor
* [NickSeagull](http://nickseagull.github.io/) - Contributor * [NickSeagull](http://nickseagull.github.io/) - Contributor
* [matt-h](https://github.com/matt-h) - Contributor
## Remarks ## Remarks

BIN
images/githubsponsor.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

BIN
images/paypal.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

View File

@ -303,6 +303,10 @@ void trigger_shift_ins_paste() {
xdo_send_keysequence_window(xdo_context, CURRENTWINDOW, "Shift+Insert", 8000); xdo_send_keysequence_window(xdo_context, CURRENTWINDOW, "Shift+Insert", 8000);
} }
void trigger_alt_shift_ins_paste() {
xdo_send_keysequence_window(xdo_context, CURRENTWINDOW, "Shift+Alt+Insert", 8000);
}
// SYSTEM MODULE // SYSTEM MODULE
// Function taken from the wmlib tool source code // Function taken from the wmlib tool source code
@ -449,7 +453,7 @@ int32_t get_active_window_executable(char *buffer, int32_t size) {
return result; return result;
} }
int32_t is_current_window_terminal() { int32_t is_current_window_special() {
char class_buffer[250]; char class_buffer[250];
int res = get_active_window_class(class_buffer, 250); int res = get_active_window_class(class_buffer, 250);
if (res > 0) { if (res > 0) {
@ -465,10 +469,16 @@ int32_t is_current_window_terminal() {
return 1; return 1;
}else if (strstr(class_buffer, "Terminator") != NULL) { // Terminator }else if (strstr(class_buffer, "Terminator") != NULL) { // Terminator
return 1; return 1;
}else if (strstr(class_buffer, "stterm") != NULL) { // Simple terminal 3
return 2;
}else if (strstr(class_buffer, "St") != NULL) { // Simple terminal }else if (strstr(class_buffer, "St") != NULL) { // Simple terminal
return 1; return 1;
}else if (strstr(class_buffer, "st") != NULL) { // Simple terminal 2
return 1;
}else if (strstr(class_buffer, "Alacritty") != NULL) { // Alacritty terminal }else if (strstr(class_buffer, "Alacritty") != NULL) { // Alacritty terminal
return 1; return 1;
}else if (strstr(class_buffer, "Emacs") != NULL) { // Emacs
return 3;
} }
} }

View File

@ -87,6 +87,11 @@ extern "C" void trigger_terminal_paste();
*/ */
extern "C" void trigger_shift_ins_paste(); extern "C" void trigger_shift_ins_paste();
/*
* Trigger alt shift ins pasting( Pressing ALT+SHIFT+INS )
*/
extern "C" void trigger_alt_shift_ins_paste();
// SYSTEM MODULE // SYSTEM MODULE
@ -106,8 +111,8 @@ extern "C" int32_t get_active_window_class(char * buffer, int32_t size);
extern "C" int32_t get_active_window_executable(char * buffer, int32_t size); extern "C" int32_t get_active_window_executable(char * buffer, int32_t size);
/* /*
* Return 1 if the current window is a terminal window, 0 otherwise. * Return a value greater than 0 if the current window needs a special paste combination, 0 otherwise.
*/ */
extern "C" int32_t is_current_window_terminal(); extern "C" int32_t is_current_window_special();
#endif //ESPANSO_BRIDGE_H #endif //ESPANSO_BRIDGE_H

View File

@ -31,7 +31,7 @@ extern {
pub fn get_active_window_name(buffer: *mut c_char, size: i32) -> i32; pub fn get_active_window_name(buffer: *mut c_char, size: i32) -> i32;
pub fn get_active_window_class(buffer: *mut c_char, size: i32) -> i32; pub fn get_active_window_class(buffer: *mut c_char, size: i32) -> i32;
pub fn get_active_window_executable(buffer: *mut c_char, size: i32) -> i32; pub fn get_active_window_executable(buffer: *mut c_char, size: i32) -> i32;
pub fn is_current_window_terminal() -> i32; pub fn is_current_window_special() -> i32;
// Keyboard // Keyboard
pub fn register_keypress_callback(cb: extern fn(_self: *mut c_void, *const u8, pub fn register_keypress_callback(cb: extern fn(_self: *mut c_void, *const u8,
@ -43,4 +43,5 @@ extern {
pub fn trigger_paste(); pub fn trigger_paste();
pub fn trigger_terminal_paste(); pub fn trigger_terminal_paste();
pub fn trigger_shift_ins_paste(); pub fn trigger_shift_ins_paste();
pub fn trigger_alt_shift_ins_paste();
} }

View File

@ -53,6 +53,7 @@ fn default_use_system_agent() -> bool { true }
fn default_config_caching_interval() -> i32 { 800 } fn default_config_caching_interval() -> i32 { 800 }
fn default_word_separators() -> Vec<char> { vec![' ', ',', '.', '\r', '\n', 22u8 as char] } fn default_word_separators() -> Vec<char> { vec![' ', ',', '.', '\r', '\n', 22u8 as char] }
fn default_toggle_interval() -> u32 { 230 } fn default_toggle_interval() -> u32 { 230 }
fn default_preserve_clipboard() -> bool {false}
fn default_backspace_limit() -> i32 { 3 } fn default_backspace_limit() -> i32 { 3 }
fn default_exclude_default_matches() -> bool {false} fn default_exclude_default_matches() -> bool {false}
fn default_matches() -> Vec<Match> { Vec::new() } fn default_matches() -> Vec<Match> { Vec::new() }
@ -98,6 +99,9 @@ pub struct Configs {
#[serde(default = "default_toggle_interval")] #[serde(default = "default_toggle_interval")]
pub toggle_interval: u32, pub toggle_interval: u32,
#[serde(default = "default_preserve_clipboard")]
pub preserve_clipboard: bool,
#[serde(default)] #[serde(default)]
pub paste_shortcut: PasteShortcut, pub paste_shortcut: PasteShortcut,
@ -145,6 +149,7 @@ impl Configs {
validate_field!(result, self.backspace_limit, default_backspace_limit()); validate_field!(result, self.backspace_limit, default_backspace_limit());
validate_field!(result, self.ipc_server_port, default_ipc_server_port()); validate_field!(result, self.ipc_server_port, default_ipc_server_port());
validate_field!(result, self.use_system_agent, default_use_system_agent()); validate_field!(result, self.use_system_agent, default_use_system_agent());
validate_field!(result, self.preserve_clipboard, default_preserve_clipboard());
result result
} }

View File

@ -95,6 +95,19 @@ impl <'a, S: KeyboardManager, C: ClipboardManager, M: ConfigManager<'a>, U: UIMa
menu menu
} }
fn return_content_if_preserve_clipboard_is_enabled(&self) -> Option<String> {
// If the preserve_clipboard option is enabled, first save the current
// clipboard content in order to restore it later.
if self.config_manager.default_config().preserve_clipboard {
match self.clipboard_manager.get_clipboard() {
Some(clipboard) => {Some(clipboard)},
None => {None},
}
}else {
None
}
}
} }
lazy_static! { lazy_static! {
@ -119,6 +132,8 @@ impl <'a, S: KeyboardManager, C: ClipboardManager, M: ConfigManager<'a>, U: UIMa
self.keyboard_manager.delete_string(char_count); self.keyboard_manager.delete_string(char_count);
let mut previous_clipboard_content : Option<String> = None;
// Manage the different types of matches // Manage the different types of matches
match &m.content { match &m.content {
// Text Match // Text Match
@ -205,6 +220,10 @@ impl <'a, S: KeyboardManager, C: ClipboardManager, M: ConfigManager<'a>, U: UIMa
} }
}, },
BackendType::Clipboard => { BackendType::Clipboard => {
// If the preserve_clipboard option is enabled, save the current
// clipboard content to restore it later.
previous_clipboard_content = self.return_content_if_preserve_clipboard_is_enabled();
self.clipboard_manager.set_clipboard(&target_string); self.clipboard_manager.set_clipboard(&target_string);
self.keyboard_manager.trigger_paste(&config.paste_shortcut); self.keyboard_manager.trigger_paste(&config.paste_shortcut);
}, },
@ -220,6 +239,10 @@ impl <'a, S: KeyboardManager, C: ClipboardManager, M: ConfigManager<'a>, U: UIMa
MatchContentType::Image(content) => { MatchContentType::Image(content) => {
// Make sure the image exist beforehand // Make sure the image exist beforehand
if content.path.exists() { if content.path.exists() {
// If the preserve_clipboard option is enabled, save the current
// clipboard content to restore it later.
previous_clipboard_content = self.return_content_if_preserve_clipboard_is_enabled();
self.clipboard_manager.set_clipboard_image(&content.path); self.clipboard_manager.set_clipboard_image(&content.path);
self.keyboard_manager.trigger_paste(&config.paste_shortcut); self.keyboard_manager.trigger_paste(&config.paste_shortcut);
}else{ }else{
@ -227,6 +250,11 @@ impl <'a, S: KeyboardManager, C: ClipboardManager, M: ConfigManager<'a>, U: UIMa
} }
}, },
} }
// Restore previous clipboard content
if let Some(previous_clipboard_content) = previous_clipboard_content {
self.clipboard_manager.set_clipboard(&previous_clipboard_content);
}
} }
fn on_enable_update(&self, status: bool) { fn on_enable_update(&self, status: bool) {

View File

@ -22,6 +22,7 @@ use serde_yaml::Mapping;
mod date; mod date;
mod shell; mod shell;
mod script; mod script;
mod random;
pub trait Extension { pub trait Extension {
fn name(&self) -> String; fn name(&self) -> String;
@ -33,5 +34,6 @@ pub fn get_extensions() -> Vec<Box<dyn Extension>> {
Box::new(date::DateExtension::new()), Box::new(date::DateExtension::new()),
Box::new(shell::ShellExtension::new()), Box::new(shell::ShellExtension::new()),
Box::new(script::ScriptExtension::new()), Box::new(script::ScriptExtension::new()),
Box::new(random::RandomExtension::new()),
] ]
} }

93
src/extension/random.rs Normal file
View File

@ -0,0 +1,93 @@
/*
* This file is part of espanso.
*
* Copyright (C) 2019 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 serde_yaml::{Mapping, Value};
use rand::seq::SliceRandom;
use log::{warn, error};
pub struct RandomExtension {}
impl RandomExtension {
pub fn new() -> RandomExtension {
RandomExtension{}
}
}
impl super::Extension for RandomExtension {
fn name(&self) -> String {
String::from("random")
}
fn calculate(&self, params: &Mapping) -> Option<String> {
let choices = params.get(&Value::from("choices"));
if choices.is_none() {
warn!("No 'choices' parameter specified for random variable");
return None
}
let choices = choices.unwrap().as_sequence();
if let Some(choices) = choices {
let str_choices = choices.iter().map(|arg| {
arg.as_str().unwrap_or_default().to_string()
}).collect::<Vec<String>>();
// Select a random choice between the possibilities
let choice = str_choices.choose(&mut rand::thread_rng());
match choice {
Some(output) => {
return Some(output.clone())
},
None => {
error!("Could not select a random choice.");
return None
},
}
}
error!("choices array have an invalid format '{:?}'", choices);
None
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::extension::Extension;
#[test]
fn test_random_basic() {
let mut params = Mapping::new();
let choices = vec!(
"first",
"second",
"third",
);
params.insert(Value::from("choices"), Value::from(choices.clone()));
let extension = RandomExtension::new();
let output = extension.calculate(&params);
assert!(output.is_some());
let output = output.unwrap();
assert!(choices.iter().any(|x| x == &output));
}
}

View File

@ -56,8 +56,20 @@ impl super::Extension for ShellExtension {
match output { match output {
Ok(output) => { Ok(output) => {
let output_str = String::from_utf8_lossy(output.stdout.as_slice()); let output_str = String::from_utf8_lossy(output.stdout.as_slice());
let mut output_str = output_str.into_owned();
Some(output_str.into_owned()) // If specified, trim the output
let trim_opt = params.get(&Value::from("trim"));
if let Some(value) = trim_opt {
let val = value.as_bool();
if let Some(val) = val {
if val {
output_str = output_str.trim().to_owned()
}
}
}
Some(output_str)
}, },
Err(e) => { Err(e) => {
error!("Could not execute cmd '{}', error: {}", cmd, e); error!("Could not execute cmd '{}', error: {}", cmd, e);
@ -65,4 +77,89 @@ impl super::Extension for ShellExtension {
}, },
} }
} }
}
#[cfg(test)]
mod tests {
use super::*;
use crate::extension::Extension;
#[test]
fn test_shell_basic() {
let mut params = Mapping::new();
params.insert(Value::from("cmd"), Value::from("echo hello world"));
let extension = ShellExtension::new();
let output = extension.calculate(&params);
assert!(output.is_some());
if cfg!(target_os = "windows") {
assert_eq!(output.unwrap(), "hello world\r\n");
}else{
assert_eq!(output.unwrap(), "hello world\n");
}
}
#[test]
fn test_shell_trimmed() {
let mut params = Mapping::new();
params.insert(Value::from("cmd"), Value::from("echo hello world"));
params.insert(Value::from("trim"), Value::from(true));
let extension = ShellExtension::new();
let output = extension.calculate(&params);
assert!(output.is_some());
assert_eq!(output.unwrap(), "hello world");
}
#[test]
fn test_shell_trimmed_2() {
let mut params = Mapping::new();
if cfg!(target_os = "windows") {
params.insert(Value::from("cmd"), Value::from("echo hello world "));
}else{
params.insert(Value::from("cmd"), Value::from("echo \" hello world \""));
}
params.insert(Value::from("trim"), Value::from(true));
let extension = ShellExtension::new();
let output = extension.calculate(&params);
assert!(output.is_some());
assert_eq!(output.unwrap(), "hello world");
}
#[test]
fn test_shell_trimmed_malformed() {
let mut params = Mapping::new();
params.insert(Value::from("cmd"), Value::from("echo hello world"));
params.insert(Value::from("trim"), Value::from("error"));
let extension = ShellExtension::new();
let output = extension.calculate(&params);
assert!(output.is_some());
if cfg!(target_os = "windows") {
assert_eq!(output.unwrap(), "hello world\r\n");
}else{
assert_eq!(output.unwrap(), "hello world\n");
}
}
#[test]
#[cfg(not(target_os = "windows"))]
fn test_shell_pipes() {
let mut params = Mapping::new();
params.insert(Value::from("cmd"), Value::from("echo hello world | cat"));
params.insert(Value::from("trim"), Value::from(true));
let extension = ShellExtension::new();
let output = extension.calculate(&params);
assert!(output.is_some());
assert_eq!(output.unwrap(), "hello world");
}
} }

View File

@ -42,12 +42,16 @@ impl super::KeyboardManager for LinuxKeyboardManager {
unsafe { unsafe {
match shortcut { match shortcut {
PasteShortcut::Default => { PasteShortcut::Default => {
let is_terminal = is_current_window_terminal(); let is_special = is_current_window_special();
// Terminals use a different keyboard combination to paste from clipboard, // Terminals use a different keyboard combination to paste from clipboard,
// so we need to check the correct situation. // so we need to check the correct situation.
if is_terminal == 0 { if is_special == 0 {
trigger_paste(); trigger_paste();
}else if is_special == 2 { // Special case for stterm
trigger_alt_shift_ins_paste();
}else if is_special == 3 { // Special case for Emacs
trigger_shift_ins_paste();
}else{ }else{
trigger_terminal_paste(); trigger_terminal_paste();
} }

View File

@ -402,9 +402,24 @@ fn start_daemon(config_set: ConfigSet) {
#[cfg(target_os = "linux")] #[cfg(target_os = "linux")]
fn start_daemon(config_set: ConfigSet) { fn start_daemon(config_set: ConfigSet) {
if config_set.default.use_system_agent { use std::process::{Command, Stdio};
use std::process::Command;
// Check if Systemd is available in the system
let status = Command::new("systemctl")
.args(&["--version"])
.stdin(Stdio::null())
.stdout(Stdio::null())
.status();
// If Systemd is not available in the system, espanso should default to unmanaged mode
// See issue https://github.com/federico-terzi/espanso/issues/139
let force_unmanaged = if let Err(status) = status {
true
} else {
false
};
if config_set.default.use_system_agent && !force_unmanaged {
// Make sure espanso is currently registered in systemd // Make sure espanso is currently registered in systemd
let res = Command::new("systemctl") let res = Command::new("systemctl")
.args(&["--user", "is-enabled", "espanso.service"]) .args(&["--user", "is-enabled", "espanso.service"])
@ -442,6 +457,10 @@ fn start_daemon(config_set: ConfigSet) {
eprintln!("Error starting systemd daemon: {}", res.unwrap_err()); eprintln!("Error starting systemd daemon: {}", res.unwrap_err());
} }
}else{ }else{
if force_unmanaged {
eprintln!("Systemd is not available in this system, switching to unmanaged mode.");
}
fork_daemon(config_set); fork_daemon(config_set);
} }
} }