From 23095d4394cf4bbb44f3900571b413a3ff271b8b Mon Sep 17 00:00:00 2001
From: Federico Terzi <federicoterzi96@gmail.com>
Date: Sun, 8 Mar 2020 19:06:01 +0100
Subject: [PATCH] Add Auto backend to automatically switch between Inject and
 Clipboard on Linux based on match content

---
 src/config/mod.rs | 15 ++++++++++++++-
 src/engine.rs     | 24 +++++++++++++++++++++++-
 2 files changed, 37 insertions(+), 2 deletions(-)

diff --git a/src/config/mod.rs b/src/config/mod.rs
index 64b7389..180566e 100644
--- a/src/config/mod.rs
+++ b/src/config/mod.rs
@@ -198,7 +198,20 @@ impl Configs {
 #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
 pub enum BackendType {
     Inject,
-    Clipboard
+    Clipboard,
+
+    // On Linux systems there is a long standing issue with text injection (which
+    // in general is better than Clipboard copy/pasting) that prevents certain
+    // apps from correctly handling special characters (such as emojis or accented letters)
+    // when injected. For this reason, espanso initially defaulted on the Clipboard
+    // backend on Linux, as it was the most reliable (working in 99% of cases),
+    // even though it was less efficient and with a few inconveniences (for example, the
+    // previous clipboard content being overwritten).
+    // The Auto backend tries to take it a step further, by automatically determining
+    // when an injection is possible (only ascii characters in the replacement), and falling
+    // back to the Clipboard backend otherwise.
+    // Should only be used on Linux systems.
+    Auto
 }
 impl Default for BackendType {
     // The default backend varies based on the operating system.
diff --git a/src/engine.rs b/src/engine.rs
index 622f169..ac22cd1 100644
--- a/src/engine.rs
+++ b/src/engine.rs
@@ -189,7 +189,25 @@ impl <'a, S: KeyboardManager, C: ClipboardManager, M: ConfigManager<'a>, U: UIMa
                     None
                 };
 
-                match config.backend {
+                let backend = if config.backend == BackendType::Auto {
+                    if cfg!(target_os = "linux") {
+                        let all_ascii = target_string.chars().all(|c| c.is_ascii());
+                        if all_ascii {
+                            debug!("All elements of the replacement are ascii, using Inject backend");
+                            &BackendType::Inject
+                        }else{
+                            debug!("There are non-ascii characters, using Clipboard backend");
+                            &BackendType::Clipboard
+                        }
+                    }else{
+                        warn!("Using Auto backend is only supported on Linux, falling back to Inject backend.");
+                        &BackendType::Inject
+                    }
+                }else{
+                    &config.backend
+                };
+
+                match backend {
                     BackendType::Inject => {
                         // Send the expected string. On linux, newlines are managed automatically
                         // while on windows and macos, we need to emulate a Enter key press.
@@ -217,6 +235,10 @@ impl <'a, S: KeyboardManager, C: ClipboardManager, M: ConfigManager<'a>, U: UIMa
                         self.clipboard_manager.set_clipboard(&target_string);
                         self.keyboard_manager.trigger_paste(&config.paste_shortcut);
                     },
+                    _ => {
+                        error!("Unsupported backend type evaluation.");
+                        return;
+                    }
                 }
 
                 if let Some(moves) = cursor_rewind {