Fix formatting
This commit is contained in:
parent
161017f024
commit
411078a503
|
@ -244,7 +244,7 @@ pub struct Configs {
|
||||||
|
|
||||||
#[serde(default = "default_secure_input_watcher_interval")]
|
#[serde(default = "default_secure_input_watcher_interval")]
|
||||||
pub secure_input_watcher_interval: i32,
|
pub secure_input_watcher_interval: i32,
|
||||||
|
|
||||||
#[serde(default = "default_mac_post_inject_delay")]
|
#[serde(default = "default_mac_post_inject_delay")]
|
||||||
pub mac_post_inject_delay: u64,
|
pub mac_post_inject_delay: u64,
|
||||||
|
|
||||||
|
@ -282,7 +282,7 @@ pub struct Configs {
|
||||||
pub global_vars: Vec<MatchVariable>,
|
pub global_vars: Vec<MatchVariable>,
|
||||||
|
|
||||||
#[serde(default = "default_modulo_path")]
|
#[serde(default = "default_modulo_path")]
|
||||||
pub modulo_path: Option<String>
|
pub modulo_path: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Macro used to validate config fields
|
// Macro used to validate config fields
|
||||||
|
|
|
@ -19,7 +19,7 @@
|
||||||
|
|
||||||
use crate::clipboard::ClipboardManager;
|
use crate::clipboard::ClipboardManager;
|
||||||
use crate::config::BackendType;
|
use crate::config::BackendType;
|
||||||
use crate::config::{Configs, ConfigManager};
|
use crate::config::{ConfigManager, Configs};
|
||||||
use crate::event::{ActionEventReceiver, ActionType, SystemEvent, SystemEventReceiver};
|
use crate::event::{ActionEventReceiver, ActionType, SystemEvent, SystemEventReceiver};
|
||||||
use crate::keyboard::KeyboardManager;
|
use crate::keyboard::KeyboardManager;
|
||||||
use crate::matcher::{Match, MatchReceiver};
|
use crate::matcher::{Match, MatchReceiver};
|
||||||
|
@ -158,9 +158,7 @@ impl<
|
||||||
if cfg!(target_os = "linux") {
|
if cfg!(target_os = "linux") {
|
||||||
let all_ascii = target_string.chars().all(|c| c.is_ascii());
|
let all_ascii = target_string.chars().all(|c| c.is_ascii());
|
||||||
if all_ascii {
|
if all_ascii {
|
||||||
debug!(
|
debug!("All elements of the replacement are ascii, using Inject backend");
|
||||||
"All elements of the replacement are ascii, using Inject backend"
|
|
||||||
);
|
|
||||||
&BackendType::Inject
|
&BackendType::Inject
|
||||||
} else {
|
} else {
|
||||||
debug!("There are non-ascii characters, using Clipboard backend");
|
debug!("There are non-ascii characters, using Clipboard backend");
|
||||||
|
@ -273,7 +271,10 @@ impl<
|
||||||
|
|
||||||
// Disallow undo backspace if cursor positioning is used
|
// Disallow undo backspace if cursor positioning is used
|
||||||
if cursor_rewind.is_none() {
|
if cursor_rewind.is_none() {
|
||||||
expansion_data = Some((m.triggers[trigger_offset].clone(), target_string.chars().count() as i32));
|
expansion_data = Some((
|
||||||
|
m.triggers[trigger_offset].clone(),
|
||||||
|
target_string.chars().count() as i32,
|
||||||
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(moves) = cursor_rewind {
|
if let Some(moves) = cursor_rewind {
|
||||||
|
@ -310,7 +311,9 @@ impl<
|
||||||
// giving back the control. Otherwise, the injected actions will be handled back
|
// giving back the control. Otherwise, the injected actions will be handled back
|
||||||
// by espanso itself.
|
// by espanso itself.
|
||||||
if cfg!(target_os = "macos") {
|
if cfg!(target_os = "macos") {
|
||||||
std::thread::sleep(std::time::Duration::from_millis(config.mac_post_inject_delay));
|
std::thread::sleep(std::time::Duration::from_millis(
|
||||||
|
config.mac_post_inject_delay,
|
||||||
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Re-allow espanso to interpret actions
|
// Re-allow espanso to interpret actions
|
||||||
|
@ -350,7 +353,8 @@ impl<
|
||||||
if let Some(ref last_expansion_data) = *last_expansion_data {
|
if let Some(ref last_expansion_data) = *last_expansion_data {
|
||||||
let (trigger_string, injected_text_len) = last_expansion_data;
|
let (trigger_string, injected_text_len) = last_expansion_data;
|
||||||
// Delete the previously injected text, minus one character as it has been consumed by the backspace
|
// Delete the previously injected text, minus one character as it has been consumed by the backspace
|
||||||
self.keyboard_manager.delete_string(&config, *injected_text_len - 1);
|
self.keyboard_manager
|
||||||
|
.delete_string(&config, *injected_text_len - 1);
|
||||||
// Restore previous text
|
// Restore previous text
|
||||||
self.inject_text(&config, trigger_string, false);
|
self.inject_text(&config, trigger_string, false);
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,8 +18,8 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
use crate::clipboard::ClipboardManager;
|
use crate::clipboard::ClipboardManager;
|
||||||
use serde_yaml::Mapping;
|
|
||||||
use crate::extension::ExtensionResult;
|
use crate::extension::ExtensionResult;
|
||||||
|
use serde_yaml::Mapping;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
pub struct ClipboardExtension {
|
pub struct ClipboardExtension {
|
||||||
|
@ -37,7 +37,12 @@ impl super::Extension for ClipboardExtension {
|
||||||
String::from("clipboard")
|
String::from("clipboard")
|
||||||
}
|
}
|
||||||
|
|
||||||
fn calculate(&self, _: &Mapping, _: &Vec<String>, _: &HashMap<String, ExtensionResult>) -> Option<ExtensionResult> {
|
fn calculate(
|
||||||
|
&self,
|
||||||
|
_: &Mapping,
|
||||||
|
_: &Vec<String>,
|
||||||
|
_: &HashMap<String, ExtensionResult>,
|
||||||
|
) -> Option<ExtensionResult> {
|
||||||
if let Some(clipboard) = self.clipboard_manager.get_clipboard() {
|
if let Some(clipboard) = self.clipboard_manager.get_clipboard() {
|
||||||
Some(ExtensionResult::Single(clipboard))
|
Some(ExtensionResult::Single(clipboard))
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -17,10 +17,10 @@
|
||||||
* along with espanso. If not, see <https://www.gnu.org/licenses/>.
|
* along with espanso. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
use chrono::{DateTime, Local, Duration};
|
use crate::extension::ExtensionResult;
|
||||||
|
use chrono::{DateTime, Duration, Local};
|
||||||
use serde_yaml::{Mapping, Value};
|
use serde_yaml::{Mapping, Value};
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use crate::extension::ExtensionResult;
|
|
||||||
|
|
||||||
pub struct DateExtension {}
|
pub struct DateExtension {}
|
||||||
|
|
||||||
|
@ -35,13 +35,18 @@ impl super::Extension for DateExtension {
|
||||||
String::from("date")
|
String::from("date")
|
||||||
}
|
}
|
||||||
|
|
||||||
fn calculate(&self, params: &Mapping, _: &Vec<String>, _: &HashMap<String, ExtensionResult>) -> Option<ExtensionResult> {
|
fn calculate(
|
||||||
|
&self,
|
||||||
|
params: &Mapping,
|
||||||
|
_: &Vec<String>,
|
||||||
|
_: &HashMap<String, ExtensionResult>,
|
||||||
|
) -> Option<ExtensionResult> {
|
||||||
let mut now: DateTime<Local> = Local::now();
|
let mut now: DateTime<Local> = Local::now();
|
||||||
|
|
||||||
// Compute the given offset
|
// Compute the given offset
|
||||||
let offset = params.get(&Value::from("offset"));
|
let offset = params.get(&Value::from("offset"));
|
||||||
if let Some(offset) = offset {
|
if let Some(offset) = offset {
|
||||||
let seconds = offset.as_i64().unwrap_or_else(|| { 0 });
|
let seconds = offset.as_i64().unwrap_or_else(|| 0);
|
||||||
let offset = Duration::seconds(seconds);
|
let offset = Duration::seconds(seconds);
|
||||||
now = now + offset;
|
now = now + offset;
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,9 +17,9 @@
|
||||||
* along with espanso. If not, see <https://www.gnu.org/licenses/>.
|
* along with espanso. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
use crate::extension::ExtensionResult;
|
||||||
use serde_yaml::{Mapping, Value};
|
use serde_yaml::{Mapping, Value};
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use crate::extension::ExtensionResult;
|
|
||||||
|
|
||||||
pub struct DummyExtension {
|
pub struct DummyExtension {
|
||||||
name: String,
|
name: String,
|
||||||
|
@ -38,11 +38,18 @@ impl super::Extension for DummyExtension {
|
||||||
self.name.clone()
|
self.name.clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn calculate(&self, params: &Mapping, _: &Vec<String>, _: &HashMap<String, ExtensionResult>) -> Option<ExtensionResult> {
|
fn calculate(
|
||||||
|
&self,
|
||||||
|
params: &Mapping,
|
||||||
|
_: &Vec<String>,
|
||||||
|
_: &HashMap<String, ExtensionResult>,
|
||||||
|
) -> Option<ExtensionResult> {
|
||||||
let echo = params.get(&Value::from("echo"));
|
let echo = params.get(&Value::from("echo"));
|
||||||
|
|
||||||
if let Some(echo) = echo {
|
if let Some(echo) = echo {
|
||||||
Some(ExtensionResult::Single(echo.as_str().unwrap_or_default().to_owned()))
|
Some(ExtensionResult::Single(
|
||||||
|
echo.as_str().unwrap_or_default().to_owned(),
|
||||||
|
))
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,10 +17,10 @@
|
||||||
* along with espanso. If not, see <https://www.gnu.org/licenses/>.
|
* along with espanso. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
use crate::{config::Configs, extension::ExtensionResult, ui::modulo::ModuloManager};
|
||||||
|
use log::{error, warn};
|
||||||
use serde_yaml::{Mapping, Value};
|
use serde_yaml::{Mapping, Value};
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use crate::{ui::modulo::ModuloManager, extension::ExtensionResult, config::Configs};
|
|
||||||
use log::{error, warn};
|
|
||||||
|
|
||||||
pub struct FormExtension {
|
pub struct FormExtension {
|
||||||
manager: ModuloManager,
|
manager: ModuloManager,
|
||||||
|
@ -29,9 +29,7 @@ pub struct FormExtension {
|
||||||
impl FormExtension {
|
impl FormExtension {
|
||||||
pub fn new(config: &Configs) -> FormExtension {
|
pub fn new(config: &Configs) -> FormExtension {
|
||||||
let manager = ModuloManager::new(config);
|
let manager = ModuloManager::new(config);
|
||||||
FormExtension {
|
FormExtension { manager }
|
||||||
manager,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -40,7 +38,12 @@ impl super::Extension for FormExtension {
|
||||||
"form".to_owned()
|
"form".to_owned()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn calculate(&self, params: &Mapping, _: &Vec<String>, _: &HashMap<String, ExtensionResult>) -> Option<ExtensionResult> {
|
fn calculate(
|
||||||
|
&self,
|
||||||
|
params: &Mapping,
|
||||||
|
_: &Vec<String>,
|
||||||
|
_: &HashMap<String, ExtensionResult>,
|
||||||
|
) -> Option<ExtensionResult> {
|
||||||
let layout = params.get(&Value::from("layout"));
|
let layout = params.get(&Value::from("layout"));
|
||||||
let layout = if let Some(value) = layout {
|
let layout = if let Some(value) = layout {
|
||||||
value.as_str().unwrap_or_default().to_string()
|
value.as_str().unwrap_or_default().to_string()
|
||||||
|
@ -48,21 +51,24 @@ impl super::Extension for FormExtension {
|
||||||
error!("invoking form extension without specifying a layout");
|
error!("invoking form extension without specifying a layout");
|
||||||
return None;
|
return None;
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut form_config = Mapping::new();
|
let mut form_config = Mapping::new();
|
||||||
form_config.insert(Value::from("layout"), Value::from(layout));
|
form_config.insert(Value::from("layout"), Value::from(layout));
|
||||||
|
|
||||||
if let Some(fields) = params.get(&Value::from("fields")) {
|
|
||||||
form_config.insert(Value::from("fields"), fields.clone());
|
|
||||||
}
|
|
||||||
|
|
||||||
let serialized_config: String = serde_yaml::to_string(&form_config).expect("unable to serialize form config");
|
|
||||||
|
|
||||||
let output = self.manager.invoke(&["form", "-i", "-"], &serialized_config);
|
if let Some(fields) = params.get(&Value::from("fields")) {
|
||||||
|
form_config.insert(Value::from("fields"), fields.clone());
|
||||||
|
}
|
||||||
|
|
||||||
|
let serialized_config: String =
|
||||||
|
serde_yaml::to_string(&form_config).expect("unable to serialize form config");
|
||||||
|
|
||||||
|
let output = self
|
||||||
|
.manager
|
||||||
|
.invoke(&["form", "-i", "-"], &serialized_config);
|
||||||
|
|
||||||
// On macOS, after the form closes we have to wait until the user releases the modifier keys
|
// On macOS, after the form closes we have to wait until the user releases the modifier keys
|
||||||
on_form_close();
|
on_form_close();
|
||||||
|
|
||||||
if let Some(output) = output {
|
if let Some(output) = output {
|
||||||
let json: Result<HashMap<String, String>, _> = serde_json::from_str(&output);
|
let json: Result<HashMap<String, String>, _> = serde_json::from_str(&output);
|
||||||
match json {
|
match json {
|
||||||
|
@ -77,7 +83,7 @@ impl super::Extension for FormExtension {
|
||||||
} else {
|
} else {
|
||||||
error!("modulo form didn't return any output");
|
error!("modulo form didn't return any output");
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -92,4 +98,4 @@ fn on_form_close() {
|
||||||
if !released {
|
if !released {
|
||||||
warn!("Wait for modifiers release timed out! Please after closing the form, release your modifiers keys (CTRL, CMD, ALT, SHIFT)");
|
warn!("Wait for modifiers release timed out! Please after closing the form, release your modifiers keys (CTRL, CMD, ALT, SHIFT)");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,20 +17,20 @@
|
||||||
* along with espanso. If not, see <https://www.gnu.org/licenses/>.
|
* along with espanso. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
use crate::{config::Configs, clipboard::ClipboardManager};
|
use crate::{clipboard::ClipboardManager, config::Configs};
|
||||||
use serde_yaml::Mapping;
|
use serde_yaml::Mapping;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
mod clipboard;
|
mod clipboard;
|
||||||
mod date;
|
mod date;
|
||||||
pub mod dummy;
|
pub mod dummy;
|
||||||
|
mod form;
|
||||||
|
pub mod multiecho;
|
||||||
mod random;
|
mod random;
|
||||||
mod script;
|
mod script;
|
||||||
mod shell;
|
mod shell;
|
||||||
pub mod multiecho;
|
|
||||||
pub mod vardummy;
|
|
||||||
mod utils;
|
mod utils;
|
||||||
mod form;
|
pub mod vardummy;
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq)]
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
pub enum ExtensionResult {
|
pub enum ExtensionResult {
|
||||||
|
@ -40,10 +40,18 @@ pub enum ExtensionResult {
|
||||||
|
|
||||||
pub trait Extension {
|
pub trait Extension {
|
||||||
fn name(&self) -> String;
|
fn name(&self) -> String;
|
||||||
fn calculate(&self, params: &Mapping, args: &Vec<String>, current_vars: &HashMap<String, ExtensionResult>) -> Option<ExtensionResult>;
|
fn calculate(
|
||||||
|
&self,
|
||||||
|
params: &Mapping,
|
||||||
|
args: &Vec<String>,
|
||||||
|
current_vars: &HashMap<String, ExtensionResult>,
|
||||||
|
) -> Option<ExtensionResult>;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_extensions(config: &Configs, clipboard_manager: Box<dyn ClipboardManager>) -> Vec<Box<dyn Extension>> {
|
pub fn get_extensions(
|
||||||
|
config: &Configs,
|
||||||
|
clipboard_manager: Box<dyn ClipboardManager>,
|
||||||
|
) -> Vec<Box<dyn Extension>> {
|
||||||
vec![
|
vec![
|
||||||
Box::new(date::DateExtension::new()),
|
Box::new(date::DateExtension::new()),
|
||||||
Box::new(shell::ShellExtension::new()),
|
Box::new(shell::ShellExtension::new()),
|
||||||
|
|
|
@ -17,9 +17,9 @@
|
||||||
* along with espanso. If not, see <https://www.gnu.org/licenses/>.
|
* along with espanso. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
use crate::extension::ExtensionResult;
|
||||||
use serde_yaml::{Mapping, Value};
|
use serde_yaml::{Mapping, Value};
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use crate::extension::ExtensionResult;
|
|
||||||
|
|
||||||
pub struct MultiEchoExtension {}
|
pub struct MultiEchoExtension {}
|
||||||
|
|
||||||
|
@ -34,7 +34,12 @@ impl super::Extension for MultiEchoExtension {
|
||||||
"multiecho".to_owned()
|
"multiecho".to_owned()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn calculate(&self, params: &Mapping, _: &Vec<String>, _: &HashMap<String, ExtensionResult>) -> Option<ExtensionResult> {
|
fn calculate(
|
||||||
|
&self,
|
||||||
|
params: &Mapping,
|
||||||
|
_: &Vec<String>,
|
||||||
|
_: &HashMap<String, ExtensionResult>,
|
||||||
|
) -> Option<ExtensionResult> {
|
||||||
let mut output: HashMap<String, String> = HashMap::new();
|
let mut output: HashMap<String, String> = HashMap::new();
|
||||||
for (key, value) in params.iter() {
|
for (key, value) in params.iter() {
|
||||||
if let Some(key) = key.as_str() {
|
if let Some(key) = key.as_str() {
|
||||||
|
|
|
@ -17,11 +17,11 @@
|
||||||
* along with espanso. If not, see <https://www.gnu.org/licenses/>.
|
* along with espanso. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
use crate::extension::ExtensionResult;
|
||||||
use log::{error, warn};
|
use log::{error, warn};
|
||||||
use rand::seq::SliceRandom;
|
use rand::seq::SliceRandom;
|
||||||
use serde_yaml::{Mapping, Value};
|
use serde_yaml::{Mapping, Value};
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use crate::extension::ExtensionResult;
|
|
||||||
|
|
||||||
pub struct RandomExtension {}
|
pub struct RandomExtension {}
|
||||||
|
|
||||||
|
@ -36,7 +36,12 @@ impl super::Extension for RandomExtension {
|
||||||
String::from("random")
|
String::from("random")
|
||||||
}
|
}
|
||||||
|
|
||||||
fn calculate(&self, params: &Mapping, args: &Vec<String>, _: &HashMap<String, ExtensionResult>) -> Option<ExtensionResult> {
|
fn calculate(
|
||||||
|
&self,
|
||||||
|
params: &Mapping,
|
||||||
|
args: &Vec<String>,
|
||||||
|
_: &HashMap<String, ExtensionResult>,
|
||||||
|
) -> Option<ExtensionResult> {
|
||||||
let choices = params.get(&Value::from("choices"));
|
let choices = params.get(&Value::from("choices"));
|
||||||
if choices.is_none() {
|
if choices.is_none() {
|
||||||
warn!("No 'choices' parameter specified for random variable");
|
warn!("No 'choices' parameter specified for random variable");
|
||||||
|
@ -89,7 +94,9 @@ mod tests {
|
||||||
|
|
||||||
let output = output.unwrap();
|
let output = output.unwrap();
|
||||||
|
|
||||||
assert!(choices.into_iter().any(|x| ExtensionResult::Single(x.to_owned()) == output));
|
assert!(choices
|
||||||
|
.into_iter()
|
||||||
|
.any(|x| ExtensionResult::Single(x.to_owned()) == output));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -107,6 +114,8 @@ mod tests {
|
||||||
|
|
||||||
let rendered_choices = vec!["first test", "second test", "test third"];
|
let rendered_choices = vec!["first test", "second test", "test third"];
|
||||||
|
|
||||||
assert!(rendered_choices.into_iter().any(|x| ExtensionResult::Single(x.to_owned()) == output));
|
assert!(rendered_choices
|
||||||
|
.into_iter()
|
||||||
|
.any(|x| ExtensionResult::Single(x.to_owned()) == output));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,12 +17,12 @@
|
||||||
* along with espanso. If not, see <https://www.gnu.org/licenses/>.
|
* along with espanso. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
use crate::extension::ExtensionResult;
|
||||||
use log::{error, warn};
|
use log::{error, warn};
|
||||||
use serde_yaml::{Mapping, Value};
|
use serde_yaml::{Mapping, Value};
|
||||||
|
use std::collections::HashMap;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use std::process::Command;
|
use std::process::Command;
|
||||||
use std::collections::HashMap;
|
|
||||||
use crate::extension::ExtensionResult;
|
|
||||||
|
|
||||||
pub struct ScriptExtension {}
|
pub struct ScriptExtension {}
|
||||||
|
|
||||||
|
@ -37,7 +37,12 @@ impl super::Extension for ScriptExtension {
|
||||||
String::from("script")
|
String::from("script")
|
||||||
}
|
}
|
||||||
|
|
||||||
fn calculate(&self, params: &Mapping, user_args: &Vec<String>, vars: &HashMap<String, ExtensionResult>) -> Option<ExtensionResult> {
|
fn calculate(
|
||||||
|
&self,
|
||||||
|
params: &Mapping,
|
||||||
|
user_args: &Vec<String>,
|
||||||
|
vars: &HashMap<String, ExtensionResult>,
|
||||||
|
) -> Option<ExtensionResult> {
|
||||||
let args = params.get(&Value::from("args"));
|
let args = params.get(&Value::from("args"));
|
||||||
if args.is_none() {
|
if args.is_none() {
|
||||||
warn!("No 'args' parameter specified for script variable");
|
warn!("No 'args' parameter specified for script variable");
|
||||||
|
@ -69,10 +74,20 @@ impl super::Extension for ScriptExtension {
|
||||||
*arg = arg.replace("%HOME%", &home_dir.to_string_lossy().to_string());
|
*arg = arg.replace("%HOME%", &home_dir.to_string_lossy().to_string());
|
||||||
}
|
}
|
||||||
if arg.contains("%CONFIG%") {
|
if arg.contains("%CONFIG%") {
|
||||||
*arg = arg.replace("%CONFIG%", &crate::context::get_config_dir().to_string_lossy().to_string());
|
*arg = arg.replace(
|
||||||
|
"%CONFIG%",
|
||||||
|
&crate::context::get_config_dir()
|
||||||
|
.to_string_lossy()
|
||||||
|
.to_string(),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
if arg.contains("%PACKAGES%") {
|
if arg.contains("%PACKAGES%") {
|
||||||
*arg = arg.replace("%PACKAGES%", &crate::context::get_package_dir().to_string_lossy().to_string());
|
*arg = arg.replace(
|
||||||
|
"%PACKAGES%",
|
||||||
|
&crate::context::get_package_dir()
|
||||||
|
.to_string_lossy()
|
||||||
|
.to_string(),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// On Windows, correct paths separators
|
// On Windows, correct paths separators
|
||||||
|
@ -162,7 +177,10 @@ mod tests {
|
||||||
let output = extension.calculate(¶ms, &vec![], &HashMap::new());
|
let output = extension.calculate(¶ms, &vec![], &HashMap::new());
|
||||||
|
|
||||||
assert!(output.is_some());
|
assert!(output.is_some());
|
||||||
assert_eq!(output.unwrap(), ExtensionResult::Single("hello world".to_owned()));
|
assert_eq!(
|
||||||
|
output.unwrap(),
|
||||||
|
ExtensionResult::Single("hello world".to_owned())
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -179,7 +197,10 @@ mod tests {
|
||||||
let output = extension.calculate(¶ms, &vec![], &HashMap::new());
|
let output = extension.calculate(¶ms, &vec![], &HashMap::new());
|
||||||
|
|
||||||
assert!(output.is_some());
|
assert!(output.is_some());
|
||||||
assert_eq!(output.unwrap(), ExtensionResult::Single("hello world\n".to_owned()));
|
assert_eq!(
|
||||||
|
output.unwrap(),
|
||||||
|
ExtensionResult::Single("hello world\n".to_owned())
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -195,7 +216,10 @@ mod tests {
|
||||||
let output = extension.calculate(¶ms, &vec!["jon".to_owned()], &HashMap::new());
|
let output = extension.calculate(¶ms, &vec!["jon".to_owned()], &HashMap::new());
|
||||||
|
|
||||||
assert!(output.is_some());
|
assert!(output.is_some());
|
||||||
assert_eq!(output.unwrap(), ExtensionResult::Single("hello world".to_owned()));
|
assert_eq!(
|
||||||
|
output.unwrap(),
|
||||||
|
ExtensionResult::Single("hello world".to_owned())
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -212,7 +236,10 @@ mod tests {
|
||||||
let output = extension.calculate(¶ms, &vec!["jon".to_owned()], &HashMap::new());
|
let output = extension.calculate(¶ms, &vec!["jon".to_owned()], &HashMap::new());
|
||||||
|
|
||||||
assert!(output.is_some());
|
assert!(output.is_some());
|
||||||
assert_eq!(output.unwrap(), ExtensionResult::Single("hello world jon".to_owned()));
|
assert_eq!(
|
||||||
|
output.unwrap(),
|
||||||
|
ExtensionResult::Single("hello world jon".to_owned())
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -228,12 +255,18 @@ mod tests {
|
||||||
let mut subvars = HashMap::new();
|
let mut subvars = HashMap::new();
|
||||||
subvars.insert("name".to_owned(), "John".to_owned());
|
subvars.insert("name".to_owned(), "John".to_owned());
|
||||||
vars.insert("form1".to_owned(), ExtensionResult::Multiple(subvars));
|
vars.insert("form1".to_owned(), ExtensionResult::Multiple(subvars));
|
||||||
vars.insert("var1".to_owned(), ExtensionResult::Single("hello".to_owned()));
|
vars.insert(
|
||||||
|
"var1".to_owned(),
|
||||||
|
ExtensionResult::Single("hello".to_owned()),
|
||||||
|
);
|
||||||
|
|
||||||
let extension = ScriptExtension::new();
|
let extension = ScriptExtension::new();
|
||||||
let output = extension.calculate(¶ms, &vec![], &vars);
|
let output = extension.calculate(¶ms, &vec![], &vars);
|
||||||
|
|
||||||
assert!(output.is_some());
|
assert!(output.is_some());
|
||||||
assert_eq!(output.unwrap(), ExtensionResult::Single("hello John".to_owned()));
|
assert_eq!(
|
||||||
|
output.unwrap(),
|
||||||
|
ExtensionResult::Single("hello John".to_owned())
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,12 +17,12 @@
|
||||||
* along with espanso. If not, see <https://www.gnu.org/licenses/>.
|
* along with espanso. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
use crate::extension::ExtensionResult;
|
||||||
use log::{error, info, warn};
|
use log::{error, info, warn};
|
||||||
use regex::{Captures, Regex};
|
use regex::{Captures, Regex};
|
||||||
use serde_yaml::{Mapping, Value};
|
use serde_yaml::{Mapping, Value};
|
||||||
use std::process::{Command, Output};
|
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use crate::extension::ExtensionResult;
|
use std::process::{Command, Output};
|
||||||
|
|
||||||
lazy_static! {
|
lazy_static! {
|
||||||
static ref POS_ARG_REGEX: Regex = if cfg!(target_os = "windows") {
|
static ref POS_ARG_REGEX: Regex = if cfg!(target_os = "windows") {
|
||||||
|
@ -150,7 +150,12 @@ impl super::Extension for ShellExtension {
|
||||||
String::from("shell")
|
String::from("shell")
|
||||||
}
|
}
|
||||||
|
|
||||||
fn calculate(&self, params: &Mapping, args: &Vec<String>, vars: &HashMap<String, ExtensionResult>) -> Option<ExtensionResult> {
|
fn calculate(
|
||||||
|
&self,
|
||||||
|
params: &Mapping,
|
||||||
|
args: &Vec<String>,
|
||||||
|
vars: &HashMap<String, ExtensionResult>,
|
||||||
|
) -> Option<ExtensionResult> {
|
||||||
let cmd = params.get(&Value::from("cmd"));
|
let cmd = params.get(&Value::from("cmd"));
|
||||||
if cmd.is_none() {
|
if cmd.is_none() {
|
||||||
warn!("No 'cmd' parameter specified for shell variable");
|
warn!("No 'cmd' parameter specified for shell variable");
|
||||||
|
@ -260,9 +265,15 @@ mod tests {
|
||||||
assert!(output.is_some());
|
assert!(output.is_some());
|
||||||
|
|
||||||
if cfg!(target_os = "windows") {
|
if cfg!(target_os = "windows") {
|
||||||
assert_eq!(output.unwrap(), ExtensionResult::Single("hello world\r\n".to_owned()));
|
assert_eq!(
|
||||||
|
output.unwrap(),
|
||||||
|
ExtensionResult::Single("hello world\r\n".to_owned())
|
||||||
|
);
|
||||||
} else {
|
} else {
|
||||||
assert_eq!(output.unwrap(), ExtensionResult::Single("hello world\n".to_owned()));
|
assert_eq!(
|
||||||
|
output.unwrap(),
|
||||||
|
ExtensionResult::Single("hello world\n".to_owned())
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -275,7 +286,10 @@ mod tests {
|
||||||
let output = extension.calculate(¶ms, &vec![], &HashMap::new());
|
let output = extension.calculate(¶ms, &vec![], &HashMap::new());
|
||||||
|
|
||||||
assert!(output.is_some());
|
assert!(output.is_some());
|
||||||
assert_eq!(output.unwrap(), ExtensionResult::Single("hello world".to_owned()));
|
assert_eq!(
|
||||||
|
output.unwrap(),
|
||||||
|
ExtensionResult::Single("hello world".to_owned())
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -290,7 +304,10 @@ mod tests {
|
||||||
let output = extension.calculate(¶ms, &vec![], &HashMap::new());
|
let output = extension.calculate(¶ms, &vec![], &HashMap::new());
|
||||||
|
|
||||||
assert!(output.is_some());
|
assert!(output.is_some());
|
||||||
assert_eq!(output.unwrap(), ExtensionResult::Single("hello world".to_owned()));
|
assert_eq!(
|
||||||
|
output.unwrap(),
|
||||||
|
ExtensionResult::Single("hello world".to_owned())
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -303,7 +320,10 @@ mod tests {
|
||||||
let output = extension.calculate(¶ms, &vec![], &HashMap::new());
|
let output = extension.calculate(¶ms, &vec![], &HashMap::new());
|
||||||
|
|
||||||
assert!(output.is_some());
|
assert!(output.is_some());
|
||||||
assert_eq!(output.unwrap(), ExtensionResult::Single("hello world".to_owned()));
|
assert_eq!(
|
||||||
|
output.unwrap(),
|
||||||
|
ExtensionResult::Single("hello world".to_owned())
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -317,7 +337,10 @@ mod tests {
|
||||||
let output = extension.calculate(¶ms, &vec![], &HashMap::new());
|
let output = extension.calculate(¶ms, &vec![], &HashMap::new());
|
||||||
|
|
||||||
assert!(output.is_some());
|
assert!(output.is_some());
|
||||||
assert_eq!(output.unwrap(), ExtensionResult::Single("hello world".to_owned()));
|
assert_eq!(
|
||||||
|
output.unwrap(),
|
||||||
|
ExtensionResult::Single("hello world".to_owned())
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -354,13 +377,16 @@ mod tests {
|
||||||
if cfg!(target_os = "windows") {
|
if cfg!(target_os = "windows") {
|
||||||
params.insert(Value::from("cmd"), Value::from("echo %ESPANSO_VAR1%"));
|
params.insert(Value::from("cmd"), Value::from("echo %ESPANSO_VAR1%"));
|
||||||
params.insert(Value::from("shell"), Value::from("cmd"));
|
params.insert(Value::from("shell"), Value::from("cmd"));
|
||||||
}else{
|
} else {
|
||||||
params.insert(Value::from("cmd"), Value::from("echo $ESPANSO_VAR1"));
|
params.insert(Value::from("cmd"), Value::from("echo $ESPANSO_VAR1"));
|
||||||
}
|
}
|
||||||
|
|
||||||
let extension = ShellExtension::new();
|
let extension = ShellExtension::new();
|
||||||
let mut vars: HashMap<String, ExtensionResult> = HashMap::new();
|
let mut vars: HashMap<String, ExtensionResult> = HashMap::new();
|
||||||
vars.insert("var1".to_owned(), ExtensionResult::Single("hello".to_owned()));
|
vars.insert(
|
||||||
|
"var1".to_owned(),
|
||||||
|
ExtensionResult::Single("hello".to_owned()),
|
||||||
|
);
|
||||||
let output = extension.calculate(¶ms, &vec![], &vars);
|
let output = extension.calculate(¶ms, &vec![], &vars);
|
||||||
|
|
||||||
assert!(output.is_some());
|
assert!(output.is_some());
|
||||||
|
@ -373,7 +399,7 @@ mod tests {
|
||||||
if cfg!(target_os = "windows") {
|
if cfg!(target_os = "windows") {
|
||||||
params.insert(Value::from("cmd"), Value::from("echo %ESPANSO_FORM1_NAME%"));
|
params.insert(Value::from("cmd"), Value::from("echo %ESPANSO_FORM1_NAME%"));
|
||||||
params.insert(Value::from("shell"), Value::from("cmd"));
|
params.insert(Value::from("shell"), Value::from("cmd"));
|
||||||
}else{
|
} else {
|
||||||
params.insert(Value::from("cmd"), Value::from("echo $ESPANSO_FORM1_NAME"));
|
params.insert(Value::from("cmd"), Value::from("echo $ESPANSO_FORM1_NAME"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,8 +1,10 @@
|
||||||
|
use crate::extension::ExtensionResult;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::process::Command;
|
use std::process::Command;
|
||||||
use crate::extension::ExtensionResult;
|
|
||||||
|
|
||||||
pub fn convert_to_env_variables(original_vars: &HashMap<String, ExtensionResult>) -> HashMap<String, String> {
|
pub fn convert_to_env_variables(
|
||||||
|
original_vars: &HashMap<String, ExtensionResult>,
|
||||||
|
) -> HashMap<String, String> {
|
||||||
let mut output = HashMap::new();
|
let mut output = HashMap::new();
|
||||||
|
|
||||||
for (key, result) in original_vars.iter() {
|
for (key, result) in original_vars.iter() {
|
||||||
|
@ -10,13 +12,13 @@ pub fn convert_to_env_variables(original_vars: &HashMap<String, ExtensionResult>
|
||||||
ExtensionResult::Single(value) => {
|
ExtensionResult::Single(value) => {
|
||||||
let name = format!("ESPANSO_{}", key.to_uppercase());
|
let name = format!("ESPANSO_{}", key.to_uppercase());
|
||||||
output.insert(name, value.clone());
|
output.insert(name, value.clone());
|
||||||
},
|
}
|
||||||
ExtensionResult::Multiple(values) => {
|
ExtensionResult::Multiple(values) => {
|
||||||
for (sub_key, sub_value) in values.iter() {
|
for (sub_key, sub_value) in values.iter() {
|
||||||
let name = format!("ESPANSO_{}_{}", key.to_uppercase(), sub_key.to_uppercase());
|
let name = format!("ESPANSO_{}_{}", key.to_uppercase(), sub_key.to_uppercase());
|
||||||
output.insert(name, sub_value.clone());
|
output.insert(name, sub_value.clone());
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -36,7 +38,6 @@ pub fn set_command_flags(command: &mut Command) {
|
||||||
// NOOP on Linux and macOS
|
// NOOP on Linux and macOS
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
@ -49,11 +50,14 @@ mod tests {
|
||||||
subvars.insert("name".to_owned(), "John".to_owned());
|
subvars.insert("name".to_owned(), "John".to_owned());
|
||||||
subvars.insert("lastname".to_owned(), "Snow".to_owned());
|
subvars.insert("lastname".to_owned(), "Snow".to_owned());
|
||||||
vars.insert("form1".to_owned(), ExtensionResult::Multiple(subvars));
|
vars.insert("form1".to_owned(), ExtensionResult::Multiple(subvars));
|
||||||
vars.insert("var1".to_owned(), ExtensionResult::Single("test".to_owned()));
|
vars.insert(
|
||||||
|
"var1".to_owned(),
|
||||||
|
ExtensionResult::Single("test".to_owned()),
|
||||||
|
);
|
||||||
|
|
||||||
let output = convert_to_env_variables(&vars);
|
let output = convert_to_env_variables(&vars);
|
||||||
assert_eq!(output.get("ESPANSO_FORM1_NAME").unwrap(), "John");
|
assert_eq!(output.get("ESPANSO_FORM1_NAME").unwrap(), "John");
|
||||||
assert_eq!(output.get("ESPANSO_FORM1_LASTNAME").unwrap(), "Snow");
|
assert_eq!(output.get("ESPANSO_FORM1_LASTNAME").unwrap(), "Snow");
|
||||||
assert_eq!(output.get("ESPANSO_VAR1").unwrap(), "test");
|
assert_eq!(output.get("ESPANSO_VAR1").unwrap(), "test");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,9 +17,9 @@
|
||||||
* along with espanso. If not, see <https://www.gnu.org/licenses/>.
|
* along with espanso. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
use crate::extension::ExtensionResult;
|
||||||
use serde_yaml::{Mapping, Value};
|
use serde_yaml::{Mapping, Value};
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use crate::extension::ExtensionResult;
|
|
||||||
|
|
||||||
pub struct VarDummyExtension {}
|
pub struct VarDummyExtension {}
|
||||||
|
|
||||||
|
@ -34,7 +34,12 @@ impl super::Extension for VarDummyExtension {
|
||||||
"vardummy".to_owned()
|
"vardummy".to_owned()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn calculate(&self, params: &Mapping, _: &Vec<String>, vars: &HashMap<String, ExtensionResult>) -> Option<ExtensionResult> {
|
fn calculate(
|
||||||
|
&self,
|
||||||
|
params: &Mapping,
|
||||||
|
_: &Vec<String>,
|
||||||
|
vars: &HashMap<String, ExtensionResult>,
|
||||||
|
) -> Option<ExtensionResult> {
|
||||||
let target = params.get(&Value::from("target"));
|
let target = params.get(&Value::from("target"));
|
||||||
|
|
||||||
if let Some(target) = target {
|
if let Some(target) = target {
|
||||||
|
|
|
@ -20,7 +20,7 @@
|
||||||
use super::PasteShortcut;
|
use super::PasteShortcut;
|
||||||
use crate::bridge::macos::*;
|
use crate::bridge::macos::*;
|
||||||
use crate::config::Configs;
|
use crate::config::Configs;
|
||||||
use log::{error};
|
use log::error;
|
||||||
use std::ffi::CString;
|
use std::ffi::CString;
|
||||||
|
|
||||||
pub struct MacKeyboardManager {}
|
pub struct MacKeyboardManager {}
|
||||||
|
@ -78,12 +78,12 @@ impl super::KeyboardManager for MacKeyboardManager {
|
||||||
|
|
||||||
pub fn wait_for_modifiers_release() -> bool {
|
pub fn wait_for_modifiers_release() -> bool {
|
||||||
let start = std::time::SystemTime::now();
|
let start = std::time::SystemTime::now();
|
||||||
while start.elapsed().unwrap_or_default().as_millis() < 3000 {
|
while start.elapsed().unwrap_or_default().as_millis() < 3000 {
|
||||||
let pressed = unsafe { crate::bridge::macos::are_modifiers_pressed() };
|
let pressed = unsafe { crate::bridge::macos::are_modifiers_pressed() };
|
||||||
if pressed == 0 {
|
if pressed == 0 {
|
||||||
return true
|
return true;
|
||||||
}
|
}
|
||||||
std::thread::sleep(std::time::Duration::from_millis(100));
|
std::thread::sleep(std::time::Duration::from_millis(100));
|
||||||
}
|
}
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
|
18
src/main.rs
18
src/main.rs
|
@ -17,7 +17,7 @@
|
||||||
* along with espanso. If not, see <https://www.gnu.org/licenses/>.
|
* along with espanso. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#![cfg_attr(not(test), windows_subsystem = "windows")]
|
#![cfg_attr(not(test), windows_subsystem = "windows")]
|
||||||
|
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate lazy_static;
|
extern crate lazy_static;
|
||||||
|
@ -352,7 +352,7 @@ fn main() {
|
||||||
fn attach_console() {
|
fn attach_console() {
|
||||||
// When using the windows subsystem we loose the terminal output.
|
// When using the windows subsystem we loose the terminal output.
|
||||||
// Therefore we try to attach to the current console if available.
|
// Therefore we try to attach to the current console if available.
|
||||||
unsafe {winapi::um::wincon::AttachConsole(0xFFFFFFFF)};
|
unsafe { winapi::um::wincon::AttachConsole(0xFFFFFFFF) };
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(target_os = "windows"))]
|
#[cfg(not(target_os = "windows"))]
|
||||||
|
@ -582,8 +582,13 @@ fn watcher_background(sender: Sender<Event>) {
|
||||||
};
|
};
|
||||||
|
|
||||||
if let Some(path) = path {
|
if let Some(path) = path {
|
||||||
if path.extension().unwrap_or_default() == "yml" &&
|
if path.extension().unwrap_or_default() == "yml"
|
||||||
!path.file_name().unwrap_or_default().to_string_lossy().starts_with("."){
|
&& !path
|
||||||
|
.file_name()
|
||||||
|
.unwrap_or_default()
|
||||||
|
.to_string_lossy()
|
||||||
|
.starts_with(".")
|
||||||
|
{
|
||||||
// Only load non-hidden yml files
|
// Only load non-hidden yml files
|
||||||
true
|
true
|
||||||
} else {
|
} else {
|
||||||
|
@ -688,7 +693,10 @@ fn worker_background(
|
||||||
|
|
||||||
let keyboard_manager = keyboard::get_manager();
|
let keyboard_manager = keyboard::get_manager();
|
||||||
|
|
||||||
let extensions = extension::get_extensions(config_manager.default_config(), Box::new(clipboard::get_manager()));
|
let extensions = extension::get_extensions(
|
||||||
|
config_manager.default_config(),
|
||||||
|
Box::new(clipboard::get_manager()),
|
||||||
|
);
|
||||||
|
|
||||||
let renderer =
|
let renderer =
|
||||||
render::default::DefaultRenderer::new(extensions, config_manager.default_config().clone());
|
render::default::DefaultRenderer::new(extensions, config_manager.default_config().clone());
|
||||||
|
|
|
@ -75,7 +75,8 @@ impl<'de> serde::Deserialize<'de> for Match {
|
||||||
impl<'a> From<&'a AutoMatch> for Match {
|
impl<'a> From<&'a AutoMatch> for Match {
|
||||||
fn from(other: &'a AutoMatch) -> Self {
|
fn from(other: &'a AutoMatch) -> Self {
|
||||||
lazy_static! {
|
lazy_static! {
|
||||||
static ref VAR_REGEX: Regex = Regex::new("\\{\\{\\s*(\\w+)(\\.\\w+)?\\s*\\}\\}").unwrap();
|
static ref VAR_REGEX: Regex =
|
||||||
|
Regex::new("\\{\\{\\s*(\\w+)(\\.\\w+)?\\s*\\}\\}").unwrap();
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut triggers = if !other.triggers.is_empty() {
|
let mut triggers = if !other.triggers.is_empty() {
|
||||||
|
@ -145,14 +146,15 @@ impl<'a> From<&'a AutoMatch> for Match {
|
||||||
};
|
};
|
||||||
|
|
||||||
MatchContentType::Text(content)
|
MatchContentType::Text(content)
|
||||||
} else if let Some(form) = &other.form { // Form shorthand
|
} else if let Some(form) = &other.form {
|
||||||
|
// Form shorthand
|
||||||
// Replace all the form fields with actual variables
|
// Replace all the form fields with actual variables
|
||||||
let new_replace = VAR_REGEX.replace_all(&form, |caps: &Captures| {
|
let new_replace = VAR_REGEX.replace_all(&form, |caps: &Captures| {
|
||||||
let var_name = caps.get(1).unwrap().as_str();
|
let var_name = caps.get(1).unwrap().as_str();
|
||||||
format!("{{{{form1.{}}}}}", var_name)
|
format!("{{{{form1.{}}}}}", var_name)
|
||||||
});
|
});
|
||||||
let new_replace = new_replace.to_string();
|
let new_replace = new_replace.to_string();
|
||||||
|
|
||||||
// Convert the form data to valid variables
|
// Convert the form data to valid variables
|
||||||
let mut params = Mapping::new();
|
let mut params = Mapping::new();
|
||||||
if let Some(fields) = &other.form_fields {
|
if let Some(fields) = &other.form_fields {
|
||||||
|
@ -163,14 +165,12 @@ impl<'a> From<&'a AutoMatch> for Match {
|
||||||
params.insert(Value::from("fields"), Value::from(mapping_fields));
|
params.insert(Value::from("fields"), Value::from(mapping_fields));
|
||||||
}
|
}
|
||||||
params.insert(Value::from("layout"), Value::from(form.to_owned()));
|
params.insert(Value::from("layout"), Value::from(form.to_owned()));
|
||||||
|
|
||||||
let vars = vec![
|
let vars = vec![MatchVariable {
|
||||||
MatchVariable {
|
name: "form1".to_owned(),
|
||||||
name: "form1".to_owned(),
|
var_type: "form".to_owned(),
|
||||||
var_type: "form".to_owned(),
|
params,
|
||||||
params,
|
}];
|
||||||
}
|
|
||||||
];
|
|
||||||
|
|
||||||
let content = TextContent {
|
let content = TextContent {
|
||||||
replace: new_replace,
|
replace: new_replace,
|
||||||
|
@ -241,7 +241,7 @@ struct AutoMatch {
|
||||||
|
|
||||||
#[serde(default = "default_form")]
|
#[serde(default = "default_form")]
|
||||||
pub form: Option<String>,
|
pub form: Option<String>,
|
||||||
|
|
||||||
#[serde(default = "default_form_fields")]
|
#[serde(default = "default_form_fields")]
|
||||||
pub form_fields: Option<HashMap<String, Value>>,
|
pub form_fields: Option<HashMap<String, Value>>,
|
||||||
|
|
||||||
|
@ -603,20 +603,24 @@ mod tests {
|
||||||
match _match.content {
|
match _match.content {
|
||||||
MatchContentType::Text(content) => {
|
MatchContentType::Text(content) => {
|
||||||
let mut mapping = Mapping::new();
|
let mut mapping = Mapping::new();
|
||||||
mapping.insert(Value::from("layout"), Value::from("Hey {{name}}, how are you? {{greet}}"));
|
mapping.insert(
|
||||||
assert_eq!(content, TextContent {
|
Value::from("layout"),
|
||||||
replace: "Hey {{form1.name}}, how are you? {{form1.greet}}".to_owned(),
|
Value::from("Hey {{name}}, how are you? {{greet}}"),
|
||||||
_has_vars: true,
|
);
|
||||||
vars: vec![
|
assert_eq!(
|
||||||
MatchVariable {
|
content,
|
||||||
|
TextContent {
|
||||||
|
replace: "Hey {{form1.name}}, how are you? {{form1.greet}}".to_owned(),
|
||||||
|
_has_vars: true,
|
||||||
|
vars: vec![MatchVariable {
|
||||||
name: "form1".to_owned(),
|
name: "form1".to_owned(),
|
||||||
var_type: "form".to_owned(),
|
var_type: "form".to_owned(),
|
||||||
params: mapping,
|
params: mapping,
|
||||||
}
|
}]
|
||||||
]
|
}
|
||||||
});
|
);
|
||||||
},
|
}
|
||||||
_ => panic!("wrong content")
|
_ => panic!("wrong content"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -639,20 +643,24 @@ mod tests {
|
||||||
submapping.insert(Value::from("name"), Value::from(name_mapping));
|
submapping.insert(Value::from("name"), Value::from(name_mapping));
|
||||||
let mut mapping = Mapping::new();
|
let mut mapping = Mapping::new();
|
||||||
mapping.insert(Value::from("fields"), Value::from(submapping));
|
mapping.insert(Value::from("fields"), Value::from(submapping));
|
||||||
mapping.insert(Value::from("layout"), Value::from("Hey {{name}}, how are you? {{greet}}"));
|
mapping.insert(
|
||||||
assert_eq!(content, TextContent {
|
Value::from("layout"),
|
||||||
replace: "Hey {{form1.name}}, how are you? {{form1.greet}}".to_owned(),
|
Value::from("Hey {{name}}, how are you? {{greet}}"),
|
||||||
_has_vars: true,
|
);
|
||||||
vars: vec![
|
assert_eq!(
|
||||||
MatchVariable {
|
content,
|
||||||
|
TextContent {
|
||||||
|
replace: "Hey {{form1.name}}, how are you? {{form1.greet}}".to_owned(),
|
||||||
|
_has_vars: true,
|
||||||
|
vars: vec![MatchVariable {
|
||||||
name: "form1".to_owned(),
|
name: "form1".to_owned(),
|
||||||
var_type: "form".to_owned(),
|
var_type: "form".to_owned(),
|
||||||
params: mapping,
|
params: mapping,
|
||||||
}
|
}]
|
||||||
]
|
}
|
||||||
});
|
);
|
||||||
},
|
}
|
||||||
_ => panic!("wrong content")
|
_ => panic!("wrong content"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -106,7 +106,7 @@ impl<'a, R: MatchReceiver, M: ConfigManager<'a>> super::Matcher for ScrollingMat
|
||||||
.word_separators
|
.word_separators
|
||||||
.contains(&c.chars().nth(0).unwrap_or_default());
|
.contains(&c.chars().nth(0).unwrap_or_default());
|
||||||
|
|
||||||
let mut was_previous_char_a_match = self.was_previous_char_a_match.borrow_mut();
|
let mut was_previous_char_a_match = self.was_previous_char_a_match.borrow_mut();
|
||||||
(*was_previous_char_a_match) = false;
|
(*was_previous_char_a_match) = false;
|
||||||
|
|
||||||
let mut was_previous_word_separator = self.was_previous_char_word_separator.borrow_mut();
|
let mut was_previous_word_separator = self.was_previous_char_word_separator.borrow_mut();
|
||||||
|
@ -212,8 +212,7 @@ impl<'a, R: MatchReceiver, M: ConfigManager<'a>> super::Matcher for ScrollingMat
|
||||||
|
|
||||||
self.receiver
|
self.receiver
|
||||||
.on_match(mtc, trailing_separator, entry.trigger_offset);
|
.on_match(mtc, trailing_separator, entry.trigger_offset);
|
||||||
|
|
||||||
|
|
||||||
(*was_previous_char_a_match) = true;
|
(*was_previous_char_a_match) = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -221,7 +220,7 @@ impl<'a, R: MatchReceiver, M: ConfigManager<'a>> super::Matcher for ScrollingMat
|
||||||
fn handle_modifier(&self, m: KeyModifier) {
|
fn handle_modifier(&self, m: KeyModifier) {
|
||||||
let config = self.config_manager.default_config();
|
let config = self.config_manager.default_config();
|
||||||
|
|
||||||
let mut was_previous_char_a_match = self.was_previous_char_a_match.borrow_mut();
|
let mut was_previous_char_a_match = self.was_previous_char_a_match.borrow_mut();
|
||||||
|
|
||||||
// TODO: at the moment, activating the passive key triggers the toggle key
|
// TODO: at the moment, activating the passive key triggers the toggle key
|
||||||
// study a mechanism to avoid this problem
|
// study a mechanism to avoid this problem
|
||||||
|
@ -280,7 +279,7 @@ impl<'a, R: MatchReceiver, M: ConfigManager<'a>> super::Matcher for ScrollingMat
|
||||||
*was_previous_char_word_separator = true;
|
*was_previous_char_word_separator = true;
|
||||||
|
|
||||||
// Disable the "backspace undo" feature
|
// Disable the "backspace undo" feature
|
||||||
let mut was_previous_char_a_match = self.was_previous_char_a_match.borrow_mut();
|
let mut was_previous_char_a_match = self.was_previous_char_a_match.borrow_mut();
|
||||||
(*was_previous_char_a_match) = false;
|
(*was_previous_char_a_match) = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,7 +27,8 @@ use serde_yaml::Value;
|
||||||
use std::collections::{HashMap, HashSet};
|
use std::collections::{HashMap, HashSet};
|
||||||
|
|
||||||
lazy_static! {
|
lazy_static! {
|
||||||
static ref VAR_REGEX: Regex = Regex::new(r"\{\{\s*((?P<name>\w+)(\.(?P<subname>(\w+)))?)\s*\}\}").unwrap();
|
static ref VAR_REGEX: Regex =
|
||||||
|
Regex::new(r"\{\{\s*((?P<name>\w+)(\.(?P<subname>(\w+)))?)\s*\}\}").unwrap();
|
||||||
static ref UNKNOWN_VARIABLE: String = "".to_string();
|
static ref UNKNOWN_VARIABLE: String = "".to_string();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -95,9 +96,8 @@ impl super::Renderer for DefaultRenderer {
|
||||||
target_vars.insert(var_name.to_owned());
|
target_vars.insert(var_name.to_owned());
|
||||||
}
|
}
|
||||||
|
|
||||||
let match_variables: HashSet<&String> = content.vars.iter().map(|var| {
|
let match_variables: HashSet<&String> =
|
||||||
&var.name
|
content.vars.iter().map(|var| &var.name).collect();
|
||||||
}).collect();
|
|
||||||
|
|
||||||
// Find the global variables that are not specified in the var list
|
// Find the global variables that are not specified in the var list
|
||||||
let mut missing_globals = Vec::new();
|
let mut missing_globals = Vec::new();
|
||||||
|
@ -106,7 +106,7 @@ impl super::Renderer for DefaultRenderer {
|
||||||
if target_vars.contains(&global_var.name) {
|
if target_vars.contains(&global_var.name) {
|
||||||
if match_variables.contains(&global_var.name) {
|
if match_variables.contains(&global_var.name) {
|
||||||
specified_globals.insert(global_var.name.clone(), &global_var);
|
specified_globals.insert(global_var.name.clone(), &global_var);
|
||||||
}else {
|
} else {
|
||||||
missing_globals.push(global_var);
|
missing_globals.push(global_var);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -120,14 +120,18 @@ impl super::Renderer for DefaultRenderer {
|
||||||
variables.extend(&content.vars);
|
variables.extend(&content.vars);
|
||||||
|
|
||||||
// Replace variable type "global" with the actual reference
|
// Replace variable type "global" with the actual reference
|
||||||
let variables: Vec<&MatchVariable> = variables.into_iter().map(|variable| {
|
let variables: Vec<&MatchVariable> = variables
|
||||||
if variable.var_type == "global" {
|
.into_iter()
|
||||||
if let Some(actual_variable) = specified_globals.get(&variable.name) {
|
.map(|variable| {
|
||||||
return actual_variable.clone();
|
if variable.var_type == "global" {
|
||||||
|
if let Some(actual_variable) = specified_globals.get(&variable.name)
|
||||||
|
{
|
||||||
|
return actual_variable.clone();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
variable
|
||||||
variable
|
})
|
||||||
}).collect();
|
.collect();
|
||||||
|
|
||||||
let mut output_map: HashMap<String, ExtensionResult> = HashMap::new();
|
let mut output_map: HashMap<String, ExtensionResult> = HashMap::new();
|
||||||
|
|
||||||
|
@ -178,11 +182,15 @@ impl super::Renderer for DefaultRenderer {
|
||||||
// Normal extension variables
|
// Normal extension variables
|
||||||
let extension = self.extension_map.get(&variable.var_type);
|
let extension = self.extension_map.get(&variable.var_type);
|
||||||
if let Some(extension) = extension {
|
if let Some(extension) = extension {
|
||||||
let ext_out = extension.calculate(&variable.params, &args, &output_map);
|
let ext_out =
|
||||||
|
extension.calculate(&variable.params, &args, &output_map);
|
||||||
if let Some(output) = ext_out {
|
if let Some(output) = ext_out {
|
||||||
output_map.insert(variable.name.clone(), output);
|
output_map.insert(variable.name.clone(), output);
|
||||||
} else {
|
} else {
|
||||||
output_map.insert(variable.name.clone(), ExtensionResult::Single("".to_owned()));
|
output_map.insert(
|
||||||
|
variable.name.clone(),
|
||||||
|
ExtensionResult::Single("".to_owned()),
|
||||||
|
);
|
||||||
warn!(
|
warn!(
|
||||||
"Could not generate output for variable: {}",
|
"Could not generate output for variable: {}",
|
||||||
variable.name
|
variable.name
|
||||||
|
@ -202,28 +210,23 @@ impl super::Renderer for DefaultRenderer {
|
||||||
let var_name = caps.name("name").unwrap().as_str();
|
let var_name = caps.name("name").unwrap().as_str();
|
||||||
let var_subname = caps.name("subname");
|
let var_subname = caps.name("subname");
|
||||||
match output_map.get(var_name) {
|
match output_map.get(var_name) {
|
||||||
Some(result) => {
|
Some(result) => match result {
|
||||||
match result {
|
ExtensionResult::Single(output) => output,
|
||||||
ExtensionResult::Single(output) => {
|
ExtensionResult::Multiple(results) => match var_subname {
|
||||||
output
|
Some(var_subname) => {
|
||||||
},
|
let var_subname = var_subname.as_str();
|
||||||
ExtensionResult::Multiple(results) => {
|
results.get(var_subname).unwrap_or(&UNKNOWN_VARIABLE)
|
||||||
match var_subname {
|
}
|
||||||
Some(var_subname) => {
|
None => {
|
||||||
let var_subname = var_subname.as_str();
|
error!(
|
||||||
results.get(var_subname).unwrap_or(&UNKNOWN_VARIABLE)
|
"nested name missing from multi-value variable: {}",
|
||||||
},
|
var_name
|
||||||
None => {
|
);
|
||||||
error!("nested name missing from multi-value variable: {}", var_name);
|
&UNKNOWN_VARIABLE
|
||||||
&UNKNOWN_VARIABLE
|
}
|
||||||
},
|
},
|
||||||
}
|
|
||||||
},
|
|
||||||
}
|
|
||||||
},
|
|
||||||
None => {
|
|
||||||
&UNKNOWN_VARIABLE
|
|
||||||
},
|
},
|
||||||
|
None => &UNKNOWN_VARIABLE,
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -793,8 +796,6 @@ mod tests {
|
||||||
verify_render(rendered, "RESULT");
|
verify_render(rendered, "RESULT");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_render_variable_order() {
|
fn test_render_variable_order() {
|
||||||
let config = get_config_for(
|
let config = get_config_for(
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
use crate::config::Configs;
|
use crate::config::Configs;
|
||||||
use std::process::{Command, Child, Output};
|
|
||||||
use log::{error, info};
|
use log::{error, info};
|
||||||
use std::io::{Error, Write};
|
use std::io::{Error, Write};
|
||||||
|
use std::process::{Child, Command, Output};
|
||||||
|
|
||||||
pub mod form;
|
pub mod form;
|
||||||
|
|
||||||
|
@ -15,9 +15,10 @@ impl ModuloManager {
|
||||||
// Check if the `MODULO_PATH` env variable is configured
|
// Check if the `MODULO_PATH` env variable is configured
|
||||||
if let Some(_modulo_path) = std::env::var_os("MODULO_PATH") {
|
if let Some(_modulo_path) = std::env::var_os("MODULO_PATH") {
|
||||||
modulo_path = Some(_modulo_path.to_string_lossy().to_string())
|
modulo_path = Some(_modulo_path.to_string_lossy().to_string())
|
||||||
} else if let Some(ref _modulo_path) = config.modulo_path { // Check the configs
|
} else if let Some(ref _modulo_path) = config.modulo_path {
|
||||||
|
// Check the configs
|
||||||
modulo_path = Some(_modulo_path.to_owned());
|
modulo_path = Some(_modulo_path.to_owned());
|
||||||
}else{
|
} else {
|
||||||
// Check in the same directory of espanso
|
// Check in the same directory of espanso
|
||||||
if let Ok(exe_path) = std::env::current_exe() {
|
if let Ok(exe_path) = std::env::current_exe() {
|
||||||
if let Some(parent) = exe_path.parent() {
|
if let Some(parent) = exe_path.parent() {
|
||||||
|
@ -46,9 +47,7 @@ impl ModuloManager {
|
||||||
info!("Using modulo at {:?}", modulo_path);
|
info!("Using modulo at {:?}", modulo_path);
|
||||||
}
|
}
|
||||||
|
|
||||||
Self {
|
Self { modulo_path }
|
||||||
modulo_path,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_valid(&self) -> bool {
|
pub fn is_valid(&self) -> bool {
|
||||||
|
@ -97,26 +96,26 @@ impl ModuloManager {
|
||||||
}
|
}
|
||||||
|
|
||||||
return Some(output.to_string());
|
return Some(output.to_string());
|
||||||
},
|
}
|
||||||
Err(error) => {
|
Err(error) => {
|
||||||
error!("error while getting output from modulo: {}", error);
|
error!("error while getting output from modulo: {}", error);
|
||||||
},
|
}
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
Err(error) => {
|
Err(error) => {
|
||||||
error!("error while sending body to modulo");
|
error!("error while sending body to modulo");
|
||||||
},
|
}
|
||||||
}
|
}
|
||||||
}else{
|
} else {
|
||||||
error!("unable to open stdin to modulo");
|
error!("unable to open stdin to modulo");
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
Err(error) => {
|
Err(error) => {
|
||||||
error!("error reported when invoking modulo: {}", error);
|
error!("error reported when invoking modulo: {}", error);
|
||||||
},
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user