commit
f28874f9b1
9
Cargo.lock
generated
9
Cargo.lock
generated
|
@ -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"
|
||||||
|
|
|
@ -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"
|
||||||
|
|
|
@ -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
BIN
images/githubsponsor.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 22 KiB |
BIN
images/paypal.png
Normal file
BIN
images/paypal.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 15 KiB |
|
@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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();
|
||||||
}
|
}
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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
93
src/extension/random.rs
Normal 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(¶ms);
|
||||||
|
|
||||||
|
assert!(output.is_some());
|
||||||
|
|
||||||
|
let output = output.unwrap();
|
||||||
|
|
||||||
|
assert!(choices.iter().any(|x| x == &output));
|
||||||
|
}
|
||||||
|
}
|
|
@ -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(¶ms);
|
||||||
|
|
||||||
|
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(¶ms);
|
||||||
|
|
||||||
|
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(¶ms);
|
||||||
|
|
||||||
|
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(¶ms);
|
||||||
|
|
||||||
|
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(¶ms);
|
||||||
|
|
||||||
|
assert!(output.is_some());
|
||||||
|
assert_eq!(output.unwrap(), "hello world");
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -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();
|
||||||
}
|
}
|
||||||
|
|
23
src/main.rs
23
src/main.rs
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user