Add form translation
This commit is contained in:
parent
316ebbb502
commit
34e08e6ec8
|
@ -211,7 +211,7 @@ mod tests {
|
||||||
let mut params = Mapping::new();
|
let mut params = Mapping::new();
|
||||||
params.insert(
|
params.insert(
|
||||||
Value::from("args"),
|
Value::from("args"),
|
||||||
Value::from(vec!["echo", "$ESPANSO_VAR1 $ESPANSO_FORM1_NAME"]),
|
Value::from(vec!["bash", "-c", "echo $ESPANSO_VAR1 $ESPANSO_FORM1_NAME"]),
|
||||||
);
|
);
|
||||||
|
|
||||||
let mut vars: HashMap<String, ExtensionResult> = HashMap::new();
|
let mut vars: HashMap<String, ExtensionResult> = HashMap::new();
|
||||||
|
@ -221,9 +221,9 @@ mod tests {
|
||||||
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![]);
|
let output = extension.calculate(¶ms, &vec![], &vars);
|
||||||
|
|
||||||
assert!(output.is_some());
|
assert!(output.is_some());
|
||||||
assert_eq!(output.unwrap(), "hello Jon");
|
assert_eq!(output.unwrap(), ExtensionResult::Single("hello John".to_owned()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* This file is part of espanso.
|
* This file is part of espans{ name: (), var_type: (), params: ()}
|
||||||
*
|
*
|
||||||
* Copyright (C) 2019 Federico Terzi
|
* Copyright (C) 2019 Federico Terzi
|
||||||
*
|
*
|
||||||
|
@ -19,9 +19,10 @@
|
||||||
|
|
||||||
use crate::event::KeyEventReceiver;
|
use crate::event::KeyEventReceiver;
|
||||||
use crate::event::{KeyEvent, KeyModifier};
|
use crate::event::{KeyEvent, KeyModifier};
|
||||||
use regex::Regex;
|
use regex::{Captures, Regex};
|
||||||
use serde::{Deserialize, Deserializer, Serialize};
|
use serde::{Deserialize, Deserializer, Serialize};
|
||||||
use serde_yaml::Mapping;
|
use serde_yaml::{Mapping, Value};
|
||||||
|
use std::collections::HashMap;
|
||||||
use std::fs;
|
use std::fs;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
|
||||||
|
@ -47,7 +48,7 @@ pub enum MatchContentType {
|
||||||
Image(ImageContent),
|
Image(ImageContent),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Clone)]
|
#[derive(Debug, Serialize, Clone, PartialEq)]
|
||||||
pub struct TextContent {
|
pub struct TextContent {
|
||||||
pub replace: String,
|
pub replace: String,
|
||||||
pub vars: Vec<MatchVariable>,
|
pub vars: Vec<MatchVariable>,
|
||||||
|
@ -143,6 +144,40 @@ impl<'a> From<&'a AutoMatch> for Match {
|
||||||
_has_vars: has_vars,
|
_has_vars: has_vars,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
MatchContentType::Text(content)
|
||||||
|
} else if let Some(form) = &other.form { // Form shorthand
|
||||||
|
// Replace all the form fields with actual variables
|
||||||
|
let new_replace = VAR_REGEX.replace_all(&form, |caps: &Captures| {
|
||||||
|
let var_name = caps.get(1).unwrap().as_str();
|
||||||
|
format!("{{{{form1.{}}}}}", var_name)
|
||||||
|
});
|
||||||
|
let new_replace = new_replace.to_string();
|
||||||
|
|
||||||
|
// Convert the form data to valid variables
|
||||||
|
let mut params = Mapping::new();
|
||||||
|
if let Some(fields) = &other.form_fields {
|
||||||
|
let mut mapping_fields = Mapping::new();
|
||||||
|
fields.iter().for_each(|(key, value)| {
|
||||||
|
mapping_fields.insert(Value::from(key.to_owned()), Value::from(value.clone()));
|
||||||
|
});
|
||||||
|
params.insert(Value::from("fields"), Value::from(mapping_fields));
|
||||||
|
}
|
||||||
|
params.insert(Value::from("layout"), Value::from(form.to_owned()));
|
||||||
|
|
||||||
|
let vars = vec![
|
||||||
|
MatchVariable {
|
||||||
|
name: "form1".to_owned(),
|
||||||
|
var_type: "form".to_owned(),
|
||||||
|
params,
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
let content = TextContent {
|
||||||
|
replace: new_replace,
|
||||||
|
vars,
|
||||||
|
_has_vars: true,
|
||||||
|
};
|
||||||
|
|
||||||
MatchContentType::Text(content)
|
MatchContentType::Text(content)
|
||||||
} else if let Some(image_path) = &other.image_path {
|
} else if let Some(image_path) = &other.image_path {
|
||||||
// Image match
|
// Image match
|
||||||
|
@ -173,7 +208,7 @@ impl<'a> From<&'a AutoMatch> for Match {
|
||||||
|
|
||||||
MatchContentType::Image(content)
|
MatchContentType::Image(content)
|
||||||
} else {
|
} else {
|
||||||
eprintln!("ERROR: no action specified for match {}, please specify either 'replace' or 'image_path'", other.trigger);
|
eprintln!("ERROR: no action specified for match {}, please specify either 'replace', 'image_path' or 'form'", other.trigger);
|
||||||
std::process::exit(2);
|
std::process::exit(2);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -204,6 +239,12 @@ struct AutoMatch {
|
||||||
#[serde(default = "default_image_path")]
|
#[serde(default = "default_image_path")]
|
||||||
pub image_path: Option<String>,
|
pub image_path: Option<String>,
|
||||||
|
|
||||||
|
#[serde(default = "default_form")]
|
||||||
|
pub form: Option<String>,
|
||||||
|
|
||||||
|
#[serde(default = "default_form_fields")]
|
||||||
|
pub form_fields: Option<HashMap<String, Value>>,
|
||||||
|
|
||||||
#[serde(default = "default_vars")]
|
#[serde(default = "default_vars")]
|
||||||
pub vars: Vec<MatchVariable>,
|
pub vars: Vec<MatchVariable>,
|
||||||
|
|
||||||
|
@ -238,6 +279,12 @@ fn default_passive_only() -> bool {
|
||||||
fn default_replace() -> Option<String> {
|
fn default_replace() -> Option<String> {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
fn default_form() -> Option<String> {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
fn default_form_fields() -> Option<HashMap<String, Value>> {
|
||||||
|
None
|
||||||
|
}
|
||||||
fn default_image_path() -> Option<String> {
|
fn default_image_path() -> Option<String> {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
@ -248,7 +295,7 @@ fn default_force_clipboard() -> bool {
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Deserialize, Clone)]
|
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
|
||||||
pub struct MatchVariable {
|
pub struct MatchVariable {
|
||||||
pub name: String,
|
pub name: String,
|
||||||
|
|
||||||
|
@ -543,4 +590,68 @@ mod tests {
|
||||||
|
|
||||||
assert_eq!(_match.triggers, vec![":..", ":..", ":.."])
|
assert_eq!(_match.triggers, vec![":..", ":..", ":.."])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_match_form_translated_correctly() {
|
||||||
|
let match_str = r###"
|
||||||
|
trigger: ":test"
|
||||||
|
form: "Hey {{name}}, how are you? {{greet}}"
|
||||||
|
"###;
|
||||||
|
|
||||||
|
let _match: Match = serde_yaml::from_str(match_str).unwrap();
|
||||||
|
match _match.content {
|
||||||
|
MatchContentType::Text(content) => {
|
||||||
|
let mut mapping = Mapping::new();
|
||||||
|
mapping.insert(Value::from("layout"), Value::from("Hey {{name}}, how are you? {{greet}}"));
|
||||||
|
assert_eq!(content, TextContent {
|
||||||
|
replace: "Hey {{form1.name}}, how are you? {{form1.greet}}".to_owned(),
|
||||||
|
_has_vars: true,
|
||||||
|
vars: vec![
|
||||||
|
MatchVariable {
|
||||||
|
name: "form1".to_owned(),
|
||||||
|
var_type: "form".to_owned(),
|
||||||
|
params: mapping,
|
||||||
|
}
|
||||||
|
]
|
||||||
|
});
|
||||||
|
},
|
||||||
|
_ => panic!("wrong content")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_match_form_with_fields_translated_correctly() {
|
||||||
|
let match_str = r###"
|
||||||
|
trigger: ":test"
|
||||||
|
form: "Hey {{name}}, how are you? {{greet}}"
|
||||||
|
form_fields:
|
||||||
|
name:
|
||||||
|
multiline: true
|
||||||
|
"###;
|
||||||
|
|
||||||
|
let _match: Match = serde_yaml::from_str(match_str).unwrap();
|
||||||
|
match _match.content {
|
||||||
|
MatchContentType::Text(content) => {
|
||||||
|
let mut name_mapping = Mapping::new();
|
||||||
|
name_mapping.insert(Value::from("multiline"), Value::Bool(true));
|
||||||
|
let mut submapping = Mapping::new();
|
||||||
|
submapping.insert(Value::from("name"), Value::from(name_mapping));
|
||||||
|
let mut mapping = Mapping::new();
|
||||||
|
mapping.insert(Value::from("fields"), Value::from(submapping));
|
||||||
|
mapping.insert(Value::from("layout"), Value::from("Hey {{name}}, how are you? {{greet}}"));
|
||||||
|
assert_eq!(content, TextContent {
|
||||||
|
replace: "Hey {{form1.name}}, how are you? {{form1.greet}}".to_owned(),
|
||||||
|
_has_vars: true,
|
||||||
|
vars: vec![
|
||||||
|
MatchVariable {
|
||||||
|
name: "form1".to_owned(),
|
||||||
|
var_type: "form".to_owned(),
|
||||||
|
params: mapping,
|
||||||
|
}
|
||||||
|
]
|
||||||
|
});
|
||||||
|
},
|
||||||
|
_ => panic!("wrong content")
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use crate::config::Configs;
|
use crate::config::Configs;
|
||||||
use std::process::{Command, Child, Output};
|
use std::process::{Command, Child, Output};
|
||||||
use log::{error};
|
use log::{error, info};
|
||||||
use std::io::{Error, Write};
|
use std::io::{Error, Write};
|
||||||
|
|
||||||
pub mod form;
|
pub mod form;
|
||||||
|
@ -42,6 +42,10 @@ impl ModuloManager {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if let Some(ref modulo_path) = modulo_path {
|
||||||
|
info!("Using modulo at {:?}", modulo_path);
|
||||||
|
}
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
modulo_path,
|
modulo_path,
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user